PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : CfgParser v2.0



blackberry
09.07.2009, 18:27
Mein zweiter Config-Parser. (der erste sollte hier irgendwo noch rumschwirren, ist aber schon relativ alt...)

Ich weiß es gibt Bibliotheken für soetwas, aber ich mache mir mein Zeug lieber selbst :)

Die Syntax ist wie folgt:

Kommentare:
... können ähnlich wie in PHP mit


/* C Stil */
// C++ Stil
# Perl Stil

eingeleitet werden.
Die Kommentare 2. und 3. werden mit einem Zeilenumbruch beendet.
1. wird durch */ beendet und kann theoretisch über mehrere Zeilen gehen.

Einträge:
... können wie folgt getätigt werden:
1 Bezeichner 1 = 123 Wert 123
Die blauen Zahlen bezeichnen mögliche Orte für Kommentare.
Dort können Kommentare stehen, müssen aber nicht.
An den Stellen, an denen nur eine eins steht ist nur ein Block-Kommentar möglich. Wo 123 steht, sind alle Kommentare möglich.
Die Bereiche nach dem "ist-gleich-Zeichen" (=) sind optional.

Das Bezeichner-Feld:
Hier stehen folgende Zeichen zur Verfügung:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX YZ0123456789_
Das heißt: a-z + A-Z + 0-9 + _ (Unterstrich)
Dieses Feld kann maximal 30 Zeichen lang sein.

Das Werte-Feld:
Hier werden 3 Typen unterschieden:


String / Zeichenkette
vorzeichenbehaftete Zahl (signed int)
Leer / Nichts

Ein String kann folgende Zeichen enthalten:

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX YZ0123456789^°!\"§$%&/()=?`´²³{[]}\\@€~|µüÜöÖäÄ+*#'-_.:,;<>\t\v\a\b\f
(C-Syntax: \t steht z.B. für einen Tabulator)
Er kann maximal 512 Bytes (1/2 KB) groß sein.

Will man Leerzeichen benutzen muss der String in einfachen bzw. doppelten Anführungszeichen (' bzw. ") stehen.

Eine Zahl kann entweder in oktaler, dezimaler, oder hexadezimaler Form angegeben werden.
Normalerweise wird die dezimale Form angenommen.
Um eine Oktalzahl zu schreiben wird der Zahl eine 0 vorausgestellt.
Um eine Hexadezimalzahl zu schreiben wird der Zahl ein 0x vorausgestellt.
Die Zahlen sind durch die Größe eines vorzeichenbehafteten Integers (signed int) begrenzt.
Hier einige Beispiele:

mydec = 1010
myhex = 0xBEEF
myoct = 044535

Ein leerer Eintrag wird erzeugt, indem man nach dem "ist-gleich-Zeichen" einen Zeilenumbruch einfügt, oder einen der folgenden Werte hinschreibt:
'', "", None, Empty, Null
Groß- bzw. Kleinschreibung wird hierbei nicht beachtet.

Benutzung:
Um den Parser benutzen zu können muss man cfgparser.c zu seinem Projekt hinzufügen und cfgparser.h inkludieren.
Anschließend ruft man die Funktion cfgp_parse auf.
Ihr übergibt man den Dateinamen als ersten und eine "Callback-Funktion" als zweiten Parameter.

Die "Callback-Funktion" besitzt folgenden Funktionsprototypen:

void cfgp_callback(char *name, void *value, int type)
Name ist hierbei der Bezeichner (siehe oben) und value ein Zeiger auf den Wert.
Von welchem Typ dieser Zeiger ist wird durch den Parameter type beschrieben.
Mögliche Werte für type sind:

#define CFGP_TYPE_INTEGER 0
#define CFGP_TYPE_STRING 1
#define CFGP_TYPE_EMPTY 2
(siehe cfgparser.h)

Im Fall von CFGP_TYPE_INTEGER ist value ein Zeiger auf einen signed int.
Für CFGP_TYPE_STRING ist value ein Zeiger auf einen char (char * - nicht char **).
Bei CFGP_TYPE_EMPTY ist value uninteressant und wird auf 0 gesetzt.

Der Rückgabewert von cfg_parse ist ein Integer, welcher im Erfolgsfall CFGP_SUCCESS (0) entspricht.
Ist ein Fehler vorhanden wird (FEHLERCODE | ZEILE) zurückgegeben (| = Bitweises einschließendes ODER).

Der Fehlercode kann mit dem Makro CFGP_ERROR_GET_CODE(x) extrahiert werden. Als Parameter wird der Rückgabewert angenommen.

Das Makro CFGP_ERROR_GET_LINE(x) nimmt ebenfalls den Rückgabewert von cfgp_parse als Parameter, gibt hingegen die Zeile zurück, in der der Fehler aufgetreten ist.

Ein Beispiel hierfür kann unten zusammen mit den anderen Sourcecodes gedownloadet werden.

PS: dieses Verfahren kann ab der Zeile 268435455 (0x0FFFFFFF) zu Fehlern führen, da sich dann die Zeilenzahl mit dem Fehlercode überlagert und diesen somit verfälscht.
Ich glaube jedoch nicht, dass jemand so große Dateien parsen wird.

Download Inhalt:
Der Download enthält folgende Dateien:


cfgparser.c - die Hauptsourcedatei
cfgparser.h - die Schnittstelle
CfgParser.dev - die Projektdatei für Dev-C++
CfgParserZustände.png - ein (unvollständiges) Zustandsdiagramm (Achtung: nicht aktuell)
main.cpp - ein Beispielprogramm, welches die Werte aus example.conf ausgibt
example.conf - eine Beispielkonfiguationsdatei - wird von main.cpp benötigt


Download:
http://bbsrc.incecx.net/cfgparser.rar <--- freundlicherweise zur Verfügung gestellt von cby (http://free-hack.com/member.php?u=75490)
MD5 Checksum: a9a287d027bcda29f05d6a4c6dcf6d8f *cfgparser.rar
Passwort: free-hack.com

Ich hoffe jemand kann das hier gebrauchen :)

