[Projektgestaltung] .ini Parser
-
Pyro Phoenix schrieb:
Struktur? Bitte mal genauer erläutern.
Also es gibt die
;Kommentar [Sektion] ;Kommentar Schlüssel=Wert
Struktur.
Also ich dachte mir, das man per Funktion ( sektion, schlüssel ) den
entsprechenden Wert herausfinden kann.Ja, davon rede ich die ganze Zeit. Diesen Aufbau mußt du auf sinnvolle Art in den RAM übertragen (den gesamten Dateiinhalt binär in den Speicher zu schreiben, ist i.a. nicht sinnvoll).
Eine Möglichkeit wäre es, Schlüssel-Einträge als Paar von Strings, Sektionen als Liste/Array/whatever von Schlüsseleinträgen (und evt. Kommentaren) und das gesamte INI-File als eine Liste/Array/whatever von Sektionen darzustellen.
-
Ich hab da ein kleines Problem:
error C2440: '=' : 'struct CIniParser::section *' kann nicht in 'struct section *' konvertiert werden
class CIniParser { private: typedef struct section * s_node; typedef struct key_value * kv_node; typedef struct section { char *sectionname; s_node next; s_node prev; kv_node first; kv_node last; }; typedef struct kev_value { char *key; char *value; kv_node next; kv_node prev; s_node member; }; int p_buffer; struct section *root; struct section *actv; struct section *prev; int getSection ( char *name ); int getTopic ( char *key, char *value ); public: CIniParser ( char *c_file ); ~CIniParser (); }; #endif
Bei:
prev->next = actv;
Ich bin grad zu verpeilt um selber rauszufinden worans liegt ...
-
"class", "private"? Bist du sicher, daß das immer noch C ist?
Ansonsten: Was soll ein typedef bringen, wenn du dem Typ dabei keinen Namen gibst?
-
Ich habs in ne class gepackt. Alles in einer Datei war mir zu unübersichtlich.
Naja hab das Problem jetz gelöst, indem ich die structs ausserhalb der Klasse
definiere.
-
Pyro Phoenix schrieb:
Ich habs in ne class gepackt. Alles in einer Datei war mir zu unübersichtlich.
Darauf wollte ich gar nicht hinaus - ich wollte dich nur darauf hinweisen, daß "class" in C nicht existiert. Und wenn du sowieso schon C++ verwendest, dann gleich richtig
-
Nächtes mal vielleicht ^^
Wie gesagt, man soll mit den grundlagen anfangen.Hab jetz aber ein anderes Problem, dessen Lösung mir nicht bekannt ist.
typedef struct key_value * kv_node; typedef struct section * s_node; struct section { char *sectionname; s_node next; s_node prev; kv_node first; kv_node last; }; struct kev_value { char *key; char *value; kv_node next; kv_node prev; s_node member; }; class CIniParser { private: struct section *root; struct section *actvs; struct section *prevs; struct key_value *actvkv; struct key_value *prevkv;
actvkv = new key_value;
ergibt:
error C2512: 'key_value' : Kein geeigneter Standardkonstruktor verfuegbar
wobei jedoch:
actvs = new section;
keine probleme verursacht.
-
Pyro Phoenix schrieb:
actvkv = new key_value;
ergibt:
error C2512: 'key_value' : Kein geeigneter Standardkonstruktor verfuegbar
nimm 'malloc' für structs.
-
Womit wir bei einer bunten Mischung aus C- und C++ Code wären - sowas ist weder besonders gut wartbar noch wirklich praktikabel. Entweder du nutzt reinen C++ Code oder reines C, aber bitte entscheide dich.
-
actvkv = (key_value *)malloc ( sizeof( key_value ) );
ergibt:
error C2027: Verwendung des undefinierten Typs "key_value" Siehe Deklaration von 'key_value'
-
Du musst halt auch lesen, was CStoll zu deinen typedefs sagt. Probiers mit:
actvkv = (struct key_value *)malloc ( sizeof( struct key_value ) );
Allerdings ist die malloc-Vergipsung schon wieder so eine Hybridformulierung. Das einzige, was dafür spricht, ist daß es in C und C++ so läuft. In C99 sollte man das ohne Cast machen, in C++ mit static Casts. Kann dir egal sein, aber ich weise darauf hin.
-
Ergibt selbes Problem.
error C2027: Verwendung des undefinierten Typs "key_value" Siehe Deklaration von 'key_value'
-
Auch auf die Gefahr hin, mich zu wiederholen: bitte verwende keinen Sprachen-Mischmasch.
(ansonsten solltest du mal etwas zusammenhängenderen Code vorführen, um das Problem zu erläutern - solche Probleme wie "Verwendung des undefinierten Typs ..." entstehen meist, weil nur eine Forward Deklaration dort steht, wo der Compiler eine vollständige Definition benötigt.
-
Sry. Ich dachte, das sei eher unproblematisch C und C++ zu vermischen.
parser.h
#ifndef INIPARSER_H #define INIPARSER_H typedef struct key_value * kv_node; typedef struct section * s_node; struct section { char *sectionname; s_node next; s_node prev; kv_node first; kv_node last; }; struct kev_value { char *key; char *value; kv_node next; kv_node prev; s_node member; }; class CIniParser { private: struct section *root; struct section *actvs; struct section *prevs; struct key_value *actvkv; struct key_value *prevkv; int getSection ( char *name ); int getTopic ( char *key, char *value ); public: CIniParser ( char *c_file ); ~CIniParser (); }; #endif
parser.cpp
#include <stdio.h> #include <malloc.h> #include "../tools/tools.h" // für sizeOfFile (); #include "parser.h" CIniParser::CIniParser ( char *c_file ) { root = NULL; actvs = NULL; actvkv = NULL; FILE *p_iniFile = NULL; // actvkv = new key_value; if ( ( p_iniFile = fopen ( c_file, "r" ) ) == NULL ) { this.~CIniParser (); } /* actvs = root; do { printf ( "%s\n", actvs->sectionname ); actvs = actvs->next; } while ( actvs != NULL ); getchar();*/ }; CIniParser::~CIniParser () { }; CIniParser::getSection ( char *name ) { if ( root == NULL ) { root = (section *)malloc ( sizeof( section ) ); actvs = root; root->first = NULL; root->last = NULL; root->next = NULL; root->prev = NULL; root->sectionname = name; return 0; } else { prevs = actvs; actvs = (section *)malloc ( sizeof( section ) ); prevs->next = actvs; actvs->first = NULL; actvs->last = NULL; actvs->next = NULL; actvs->prev = prevs; actvs->sectionname = name; return 0; } return 1; }; CIniParser::getTopic ( char *key, char *value ) { if ( root->first == NULL ) { actvkv = (key_value *)malloc ( sizeof( struct key_value ) ); return 0; } else { return 0; } return 1; };
-
Es ist vielleicht möglich, aber es ist verdammt schlechter Stil. Und mit C++ Mitteln kommst du idR wesentlich einfacher zum Ziel.
Ansonsten zu deinem Programm:
- in C++ ist es nicht mehr nötig "struct" vor deine Datentypen zu schreiben
- ein Destruktor sollte nur unter bestimmten Umständen von Hand aufgerufen werden (prinzipiell nur, wenn du dein Objekt mit placement new erzeugt hast). Wenn du es nicht schaffst, dein Objekt zu konstruieren, kannst du entweder eine Exception werfen oder dich in einen "hier geht nichts" Status setzen.
- wer kümmert sich eigentlich darum, deinen Speicher wieder freizugeben?
- und last, but not least: Wo genau tritt der Fehler auf?
-
Pyro Phoenix schrieb:
Sry. Ich dachte, das sei eher unproblematisch C und C++ zu vermischen.
die syntaxen beider sprachen ist sich sehr änhlich, aber damit hat sich's dann auch schon. mit mischen kommst du auf kurz oder lang in teufels küche.
-
CStoll schrieb:
- und last, but not least: Wo genau tritt der Fehler auf?
Zeile 76 (parser.cpp)
-
Ohohoho ...
Ihr habt nen Arschtitt bei mir gut ...
Ein typo in Linie 17 ( parser.h )
v anstatt y
-
warum tust du dir den malloc krempel an, wenn du sowieso nen c++ compiler verwenden musst?
-
Darum.
So:
getSection ( char *name ) { if ( root == NULL ) { root = (section *)malloc ( sizeof( section ) ); // Neues Sektions-Objekt bereitstellen. actvs = root; // Aktive Sektion = root root->first = NULL; root->last = NULL; root->next = NULL; root->prev = NULL; root->sectionname = name; // Name zuweisen. prevs = actvs; // Fertig. Vorherige Sektion = Aktive Sektion. return 0; } else { actvs = (section *)malloc ( sizeof( section ) ); // Neues Sektions-Objekt bereitstellen. prevs->next = actvs; // Neue Sektion mit der vorherigen Sektion verlinken. actvs->first = NULL; actvs->last = NULL; actvs->next = NULL; actvs->prev = prevs; // Vorherige Sektion in der neuen Sektion verlinken. actvs->sectionname = name; // Name zuweisen. prevs = actvs; // Fertig. Vorherige Sektion = aktive Sektion. return 0; } return 1; };
getTopic ( char *key, char *value ) { if ( actvs->first == NULL ) { actvkv = (key_value *)malloc ( sizeof( struct key_value ) ); // Neues Key-Value-Objekt bereitstellen. actvs->first = actvkv; // Erstes Key-Value-Objekt mit aktiver Sektion verlinken actvkv->member = actvs; // KV-Objekt ist Member der aktiven Sektion. actvkv->key = key; actvkv->value = value; actvkv->prev = NULL; actvkv->next = NULL; prevkv = actvkv; // Fertig. Vorheriges KV-Objekt = aktives KV-Objekt. return 0; } else { actvkv = (key_value *)malloc ( sizeof( struct key_value ) ); // Neues KV-Objekt bereitstellen. prevkv->next = actvkv; // Aktives KV-Objekt im vorherigen verlinken. actvkv->member = actvs; // KV-Objekt ist Member der aktiven Sektion. actvkv->key = key; actvkv->value = value; actvkv->prev = prevkv; // Vorheriges KV-Objekt im aktuellen verlinken. actvkv->next = NULL; prevkv = actvkv; // Fertig. Vorheriges KV-Objekt = aktives KV-Objekt. return 0; } return 1; };
Funktioniert 1A ... Jetzt wag ich mich mal an den Parser selbst.