/* csv.c : really dumb CSV parser */ #include #include #include #include #include #include "csv.h" #define CSV_MAX_COLS 256 #define CSV_MAX_BUF 4096 struct csv { FILE *f; int current_row; int cols; char filename[32]; char *colptr[CSV_MAX_COLS]; char buf[CSV_MAX_BUF]; int error; }; struct csv *csv_open(const char *filename) { struct csv *st; FILE *f; f = fopen(filename, "r"); if (!f) { perror(filename); return NULL; } st = calloc(1, sizeof(*st)); if (!st) { fclose(f); return NULL; } st->f = f; snprintf(st->filename, sizeof(st->filename), "%s", filename); st->cols = 0; st->current_row = 0; st->colptr[0] = 0; st->error = 0; return st; } void csv_close(struct csv *st) { fclose(st->f); st->f = NULL; st->filename[0] = 0; st->current_row = 0; st->cols = 0; free(st); } /* return 0 on error */ static int csv_parse_row(struct csv *st) { char *in, *out; char *start; in = out = st->buf; st->cols = 0; while (*in) { while (isspace(*in)) in++; if (*in == '"') { /* start of quoted element */ in++; start = out; while (1) { if (!*in) { st->error++; return 0; /* parse error */ } if (*in == '"') { /* is this a double quote? */ in++; if (*in == '"') { /* it it a pair? */ in++; *out++ = '"'; /* insert the quote */ } else { /* no, it's the end of the element */ break; /* done! */ } } else { *out++ = *in++; } } while (isspace(*in)) in++; if (*in == ',') { in++; } else if (*in) { st->error++; return 0; /* parse error */ } *out++ = 0; st->colptr[st->cols++] = start; } else if (*in == 0) { break; /* end of line */ } else { /* unquoted element */ start = out; while (*in) { if (*in == ',') { in++; break; } *out++ = *in++; } *out++ = 0; st->colptr[st->cols++] = start; } } return 1; /* no error */ } static int trimnl(char *buf) { int len; len = strlen(buf); if (buf[len - 1] == '\n') { len--; buf[len] = 0; } return len; } /* return 0 on EOF or error */ int csv_next(struct csv *st) { st->cols = 0; memset(st->colptr, 0, sizeof(st->colptr)); if (!fgets(st->buf, sizeof(st->buf), st->f)) return 0; /* EOF */ st->current_row++; trimnl(st->buf); return csv_parse_row(st); } int csv_current_row(struct csv *st) { return st->current_row; } int csv_cols(struct csv *st) { return st->cols; } const char *csv_element(struct csv *st, int elem) { assert(elem < st->cols ? st->colptr[elem] : "dummy"); return elem < st->cols ? st->colptr[elem] : NULL; } int csv_error(struct csv *st) { return st->error; }