summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorThomas Schmucker <ts@its1.de>2020-08-29 09:37:29 +0200
committerThomas Schmucker <ts@its1.de>2020-08-29 09:37:29 +0200
commit8b29decb942b2e598040d0fd8d01892796846833 (patch)
tree6ebeced94605461894c2e534df1f6b30fdf873e4 /doc
parentff35dcfa63088beb23e140932bbc28d541b6874c (diff)
downloadlibcsv-8b29decb942b2e598040d0fd8d01892796846833.tar.gz
libcsv-8b29decb942b2e598040d0fd8d01892796846833.tar.bz2
libcsv-8b29decb942b2e598040d0fd8d01892796846833.zip
Aktualisiere Dokumentation
Diffstat (limited to 'doc')
-rw-r--r--doc/csv.md94
1 files changed, 76 insertions, 18 deletions
diff --git a/doc/csv.md b/doc/csv.md
index ea775aa..ccbeba8 100644
--- a/doc/csv.md
+++ b/doc/csv.md
@@ -13,27 +13,27 @@ Kurz: suckless!
13 13
14## Schnellstart für Ungeduldige 14## Schnellstart für Ungeduldige
15 15
161\. Füge die beiden Dateien [csv.c](csv.c) und [csv.h](csv.h) Deinem C/C++ Projekt hinzu. 16**1\. Füge die beiden Dateien [csv.c](csv.c) und [csv.h](csv.h) Deinem C/C++ Projekt hinzu.**
17 17
182\. Inkludiere die Headerdatei `csv.h`. 18**2\. Inkludiere die Headerdatei `csv.h`:**
19 19
20~~~ 20~~~
21#include "csv.h" 21#include "csv.h"
22~~~ 22~~~
23 23
243\. Erstelle und initialisiere ein CSV-Objekt. 24**3\. Erstelle und initialisiere ein CSV-Objekt:**
25 25
26~~~ 26~~~
27csv_t csv = { 0 }; oder csv_t csv; 27csv_t csv = { 0 }; oder csv_t csv;
28 csv_init(&csv); 28 csv_init(&csv);
29~~~ 29~~~
30 30
314\. Verarbeite die CSV-Datei 31**4\. Verarbeite die CSV-Datei:**
32 32
33~~~ 33~~~
34for ( size_t nf; (nf = csv_read(&csv, in)) != 0; ) { /* eine Zeile aus `in` lesen */ 34for ( size_t nf; (nf = csv_read(&csv, in)) != 0; ) { /* eine Zeile aus `in` lesen */
35 for ( size_t i = 0; i != nf; i++ ) { /* `nf` beinhaltet die Feldanzahl */ 35 for ( size_t i = 0; i != nf; i++ ) { /* `nf` beinhaltet die Feldanzahl */
36 const char *s = csv_field(&csv, i); /* Feld `i` der gelesenen Zeile ansprechen */ 36 const char *s = csv_field(&csv, i); /* Feld `i` der gelesenen Zeile ansprechen */
37 /* ... */ 37 /* ... */
38 } 38 }
39} 39}
@@ -45,15 +45,16 @@ Es sind nur zwei Funktionen notwendig, um die Daten des FILE-Streams `in` vollst
45 45
46Der Speicher für das CSV-Objekt wird automatisch von `csv_read()` beim ersten Aufruf alloziert und wieder freigeben nachdem der Stream `in` vollständig gelesen wurde. 46Der Speicher für das CSV-Objekt wird automatisch von `csv_read()` beim ersten Aufruf alloziert und wieder freigeben nachdem der Stream `in` vollständig gelesen wurde.
47 47
48Mehr Arbeit ist nur noch dann notwendig, wenn eine Fehlerbehandlung zum Projekt hinzugefügt wird. Für die meisten einfachen Fälle reichen diese Schritte wahrscheinlich schon aus.
49
48## Motivation 50## Motivation
49 51
50Die meisten anderen CSV-Bibliotheken passen nicht: 52Die meisten anderen CSV-Bibliotheken passen nicht:
51 53
52- falsche Verarbeitung bei eingeklammerten Feldern: 54- falsche Verarbeitung bei eingeklammerten Feldern:
53 C++: `getline()` -> `stringstream` -> `getline()`; 55 C++: `getline()` -> `stringstream` -> `getline()`;
54 C: `fgets()` -> `strtok`() 56 C: `fgets()` -> `strtok()`
55 Irgendwelche regulären Ausdrücke 57- fehlerhafte Verarbeitung von "problematischen" CSV-Dateien (Zeilenumbrüche innerhalb einer Zelle)
56- fehlerhafte Verarbeitung von "problematischen" CSV-Dateien (Linebreaks innerhalb einer Zelle)
57- unvorteilhafte Lizenz (GPL) 58- unvorteilhafte Lizenz (GPL)
58- umständliche API (Callbacks zum Verarbeiten der Inhalte, seltsames Handling am Dateiende) 59- umständliche API (Callbacks zum Verarbeiten der Inhalte, seltsames Handling am Dateiende)
59- globale Variablen, die den Einsatz in Multi-Threadumgebungen unmöglich machen 60- globale Variablen, die den Einsatz in Multi-Threadumgebungen unmöglich machen
@@ -62,7 +63,7 @@ Die meisten anderen CSV-Bibliotheken passen nicht:
62- Langsam, Aufgebläht 63- Langsam, Aufgebläht
63- schlecht oder gar nicht anpassbar 64- schlecht oder gar nicht anpassbar
64 65
65=> Selber schreiben! 66Lösung: => Selber schreiben!
66 67
67## Tutorial 68## Tutorial
68 69
@@ -81,7 +82,7 @@ processFile(const char *filename)
81 return false; 82 return false;
82 } 83 }
83 84
84 // [ HIERHER KOMMT DER CSV-HANDLING CODE ] 85 // HIERHER KOMMT DER CSV-HANDLING CODE
85 86
86 fclose(in); 87 fclose(in);
87 return true; 88 return true;
@@ -103,13 +104,27 @@ csv_cleanup(&csv);
103 104
104Dieser Code erzeugt ein neues `csv_t`-Objekt im Speicher welches anschließend mit `csv_init()` mit Standardwerten initialisiert wird. 105Dieser Code erzeugt ein neues `csv_t`-Objekt im Speicher welches anschließend mit `csv_init()` mit Standardwerten initialisiert wird.
105 106
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. 107Dann wird der Datenstrom `in` zeilenweise in den Speicher eingelesen und innerhalb der Schleife verarbeitet. Die Anzahl der Felder pro Zeile wird mit Hilfe der Funktion `csv_nfields()` ermittelt. Alternativ liefert auch der Returnwert von `csv_read()` die Feldanzahl:
108
109~~~
110// ...
111size_t nf;
112while ( (nf = csv_read(&csv, in)) != 0 ) {
113 // ...
114}
115// ...
116~~~
117
118Der Rückgabewert 0 bei einem Aufruf von `csv_read()` kennzeichnet das Ende des Datenstroms.
119
120> **Hinweis:**
121> Das Ende einer CSV-Datei mit 0-gelesenen Feldern zu kennzeichnen ist vollkommen legitim. Eine "leere" Zeile innerhalb der Datei würde nämlich als genau ein (leeres) Feld interpretiert, so dass der Rückgabewert hier 1 wäre. Anders gesagt: Es gibt in CSV-Dateien keine Zeilen mit 0 Feldern.
107 122
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. 123Der 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 124
110**2\. Optionen einstellen** 125**2\. Optionen einstellen**
111 126
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. 127Wenn 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 (`;`) zum Trennen der einzelnen Felder.
113 128
114Wir berücksichtigen dies bei der Initialisierung eines `csv_options_t`-Objektes. 129Wir berücksichtigen dies bei der Initialisierung eines `csv_options_t`-Objektes.
115 130
@@ -122,7 +137,7 @@ csv_t csv;
122csv_init_opt(&csv, &csv_options); 137csv_init_opt(&csv, &csv_options);
123~~~ 138~~~
124 139
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`. 140Damit wir nicht alle Felder in `csv_options` ändern müssen, initialisieren wir dieses zunächst mit `csv_default_options` und passen dann `field_delimiter` und `field_separator` an. Das `csv`-Objekt wird nun mit der Funktion `csv_init_opt()` initialisiert, die einen zusätzlichen Zeiger auf ein `csv_options_t`-Objekt erwartet.
126 141
127> **Hinweis:** 142> **Hinweis:**
128> `csv_init(&csv);` ist letztlich nur eine kürzere Schreibweise für `csv_init_opt(&csv, &csv_default_options);`. 143> `csv_init(&csv);` ist letztlich nur eine kürzere Schreibweise für `csv_init_opt(&csv, &csv_default_options);`.
@@ -131,8 +146,7 @@ Der Rest der Schleife bleibt gleich.
131 146
132**3\. Fehlerbehandlung hinzufügen** 147**3\. Fehlerbehandlung hinzufügen**
133 148
134Bei der Verarbeitung können verschiedene Fehler auftreten, die ein robustes Programm selbstverständlich behandelt. 149Bei der Verarbeitung können verschiedene Fehler auftreten, die ein robustes Programm selbstverständlich behandelt. Leider stellt die Programmiersprache C keinen Exception-Mechanismus zur Verfügung, so dass sich der Programmierer an dieser Stelle anders behelfen muss.
135Leider stellt die Programmiersprache C keinen Exception-Mechanismus zur Verfügung, so dass sich der Programmierer an dieser Stelle anders behelfen muss.
136 150
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: 151Die 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 152
@@ -246,18 +260,44 @@ void csv_init(csv_t *csv);
246void csv_init_opt(csv_t *csv, const csv_options_t *const csv_options); 260void csv_init_opt(csv_t *csv, const csv_options_t *const csv_options);
247~~~ 261~~~
248 262
263Initialisiert ein `csv_t`-Objekt.
264
265Parameter
266: **`csv`** ein Zeiger vom Typ `csv_t`.
267: **`csv_options`** ein Zeiger vom Typ `csv_options_t`
268
269`csv_init(&c);` ist eine kürzere Schreibweise für `csv_init_opt(&c, &csv_csv_default_options);`
270
271Mit der Funktion `csv_init_opt()` und einem angepassten `csv_options_t`-Objektes kann das Verhalten des CSV-Parsers zur Laufzeit parametrisiert werden.
272
249**Manuelles Freigeben** 273**Manuelles Freigeben**
250 274
251~~~ 275~~~
252void csv_cleanup(csv_t *csv); 276void csv_cleanup(csv_t *csv);
253~~~ 277~~~
254 278
279Gibt den belegten Speicher eines `csv_t`-Objektes wieder frei.
280
281Parameter
282: **`csv`** ein Zeiger initialisiertes `csv_t`-Objekt.
283
284`csv_cleanup()` gibt den verwendeten Speicher des csv-Objektes wieder frei. Ein direkter Aufruf dieser Funktion ist nur im Fehlerfall notwendig weil dann die automatische Speicherfreigabe der Bibliothek nicht greift.
285
255**Zeilenweises Lesen** 286**Zeilenweises Lesen**
256 287
257~~~ 288~~~
258size_t csv_read(csv_t *csv, FILE *in); 289size_t csv_read(csv_t *csv, FILE *in);
259~~~ 290~~~
260 291
292Liest einen Datensatz aus dem FILE-Stream, speichert das Ergebnis in `csv` und liefert die Anzahl der gefundenen Felder zurück.
293
294Parameter
295: **`csv`** ein Zeiger initialisiertes `csv_t`-Objekt.
296: **`in`** ein Zeiger auf einen geöffneten C-FILE-Stream.
297
298Rückgabe
299: Anzahl der gelesenen CSV-Felder einer Zeile oder 0 bei Dateiende.
300
261**Feldzugriff** 301**Feldzugriff**
262 302
263~~~ 303~~~
@@ -265,19 +305,37 @@ size_t csv_nfields(const csv_t *const csv);
265const char *csv_field(const csv_t *const csv, size_t idx); 305const char *csv_field(const csv_t *const csv, size_t idx);
266~~~ 306~~~
267 307
308Die beiden Funktionen ermöglichen einen Zugriff auf die einzelnen Felder des zuletzt gelesenen Datensatzes.
309
310Parameter
311: **`csv`** ein Zeiger initialisiertes `csv_t`-Objekt.
312: **`idx`** Index des zu lesenden Feldes. (0 <= idx < `csv_nfields(&csv)`)
313
314Rückgabe
315: `csv_nfields()` liefert die Anzahl der Felder des zuletzt gelesenen Datensatzes.
316: `csv_field()` liefert einen Zeiger auf das Feld `idx` des zuletzt gelesenen Datensatzes.
317
268**Fehlercodes als Textmeldung** 318**Fehlercodes als Textmeldung**
269 319
270~~~ 320~~~
271const char *csv_err_str(csv_err_t csv_err); 321const char *csv_err_str(csv_err_t csv_err);
272~~~ 322~~~
273 323
324Liefere eine textuelle Meldung zum Fehlercode `csv_err`.
325
326Parameter
327: **`csv_err`** ein Fehlercode vom Typ `csv_err_t`.
328
329Rückgabe
330: Zeiger auf die entspreche Fehlermeldung.
331
274## Anpassungen 332## Anpassungen
275 333
276Die CSV-Bibliothek kann an verschiedene Bedürfnisse angepasst werden. 334Die CSV-Bibliothek kann an verschiedene Bedürfnisse angepasst werden.
277 335
278### Übersetzungsoptionen 336### Übersetzungsoptionen
279 337
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. 338Beim 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.
281 339
282Option Beschreibung Standardwert 340Option Beschreibung Standardwert
283-------------------------- -------------- --------------------------------- 341-------------------------- -------------- ---------------------------------
@@ -286,7 +344,7 @@ Option Beschreibung Standardwert
286-------------------------- -------------- --------------------------------- 344-------------------------- -------------- ---------------------------------
287Table: Makros 345Table: Makros
288 346
289Soll beispielsweise das in Deutschland viel häufiger vorkommende Semikolon (`;`) statt einem Komma (`,`) als Trennsymbol zwischen den Feldern einer CSV-Datei benutzt werden sieht der Aufruf zum Compilieren so aus: 347Soll beispielsweise das in Deutschland viel häufiger vorkommende Semikolon (`;`) statt einem Komma (`,`) standardmäßig als Trennsymbol zwischen den Feldern einer CSV-Datei benutzt werden sieht der Aufruf zum Compilieren so aus:
290 348
291~~~ 349~~~
292cc -DCSV_DEFAULT_SEPARATOR="';'" -o csv-german.o -c csv.c 350cc -DCSV_DEFAULT_SEPARATOR="';'" -o csv-german.o -c csv.c