diff options
Diffstat (limited to 'csv.c')
| -rw-r--r-- | csv.c | 89 |
1 files changed, 36 insertions, 53 deletions
| @@ -44,18 +44,6 @@ mul_overflow(size_t a, size_t b, size_t *out) | |||
| 44 | #endif | 44 | #endif |
| 45 | 45 | ||
| 46 | static void * | 46 | static void * |
| 47 | csv_mem_allocate(size_t number, size_t size, void *cb_arg) | ||
| 48 | { | ||
| 49 | UNUSED(cb_arg); | ||
| 50 | |||
| 51 | size_t len = 0; | ||
| 52 | if ( number == 0 || size == 0 || mul_overflow(number, size, &len) ) { | ||
| 53 | return NULL; | ||
| 54 | } | ||
| 55 | return malloc(len); | ||
| 56 | } | ||
| 57 | |||
| 58 | static void * | ||
| 59 | csv_mem_reallocate(void *ptr, size_t number, size_t size, void *cb_arg) | 47 | csv_mem_reallocate(void *ptr, size_t number, size_t size, void *cb_arg) |
| 60 | { | 48 | { |
| 61 | UNUSED(cb_arg); | 49 | UNUSED(cb_arg); |
| @@ -83,7 +71,6 @@ const csv_options_t csv_default_options = { | |||
| 83 | .field_delimiter = CSV_DEFAULT_DELIMITER, | 71 | .field_delimiter = CSV_DEFAULT_DELIMITER, |
| 84 | .field_separator = CSV_DEFAULT_SEPARATOR, | 72 | .field_separator = CSV_DEFAULT_SEPARATOR, |
| 85 | .cb_error = NULL, | 73 | .cb_error = NULL, |
| 86 | .cb_allocate = csv_mem_allocate, | ||
| 87 | .cb_reallocate = csv_mem_reallocate, | 74 | .cb_reallocate = csv_mem_reallocate, |
| 88 | .cb_free = csv_mem_free | 75 | .cb_free = csv_mem_free |
| 89 | }; | 76 | }; |
| @@ -129,34 +116,32 @@ csv_string_isempty(csv_string_t *csv_string) | |||
| 129 | } | 116 | } |
| 130 | 117 | ||
| 131 | static inline void | 118 | static inline void |
| 132 | csv_string_append(csv_string_t *csv_string, int ch, const csv_options_t *const csv_options) | 119 | csv_string_grow_if_needed(csv_string_t *csv_string, const csv_options_t *const csv_options) |
| 133 | { | 120 | { |
| 134 | assert(csv_string != NULL); | 121 | assert(csv_string != NULL); |
| 135 | assert(csv_options != NULL); | 122 | assert(csv_options != NULL); |
| 136 | 123 | ||
| 137 | static const size_t INITIAL_CAP = 16; | 124 | static const size_t INITIAL_CAP = 16; |
| 138 | 125 | ||
| 139 | if ( csv_string->pos == csv_string->cap ) { // grow if needed | 126 | if ( csv_string->pos == csv_string->cap ) { |
| 140 | if ( csv_string->str == NULL ) { // first call? | 127 | size_t cap = (csv_string->str == NULL) ? INITIAL_CAP : (csv_string->cap * 3) / 2; |
| 141 | char *str = csv_options->cb_allocate(INITIAL_CAP, 1, csv_options->cb_memory_arg); | 128 | char *str = csv_options->cb_reallocate(csv_string->str, cap, 1, csv_options->cb_memory_arg); |
| 142 | if ( str == NULL ) { | 129 | if ( str == NULL ) { |
| 143 | csv_fatal_error(CSV_ERR_OUT_OF_MEMORY, csv_options); | 130 | csv_fatal_error(CSV_ERR_OUT_OF_MEMORY, csv_options); |
| 144 | return; | 131 | return; |
| 145 | } | ||
| 146 | csv_string->str = str; | ||
| 147 | csv_string->cap = INITIAL_CAP; | ||
| 148 | } | ||
| 149 | else { // subsequent call | ||
| 150 | size_t cap = (csv_string->cap * 3) / 2; // *= 1.5 | ||
| 151 | char *str = csv_options->cb_reallocate(csv_string->str, cap, 1, csv_options->cb_memory_arg); | ||
| 152 | if ( str == NULL ) { | ||
| 153 | csv_fatal_error(CSV_ERR_OUT_OF_MEMORY, csv_options); | ||
| 154 | return; | ||
| 155 | } | ||
| 156 | csv_string->str = str; | ||
| 157 | csv_string->cap = cap; | ||
| 158 | } | 132 | } |
| 133 | csv_string->str = str; | ||
| 134 | csv_string->cap = cap; | ||
| 159 | } | 135 | } |
| 136 | } | ||
| 137 | |||
| 138 | static inline void | ||
| 139 | csv_string_append(csv_string_t *csv_string, int ch, const csv_options_t *const csv_options) | ||
| 140 | { | ||
| 141 | assert(csv_string != NULL); | ||
| 142 | assert(csv_options != NULL); | ||
| 143 | |||
| 144 | csv_string_grow_if_needed(csv_string, csv_options); | ||
| 160 | 145 | ||
| 161 | csv_string->str[csv_string->pos++] = (char) ch; // append char | 146 | csv_string->str[csv_string->pos++] = (char) ch; // append char |
| 162 | } | 147 | } |
| @@ -194,34 +179,32 @@ csv_field_reset(csv_field_t *csv_field) | |||
| 194 | } | 179 | } |
| 195 | 180 | ||
| 196 | static inline void | 181 | static inline void |
| 197 | csv_field_append(csv_field_t *csv_field, size_t idx, const csv_options_t *const csv_options) | 182 | csv_field_grow_if_needed(csv_field_t *csv_field, const csv_options_t *const csv_options) |
| 198 | { | 183 | { |
| 199 | assert(csv_field != NULL); | 184 | assert(csv_field != NULL); |
| 200 | assert(csv_options != NULL); | 185 | assert(csv_options != NULL); |
| 201 | 186 | ||
| 202 | static const size_t INITIAL_CAP = 16; | 187 | static const size_t INITIAL_CAP = 16; |
| 203 | 188 | ||
| 204 | if ( csv_field->pos == csv_field->cap ) { // grow if needed | 189 | if ( csv_field->pos == csv_field->cap ) { |
| 205 | if ( csv_field->fields == NULL ) { // first call | 190 | size_t cap = (csv_field->fields == NULL) ? INITIAL_CAP : (csv_field->cap * 3) / 2; |
| 206 | size_t *fields = csv_options->cb_allocate(INITIAL_CAP, sizeof(csv_field->fields[0]), csv_options->cb_memory_arg); | 191 | size_t *fields = csv_options->cb_reallocate(csv_field->fields, cap, sizeof(csv_field->fields[0]), csv_options->cb_memory_arg); |
| 207 | if ( fields == NULL ) { | 192 | if ( fields == NULL ) { |
| 208 | csv_fatal_error(CSV_ERR_OUT_OF_MEMORY, csv_options); | 193 | csv_fatal_error(CSV_ERR_OUT_OF_MEMORY, csv_options); |
| 209 | return; | 194 | return; |
| 210 | } | ||
| 211 | csv_field->fields = fields; | ||
| 212 | csv_field->cap = INITIAL_CAP; | ||
| 213 | } | ||
| 214 | else { // subsequent call | ||
| 215 | size_t cap = (csv_field->cap * 3) / 2; // *= 1.5 | ||
| 216 | size_t *fields = csv_options->cb_reallocate(csv_field->fields, cap, sizeof(csv_field->fields[0]), csv_options->cb_memory_arg); | ||
| 217 | if ( fields == NULL ) { | ||
| 218 | csv_fatal_error(CSV_ERR_OUT_OF_MEMORY, csv_options); | ||
| 219 | return; | ||
| 220 | } | ||
| 221 | csv_field->fields = fields; | ||
| 222 | csv_field->cap = cap; | ||
| 223 | } | 195 | } |
| 196 | csv_field->fields = fields; | ||
| 197 | csv_field->cap = cap; | ||
| 224 | } | 198 | } |
| 199 | } | ||
| 200 | |||
| 201 | static inline void | ||
| 202 | csv_field_append(csv_field_t *csv_field, size_t idx, const csv_options_t *const csv_options) | ||
| 203 | { | ||
| 204 | assert(csv_field != NULL); | ||
| 205 | assert(csv_options != NULL); | ||
| 206 | |||
| 207 | csv_field_grow_if_needed(csv_field, csv_options); | ||
| 225 | 208 | ||
| 226 | csv_field->fields[csv_field->pos++] = idx; // append index | 209 | csv_field->fields[csv_field->pos++] = idx; // append index |
| 227 | } | 210 | } |
