tsv.c - ploot - simple plotting tools HTML git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot DIR Log DIR Files DIR Refs DIR Tags DIR README DIR LICENSE --- tsv.c (3148B) --- 1 #include "tsv.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 TSV data onto a set of (struct tsv) and some utilities to work on these data. 13 */ 14 15 int 16 tsv_min_max(struct tsv *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 tsv_add_time(struct tsv *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 tsv_add_val(struct tsv *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 tsv_add_row(struct tsv *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, "\t")) == 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 tsv_add_time(vl, l); 82 tbuf = vl[0].t; 83 for (; (field = strsep(&line, "\t")); 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 tsv_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 tsv_labels(FILE *fp, struct tsv **vlp, size_t *ncol) 102 { 103 char *field, *line, *cp; 104 struct tsv *vl, *col; 105 size_t sz; 106 107 sz = 0, line = NULL; 108 getline(&line, &sz, fp); 109 if (ferror(fp)) 110 err(111, "error while reading from file"); 111 if (feof(fp)) 112 err(100, "missing label line"); 113 strchomp(line); 114 115 cp = line; 116 if (strcmp(strsep(&cp, "\t"), "epoch") != 0) 117 err(1, "first label must be 'epoch'"); 118 119 sz = 0, vl = NULL, *ncol = 0; 120 while ((field = strsep(&cp, "\t"))) { 121 if ((vl = realloc(vl, sz += sizeof *vl)) == NULL) 122 err(1, "realloc: %s", strerror(errno)); 123 col = vl + (*ncol)++; 124 memset(col, 0, sizeof *vl); 125 strlcpy(col->label, field, sizeof col->label); 126 } 127 free(line); 128 *vlp = vl; 129 } 130 131 /* 132 * < (ncol) > 133 * val1a,val1b,val1c ^ 134 * val2a,val2b,val2c | 135 * val3a,val3b,val3c (vl->n) 136 * val4a,val4b,val4c | 137 * val5a,val5b,val5c v 138 */ 139 void 140 tsv_values(FILE *fp, struct tsv *vl, size_t ncol) 141 { 142 char *line; 143 size_t sz; 144 145 sz = 0, line = NULL; 146 while (getline(&line, &sz, fp) > -1) 147 tsv_add_row(vl, ncol, line); 148 if (vl->n == 0) 149 err(1, "no value could be read"); 150 if (vl->n == 1) 151 err(1, "only one value could be read"); 152 free(line); 153 }