aboutsummaryrefslogtreecommitdiff
path: root/csv.c
diff options
context:
space:
mode:
Diffstat (limited to 'csv.c')
-rw-r--r--csv.c89
1 files changed, 36 insertions, 53 deletions
diff --git a/csv.c b/csv.c
index 4f3cd14..b68189b 100644
--- a/csv.c
+++ b/csv.c
@@ -44,18 +44,6 @@ mul_overflow(size_t a, size_t b, size_t *out)
44#endif 44#endif
45 45
46static void * 46static void *
47csv_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
58static void *
59csv_mem_reallocate(void *ptr, size_t number, size_t size, void *cb_arg) 47csv_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
131static inline void 118static inline void
132csv_string_append(csv_string_t *csv_string, int ch, const csv_options_t *const csv_options) 119csv_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
138static inline void
139csv_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
196static inline void 181static inline void
197csv_field_append(csv_field_t *csv_field, size_t idx, const csv_options_t *const csv_options) 182csv_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
201static inline void
202csv_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}