-
Notifications
You must be signed in to change notification settings - Fork 44
Open
Description
I think it would really help if the examples/ area has a program that demonstrates how to get and process CSV data. I offer the following, maybe call it csvdump.c. I believe it frees all resources but please double check, my C skills are a little rusty.
// Parse CSV file using libcsv and emit rows on stdout.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "csv.h"
// Storage for one row of data and parse state
typedef struct {
size_t row;
char **fields;
size_t alloc;
size_t cur_field;
int error;
} csv_reader;
// Parser calls this function when it detects end of a field
void field_cb(void *field, size_t field_len, void *data) {
csv_reader *cr = (csv_reader*)data;
if (cr->error)
return;
// check for space to store this field
if (cr->cur_field == cr->alloc) {
cr->alloc *= 2;
cr->fields = realloc(cr->fields, sizeof(char *) * cr->alloc);
if (cr->fields == NULL) {
fprintf(stderr, "field_cb: failed to reallocate %zu bytes",
sizeof(char *) * cr->alloc);
perror(NULL);
cr->error = 1;
return;
}
}
cr->fields[cr->cur_field] = strndup((char*)field, field_len);
cr->cur_field += 1;
}
// Parser calls this function when it detects end of a row
void row_cb(int delim __attribute__((unused)), void *data) {
csv_reader *cr = (csv_reader*)data;
if (cr->error)
return;
printf("Row %zu:\n", cr->row);
for (size_t i = 0; i < cr->cur_field; ++i) {
printf("\tField %zu: %s\n", i, cr->fields[i]);
free(cr->fields[i]);
}
cr->cur_field = 0;
cr->row += 1;
}
// Parse data from file at the specified path.
// Return 0 on success, non-zero on failure.
int parse_csv_file(const char *path) {
int retval = 1;
struct csv_parser cp;
int rc = csv_init(&cp, CSV_STRICT);
if (rc != 0) {
fputs("failed to initialize CSV parser\n", stderr);
goto FINAL;
}
// Preallocate space for some fields
csv_reader cr;
memset((void*)&cr, 0, sizeof(csv_reader));
cr.alloc = 16;
cr.fields = malloc(sizeof(char *) * cr.alloc);
if (cr.fields == NULL) {
fprintf(stderr, "failed to allocate %zu bytes\n",
sizeof(char *) * cr.alloc);
goto FINAL;
}
FILE *fp = fopen(path, "rb");
if (!fp) {
fprintf(stderr, "failed to open file %s\n", path);
retval = 1;
goto FAIL_FP;
}
char buf[4096];
size_t bytes_read;
while ((bytes_read = fread(buf, 1, sizeof(buf), fp)) > 0) {
if (csv_parse(&cp, buf, bytes_read, field_cb, row_cb, &cr) != bytes_read) {
fprintf(stderr, "Error while parsing file: %s\n",
csv_strerror(csv_error(&cp)) );
goto FAIL_CR;
}
}
rc = csv_fini(&cp, field_cb, row_cb, &cr);
if (cr.error || rc != 0) {
fputs("Parse failed\n", stderr);
goto FAIL_CR;
}
SUCCESS:
retval = 0;
FAIL_CR:
fclose(fp);
FAIL_FP:
free(cr.fields);
FINAL:
return retval;
}
// Invoke the parser with the first argument as file path
int main(int argc, const char **argv) {
if (argc != 2) {
fprintf(stderr, "Usage: %s file.csv\n", argv[0]);
return 1;
}
return parse_csv_file(argv[1]);
}
Metadata
Metadata
Assignees
Labels
No labels