|
|
tcsv.c - ploot - simple plotting tools |
|
|
 |
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot (git://bitreich.org) |
|
|
 |
Log |
|
|
 |
Files |
|
|
 |
Refs |
|
|
 |
Tags |
|
|
 |
README |
|
|
|
--- |
|
|
|
tcsv.c (2343B) |
|
|
|
--- |
|
|
|
1 #include "csv.h" |
|
|
|
2 |
|
|
|
3 #include <errno.h> |
|
|
|
4 #include <assert.h> |
|
|
|
5 #include <string.h> |
|
|
|
6 #include <time.h> |
|
|
|
7 #include <stdlib.h> |
|
|
|
8 #include <limits.h> |
|
|
|
9 #include <time.h> |
|
|
|
10 |
|
|
|
11 #include "log.h" |
|
|
|
12 #include "util.h" |
|
|
|
13 |
|
|
|
14 /* |
|
|
|
15 * Read CSV data onto a set of (struct csv). |
|
|
|
16 */ |
|
|
|
17 |
|
|
|
18 static void |
|
|
|
19 csv_addtime(struct csv *vl, time_t epoch) |
|
|
|
20 { |
|
|
|
21 assert(vl->t = realloc(vl->t, (vl->n + 1) * sizeof(*vl->t))); |
|
|
|
22 vl->t[vl->n] = epoch; |
|
|
|
23 } |
|
|
|
24 |
|
|
|
25 static void |
|
|
|
26 csv_addval(struct csv *vl, double field) |
|
|
|
27 { |
|
|
|
28 assert(vl->v = realloc(vl->v, (vl->n + 1) * sizeof(*vl->v))); |
|
|
|
29 vl->v[vl->n] = field; |
|
|
|
30 } |
|
|
|
31 |
|
|
|
32 /* |
|
|
|
33 * Add to each column the value on the current row. The time_t |
|
|
|
34 * buffer is shared among all fields. |
|
|
|
35 */ |
|
|
|
36 void |
|
|
|
37 csv_addrow(struct csv *vl, size_t ncol, char *line) |
|
|
|
38 { |
|
|
|
39 char *field; |
|
|
|
40 time_t *tbuf; |
|
|
|
41 long l; |
|
|
|
42 double d; |
|
|
|
43 |
|
|
|
44 field = strsep(&line, ","); |
|
|
|
45 if (!field) |
|
|
|
46 die(1, "missing epoch at row %zu", vl->n); |
|
|
|
47 |
|
|
|
48 l = strtol(field, NULL, 10); |
|
|
|
49 if (errno) |
|
|
|
50 die(100, "parsing number '%s'", field); |
|
|
|
51 csv_addtime(vl, l); |
|
|
|
52 tbuf = vl[0].t; |
|
|
|
53 for (; (field = strsep(&line, ",")); ncol--, vl->n++, vl++) { |
|
|
|
54 if (ncol == 0) |
|
|
|
55 die(1, "too many fields at line %zu", vl->n); |
|
|
|
56 d = strtod(field, NULL); |
|
|
|
57 if (errno) |
|
|
|
58 die(100, "parsing double '%s'", field); |
|
|
|
59 csv_addval(vl, d); |
|
|
|
60 vl->t = tbuf; |
|
|
|
61 } |
|
|
|
62 if (ncol > 0) |
|
|
|
63 die(1, "too few fields at line %zu", vl->n); |
|
|
|
64 } |
|
|
|
65 |
|
|
|
66 /* |
|
|
|
67 * < *ncol > |
|
|
|
68 * epoch,label1,label2,label3 |
|
|
|
69 */ |
|
|
|
70 void |
|
|
|
71 csv_labels(FILE *fp, struct csv **vl, size_t *ncol) |
|
|
|
72 { |
|
|
|
73 char *field, *line, *cp; |
|
|
|
74 struct csv *col; |
|
|
|
75 size_t sz; |
|
|
|
76 ssize_t r; |
|
|
|
77 |
|
|
|
78 sz = 0, line = NULL; |
|
|
|
79 r = getline(&line, &sz, fp); |
|
|
|
80 if (ferror(fp)) |
|
|
|
81 die(111, "error while reading from file"); |
|
|
|
82 if (r == -1) |
|
|
|
83 die(100, "missing label line"); |
|
|
|
84 strchomp(line); |
|
|
|
85 |
|
|
|
86 cp = line; |
|
|
|
87 if (strcmp(strsep(&cp, ","), "epoch") != 0) |
|
|
|
88 die(1, "first label must be 'epoch'"); |
|
|
|
89 |
|
|
|
90 *vl = NULL; |
|
|
|
91 *ncol = 0; |
|
|
|
92 while ((field = strsep(&cp, ","))) { |
|
|
|
93 assert(*vl = realloc(*vl, sz += sizeof(**vl))); |
|
|
|
94 col = (*vl) + (*ncol)++; |
|
|
|
95 strlcpy(col->label, field, sizeof(col->label)); |
|
|
|
96 } |
|
|
|
97 |
|
|
|
98 free(line); |
|
|
|
99 } |
|
|
|
100 |
|
|
|
101 /* |
|
|
|
102 * < ncol > |
|
|
|
103 * epoch,a1,b1,c1 ^ |
|
|
|
104 * epoch,a2,b2,c2 vl->n |
|
|
|
105 * epoch,a3,b3,c3 v |
|
|
|
106 */ |
|
|
|
107 void |
|
|
|
108 csv_values(FILE *fp, struct csv *vl, size_t ncol) |
|
|
|
109 { |
|
|
|
110 char *line; |
|
|
|
111 size_t sz; |
|
|
|
112 |
|
|
|
113 sz = 0, line = NULL; |
|
|
|
114 while (getline(&line, &sz, fp) > -1) |
|
|
|
115 csv_addrow(vl, ncol, line); |
|
|
|
116 if (vl->n == 0) |
|
|
|
117 die(1, "no value could be read"); |
|
|
|
118 if (vl->n == 1) |
|
|
|
119 die(1, "only one value could be read"); |
|
|
|
120 |
|
|
|
121 free(line); |
|
|
|
122 } |
|