|
|
tsv.c - ploot - simple plotting tools |
|
|
 |
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
 |
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 } |
|