tsv.c - ploot - simple plotting tools
(HTM) 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 }