diff --git a/src/csv-data-manipulation.c b/src/csv-data-manipulation.c index e4bfc94..50c558a 100644 --- a/src/csv-data-manipulation.c +++ b/src/csv-data-manipulation.c @@ -17,13 +17,16 @@ typedef struct { - char delim; + char * delim; unsigned int rows; unsigned int cols; char ** table; } CSV; -/* trim whitespaces from left & right of a string */ + +/** + * Utility function to trim whitespaces from left & right of a string + */ int trim(char ** str) { int trimmed; int n; @@ -49,20 +52,40 @@ int trim(char ** str) { return trimmed; } -CSV * csv_create() { + +/** + * De-allocate csv structure + */ +int csv_destroy(CSV * csv) { + if (csv == NULL) { return 0; } + if (csv->table != NULL) { free(csv->table); } + if (csv->delim != NULL) { free(csv->delim); } + free(csv); + return 0; +} + + +/** + * Allocate memory for a CSV structure + */ +CSV * csv_create(unsigned int cols, unsigned int rows) { CSV * csv; csv = malloc(sizeof(CSV)); - csv->rows = 0; - csv->cols = 0; - csv->table = NULL; + csv->rows = rows; + csv->cols = cols; + csv->delim = strdup(","); + + csv->table = malloc(sizeof(char *) * cols * rows); + if (csv->table == NULL) { goto error; } + + memset(csv->table, 0, sizeof(char *) * cols * rows); return csv; -} -int csv_destroy(CSV * csv) { - free(csv); - return 0; +error: + csv_destroy(csv); + return NULL; } @@ -70,7 +93,9 @@ int csv_destroy(CSV * csv) { * Get value in CSV table at COL, ROW */ char * csv_get(CSV * csv, unsigned int col, unsigned int row) { - return NULL; + unsigned int idx; + idx = col + (row * csv->cols); + return csv->table[idx]; } @@ -78,9 +103,32 @@ char * csv_get(CSV * csv, unsigned int col, unsigned int row) { * Set value in CSV table at COL, ROW */ int csv_set(CSV * csv, unsigned int col, unsigned int row, char * value) { + unsigned int idx; + idx = col + (row * csv->cols); + csv->table[idx] = value; return 0; } +void csv_display(CSV * csv) { + int row, col; + char * content; + if ((csv->rows == 0) || (csv->cols==0)) { + printf("[Empty table]\n"); + return ; + } + + printf("\n[Table cols=%d rows=%d]\n", csv->cols, csv->rows); + for (row=0; rowrows; row++) { + printf("[|"); + for (col=0; colcols; col++) { + content = csv_get(csv, col, row); + printf("%s\t|", content); + } + printf("]\n"); + } + printf("\n"); +} + /* Resize CSV table * - grow columns: on each row, add missing columns cells * - grow rows: add now rows, with all columns count @@ -97,14 +145,12 @@ int csv_resize(CSV * old_csv, unsigned int new_cols, unsigned int new_rows) { bool in_old, in_new; /* Build a new (fake) csv */ - new_csv = csv_create(); + new_csv = csv_create(new_cols, new_rows); + if (new_csv == NULL) { goto error; } + new_csv->rows = new_rows; new_csv->cols = new_cols; - new_csv->table = malloc(sizeof(char *) * new_cols * new_rows); - memset(new_csv->table, 0, sizeof(char *) * new_cols * new_rows); - - if (new_csv->table == NULL) { goto error; } max_cols = (new_cols > old_csv->cols)? new_cols : old_csv->cols; max_rows = (new_rows > old_csv->rows)? new_rows : old_csv->rows; @@ -122,10 +168,7 @@ int csv_resize(CSV * old_csv, unsigned int new_cols, unsigned int new_rows) { /* destroy data */ content = csv_get(old_csv, cur_col, cur_row); free(content); - } else { - /* skip */ - /* csv_set(new_csv, cur_col, cur_row, NULL); */ - } + } else { /* skip */ } } } /* on rows */ @@ -133,6 +176,9 @@ int csv_resize(CSV * old_csv, unsigned int new_cols, unsigned int new_rows) { old_csv->rows = new_rows; old_csv->cols = new_cols; old_csv->table = new_csv->table; + new_csv->table = NULL; + csv_destroy(new_csv); + return 0; error: @@ -151,34 +197,52 @@ int csv_open(CSV * csv, char * filename) { fp = fopen(filename, "r"); - if (fp == NULL) { exit(EXIT_FAILURE); } + if (fp == NULL) { goto error; } m_rows = 0; m_cols = 0; while(fgets(line, sizeof(line), fp) != NULL) { - /* printf("Got line: %s", line); */ m_rows += 1; cols = 0; lineptr = line; - while ((token = strtok(lineptr, ",")) != NULL) { + while ((token = strtok(lineptr, csv->delim)) != NULL) { lineptr = NULL; trim(&token); - printf("%s\t|", token); cols += 1; if (cols > m_cols) { m_cols = cols; } csv_resize(csv, m_cols, m_rows); + csv_set(csv, cols-1, m_rows-1, strdup(token)); } - printf("\n"); } fclose(fp); - csv->delim = '\t'; csv->rows = m_rows; csv->cols = m_cols; return 0; + +error: + fclose(fp); + printf("Unable to open %s for reading.", filename); + return -1; } + int csv_save(CSV * csv, char * filename) { + FILE * fp; + int row, col; + char * content; + + fp = fopen(filename, "w"); + for (row=0; rowrows; row++) { + for (col=0; colcols; col++) { + content = csv_get(csv, col, row); + fprintf(fp, "%s%s", content, + ((col == csv->cols-1) ? "" : csv->delim) ); + } + fprintf(fp, "\n"); + } + + fclose(fp); return 0; } @@ -187,17 +251,18 @@ int main(int argc, char ** argv) { printf("%s\n%s\n\n",TITLE, URL); - - csv = csv_create(); + csv = csv_create(0, 0); csv_open(csv, "fixtures/csv-data-manipulation.csv"); + csv_display(csv); csv_set(csv, 0, 0, "Column0"); csv_set(csv, 1, 1, "100"); csv_set(csv, 2, 2, "200"); csv_set(csv, 3, 3, "300"); csv_set(csv, 4, 4, "400"); + csv_display(csv); - csv_save(csv, "fixtures/csv-data-manupulation.out.csv"); + csv_save(csv, "tmp/csv-data-manupulation.out.csv"); csv_destroy(csv); return 0;