From d0a8e4d7c49f3d082981318f37181da2d10d7886 Mon Sep 17 00:00:00 2001 From: Thomas Schmucker Date: Sun, 14 Jun 2020 16:40:13 +0200 Subject: Fehlerbehandlung hinzugefügt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- csv-test.c | 223 ++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 131 insertions(+), 92 deletions(-) diff --git a/csv-test.c b/csv-test.c index 3da0afe..3c9836d 100644 --- a/csv-test.c +++ b/csv-test.c @@ -3,6 +3,8 @@ #include #include #include +#include +#include #define INLINE static inline @@ -13,48 +15,70 @@ typedef struct { int cap, pos; } csv_string_t; -INLINE void -csv_string_init(csv_string_t *csv_string) +INLINE bool +csv_string_init(csv_string_t *csv_string, jmp_buf env) { + assert(csv_string != NULL); + static const int INITIAL_CAP = 16; - if ( (csv_string->str = malloc(INITIAL_CAP)) != NULL ) { - csv_string->cap = INITIAL_CAP; - csv_string->pos = 0; + if ( (csv_string->str = malloc(INITIAL_CAP)) == NULL ) { + if ( env ) { + longjmp(env, 66); + } + return false; } + + csv_string->cap = INITIAL_CAP; + csv_string->pos = 0; + + return true; } INLINE void csv_string_reset(csv_string_t *csv_string) { + assert(csv_string != NULL); + csv_string->pos = 0; } INLINE bool csv_string_empty(csv_string_t *csv_string) { + assert(csv_string != NULL); + return ( csv_string->pos == 0 ) ? true : false; } -INLINE void -csv_string_append(csv_string_t *csv_string, int ch) +INLINE bool +csv_string_append(csv_string_t *csv_string, char ch, jmp_buf env) { + assert(csv_string != NULL); + if ( csv_string->pos == csv_string->cap ) { /* grow if needed */ int cap = (csv_string->cap * 3) / 2; /* *= 1.5 */ char *str = realloc(csv_string->str, cap); if ( str == NULL ) { - return; + if ( env ) { + longjmp(env, 68); + } + return false; } csv_string->str = str; csv_string->cap = cap; } csv_string->str[csv_string->pos++] = ch; /* append char */ + + return true; } INLINE void csv_string_free(csv_string_t *csv_string) { + assert(csv_string != NULL); + free(csv_string->str); } @@ -65,42 +89,62 @@ typedef struct { int cap, pos; } csv_field_t; -INLINE void -csv_field_init(csv_field_t *csv_field) +INLINE bool +csv_field_init(csv_field_t *csv_field, jmp_buf env) { + assert(csv_field != NULL); + static const size_t INITIAL_CAP = 16; - if ( (csv_field->fields = calloc(INITIAL_CAP, sizeof(csv_field->fields[0]))) != NULL ) { - csv_field->cap = INITIAL_CAP; - csv_field->pos = 0; + if ( (csv_field->fields = calloc(INITIAL_CAP, sizeof(csv_field->fields[0]))) == NULL ) { + if ( env ) { + longjmp(env, 88); + } + return false; } + + csv_field->cap = INITIAL_CAP; + csv_field->pos = 0; + + return true; } INLINE void csv_field_reset(csv_field_t *csv_field) { + assert(csv_field != NULL); + csv_field->pos = 0; } -INLINE void -csv_field_append(csv_field_t *csv_field, int idx) +INLINE bool +csv_field_append(csv_field_t *csv_field, int idx, jmp_buf env) { + assert(csv_field != NULL); + if ( csv_field->pos == csv_field->cap ) { /* grow if needed */ int cap = (csv_field->cap * 3) / 2; /* *= 1.5 */ int *fields = reallocarray(csv_field->fields, cap, sizeof(csv_field->fields[0])); if ( fields == NULL ) { - return; + if ( env ) { + longjmp(env, 66); + } + return false; } csv_field->fields = fields; csv_field->cap = cap; } csv_field->fields[csv_field->pos++] = idx; /* append idx */ + + return true; } INLINE void csv_field_free(csv_field_t *csv_field) { + assert(csv_field != NULL); + free(csv_field->fields); } @@ -117,29 +161,59 @@ static csv_options_t default_csv_options = { }; typedef struct { + FILE *in; csv_options_t *csv_options; csv_string_t csv_string; csv_field_t csv_field; + jmp_buf env; } csv_t; -void -csv_init_opt(csv_t *csv, csv_options_t *csv_options) +int csv_init(csv_t *csv, FILE *in); +int csv_init_opt(csv_t *csv, FILE *in, csv_options_t *csv_options); +void csv_free(csv_t *csv); +int csv_nfields(csv_t *csv); +const char * csv_field(csv_t *csv, int idx); +int csv_read(csv_t *csv); +void csv_write(csv_t *csv, int n, const char *fields[], FILE *out); + +int +csv_init(csv_t *csv, FILE *in) { - csv->csv_options = ( csv_options != NULL ) ? csv_options : &default_csv_options; + assert(csv != NULL); - csv_string_init(&csv->csv_string); - csv_field_init(&csv->csv_field); + return csv_init_opt(csv, in, &default_csv_options); } -void -csv_init(csv_t *csv) +int +csv_init_opt(csv_t *csv, FILE *in, csv_options_t *csv_options) { - csv_init_opt(csv, &default_csv_options); + assert(csv != NULL); + + csv->in = in; + csv->csv_options = ( csv_options != NULL ) ? csv_options : &default_csv_options; + + int err = setjmp(csv->env); + + if ( !err ) { + if ( !csv_string_init(&csv->csv_string, NULL) ) { + return -1; + } + if ( !csv_field_init(&csv->csv_field, NULL) ) { + csv_string_free(&csv->csv_string); + return -2; + } + } + else { + csv_free(csv); + } + return err; } void csv_free(csv_t *csv) { + assert(csv != NULL); + csv_string_free(&csv->csv_string); csv_field_free(&csv->csv_field); } @@ -147,6 +221,8 @@ csv_free(csv_t *csv) int csv_nfields(csv_t *csv) { + assert(csv != NULL); + if ( csv->csv_string.pos != 0 ) { return csv->csv_field.pos; } @@ -156,12 +232,16 @@ csv_nfields(csv_t *csv) const char * csv_field(csv_t *csv, int idx) { + assert(csv != NULL); + return &csv->csv_string.str[csv->csv_field.fields[idx]]; } int -csv_read(csv_t *csv, FILE *in) +csv_read(csv_t *csv) { + assert(csv != NULL); + enum { STATE_START_FIELD, STATE_QUOTED_FIELD, @@ -182,16 +262,16 @@ csv_read(csv_t *csv, FILE *in) switch ( state ) { case STATE_START_FIELD: - csv_field_append(&csv->csv_field, csv->csv_string.pos); + csv_field_append(&csv->csv_field, csv->csv_string.pos, csv->env); - ch = getc(in); + ch = getc(csv->in); if ( ch == EOF ) { state = STATE_END_FILE; } else if ( ch == '\r' ) { /* Teste auf CR.. */ - ch = getc(in); + ch = getc(csv->in); if ( ch != '\n' ) { /* ... LF */ - ungetc(ch, in); + ungetc(ch, csv->in); } state = STATE_END_LINE; } @@ -205,32 +285,32 @@ csv_read(csv_t *csv, FILE *in) state = STATE_QUOTED_FIELD; } else { - csv_string_append(&csv->csv_string, ch); + csv_string_append(&csv->csv_string, ch, csv->env); state = STATE_SIMPLE_FIELD; } break; case STATE_QUOTED_FIELD: do { - ch = getc(in); + ch = getc(csv->in); if ( ch == EOF ) { state = STATE_END_FILE; } else if ( ch == QUOTE ) { - ch = getc(in); + ch = getc(csv->in); if ( ch == EOF ) { state = STATE_END_FILE; } else if ( ch == QUOTE ) { - csv_string_append(&csv->csv_string, QUOTE); + csv_string_append(&csv->csv_string, QUOTE, csv->env); } else if ( ch == SEP ) { state = STATE_END_FIELD; } else if ( ch == '\r' ) { - ch = getc(in); + ch = getc(csv->in); if ( ch != '\n' ) { - ungetc(ch, in); + ungetc(ch, csv->in); } state = STATE_END_LINE; } @@ -238,19 +318,19 @@ csv_read(csv_t *csv, FILE *in) state = STATE_END_LINE; } else { - csv_string_append(&csv->csv_string, QUOTE); - ungetc(ch, in); /* zuviel gelesenes Zeichen zurückstellen */ + csv_string_append(&csv->csv_string, QUOTE, csv->env); + ungetc(ch, csv->in); /* zuviel gelesenes Zeichen zurückstellen */ } } else { - csv_string_append(&csv->csv_string, ch); + csv_string_append(&csv->csv_string, ch, csv->env); } } while ( state == STATE_QUOTED_FIELD ); break; case STATE_SIMPLE_FIELD: do { - ch = getc(in); + ch = getc(csv->in); if ( ch == EOF ) { state = STATE_END_FILE; } @@ -258,9 +338,9 @@ csv_read(csv_t *csv, FILE *in) state = STATE_END_FIELD; } else if ( ch == '\r' ) { - ch = getc(in); + ch = getc(csv->in); if ( ch != '\n' ) { - ungetc(ch, in); + ungetc(ch, csv->in); } state = STATE_END_LINE; } @@ -268,18 +348,18 @@ csv_read(csv_t *csv, FILE *in) state = STATE_END_LINE; } else { - csv_string_append(&csv->csv_string, ch); + csv_string_append(&csv->csv_string, ch, csv->env); } } while ( state == STATE_SIMPLE_FIELD ); break; case STATE_END_FIELD: - csv_string_append(&csv->csv_string, '\0'); + csv_string_append(&csv->csv_string, '\0', csv->env); state = STATE_START_FIELD; break; case STATE_END_LINE: - csv_string_append(&csv->csv_string, '\0'); + csv_string_append(&csv->csv_string, '\0', csv->env); return csv->csv_field.pos; case STATE_END_FILE: @@ -289,7 +369,7 @@ csv_read(csv_t *csv, FILE *in) /* EOF wurde gelesen, allerdings sind Daten zur Vearbeitung vorhanden! */ /* => aktuelles Feld abschließen... */ - csv_string_append(&csv->csv_string, '\0'); + csv_string_append(&csv->csv_string, '\0', csv->env); /* ... und die Anzahl der Felder zurückliefern! */ return csv->csv_field.pos; @@ -301,6 +381,8 @@ csv_read(csv_t *csv, FILE *in) static void csv_write_field(csv_t *csv, const char *field, FILE *out) { + assert(csv != NULL); + const char QUOTE = csv->csv_options->quote_symbol; if ( *field != '\0' ) { @@ -323,6 +405,8 @@ csv_write_field(csv_t *csv, const char *field, FILE *out) void csv_write(csv_t *csv, int n, const char *fields[], FILE *out) { + assert(csv != NULL); + const char SEP = csv->csv_options->quote_symbol; /* process first field */ @@ -344,54 +428,10 @@ main(void) csv_t csv[1]; int n, line = 0; -#if 0 - char data[] = "\"\"aaa\",\"b\"\"bb\",\"ccc\"\n" - "zzz,,yyy,xxx\n" - ",\n" - ""; - FILE *in = fmemopen(data, strlen(data), "rb"); - - if ( in == NULL ) { - printf("no data...\n"); - return 0; - } - - csv_init(csv); - while ( (n = csv_read(csv, in)) != -1 ) { - printf("%4d: ", ++line); - - for ( int i = 0; i < n; ++i ) { - printf("'%s' ", csv_field(csv, i)); - } - putchar('\n'); - - if ( line == 100 ) - break; - } - csv_free(csv); -#endif - -#if 0 - csv_init(csv); - while ( (n = csv_read(csv, stdin)) != -1 ) { - printf("%4d: ", ++line); - - for ( int i = 0; i < n; ++i ) { - printf("'%s' ", csv_field(csv, i)); - } - putchar('\n'); - - if ( line == 100 ) - break; - } - csv_free(csv); -#endif - -#if 1 clock_t start = clock(); - csv_init(csv); - while ( (n = csv_read(csv, stdin)) != -1 ) { + csv_init(csv, stdin); + while ( (n = csv_read(csv)) != -1 ) { ++line; } csv_free(csv); @@ -401,5 +441,4 @@ main(void) printf("%d lines processed, duration: %.3lf sec\n", line, ((double)(end - start)) / CLOCKS_PER_SEC); return EXIT_SUCCESS; -#endif } -- cgit v1.3