tcsv.c - ploot - simple plotting tools HTML git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot DIR Log DIR Files DIR Refs DIR Tags --- tcsv.c (3160B) --- 1 #include "csv.h" 2 #include <errno.h> 3 #include <assert.h> 4 #include <string.h> 5 #include <time.h> 6 #include <stdlib.h> 7 #include <limits.h> 8 #include <time.h> 9 #include "util.h" 10 11 /* 12 * Read CSV data onto a set of (struct csv) and some utilities to work on these data. 13 */ 14 15 int 16 csv_min_max(struct csv *vl, int ncol, 17 time_t *tmin, time_t *tmax, 18 double *vmin, double *vmax) 19 { 20 double *v; 21 time_t *t; 22 size_t n; 23 24 *vmin = *vmax = 0; /* always show 0 on the scale */ 25 *tmin = *tmax = *vl->t; 26 27 for (; ncol > 0; ncol--, vl++) { 28 for (t = vl->t, v = vl->v, n = vl->n; n > 0; t++, v++, n--) { 29 if (*v < *vmin) *vmin = *v; 30 if (*v > *vmax) *vmax = *v; 31 if (*t < *tmin) *tmin = *t; 32 if (*t > *tmax) *tmax = *t; 33 } 34 } 35 if (*tmin == *tmax) 36 return -1; 37 return 0; 38 } 39 40 static void 41 csv_add_time(struct csv *vl, time_t epoch) 42 { 43 void *mem; 44 45 if ((mem = realloc(vl->t, (vl->n + 1) * sizeof *vl->t)) == NULL) 46 err(1, "realloc: %s", strerror(errno)); 47 vl->t = mem; 48 vl->t[vl->n] = epoch; 49 } 50 51 static void 52 csv_add_val(struct csv *vl, double field) 53 { 54 void *mem; 55 56 if ((mem = realloc(vl->v, (vl->n + 1) * sizeof *vl->v)) == NULL) 57 err(1, "", strerror(errno)); 58 vl->v = mem; 59 vl->v[vl->n] = field; 60 } 61 62 /* 63 * Add to each column the value on the current row. The time_t 64 * buffer is shared among all fields. 65 */ 66 static void 67 csv_add_row(struct csv *vl, size_t ncol, char *line) 68 { 69 char *field; 70 time_t *tbuf; 71 long l; 72 double d; 73 74 if ((field = strsep(&line, ",")) == NULL) 75 err(1, "missing epoch at row %zu", vl->n); 76 77 l = strtol(field, NULL, 10); 78 if (errno) 79 err(100, "parsing number '%s'", field); 80 81 csv_add_time(vl, l); 82 tbuf = vl[0].t; 83 for (; (field = strsep(&line, ",")); ncol--, vl->n++, vl++) { 84 if (ncol == 0) 85 err(1, "too many fields at line %zu", vl->n); 86 d = strtod(field, NULL); 87 if (errno) 88 err(100, "parsing double '%s'", field); 89 csv_add_val(vl, d); 90 vl->t = tbuf; 91 } 92 if (ncol > 0) 93 err(1, "too few fields at line %zu", vl->n); 94 } 95 96 /* 97 * < (ncol) > 98 * label1,label2,label3 99 */ 100 void 101 csv_labels(FILE *fp, struct csv **vlp, size_t *ncol) 102 { 103 char *field, *line, *cp; 104 struct csv *vl, *col; 105 size_t sz; 106 ssize_t r; 107 108 sz = 0, line = NULL; 109 r = getline(&line, &sz, fp); 110 if (ferror(fp)) 111 err(111, "error while reading from file"); 112 if (feof(fp)) 113 err(100, "missing label line"); 114 strchomp(line); 115 116 cp = line; 117 if (strcmp(strsep(&cp, ","), "epoch") != 0) 118 err(1, "first label must be 'epoch'"); 119 120 sz = 0, vl = NULL, *ncol = 0; 121 while ((field = strsep(&cp, ","))) { 122 if ((vl = realloc(vl, sz += sizeof *vl)) == NULL) 123 err(1, "realloc: %s", strerror(errno)); 124 col = vl + (*ncol)++; 125 memset(col, 0, sizeof *vl); 126 strlcpy(col->label, field, sizeof col->label); 127 } 128 free(line); 129 *vlp = vl; 130 } 131 132 /* 133 * < (ncol) > 134 * val1a,val1b,val1c ^ 135 * val2a,val2b,val2c | 136 * val3a,val3b,val3c (vl->n) 137 * val4a,val4b,val4c | 138 * val5a,val5b,val5c v 139 */ 140 void 141 csv_values(FILE *fp, struct csv *vl, size_t ncol) 142 { 143 char *line; 144 size_t sz; 145 146 sz = 0, line = NULL; 147 while (getline(&line, &sz, fp) > -1) 148 csv_add_row(vl, ncol, line); 149 if (vl->n == 0) 150 err(1, "no value could be read"); 151 if (vl->n == 1) 152 err(1, "only one value could be read"); 153 free(line); 154 }