diff options
| author | Thomas Schmucker <ts@its1.de> | 2020-07-05 11:25:46 +0200 |
|---|---|---|
| committer | Thomas Schmucker <ts@its1.de> | 2020-07-05 11:25:46 +0200 |
| commit | 12b36ad95dc633648b6c93d7626e17a0016b4547 (patch) | |
| tree | c4fa5d915d19e9e165b7adc94c20c6d3338ba9a5 /csv.md | |
| parent | a0fc70b0c6b3860236e783a05aa5d70cfc831669 (diff) | |
| download | libcsv-12b36ad95dc633648b6c93d7626e17a0016b4547.tar.gz libcsv-12b36ad95dc633648b6c93d7626e17a0016b4547.tar.bz2 libcsv-12b36ad95dc633648b6c93d7626e17a0016b4547.zip | |
erster Versuch einer Dokumentation
Diffstat (limited to 'csv.md')
| -rw-r--r-- | csv.md | 197 |
1 files changed, 197 insertions, 0 deletions
| @@ -0,0 +1,197 @@ | |||
| 1 | # csv - CSV-Dateien parsen | ||
| 2 | |||
| 3 | - [x] korrekt | ||
| 4 | - [x] einfach | ||
| 5 | - [x] intuitiv | ||
| 6 | - [x] schnell | ||
| 7 | - [x] klein | ||
| 8 | - [x] erweiterbar | ||
| 9 | - [x] robust | ||
| 10 | - [x] einfachst mögliche Lizenz | ||
| 11 | |||
| 12 | Kurz: suckless! | ||
| 13 | |||
| 14 | ## Schnellstart für Ungeduldige | ||
| 15 | |||
| 16 | 1\. Füge die beiden Dateien [csv.c](csv.c) und [csv.h](csv.h) Deinem C/C++ Projekt hinzu. | ||
| 17 | |||
| 18 | 2\. Inkludiere die Headerdatei `csv.h`. | ||
| 19 | |||
| 20 | ~~~ | ||
| 21 | #include "csv.h" | ||
| 22 | ~~~ | ||
| 23 | |||
| 24 | 3\. Erstelle und initialisiere ein CSV-Objekt. | ||
| 25 | |||
| 26 | ~~~ | ||
| 27 | csv_t csv = { 0 }; | ||
| 28 | ~~~ | ||
| 29 | |||
| 30 | 4\. Verarbeite die CSV-Datei | ||
| 31 | |||
| 32 | ~~~ | ||
| 33 | for ( int nf; (nf = csv_read(&csv, in)) != EOF; ) { /* eine Zeile aus `in` lesen */ | ||
| 34 | for ( int i = 0; i < nf; i++ ) { /* `nf` beinhaltet die Feldanzahl */ | ||
| 35 | const char *s = csv_field(&csv, i); /* jedes Feld der Zeile ansprechen */ | ||
| 36 | /* ... */ | ||
| 37 | } | ||
| 38 | } | ||
| 39 | ~~~ | ||
| 40 | |||
| 41 | Es sind nur zwei Funktionen notwendig, um die Daten des FILE-Streams `in` vollständig zu verarbeiten: | ||
| 42 | `csv_read()` liest eine Zeile aus dem Parameter `in` und liefert die Anzahl der erfolgreich geparsten Felder oder **`EOF`** bei Dateiende. | ||
| 43 | `csv_field()` liefert einen (read only) `const char`-Zeiger für das i-te Feld. | ||
| 44 | |||
| 45 | Der Speicher für das CSV-Objekt wird automatisch von `csv_read()` beim ersten Aufruf alloziert und wieder freigeben wenn der Stream `in` vollständig gelesen wurde. | ||
| 46 | |||
| 47 | ## Motivation | ||
| 48 | |||
| 49 | Die meisten anderen CSV-Bibliotheken passen nicht: | ||
| 50 | |||
| 51 | - falsche Verarbeitung bei eingeklammerten Feldern: | ||
| 52 | C++: getline() -> stringstream -> getline(); | ||
| 53 | C: fgets() -> strtok() | ||
| 54 | - fehlerhafte Verarbeitung von "problematischen" CSV-Dateien (Linebreaks innerhalb einer Zelle) | ||
| 55 | - unvorteilhafte Lizenz (GPL) | ||
| 56 | - umständliche API (Callbacks zum Verarbeiten der Inhalte, seltsames Handling am Dateiende) | ||
| 57 | - globale Variablen, die den Einsatz in Multi-Threadumgebungen unmöglich machen | ||
| 58 | - C++ wenn ich C brauche | ||
| 59 | - Java/Python/Rust/Ruby/${YourLanguageHere} wenn ich C brauche | ||
| 60 | - Langsam, Aufgebläht | ||
| 61 | - schlecht oder gar nicht anpassbar | ||
| 62 | |||
| 63 | => Selber schreiben! | ||
| 64 | |||
| 65 | ## Tutorial | ||
| 66 | |||
| 67 | to be written | ||
| 68 | |||
| 69 | ## API | ||
| 70 | |||
| 71 | ### Typen | ||
| 72 | |||
| 73 | **Fehlercodes** für die Callbackhandler: | ||
| 74 | |||
| 75 | ~~~ | ||
| 76 | typedef enum { | ||
| 77 | CSV_ERR_OK = 0, | ||
| 78 | CSV_ERR_OUT_OF_MEMORY = -1, | ||
| 79 | CSV_ERR_OUT_OF_RANGE = -2, | ||
| 80 | CSV_ERR_IO_READ = -3, | ||
| 81 | CSV_ERR_IO_WRITE = -4 | ||
| 82 | } csv_err_t; | ||
| 83 | ~~~ | ||
| 84 | |||
| 85 | **Optionen** für das Parsen eines CSV-Streams: | ||
| 86 | |||
| 87 | ~~~ | ||
| 88 | typedef struct { | ||
| 89 | int field_delimiter; | ||
| 90 | int field_separator; | ||
| 91 | |||
| 92 | void (*cb_error)(csv_err_t, void *); | ||
| 93 | void *cb_error_arg; | ||
| 94 | |||
| 95 | void *(*cb_allocate)(size_t, size_t, void *); | ||
| 96 | void *(*cb_reallocate)(void *, size_t, size_t, void *); | ||
| 97 | void (*cb_free)(void *, size_t, size_t, void *); | ||
| 98 | void *cb_memory_arg; | ||
| 99 | } csv_options_t; | ||
| 100 | |||
| 101 | extern const csv_options_t csv_default_options; | ||
| 102 | ~~~ | ||
| 103 | |||
| 104 | **Contextobjekt** zur Aufnahme der aktuell gelesenen Zeile: | ||
| 105 | |||
| 106 | ~~~ | ||
| 107 | typedef struct { | ||
| 108 | csv_options_t *csv_options; | ||
| 109 | /* additional internal fields */ | ||
| 110 | } csv_t; | ||
| 111 | |||
| 112 | ~~~ | ||
| 113 | |||
| 114 | ### Funktionen | ||
| 115 | |||
| 116 | **Initialisieren** | ||
| 117 | |||
| 118 | ~~~ | ||
| 119 | void csv_init(csv_t *csv); | ||
| 120 | void csv_init_opt(csv_t *csv, const csv_options_t * const csv_options); | ||
| 121 | ~~~ | ||
| 122 | |||
| 123 | **Manuelles Freigeben** | ||
| 124 | |||
| 125 | ~~~ | ||
| 126 | void csv_cleanup(csv_t *csv); | ||
| 127 | ~~~ | ||
| 128 | |||
| 129 | **Zeilenweises Lesen** | ||
| 130 | |||
| 131 | ~~~ | ||
| 132 | int csv_read(csv_t *csv, FILE *in); | ||
| 133 | ~~~ | ||
| 134 | |||
| 135 | **Feldzugriff** | ||
| 136 | |||
| 137 | ~~~ | ||
| 138 | int csv_nfields(const csv_t * const csv); | ||
| 139 | const char * csv_field(const csv_t * const csv, int idx); | ||
| 140 | ~~~ | ||
| 141 | |||
| 142 | **Fehlercodes als Textmeldung** | ||
| 143 | |||
| 144 | ~~~ | ||
| 145 | const char * csv_err_str(csv_err_t csv_err); | ||
| 146 | ~~~ | ||
| 147 | |||
| 148 | ## Fehlerbehandlung | ||
| 149 | |||
| 150 | to be written | ||
| 151 | |||
| 152 | ## Anpassungen | ||
| 153 | |||
| 154 | Die CSV-Bibliothek kann an verschiedene Bedürfnisse angepasst werden. | ||
| 155 | |||
| 156 | ### Übersetzungsoptionen | ||
| 157 | |||
| 158 | Beim 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. | ||
| 159 | |||
| 160 | Option Beschreibung Standardwert | ||
| 161 | -------------------------- -------------- --------------------------------- | ||
| 162 | `CSV_DEFAULT_DELIMITER` Feldbegrenzer `"` | ||
| 163 | `CSV_DEFAULT_SEPARATOR` Feldtrenner `,` | ||
| 164 | -------------------------- -------------- --------------------------------- | ||
| 165 | Table: Makros | ||
| 166 | |||
| 167 | Soll 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: | ||
| 168 | |||
| 169 | ~~~ | ||
| 170 | cc -DCSV_DEFAULT_SEPARATOR="';'" -o csv-german.o -c csv.c | ||
| 171 | ~~~ | ||
| 172 | |||
| 173 | Anschließend wird die Datei `csv-german.o` statt `csv.o` zum Projekt dazugelinkt. | ||
| 174 | |||
| 175 | Die Headerdatei (`csv.h`) bleibt unverändert. | ||
| 176 | |||
| 177 | ### Eigener Speicherallozierer | ||
| 178 | |||
| 179 | to be written | ||
| 180 | |||
| 181 | ## Performance | ||
| 182 | |||
| 183 | to be written | ||
| 184 | |||
| 185 | ## Lizenz | ||
| 186 | |||
| 187 | In 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. | ||
| 188 | |||
| 189 | Aus diesem Grund stelle ich meine Software (sofern nicht anders angegeben) unter der freizügigen [Do What the Fuck You Want to Public License](http://www.wtfpl.net) zur Verfügung. Vielleicht findet jemand den Code nützlich oder kann Erkenntnisse daraus gewinnen. | ||
| 190 | |||
| 191 | ~~~ | ||
| 192 | Copyright © 2020 Thomas Schmucker | ||
| 193 | This work is free. You can redistribute it and/or modify it under the | ||
| 194 | terms of the Do What The Fuck You Want To Public License, Version 2, | ||
| 195 | as published by Sam Hocevar. See https://www.wtfpl.net/ for more details. | ||
| 196 | ~~~ | ||
| 197 | |||
