From 5b06a00890fe3e2c77c7c5835c975e87b8c7dfb0 Mon Sep 17 00:00:00 2001 From: Thomas Schmucker Date: Thu, 11 Jun 2020 18:27:39 +0200 Subject: erster Commit --- csv-test.c | 358 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ seq-read.c | 33 ++++++ 2 files changed, 391 insertions(+) create mode 100644 csv-test.c create mode 100644 seq-read.c diff --git a/csv-test.c b/csv-test.c new file mode 100644 index 0000000..97cc558 --- /dev/null +++ b/csv-test.c @@ -0,0 +1,358 @@ +#include +#include +#include +#include +#include + +/* === CSV-STRING Interface === */ + +typedef struct { + char *str; + int cap, pos; +} csv_string_t; + +static void +csv_string_init(csv_string_t *csv_string) +{ + static const int INITIAL_CAP = 16; + + if ( (csv_string->str = malloc(INITIAL_CAP)) != NULL ) { + csv_string->cap = INITIAL_CAP; + csv_string->pos = 0; + } +} + +static void +csv_string_reset(csv_string_t *csv_string) +{ + csv_string->pos = 0; +} + +static bool +csv_string_empty(csv_string_t *csv_string) +{ + return ( csv_string->pos == 0 ) ? true : false; +} + +inline static void +csv_string_append(csv_string_t *csv_string, int ch) +{ + 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; + } + csv_string->str = str; + csv_string->cap = cap; + } + + csv_string->str[csv_string->pos++] = ch; /* append char */ +} + +static void +csv_string_free(csv_string_t *csv_string) +{ + free(csv_string->str); +} + +/* === CSV-FIELD Interface === */ + +typedef struct { + int *fields; + int cap, pos; +} csv_field_t; + +static void +csv_field_init(csv_field_t *csv_field) +{ + static const size_t INITIAL_CAP = 16; + + if ( (csv_field->fields = malloc(INITIAL_CAP * sizeof(csv_field->fields[0]))) != NULL ) { + csv_field->cap = INITIAL_CAP; + csv_field->pos = 0; + } +} + +static void +csv_field_reset(csv_field_t *csv_field) +{ + csv_field->pos = 0; +} + +static void +csv_field_append(csv_field_t *csv_field, int idx) +{ + if ( csv_field->pos == csv_field->cap ) { /* grow if needed */ + int cap = (csv_field->cap * 3) / 2; /* *= 1.5 */ + int *fields = realloc(csv_field->fields, cap * sizeof(csv_field->fields[0])); + if ( fields == NULL ) { + return; + } + csv_field->fields = fields; + csv_field->cap = cap; + } + + csv_field->fields[csv_field->pos++] = idx; /* append idx */ +} + +static void +csv_field_free(csv_field_t *csv_field) +{ + free(csv_field->fields); +} + +/* === CSV Interface === */ + +typedef struct { + char quote_symbol; + char sep_symbol; +} csv_options_t; + +static csv_options_t default_csv_options = { + .quote_symbol = '"', + .sep_symbol = ',' +}; + +typedef struct { + csv_options_t *csv_options; + csv_string_t csv_string; + csv_field_t csv_field; +} csv_t; + +void +csv_init_opt(csv_t *csv, csv_options_t *csv_options) +{ + csv->csv_options = ( csv_options != NULL ) ? csv_options : &default_csv_options; + + csv_string_init(&csv->csv_string); + csv_field_init(&csv->csv_field); +} + +void +csv_init(csv_t *csv) +{ + csv_init_opt(csv, &default_csv_options); +} + +void +csv_free(csv_t *csv) +{ + csv_string_free(&csv->csv_string); + csv_field_free(&csv->csv_field); +} + +int +csv_nfields(csv_t *csv) +{ + if ( csv->csv_string.pos != 0 ) { + return csv->csv_field.pos; + } + return 0; +} + +const char * +csv_field(csv_t *csv, int idx) +{ + return &csv->csv_string.str[csv->csv_field.fields[idx]]; +} + +int +csv_read(csv_t *csv, FILE *in) +{ + enum { + ZST_START_FIELD, + ZST_QUOTED_FIELD, + ZST_SIMPLE_FIELD, + ZST_END_FIELD, + ZST_END_LINE, + ZST_END_FILE, + }; + + register const int QUOTE = csv->csv_options->quote_symbol; + register const int SEP = csv->csv_options->sep_symbol; + + csv_string_reset(&csv->csv_string); + csv_field_reset(&csv->csv_field); + + for ( int zst = ZST_START_FIELD; ; ) { + int ch; + + switch ( zst ) { + case ZST_START_FIELD: + csv_field_append(&csv->csv_field, csv->csv_string.pos); + + ch = fgetc(in); + if ( ch == EOF ) { + zst = ZST_END_FILE; + } + else if ( ch == '\r' ) { /* Teste auf CR.. */ + ch = fgetc(in); + if ( ch != '\n' ) { /* ... LF */ + ungetc(ch, in); + } + zst = ZST_END_LINE; + } + else if ( ch == '\n' ) { + zst = ZST_END_LINE; + } + else if ( ch == SEP ) { + zst = ZST_END_FIELD; + } + else if ( ch == QUOTE ) { + zst = ZST_QUOTED_FIELD; + } + else { + csv_string_append(&csv->csv_string, ch); + zst = ZST_SIMPLE_FIELD; + } + break; + + case ZST_QUOTED_FIELD: + do { + ch = fgetc(in); + if ( ch == EOF ) { + zst = ZST_END_FILE; + } + else if ( ch == QUOTE ) { + ch = fgetc(in); + if ( ch == EOF ) { + zst = ZST_END_FILE; + } + else if ( ch == QUOTE ) { + csv_string_append(&csv->csv_string, QUOTE); + } + else if ( ch == SEP ) { + zst = ZST_END_FIELD; + } + else if ( ch == '\r' ) { + ch = fgetc(in); + if ( ch != '\n' ) { + ungetc(ch, in); + } + zst = ZST_END_LINE; + } + else if ( ch == '\n' ) { + zst = ZST_END_LINE; + } + else { + csv_string_append(&csv->csv_string, QUOTE); + ungetc(ch, in); /* zuviel gelesenes Zeichen zurückstellen */ + } + } + else { + csv_string_append(&csv->csv_string, ch); + } + } while ( zst == ZST_QUOTED_FIELD ); + break; + + case ZST_SIMPLE_FIELD: + do { + ch = fgetc(in); + if ( ch == EOF ) { + zst = ZST_END_FILE; + } + else if ( ch == SEP ) { + zst = ZST_END_FIELD; + } + else if ( ch == '\r' ) { + ch = fgetc(in); + if ( ch != '\n' ) { + ungetc(ch, in); + } + zst = ZST_END_LINE; + } + else if ( ch == '\n' ) { + zst = ZST_END_LINE; + } + else { + csv_string_append(&csv->csv_string, ch); + } + } while ( zst == ZST_SIMPLE_FIELD ); + break; + + case ZST_END_FIELD: + csv_string_append(&csv->csv_string, '\0'); + zst = ZST_START_FIELD; + break; + + case ZST_END_LINE: + csv_string_append(&csv->csv_string, '\0'); + return csv->csv_field.pos; + + case ZST_END_FILE: + if ( !csv_string_empty(&csv->csv_string) ) { + /* EOF wurde gelesen, allerdings sind Daten zur Vearbeitung vorhanden! */ + csv_string_append(&csv->csv_string, '\0'); + return csv->csv_field.pos; + } + return -1; /* EOF reached */ + } + } +} + +int +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 ) { + ++line; + } + csv_free(csv); + + clock_t end = clock(); + + printf("%d lines processed, duration: %.3lf sec\n", line, ((double)(end - start)) / CLOCKS_PER_SEC); + + return EXIT_SUCCESS; +#endif +} diff --git a/seq-read.c b/seq-read.c new file mode 100644 index 0000000..b9ef58b --- /dev/null +++ b/seq-read.c @@ -0,0 +1,33 @@ +#include +#include +#include + +int +main(void) +{ + clock_t start = clock(); + size_t sum = 0; + +#if 0 + int ch; + while ((ch = getc(stdin)) != EOF) { + sum += (unsigned char) ch; + } +#endif + +#if 1 + unsigned char buffer[1024]; + size_t n; + while ((n = fread(buffer, 1, sizeof buffer, stdin)) > 0) { + for ( size_t z = 0; z != n; ++z ) { + sum += buffer[z]; + } + } +#endif + + clock_t end = clock(); + + printf("Result: %zu, Duration: %.3lf sec\n", sum, (double)(end - start) / CLOCKS_PER_SEC); + + return EXIT_SUCCESS; +} -- cgit v1.3