aboutsummaryrefslogtreecommitdiff
path: root/doc/csv.md
diff options
context:
space:
mode:
Diffstat (limited to 'doc/csv.md')
-rw-r--r--doc/csv.md142
1 files changed, 127 insertions, 15 deletions
diff --git a/doc/csv.md b/doc/csv.md
index cfdd8ee..ea775aa 100644
--- a/doc/csv.md
+++ b/doc/csv.md
@@ -66,7 +66,132 @@ Die meisten anderen CSV-Bibliotheken passen nicht:
66 66
67## Tutorial 67## Tutorial
68 68
69to be written 69**1\. Ausgangspunkt: ein Grundgerüst**
70
71Nehmen wir an, wir schreiben eine Funktion zur CSV-Verarbeitung.
72Das Grundgerüst sieht dann etwa so aus:
73
74~~~
75bool
76processFile(const char *filename)
77{
78 FILE *in;
79
80 if ( (in = fopen(filename, "r")) == NULL ) {
81 return false;
82 }
83
84 // [ HIERHER KOMMT DER CSV-HANDLING CODE ]
85
86 fclose(in);
87 return true;
88}
89~~~
90
91Wir fügen als erstes etwas Code hinzu:
92
93~~~
94csv_t csv;
95csv_init(&csv);
96
97while ( csv_read(&csv, in) ) {
98 const size_t nf = csv_nfields(&csv);
99 // ...
100}
101csv_cleanup(&csv);
102~~~
103
104Dieser Code erzeugt ein neues `csv_t`-Objekt im Speicher welches anschließend mit `csv_init()` mit Standardwerten initialisiert wird.
105
106Dann wird der Datenstrom `in` zeilenweise in den Speicher eingelesen und innerhalb der Schleife verarbeitet. Die Anzahl der Felder pro Zeile wird in der Schleife mit Hilfe der Funktion `csv_nfields()` ermittelt. Alternativ liefert auch der Returnwert des vorherigen `csv_read()`-Aufrufs die Feldanzahl.
107
108Der Aufruf von `csv_cleanup()` ist nicht zwingend notwendig, da alle belegten Ressourcen beim letzten `csv_read()` automatisch freigegeben werden, wenn es keinen Fehler bei der Dateiverarbeitung gab.
109
110**2\. Optionen einstellen**
111
112Wenn nichts weiter angegeben ist, gehen wir von einem Komma (`,`) als Feldtrenner sowie doppelten Anführungszeichen (`"`) als Feldbegrenzer aus. Die meisten CSV-Dateien im deutschsprachigen Raum verwenden jedoch ein Semikolon (`;`) als Feldtrenner.
113
114Wir berücksichtigen dies bei der Initialisierung eines `csv_options_t`-Objektes.
115
116~~~
117csv_options_t csv_options = csv_default_options;
118csv_options.field_delimiter = '"';
119csv_options.field_separator = ',';
120
121csv_t csv;
122csv_init_opt(&csv, &csv_options);
123~~~
124
125Das `csv`-Objekt wird nun mit der Funktion `csv_init_opt()` initialisiert, die einen zusätzlichen Zeiger auf ein `csv_options_t`-Objekt erwartet. Damit wir nicht alle Felder von `csv_options` ändern müssen, initialisieren wir dieses zunächst mit `csv_default_options`.
126
127> **Hinweis:**
128> `csv_init(&csv);` ist letztlich nur eine kürzere Schreibweise für `csv_init_opt(&csv, &csv_default_options);`.
129
130Der Rest der Schleife bleibt gleich.
131
132**3\. Fehlerbehandlung hinzufügen**
133
134Bei der Verarbeitung können verschiedene Fehler auftreten, die ein robustes Programm selbstverständlich behandelt.
135Leider stellt die Programmiersprache C keinen Exception-Mechanismus zur Verfügung, so dass sich der Programmierer an dieser Stelle anders behelfen muss.
136
137Die beste Variante, die dem klassischen Exceptions am nächsten kommt, sind die beiden C-Funktionen `setjmp()` und `longjmp()`, mit deren Hilfe wir nun die Fehlerbehandlung umsetzen. Wir benötigen dafür die beiden Felder `cb_error` und `cb_error_arg` des `csv_options`-Objektes:
138
139~~~
140jmp_buf env;
141csv_options.cb_error = csvErrorHandler;
142csv_options.cb_error_arg = &env;
143~~~
144
145`cb_error` ist ein Zeiger auf eine Callback-Funktion, die im Falle eines Fehlers aus der CSV-Bibliothek heraus aufgerufen wird. Ihr werden ein Fehlerwert vom Typ `csv_err_t` sowie ein Zeiger auf benutzerdefinierte Daten -- in unserem Fall ein Zeiger auf eine `jmp_buf`-Variable -- mit übergeben:
146
147~~~
148static void
149csvErrorHandler(csv_err_t err, void *cb_arg)
150{
151 fprintf(stderr, "error while csv-processing: %s\n", csv_err_str(err));
152 longjmp(*((jmp_buf *) cb_arg), err);
153}
154~~~
155
156Mit Hilfe des Parameter `err` wird eine einfache Fehlermeldung protokolliert. Anschließend rufen wir `longjmp()` auf, damit die Fehlerbehandlung auf höherer Ebene fortgesetzt wird.
157
158Die Hauptschleife in unserer Funktion sieht nun so aus:
159
160~~~
161csv_options_t csv_options = csv_default_options;
162csv_options.field_delimiter = '"';
163csv_options.field_separator = ',';
164
165jmp_buf env;
166csv_options.cb_error = csvErrorHandler;
167csv_options.cb_error_arg = &env;
168
169csv_t csv;
170csv_init_opt(&csv, &csv_options);
171
172switch ( setjmp(env) ) {
173case CSV_ERR_OK:
174 while ( csv_read(&csv, in) ) {
175 const size_t nf = csv_nfields(&csv);
176 // ...
177 }
178 // kein csv_cleanup() notwendig weil die Datei an
179 // dieser Stelle vollständig verarbeitet wurde.
180 break;
181
182case CSV_ERR_OUT_OF_MEMORY:
183 csv_cleanup(&csv);
184 break;
185
186case CSV_ERR_OUT_OF_RANGE:
187 csv_cleanup(&csv);
188 break;
189
190case CSV_ERR_IO_READ:
191 csv_cleanup(&csv);
192 break;
193}
194~~~
70 195
71## API 196## API
72 197
@@ -110,7 +235,6 @@ typedef struct {
110 csv_options_t *csv_options; 235 csv_options_t *csv_options;
111 /* additional internal fields */ 236 /* additional internal fields */
112} csv_t; 237} csv_t;
113
114~~~ 238~~~
115 239
116### Funktionen 240### Funktionen
@@ -147,10 +271,6 @@ const char *csv_field(const csv_t *const csv, size_t idx);
147const char *csv_err_str(csv_err_t csv_err); 271const char *csv_err_str(csv_err_t csv_err);
148~~~ 272~~~
149 273
150## Fehlerbehandlung
151
152to be written
153
154## Anpassungen 274## Anpassungen
155 275
156Die CSV-Bibliothek kann an verschiedene Bedürfnisse angepasst werden. 276Die CSV-Bibliothek kann an verschiedene Bedürfnisse angepasst werden.
@@ -159,7 +279,7 @@ Die CSV-Bibliothek kann an verschiedene Bedürfnisse angepasst werden.
159 279
160Beim Compilieren der Datei csv.c können die Standardwerte für Feldbegrenzer und Feldtrenner als Makrodefinitionen `CSV_DEFAULT_DELIMITER` und `CSV_DEFAULT_SEPARATOR` voreingestellt werden. 280Beim Compilieren der Datei csv.c können die Standardwerte für Feldbegrenzer und Feldtrenner als Makrodefinitionen `CSV_DEFAULT_DELIMITER` und `CSV_DEFAULT_SEPARATOR` voreingestellt werden.
161 281
162Option Beschreibung Standardwert 282Option Beschreibung Standardwert
163-------------------------- -------------- --------------------------------- 283-------------------------- -------------- ---------------------------------
164`CSV_DEFAULT_DELIMITER` Feldbegrenzer `"` 284`CSV_DEFAULT_DELIMITER` Feldbegrenzer `"`
165`CSV_DEFAULT_SEPARATOR` Feldtrenner `,` 285`CSV_DEFAULT_SEPARATOR` Feldtrenner `,`
@@ -176,14 +296,6 @@ Anschließend wird die Datei `csv-german.o` statt `csv.o` zum Projekt dazugelink
176 296
177Die Headerdatei (`csv.h`) bleibt unverändert. 297Die Headerdatei (`csv.h`) bleibt unverändert.
178 298
179### Eigener Speicherallozierer
180
181to be written
182
183## Performance
184
185to be written
186
187## Lizenz 299## Lizenz
188 300
189In den letzten Jahrzehnten habe ich massiv vom Internet und seinen Inhalten profitiert. Ein gutes Stück meiner Kenntnisse und Fähigkeiten verdanke ich den vielen Foren, Webseiten, Newsgroups und Individuen die Informationen und Software kostenfrei und allgemein zugänglich bereitstellen. 301In den letzten Jahrzehnten habe ich massiv vom Internet und seinen Inhalten profitiert. Ein gutes Stück meiner Kenntnisse und Fähigkeiten verdanke ich den vielen Foren, Webseiten, Newsgroups und Individuen die Informationen und Software kostenfrei und allgemein zugänglich bereitstellen.