csv

Unnamed repository
Log | Files | Refs

commit c24462e068a3181a57e4f0126700fbf1c3c9ba0c
parent 4a01eb737eae0d6d454a5cc7090336643886fe25
Author: aabacchus <ben@bvnf.space>
Date:   Sat,  2 Oct 2021 21:38:19 +0100

create archive

Diffstat:
M.gitignore | 3++-
MMakefile | 15++++++++++++---
Dcsv.c | 237-------------------------------------------------------------------------------
Alibcsv.c | 190+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 204 insertions(+), 241 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1 +1,2 @@ -csv +*.o +*.a diff --git a/Makefile b/Makefile @@ -1,10 +1,19 @@ .POSIX: XCFLAGS = $(CFLAGS) -Wall -Wextra -Wpedantic -Og -ggdb3 -D_XOPEN_SOURCE=600 -csv: csv.c - $(CC) $(XCFLAGS) -o $@ $< +OBJS = libcsv.o + +all: libcsv.a + +$(OBJS:.o=.c): csv.h + +.c.o: + $(CC) -c $(XCFLAGS) -o $@ $< + +libcsv.a: $(OBJS) + $(AR) -rcs $@ $(OBJS) clean: - rm -f csv + rm -f $(OBJS) libcsv.a .PHONY: clean diff --git a/csv.c b/csv.c @@ -1,237 +0,0 @@ -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "csv.h" - -#define MAX_LINE 2048 - -struct csv * -csv_create(void) { - struct csv *c; - c = malloc(sizeof c + sizeof(char *) + sizeof(float *)); - if (c == NULL) - return NULL; - - c->cols = 0; - c->rows = 0; - - char **h = malloc(sizeof (char *) * MAX_LINE); - if (h == NULL) - return NULL; - c->headers = h; - - float **d = malloc(sizeof (float *)); - if (d == NULL) - return NULL; - c->data = d; - - return c; -} - -void -csv_destroy(struct csv *c) { - int i; - for (i = 0; i < c->cols; i++) - free(c->headers[i]); - for (i = 0; i < c->rows; i++) - free(c->data[i]); - free(c); -} - -/* read_header reads each header field name from the first line of the file - * into *header, and returns the number of columns. - * This function mallocs the returned value of fields in *header[0..n-1] - */ -static int -read_header(FILE *f, char **header) { - char **headerp = header; - int c; - int ncols = 0; - char *n = malloc(MAX_LINE); - char *np = n; - while ((c = fgetc(f)) != EOF) { - if (c == ',' || c == '\n') { - *np++ = '\0'; - *headerp = malloc(strlen(n)); - strcpy(*headerp, n); - headerp++; - np = n; - ncols++; - if (c == '\n') break; - continue; - } - *np++ = c; - } - free(n); - return ncols; -} - -/* read_data reads all the comma-separated values from f into *datap, - * and returns the number of rows. - * This function mallocs the number of rows in *header[0..n-1] - * -1 is returned on error. - */ -static int -read_data(FILE *f, float ***datap, int ncols) { - float **data = *datap; - int nrows = 0; - char *n = malloc(MAX_LINE); - if (n == NULL) { - perror("malloc"); - return -1; - } - char *np = n; - data[0] = malloc(sizeof (float) * ncols); - if (data[0] == NULL) { - perror("malloc"); - free(n); - return -1; - } - int c, x, y; - x = y = 0; - while ((c = fgetc(f)) != EOF) { - if (c == ',' || c == '\n') { - if (n == np) { - /* nothing in this column */ - fprintf(stderr, "warning: no value in cell at row %d, col %d\n", y + 1, x + 1); - data[y][x] = 0.; - } else { - *np++ = '\0'; - data[y][x] = (float)atof(n); - np = n; - } - x++; - if (x > ncols) { - /* extra cells in the row. eat up the rest of the row to avoid writing into - * unallocated memory */ - fprintf(stderr, "warning: extra cells in row %d\n", y + 1); - while (c != '\n' && c != EOF) - c = fgetc(f); - if (c == EOF) - break; - } - if (c == '\n') { - if (x < ncols) { - fprintf(stderr, "warning: %d cells missing from row %d\n", ncols - x, y + 1); - for (; x < ncols; x++) - data[y][x] = 0.; - } - nrows++; - y++; - x = 0; - float **tmp = realloc(data, sizeof (float *) * (nrows + 1)); - if (tmp == NULL) { - perror("malloc"); - goto cleanup; - } - data = tmp; - data[y] = malloc(sizeof (float) * ncols); - if (data[y] == NULL) { - nrows--; - perror("malloc"); - goto cleanup; - } - continue; - } - continue; - } - *np++ = c; - } - free(n); - *datap = data; - return nrows; -cleanup: - free(n); - for (int i = 0; i < nrows; y++) - free(data[i]); - return -1; -} - -/* -int -main(int argc, char **argv) { - int c; - char flag_H = 0; - while ((c = getopt(argc, argv, "Hh")) != -1) { - switch (c) { - case 'H': - flag_H = 1; - break; - case 'h': - goto usage; - } - } - if (argc - optind > 1) { -usage: - fprintf(stderr, - "usage: %s [-H] [file]\n if no filename given, data is read from stdin\n" - " -H\tread data headers from first line\n", argv[0]); - return 1; - } - - FILE *f; - if (argc - optind == 0) { - f = stdin; - } else { - f = fopen(argv[optind], "r"); - if (f == NULL) { - perror(argv[optind]); - return 1; - } - } - - struct csv *csv = csv_create(); - if (csv == NULL) { - perror("csv_create"); - return 1; - } - int ret = csv_read_file(f, csv, flag_H); - if (ret != 0) { - csv_destroy(csv); - return 1; - } - return 0; -} -*/ - -int -csv_read_file(FILE *f, struct csv *c, char hdr) { - int ch; - int ncols = 0; - if (hdr) { - /* read header */ - ncols = read_header(f, c->headers); - for (int i = 0; i < ncols; i++) { - printf("%s\t", c->headers[i]); - } - printf("\n"); - } else { - /* scan the first line to get the value of ncols */ - while ((ch = fgetc(f)) != EOF) { - if (ch == ',') ncols++; - if (ch == '\n') { - ncols++; - break; - } - } - /* ensure we can properly scan the first line when we come to it */ - rewind(f); - } - c->cols = ncols; - - /* read data */ - int nrows = read_data(f, &c->data, ncols); - fclose(f); - if (nrows == -1) { - csv_destroy(c); - return 1; - } - for (int i = 0; i < nrows; i++) { - for (int j = 0; j < ncols; j++) - printf("%g\t", c->data[i][j]); - printf("\n"); - } - c->rows = nrows; - return 0; -} diff --git a/libcsv.c b/libcsv.c @@ -0,0 +1,190 @@ +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "csv.h" + +#define MAX_LINE 2048 + +struct csv * +csv_create(void) { + struct csv *c; + c = malloc(sizeof c + sizeof(char *) + sizeof(float *)); + if (c == NULL) + return NULL; + + c->cols = 0; + c->rows = 0; + + char **h = malloc(sizeof (char *) * MAX_LINE); + if (h == NULL) + return NULL; + c->headers = h; + + float **d = malloc(sizeof (float *)); + if (d == NULL) + return NULL; + c->data = d; + + return c; +} + +void +csv_destroy(struct csv *c) { + int i; + for (i = 0; i < c->cols; i++) + free(c->headers[i]); + for (i = 0; i < c->rows; i++) + free(c->data[i]); + free(c); +} + +/* read_header reads each header field name from the first line of the file + * into *header, and returns the number of columns. + * This function mallocs the returned value of fields in *header[0..n-1] + */ +static int +read_header(FILE *f, char **header) { + char **headerp = header; + int c; + int ncols = 0; + char *n = malloc(MAX_LINE); + char *np = n; + while ((c = fgetc(f)) != EOF) { + if (c == ',' || c == '\n') { + *np++ = '\0'; + *headerp = malloc(strlen(n)); + strcpy(*headerp, n); + headerp++; + np = n; + ncols++; + if (c == '\n') break; + continue; + } + *np++ = c; + } + free(n); + return ncols; +} + +/* read_data reads all the comma-separated values from f into *datap, + * and returns the number of rows. + * This function mallocs the number of rows in *header[0..n-1] + * -1 is returned on error. + */ +static int +read_data(FILE *f, float ***datap, int ncols) { + float **data = *datap; + int nrows = 0; + char *n = malloc(MAX_LINE); + if (n == NULL) { + perror("malloc"); + return -1; + } + char *np = n; + data[0] = malloc(sizeof (float) * ncols); + if (data[0] == NULL) { + perror("malloc"); + free(n); + return -1; + } + int c, x, y; + x = y = 0; + while ((c = fgetc(f)) != EOF) { + if (c == ',' || c == '\n') { + if (n == np) { + /* nothing in this column */ + fprintf(stderr, "warning: no value in cell at row %d, col %d\n", y + 1, x + 1); + data[y][x] = 0.; + } else { + *np++ = '\0'; + data[y][x] = (float)atof(n); + np = n; + } + x++; + if (x > ncols) { + /* extra cells in the row. eat up the rest of the row to avoid writing into + * unallocated memory */ + fprintf(stderr, "warning: extra cells in row %d\n", y + 1); + while (c != '\n' && c != EOF) + c = fgetc(f); + if (c == EOF) + break; + } + if (c == '\n') { + if (x < ncols) { + fprintf(stderr, "warning: %d cells missing from row %d\n", ncols - x, y + 1); + for (; x < ncols; x++) + data[y][x] = 0.; + } + nrows++; + y++; + x = 0; + float **tmp = realloc(data, sizeof (float *) * (nrows + 1)); + if (tmp == NULL) { + perror("malloc"); + goto cleanup; + } + data = tmp; + data[y] = malloc(sizeof (float) * ncols); + if (data[y] == NULL) { + nrows--; + perror("malloc"); + goto cleanup; + } + continue; + } + continue; + } + *np++ = c; + } + free(n); + *datap = data; + return nrows; +cleanup: + free(n); + for (int i = 0; i < nrows; y++) + free(data[i]); + return -1; +} + +int +csv_read_file(FILE *f, struct csv *c, char hdr) { + int ch; + int ncols = 0; + if (hdr) { + /* read header */ + ncols = read_header(f, c->headers); + for (int i = 0; i < ncols; i++) { + printf("%s\t", c->headers[i]); + } + printf("\n"); + } else { + /* scan the first line to get the value of ncols */ + while ((ch = fgetc(f)) != EOF) { + if (ch == ',') ncols++; + if (ch == '\n') { + ncols++; + break; + } + } + /* ensure we can properly scan the first line when we come to it */ + rewind(f); + } + c->cols = ncols; + + /* read data */ + int nrows = read_data(f, &c->data, ncols); + fclose(f); + if (nrows == -1) { + csv_destroy(c); + return 1; + } + for (int i = 0; i < nrows; i++) { + for (int j = 0; j < ncols; j++) + printf("%g\t", c->data[i][j]); + printf("\n"); + } + c->rows = nrows; + return 0; +}