diff options
Diffstat (limited to 'csv-test.c')
| -rw-r--r-- | csv-test.c | 62 |
1 files changed, 48 insertions, 14 deletions
| @@ -9,13 +9,42 @@ | |||
| 9 | 9 | ||
| 10 | #define INLINE static inline | 10 | #define INLINE static inline |
| 11 | 11 | ||
| 12 | /* === CSV-MEMORY Interface === */ | ||
| 13 | |||
| 14 | static void * | ||
| 15 | csv_mem_allocate(size_t n, size_t sz, void *cb_arg) | ||
| 16 | { | ||
| 17 | (void) cb_arg; | ||
| 18 | |||
| 19 | return calloc(n, sz); | ||
| 20 | } | ||
| 21 | |||
| 22 | static void * | ||
| 23 | csv_mem_reallocate(void *ptr, size_t n, size_t sz, void *cb_arg) | ||
| 24 | { | ||
| 25 | (void) cb_arg; | ||
| 26 | |||
| 27 | return reallocarray(ptr, n, sz); | ||
| 28 | } | ||
| 29 | |||
| 30 | static void | ||
| 31 | csv_mem_free(void *ptr, void *cb_arg) | ||
| 32 | { | ||
| 33 | (void) cb_arg; | ||
| 34 | |||
| 35 | free(ptr); | ||
| 36 | } | ||
| 37 | |||
| 12 | /* === CSV-OPTIONS Interface === */ | 38 | /* === CSV-OPTIONS Interface === */ |
| 13 | 39 | ||
| 14 | typedef struct { | 40 | typedef struct { |
| 15 | char quote_symbol; | 41 | char quote_symbol; |
| 16 | char sep_symbol; | 42 | char sep_symbol; |
| 17 | void *cb_arg; | 43 | void *cb_arg; |
| 18 | void (*cb_func)(const char *, void *); | 44 | void (*cb_error)(const char *, void *); |
| 45 | void *(*cb_allocate)(size_t, size_t, void *); | ||
| 46 | void *(*cb_reallocate)(void *, size_t, size_t, void *); | ||
| 47 | void (*cb_free)(void *, void *); | ||
| 19 | } csv_options_t; | 48 | } csv_options_t; |
| 20 | 49 | ||
| 21 | extern const csv_options_t csv_default_options; | 50 | extern const csv_options_t csv_default_options; |
| @@ -23,7 +52,10 @@ extern const csv_options_t csv_default_options; | |||
| 23 | const csv_options_t csv_default_options = { | 52 | const csv_options_t csv_default_options = { |
| 24 | .quote_symbol = '"', | 53 | .quote_symbol = '"', |
| 25 | .sep_symbol = ',', | 54 | .sep_symbol = ',', |
| 26 | .cb_func = NULL | 55 | .cb_error = NULL, |
| 56 | .cb_allocate = csv_mem_allocate, | ||
| 57 | .cb_reallocate = csv_mem_reallocate, | ||
| 58 | .cb_free = csv_mem_free | ||
| 27 | }; | 59 | }; |
| 28 | 60 | ||
| 29 | /* === CSV-ERROR Interface === */ | 61 | /* === CSV-ERROR Interface === */ |
| @@ -31,8 +63,8 @@ const csv_options_t csv_default_options = { | |||
| 31 | INLINE void | 63 | INLINE void |
| 32 | csv_fatal_error(const char *msg, const csv_options_t * const csv_options) | 64 | csv_fatal_error(const char *msg, const csv_options_t * const csv_options) |
| 33 | { | 65 | { |
| 34 | if ( csv_options->cb_func != NULL ) { | 66 | if ( csv_options->cb_error != NULL ) { |
| 35 | (*csv_options->cb_func)(msg, csv_options->cb_arg); | 67 | (*csv_options->cb_error)(msg, csv_options->cb_arg); |
| 36 | } | 68 | } |
| 37 | 69 | ||
| 38 | fprintf(stderr, "fatal error: %s\n", msg); | 70 | fprintf(stderr, "fatal error: %s\n", msg); |
| @@ -82,7 +114,7 @@ csv_string_append(csv_string_t *csv_string, char ch, const csv_options_t * const | |||
| 82 | 114 | ||
| 83 | if ( csv_string->pos == csv_string->cap ) { /* grow if needed */ | 115 | if ( csv_string->pos == csv_string->cap ) { /* grow if needed */ |
| 84 | if ( csv_string->str == NULL ) { /* first call? */ | 116 | if ( csv_string->str == NULL ) { /* first call? */ |
| 85 | if ( (csv_string->str = malloc(INITIAL_CAP)) == NULL ) { | 117 | if ( (csv_string->str = csv_options->cb_allocate(INITIAL_CAP, 1, csv_options->cb_arg)) == NULL ) { |
| 86 | csv_fatal_error("out of memory...", csv_options); | 118 | csv_fatal_error("out of memory...", csv_options); |
| 87 | return; | 119 | return; |
| 88 | } | 120 | } |
| @@ -91,7 +123,7 @@ csv_string_append(csv_string_t *csv_string, char ch, const csv_options_t * const | |||
| 91 | } | 123 | } |
| 92 | else { /* subsequent call */ | 124 | else { /* subsequent call */ |
| 93 | int cap = (csv_string->cap * 3) / 2; /* *= 1.5 */ | 125 | int cap = (csv_string->cap * 3) / 2; /* *= 1.5 */ |
| 94 | char *str = realloc(csv_string->str, cap); | 126 | char *str = csv_options->cb_reallocate(csv_string->str, cap, 1, csv_options->cb_arg); |
| 95 | if ( str == NULL ) { | 127 | if ( str == NULL ) { |
| 96 | csv_fatal_error("out of memory...", csv_options); | 128 | csv_fatal_error("out of memory...", csv_options); |
| 97 | return; | 129 | return; |
| @@ -105,11 +137,12 @@ csv_string_append(csv_string_t *csv_string, char ch, const csv_options_t * const | |||
| 105 | } | 137 | } |
| 106 | 138 | ||
| 107 | INLINE void | 139 | INLINE void |
| 108 | csv_string_free(csv_string_t *csv_string) | 140 | csv_string_free(csv_string_t *csv_string, const csv_options_t * const csv_options) |
| 109 | { | 141 | { |
| 110 | assert(csv_string != NULL); | 142 | assert(csv_string != NULL); |
| 143 | assert(csv_options != NULL); | ||
| 111 | 144 | ||
| 112 | free(csv_string->str); | 145 | csv_options->cb_free(csv_string->str, csv_options->cb_arg); |
| 113 | 146 | ||
| 114 | /* call *_init() for sane default values; prevent possible double-free */ | 147 | /* call *_init() for sane default values; prevent possible double-free */ |
| 115 | csv_string_init(csv_string); | 148 | csv_string_init(csv_string); |
| @@ -150,7 +183,7 @@ csv_field_append(csv_field_t *csv_field, int idx, const csv_options_t * const cs | |||
| 150 | 183 | ||
| 151 | if ( csv_field->pos == csv_field->cap ) { /* grow if needed */ | 184 | if ( csv_field->pos == csv_field->cap ) { /* grow if needed */ |
| 152 | if ( csv_field->fields == NULL ) { | 185 | if ( csv_field->fields == NULL ) { |
| 153 | if ( (csv_field->fields = calloc(INITIAL_CAP, sizeof(csv_field->fields[0]))) == NULL ) { | 186 | if ( (csv_field->fields = csv_options->cb_allocate(INITIAL_CAP, sizeof(csv_field->fields[0]), csv_options->cb_arg)) == NULL ) { |
| 154 | csv_fatal_error("out of memory", csv_options); | 187 | csv_fatal_error("out of memory", csv_options); |
| 155 | return; | 188 | return; |
| 156 | } | 189 | } |
| @@ -159,7 +192,7 @@ csv_field_append(csv_field_t *csv_field, int idx, const csv_options_t * const cs | |||
| 159 | } | 192 | } |
| 160 | else { | 193 | else { |
| 161 | int cap = (csv_field->cap * 3) / 2; /* *= 1.5 */ | 194 | int cap = (csv_field->cap * 3) / 2; /* *= 1.5 */ |
| 162 | int *fields = reallocarray(csv_field->fields, cap, sizeof(csv_field->fields[0])); | 195 | int *fields = csv_options->cb_reallocate(csv_field->fields, cap, sizeof(csv_field->fields[0]), csv_options->cb_arg); |
| 163 | if ( fields == NULL ) { | 196 | if ( fields == NULL ) { |
| 164 | csv_fatal_error("out of memory", csv_options); | 197 | csv_fatal_error("out of memory", csv_options); |
| 165 | return; | 198 | return; |
| @@ -173,11 +206,12 @@ csv_field_append(csv_field_t *csv_field, int idx, const csv_options_t * const cs | |||
| 173 | } | 206 | } |
| 174 | 207 | ||
| 175 | INLINE void | 208 | INLINE void |
| 176 | csv_field_free(csv_field_t *csv_field) | 209 | csv_field_free(csv_field_t *csv_field, const csv_options_t * const csv_options) |
| 177 | { | 210 | { |
| 178 | assert(csv_field != NULL); | 211 | assert(csv_field != NULL); |
| 212 | assert(csv_options != NULL); | ||
| 179 | 213 | ||
| 180 | free(csv_field->fields); | 214 | csv_options->cb_free(csv_field->fields, csv_options->cb_arg); |
| 181 | 215 | ||
| 182 | csv_field_init(csv_field); | 216 | csv_field_init(csv_field); |
| 183 | } | 217 | } |
| @@ -227,8 +261,8 @@ csv_free(csv_t *csv) | |||
| 227 | { | 261 | { |
| 228 | assert(csv != NULL); | 262 | assert(csv != NULL); |
| 229 | 263 | ||
| 230 | csv_string_free(&csv->csv_string); | 264 | csv_string_free(&csv->csv_string, csv->csv_options); |
| 231 | csv_field_free(&csv->csv_field); | 265 | csv_field_free(&csv->csv_field, csv->csv_options); |
| 232 | } | 266 | } |
| 233 | 267 | ||
| 234 | int | 268 | int |
