diff options
| author | Thomas Schmucker <ts@its1.de> | 2023-08-27 13:15:02 +0200 |
|---|---|---|
| committer | Thomas Schmucker <ts@its1.de> | 2023-08-27 13:15:02 +0200 |
| commit | 25eed0fcaca4c72bfddb71ded3930912c8e672fb (patch) | |
| tree | f01028f4886d58ddcf1948acb328773bd05821a2 | |
| parent | c684b9b035082c4e5f69d856a33888ede45ba204 (diff) | |
| download | libcsv-25eed0fcaca4c72bfddb71ded3930912c8e672fb.tar.gz libcsv-25eed0fcaca4c72bfddb71ded3930912c8e672fb.tar.bz2 libcsv-25eed0fcaca4c72bfddb71ded3930912c8e672fb.zip | |
Einfacheres Speichermanagement implementiert
| -rw-r--r-- | csv-tutorial.c | 36 | ||||
| -rw-r--r-- | csv.c | 89 |
2 files changed, 48 insertions, 77 deletions
diff --git a/csv-tutorial.c b/csv-tutorial.c index 17b95c8..9bdb7e6 100644 --- a/csv-tutorial.c +++ b/csv-tutorial.c | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | bool | 8 | bool |
| 9 | processFile(const char *filename) | 9 | processFile(const char *filename) |
| 10 | { | 10 | { |
| 11 | FILE *in; | 11 | FILE *in = fopen(filename, "r"); |
| 12 | 12 | ||
| 13 | if ( (in = fopen(filename, "r")) == NULL ) { | 13 | if ( in == NULL ) { |
| 14 | return false; | 14 | return false; |
| 15 | } | 15 | } |
| 16 | 16 | ||
| @@ -18,22 +18,21 @@ processFile(const char *filename) | |||
| 18 | csv_init(&csv); | 18 | csv_init(&csv); |
| 19 | 19 | ||
| 20 | while ( csv_read(&csv, in) ) { | 20 | while ( csv_read(&csv, in) ) { |
| 21 | const size_t nf = csv_nfields(&csv); | 21 | const size_t nfields = csv_nfields(&csv); |
| 22 | (void) nf; | ||
| 23 | // ... | 22 | // ... |
| 24 | } | 23 | } |
| 25 | csv_cleanup(&csv); | 24 | csv_cleanup(&csv); |
| 26 | 25 | ||
| 27 | fclose(in); | 26 | (void) fclose(in); |
| 28 | return true; | 27 | return true; |
| 29 | } | 28 | } |
| 30 | 29 | ||
| 31 | bool | 30 | bool |
| 32 | processFile_options(const char *filename) | 31 | processFile_options(const char *filename) |
| 33 | { | 32 | { |
| 34 | FILE *in; | 33 | FILE *in = fopen(filename, "r"); |
| 35 | 34 | ||
| 36 | if ( (in = fopen(filename, "r")) == NULL ) { | 35 | if ( in == NULL ) { |
| 37 | return false; | 36 | return false; |
| 38 | } | 37 | } |
| 39 | 38 | ||
| @@ -45,13 +44,12 @@ processFile_options(const char *filename) | |||
| 45 | csv_init_opt(&csv, &csv_options); | 44 | csv_init_opt(&csv, &csv_options); |
| 46 | 45 | ||
| 47 | while ( csv_read(&csv, in) ) { | 46 | while ( csv_read(&csv, in) ) { |
| 48 | const size_t nf = csv_nfields(&csv); | 47 | const size_t nfields = csv_nfields(&csv); |
| 49 | (void) nf; | ||
| 50 | // ... | 48 | // ... |
| 51 | } | 49 | } |
| 52 | csv_cleanup(&csv); | 50 | csv_cleanup(&csv); |
| 53 | 51 | ||
| 54 | fclose(in); | 52 | (void) fclose(in); |
| 55 | return true; | 53 | return true; |
| 56 | } | 54 | } |
| 57 | 55 | ||
| @@ -64,9 +62,9 @@ csvErrorHandler(csv_err_t err, void *cb_arg) | |||
| 64 | bool | 62 | bool |
| 65 | processFile_error(const char *filename) | 63 | processFile_error(const char *filename) |
| 66 | { | 64 | { |
| 67 | FILE *in; | 65 | FILE *in = fopen(filename, "r"); |
| 68 | 66 | ||
| 69 | if ( (in = fopen(filename, "r")) == NULL ) { | 67 | if ( in == NULL ) { |
| 70 | return false; | 68 | return false; |
| 71 | } | 69 | } |
| 72 | 70 | ||
| @@ -84,30 +82,20 @@ processFile_error(const char *filename) | |||
| 84 | switch ( setjmp(env) ) { | 82 | switch ( setjmp(env) ) { |
| 85 | case CSV_ERR_OK: | 83 | case CSV_ERR_OK: |
| 86 | while ( csv_read(&csv, in) ) { | 84 | while ( csv_read(&csv, in) ) { |
| 87 | const size_t nf = csv_nfields(&csv); | 85 | const size_t nfields = csv_nfields(&csv); |
| 88 | (void) nf; | ||
| 89 | // ... | 86 | // ... |
| 90 | } | 87 | } |
| 91 | break; | 88 | break; |
| 92 | 89 | ||
| 93 | case CSV_ERR_OUT_OF_MEMORY: | 90 | case CSV_ERR_OUT_OF_MEMORY: |
| 94 | csv_cleanup(&csv); | ||
| 95 | break; | ||
| 96 | |||
| 97 | case CSV_ERR_OUT_OF_RANGE: | 91 | case CSV_ERR_OUT_OF_RANGE: |
| 98 | csv_cleanup(&csv); | ||
| 99 | break; | ||
| 100 | |||
| 101 | case CSV_ERR_IO_READ: | 92 | case CSV_ERR_IO_READ: |
| 102 | csv_cleanup(&csv); | ||
| 103 | break; | ||
| 104 | |||
| 105 | case CSV_ERR_IO_WRITE: | 93 | case CSV_ERR_IO_WRITE: |
| 106 | csv_cleanup(&csv); | 94 | csv_cleanup(&csv); |
| 107 | break; | 95 | break; |
| 108 | } | 96 | } |
| 109 | 97 | ||
| 110 | fclose(in); | 98 | (void) fclose(in); |
| 111 | return true; | 99 | return true; |
| 112 | } | 100 | } |
| 113 | 101 | ||
| @@ -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 | } |
