summaryrefslogtreecommitdiff
path: root/csv-test.c
diff options
context:
space:
mode:
Diffstat (limited to 'csv-test.c')
-rw-r--r--csv-test.c97
1 files changed, 54 insertions, 43 deletions
diff --git a/csv-test.c b/csv-test.c
index 85e0e91..6c32a04 100644
--- a/csv-test.c
+++ b/csv-test.c
@@ -9,6 +9,34 @@
9 9
10#define INLINE static inline 10#define INLINE static inline
11 11
12/* === CSV Options Interface === */
13
14typedef struct {
15 char quote_symbol;
16 char sep_symbol;
17 void *cb_arg;
18 void (*cb_func)(const char *, void *);
19} csv_options_t;
20
21static csv_options_t default_csv_options = {
22 .quote_symbol = '"',
23 .sep_symbol = ',',
24 .cb_func = NULL
25};
26
27/* === CSV-ERROR Interface === */
28
29INLINE void
30csv_fatal_error(const char *msg, const csv_options_t * const csv_options)
31{
32 if ( csv_options->cb_func != NULL ) {
33 (*csv_options->cb_func)(msg, csv_options->cb_arg);
34 }
35
36 fprintf(stderr, "fatal error: %s\n", msg);
37 abort();
38}
39
12/* === CSV-STRING Interface === */ 40/* === CSV-STRING Interface === */
13 41
14typedef struct { 42typedef struct {
@@ -43,14 +71,7 @@ csv_string_empty(csv_string_t *csv_string)
43} 71}
44 72
45INLINE void 73INLINE void
46csv_fatal_error(const char *msg) 74csv_string_append(csv_string_t *csv_string, char ch, const csv_options_t * const csv_options)
47{
48 fprintf(stderr, "fatal error: %s\n", msg);
49 abort();
50}
51
52INLINE void
53csv_string_append(csv_string_t *csv_string, char ch)
54{ 75{
55 assert(csv_string != NULL); 76 assert(csv_string != NULL);
56 77
@@ -59,7 +80,7 @@ csv_string_append(csv_string_t *csv_string, char ch)
59 if ( csv_string->pos == csv_string->cap ) { /* grow if needed */ 80 if ( csv_string->pos == csv_string->cap ) { /* grow if needed */
60 if ( csv_string->str == NULL ) { /* first call? */ 81 if ( csv_string->str == NULL ) { /* first call? */
61 if ( (csv_string->str = malloc(INITIAL_CAP)) == NULL ) { 82 if ( (csv_string->str = malloc(INITIAL_CAP)) == NULL ) {
62 csv_fatal_error("out of memory..."); 83 csv_fatal_error("out of memory...", csv_options);
63 return; 84 return;
64 } 85 }
65 86
@@ -69,7 +90,7 @@ csv_string_append(csv_string_t *csv_string, char ch)
69 int cap = (csv_string->cap * 3) / 2; /* *= 1.5 */ 90 int cap = (csv_string->cap * 3) / 2; /* *= 1.5 */
70 char *str = realloc(csv_string->str, cap); 91 char *str = realloc(csv_string->str, cap);
71 if ( str == NULL ) { 92 if ( str == NULL ) {
72 csv_fatal_error("out of memory..."); 93 csv_fatal_error("out of memory...", csv_options);
73 return; 94 return;
74 } 95 }
75 csv_string->str = str; 96 csv_string->str = str;
@@ -117,7 +138,7 @@ csv_field_reset(csv_field_t *csv_field)
117} 138}
118 139
119INLINE void 140INLINE void
120csv_field_append(csv_field_t *csv_field, int idx) 141csv_field_append(csv_field_t *csv_field, int idx, const csv_options_t * const csv_options)
121{ 142{
122 assert(csv_field != NULL); 143 assert(csv_field != NULL);
123 144
@@ -126,7 +147,7 @@ csv_field_append(csv_field_t *csv_field, int idx)
126 if ( csv_field->pos == csv_field->cap ) { /* grow if needed */ 147 if ( csv_field->pos == csv_field->cap ) { /* grow if needed */
127 if ( csv_field->fields == NULL ) { 148 if ( csv_field->fields == NULL ) {
128 if ( (csv_field->fields = calloc(INITIAL_CAP, sizeof(csv_field->fields[0]))) == NULL ) { 149 if ( (csv_field->fields = calloc(INITIAL_CAP, sizeof(csv_field->fields[0]))) == NULL ) {
129 csv_fatal_error("out of memory"); 150 csv_fatal_error("out of memory", csv_options);
130 return; 151 return;
131 } 152 }
132 153
@@ -136,7 +157,7 @@ csv_field_append(csv_field_t *csv_field, int idx)
136 int cap = (csv_field->cap * 3) / 2; /* *= 1.5 */ 157 int cap = (csv_field->cap * 3) / 2; /* *= 1.5 */
137 int *fields = reallocarray(csv_field->fields, cap, sizeof(csv_field->fields[0])); 158 int *fields = reallocarray(csv_field->fields, cap, sizeof(csv_field->fields[0]));
138 if ( fields == NULL ) { 159 if ( fields == NULL ) {
139 csv_fatal_error("out of memory"); 160 csv_fatal_error("out of memory", csv_options);
140 return; 161 return;
141 } 162 }
142 csv_field->fields = fields; 163 csv_field->fields = fields;
@@ -160,16 +181,6 @@ csv_field_free(csv_field_t *csv_field)
160/* === CSV Interface === */ 181/* === CSV Interface === */
161 182
162typedef struct { 183typedef struct {
163 char quote_symbol;
164 char sep_symbol;
165} csv_options_t;
166
167static csv_options_t default_csv_options = {
168 .quote_symbol = '"',
169 .sep_symbol = ','
170};
171
172typedef struct {
173 csv_options_t *csv_options; 184 csv_options_t *csv_options;
174 csv_string_t csv_string; 185 csv_string_t csv_string;
175 csv_field_t csv_field; 186 csv_field_t csv_field;
@@ -181,7 +192,7 @@ void csv_free(csv_t *csv);
181int csv_nfields(csv_t *csv); 192int csv_nfields(csv_t *csv);
182const char * csv_field(csv_t *csv, int idx); 193const char * csv_field(csv_t *csv, int idx);
183int csv_read(csv_t *csv, FILE *in); 194int csv_read(csv_t *csv, FILE *in);
184void csv_write(csv_t *csv, int n, const char *fields[], FILE *out); 195void csv_write(const csv_options_t * const csv_options, int n, const char *fields[], FILE *out);
185 196
186void 197void
187csv_init(csv_t *csv) 198csv_init(csv_t *csv)
@@ -229,7 +240,7 @@ csv_field(csv_t *csv, int idx)
229 assert(idx >= 0 && idx < csv->csv_field.pos); 240 assert(idx >= 0 && idx < csv->csv_field.pos);
230 241
231 if ( idx < 0 || idx >= csv->csv_field.pos ) { 242 if ( idx < 0 || idx >= csv->csv_field.pos ) {
232 csv_fatal_error("range error"); 243 csv_fatal_error("range error", csv->csv_options);
233 } 244 }
234 245
235 return &csv->csv_string.str[csv->csv_field.fields[idx]]; 246 return &csv->csv_string.str[csv->csv_field.fields[idx]];
@@ -260,7 +271,7 @@ csv_read(csv_t *csv, FILE *in)
260 271
261 switch ( state ) { 272 switch ( state ) {
262 case STATE_START_FIELD: 273 case STATE_START_FIELD:
263 csv_field_append(&csv->csv_field, csv->csv_string.pos); 274 csv_field_append(&csv->csv_field, csv->csv_string.pos, csv->csv_options);
264 275
265 ch = getc(in); 276 ch = getc(in);
266 if ( ch == EOF ) { 277 if ( ch == EOF ) {
@@ -283,7 +294,7 @@ csv_read(csv_t *csv, FILE *in)
283 state = STATE_QUOTED_FIELD; 294 state = STATE_QUOTED_FIELD;
284 } 295 }
285 else { 296 else {
286 csv_string_append(&csv->csv_string, ch); 297 csv_string_append(&csv->csv_string, ch, csv->csv_options);
287 state = STATE_SIMPLE_FIELD; 298 state = STATE_SIMPLE_FIELD;
288 } 299 }
289 break; 300 break;
@@ -300,7 +311,7 @@ csv_read(csv_t *csv, FILE *in)
300 state = STATE_END_FILE; 311 state = STATE_END_FILE;
301 } 312 }
302 else if ( ch == QUOTE ) { 313 else if ( ch == QUOTE ) {
303 csv_string_append(&csv->csv_string, QUOTE); 314 csv_string_append(&csv->csv_string, QUOTE, csv->csv_options);
304 } 315 }
305 else if ( ch == SEP ) { 316 else if ( ch == SEP ) {
306 state = STATE_END_FIELD; 317 state = STATE_END_FIELD;
@@ -316,12 +327,12 @@ csv_read(csv_t *csv, FILE *in)
316 state = STATE_END_LINE; 327 state = STATE_END_LINE;
317 } 328 }
318 else { 329 else {
319 csv_string_append(&csv->csv_string, QUOTE); 330 csv_string_append(&csv->csv_string, QUOTE, csv->csv_options);
320 ungetc(ch, in); /* zuviel gelesenes Zeichen zurückstellen */ 331 ungetc(ch, in); /* zuviel gelesenes Zeichen zurückstellen */
321 } 332 }
322 } 333 }
323 else { 334 else {
324 csv_string_append(&csv->csv_string, ch); 335 csv_string_append(&csv->csv_string, ch, csv->csv_options);
325 } 336 }
326 } while ( state == STATE_QUOTED_FIELD ); 337 } while ( state == STATE_QUOTED_FIELD );
327 break; 338 break;
@@ -346,18 +357,18 @@ csv_read(csv_t *csv, FILE *in)
346 state = STATE_END_LINE; 357 state = STATE_END_LINE;
347 } 358 }
348 else { 359 else {
349 csv_string_append(&csv->csv_string, ch); 360 csv_string_append(&csv->csv_string, ch, csv->csv_options);
350 } 361 }
351 } while ( state == STATE_SIMPLE_FIELD ); 362 } while ( state == STATE_SIMPLE_FIELD );
352 break; 363 break;
353 364
354 case STATE_END_FIELD: 365 case STATE_END_FIELD:
355 csv_string_append(&csv->csv_string, '\0'); 366 csv_string_append(&csv->csv_string, '\0', csv->csv_options);
356 state = STATE_START_FIELD; 367 state = STATE_START_FIELD;
357 break; 368 break;
358 369
359 case STATE_END_LINE: 370 case STATE_END_LINE:
360 csv_string_append(&csv->csv_string, '\0'); 371 csv_string_append(&csv->csv_string, '\0', csv->csv_options);
361 return csv->csv_field.pos; 372 return csv->csv_field.pos;
362 373
363 case STATE_END_FILE: 374 case STATE_END_FILE:
@@ -367,7 +378,7 @@ csv_read(csv_t *csv, FILE *in)
367 378
368 /* EOF wurde gelesen, allerdings sind Daten zur Vearbeitung vorhanden! */ 379 /* EOF wurde gelesen, allerdings sind Daten zur Vearbeitung vorhanden! */
369 /* => aktuelles Feld abschließen... */ 380 /* => aktuelles Feld abschließen... */
370 csv_string_append(&csv->csv_string, '\0'); 381 csv_string_append(&csv->csv_string, '\0', csv->csv_options);
371 382
372 /* ... und die Anzahl der Felder zurückliefern! */ 383 /* ... und die Anzahl der Felder zurückliefern! */
373 return csv->csv_field.pos; 384 return csv->csv_field.pos;
@@ -381,11 +392,11 @@ csv_read(csv_t *csv, FILE *in)
381} 392}
382 393
383static void 394static void
384csv_write_field(csv_t *csv, const char *field, FILE *out) 395csv_write_field(const csv_options_t * const csv_options, const char *field, FILE *out)
385{ 396{
386 assert(csv != NULL); 397 assert(csv_options != NULL);
387 398
388 const char QUOTE = csv->csv_options->quote_symbol; 399 const char QUOTE = csv_options->quote_symbol;
389 400
390 if ( *field != '\0' ) { 401 if ( *field != '\0' ) {
391 putc(QUOTE, out); 402 putc(QUOTE, out);
@@ -405,20 +416,20 @@ csv_write_field(csv_t *csv, const char *field, FILE *out)
405} 416}
406 417
407void 418void
408csv_write(csv_t *csv, int n, const char *fields[], FILE *out) 419csv_write(const csv_options_t * const csv_options, int n, const char *fields[], FILE *out)
409{ 420{
410 assert(csv != NULL); 421 assert(csv_options != NULL);
411 422
412 const char SEP = csv->csv_options->quote_symbol; 423 const char SEP = csv_options->quote_symbol;
413 424
414 /* process first field */ 425 /* process first field */
415 if ( 0 != n && fields[0] != NULL ) { 426 if ( 0 != n && fields[0] != NULL ) {
416 csv_write_field(csv, fields[0], out); 427 csv_write_field(csv_options, fields[0], out);
417 428
418 /* process next fields */ 429 /* process next fields */
419 for ( int i = 1; i != n && fields[i] != NULL; ++i ) { 430 for ( int i = 1; i != n && fields[i] != NULL; ++i ) {
420 putc(SEP, out); 431 putc(SEP, out);
421 csv_write_field(csv, fields[i], out); 432 csv_write_field(csv_options, fields[i], out);
422 } 433 }
423 } 434 }
424 fprintf(out, "\r\n"); 435 fprintf(out, "\r\n");
@@ -451,7 +462,7 @@ main(void)
451 csv_init(csv); 462 csv_init(csv);
452 if ( setjmp(env) == 0 ) { 463 if ( setjmp(env) == 0 ) {
453 while ( (n = csv_read(csv, in)) != -1 ) { 464 while ( (n = csv_read(csv, in)) != -1 ) {
454 csv_field(csv, -1); 465 //if ( line == 500000 ) csv_field(csv, -1);
455 ++line; 466 ++line;
456 } 467 }
457 } 468 }