summaryrefslogtreecommitdiff
path: root/csv-parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'csv-parse.c')
-rw-r--r--csv-parse.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/csv-parse.c b/csv-parse.c
new file mode 100644
index 0000000..6feefcb
--- /dev/null
+++ b/csv-parse.c
@@ -0,0 +1,113 @@
+#include "csv-parse.h"
+
+token *tokens = 0;
+token *last_tok = 0;
+
+line *lines = 0;
+line *last_line = 0;
+
+
+inline int iseol(char c) {
+ return (c == '\n' || c == '\0');
+}
+
+token *make_token(char *value) {
+ token *new_tok = malloc(sizeof(token));
+ (last_tok) ? (last_tok->next = new_tok) : (tokens = new_tok);
+ new_tok->value = value;
+ new_tok->next = NULL;
+ last_tok = new_tok;
+ return new_tok;
+}
+
+line *get_line(char *str) {
+ token *t = NULL;
+ int skip = 0; /* Blank column count. */
+ int isblank = 0; /* Used to check if this line is blank. */
+ int i = 0;
+ while (!iseol(str[i])) {
+ char *value = NULL;
+ switch (str[i]) {
+ case '\"': for (++str; str[i] != '\"' && !iseol(str[i]); i++); break;
+ default : for ( ; str[i] != ',' && !iseol(str[i]); i++); break;
+ }
+ /* Is there anything in this column? */
+ if (i) {
+ /* Copy the column contents, and null terminate it. */
+ value = malloc(i+1);
+ memcpy(value, str, i);
+ value[i] = '\0';
+ /* Create the new column. */
+ t = make_token(value);
+ t->skip = skip;
+ skip = 0;
+ t = t->next;
+ } else {
+ value = NULL;
+ skip += (t == NULL);
+ }
+ str += i+1; /* Shift the start of the line to the start of the next column. */
+ i = 0;
+ }
+ isblank = (tokens == NULL && last_tok == NULL);
+ /* Is this line blank? */
+ if (!isblank) {
+ line *l = malloc(sizeof(line));
+ /* If there was a previous line, set the next line to the new line.
+ * Otherwise, set the starting line to the new line. */
+ (last_line) ? (last_line->next = l) : (lines = l);
+ /* Save the starting, and ending columns for this line. */
+ l->tok = tokens;
+ l->last_tok = last_tok;
+
+ tokens = NULL;
+ last_tok = NULL;
+
+ l->next = NULL;
+ last_line = l;
+ return l;
+ } else {
+ return NULL;
+ }
+}
+
+void parse_csv(FILE *fp) {
+ char buf[0x1000];
+ int blank_lines = 0;
+ line *l;
+
+ while (fgets(buf, sizeof(buf), fp) != NULL && !feof(fp)) {
+ l = get_line(buf);
+ blank_lines += (l == NULL);
+ if (l != NULL) {
+ l->skip = blank_lines;
+ blank_lines = 0;
+ }
+ }
+}
+
+void free_tokens(token *t, token *lt, int row) {
+ token *tok;
+ int i = 0;
+ int skip = 0;
+ while (t != NULL) {
+ tok = t;
+ free(tok->value);
+ t = t->next;
+ i++;
+ free(tok);
+ }
+}
+
+void free_lines() {
+ line *l = lines;
+ line *ln;
+ int i = 0;
+ while (l != NULL) {
+ free_tokens(l->tok, l->last_tok, i);
+ i++;
+ ln = l;
+ l = l->next;
+ free(ln);
+ }
+}