commit c24462e068a3181a57e4f0126700fbf1c3c9ba0c
parent 4a01eb737eae0d6d454a5cc7090336643886fe25
Author: aabacchus <ben@bvnf.space>
Date: Sat, 2 Oct 2021 21:38:19 +0100
create archive
Diffstat:
M | .gitignore | | | 3 | ++- |
M | Makefile | | | 15 | ++++++++++++--- |
D | csv.c | | | 237 | ------------------------------------------------------------------------------- |
A | libcsv.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;
+}