PS: Feedback ist erwünscht - ich hab das Programm heute erst fertiggestellt, also wer lust hat kann gerne nach Bugs suchen.


mfG. BlackBerry

]=-antr4xx-=[
11.07.2009, 02:22
Echt cool dieses Programm, gefaellt mir von der Idee bis zur Umsetzung sehr gut.
Ich wuerde fast sagen, das ist das beste und brauchbarste was hier gepostet wurde. Und mal was anderes als diese C&P Stealer, Trojaner, Crypter, endlos-schleifen-messagebox etc.

Grosses Lob von meiner Seite.

ir0n
11.07.2009, 03:19
Hi.
Ich mache solche Sachen eigentlich auch immer ganz gerne selber.
Werde mir mal den Source anschauen, in C habe ich großen Vergleichs- und Analysekram eigentlich immer gemieden, da ich mit Strings nicht so wirklich klar kam :D
Solangsam wird's aber, danke :)

Achja, wie wäre es, wenn du die möglichkeit gibst, eine Überladung von cfg_parse zu erstellen die einen Zeiger einen vector<cfgStruct> aus der STL akzeptiert? Das fände ich irgendwie besser & einfacher ;)

Gruß

blackberry
11.07.2009, 16:38
Achja, wie wäre es, wenn du die möglichkeit gibst, eine Überladung von cfg_parse zu erstellen die einen Zeiger einen vector<cfgStruct> aus der STL akzeptiert? Das fände ich irgendwie besser & einfacher ;)

Das war zwar eigentlich nicht meine Absicht, aber da die Idee ja nicht so schlecht ist habe ich mich nochmal drangesetzt :)

Überladen habe ich die Funktion jedoch nicht, da man, wenn man es verwendet, ja sowieso nur eine Version davon verwenden würde, also habe ich den Code nur etwas modifiziert.

Der neue Funktionsprototyp der Funktion cfgp_parse lautet nun:

int cfgp_parse(char *, vector<cfgpStruct> *);cfgpStruct ist wie folgt definiert:

typedef struct cfgpStruct
{
int type;
char *name;
union
{
void *value;
char *valStr;
int *valInt;
};
};Die namenlose Union deshalb, um sich unnötiges Typecasting sparen zu können.

Beispiel Code (als main.cpp im Download enthalten):

#include <stdlib.h>
#include <stdio.h>
#include "cfgparser.h"


int main(int argc, char *argv[])
{
vector<cfgpStruct> vect;
int ret;
int i;

printf(
"BlackBerry's CFG Parser v2.0\n"
"----------------------------\n"
"\n"
);

ret = cfgp_parse("example.conf", &vect);
switch(CFGP_ERROR_GET_CODE(ret))
{
case CFGP_ERROR_INVALIDFILE:
puts("\nError: couldn't open 'example.conf'");
break;
case CFGP_ERROR_OUT_OF_MEM:
puts("\nError: out of memory / the file is too big");
break;
case CFGP_ERROR_INVALID_CHAR:
printf("\nSyntax-Error@%d: invalid character\n", CFGP_ERROR_GET_LINE(ret));
break;
case CFGP_ERROR_NAMETOOLONG:
printf("\nSyntax-Error@%d: a name or a value is too long for the buffer\n", CFGP_ERROR_GET_LINE(ret));
break;
case CFGP_ERROR_EMPTY_NAME:
printf("\nSyntax-Error@%d: the name must contain at least one character\n", CFGP_ERROR_GET_LINE(ret));
break;
case CFGP_ERROR_UNCLOSED_STR:
printf("\nSyntax-Error@%d: a stringliteral wasn't closed\n", CFGP_ERROR_GET_LINE(ret));
break;
case CFGP_ERROR_INVAL_ESCSEQ:
printf("\nSyntax-Error@%d: invalid escape-sequence\n", CFGP_ERROR_GET_LINE(ret));
break;
}

for(i = 0; i < vect.size(); i++)
{
printf("callbk: '%s' = ", vect[i].name);

switch(vect[i].type)
{
case CFGP_TYPE_INTEGER:
printf("%d\n", *vect[i].valInt);
break;
case CFGP_TYPE_STRING:
printf("'%s'\n", vect[i].valStr);
break;
case CFGP_TYPE_EMPTY:
printf("[EMPTY]\n");
break;
default:
printf("[UNKNOWN]\n");
}
}

getc(stdin);
return 0;
}

Da wegen dem Vector für jedes Element Speicherplatz reserviert wird (mit new), sollte man diesen bei großen Projekten mit delete wieder freigeben.

Download:
http://www.megaupload.com/?d=AKB4ECG1
Passwort: free-hack.com


mfG. BlackBerry

ir0n
11.07.2009, 22:01
Hi.
Ja, so gefällt mir dass doch gleich viel besser :)
Ich wusste gar nicht, dass es sowas wie `union` gibt, kann ich für eines meiner Projekte auch gut gebrauchen (auch ein Parser für KeyValues ;)).

Gruß