ploot-feed.c - ploot - simple plotting tools | |
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
ploot-feed.c (4792B) | |
--- | |
1 #include <ctype.h> | |
2 #include <errno.h> | |
3 #include <fcntl.h> | |
4 #include <limits.h> | |
5 #include <stdint.h> | |
6 #include <stdio.h> | |
7 #include <stdlib.h> | |
8 #include <string.h> | |
9 #include <time.h> | |
10 #include <unistd.h> | |
11 #include "util.h" | |
12 | |
13 #ifndef __OpenBSD__ | |
14 #define pledge(...) 0 | |
15 #endif | |
16 | |
17 #define WIDTH_MAX 1024 | |
18 #define BRAILLE_START 10240 | |
19 | |
20 static int wflag = 80; | |
21 static int width = 0; | |
22 | |
23 /* | |
24 * Turn the bit at position (row, col) on in the . | |
25 */ | |
26 static void | |
27 plot_dot(long *out, int row, int col) | |
28 { | |
29 long flags[4][2] = { | |
30 { 0x01, 0x08 }, | |
31 { 0x02, 0x10 }, | |
32 { 0x04, 0x20 }, | |
33 { 0x40, 0x80 }, | |
34 }; | |
35 | |
36 *out |= flags[row][col];; | |
37 } | |
38 | |
39 static void | |
40 plot_val(long *out, double val, double max, int row) | |
41 { | |
42 int col, c; | |
43 | |
44 val = MIN(max, val); | |
45 col = (int)(val * (double)(width - 1) / max * 2); | |
46 for (c = 0; c < col; c++) | |
47 plot_dot(out + c / 2, row, c % 2); | |
48 } | |
49 | |
50 /* | |
51 * Change the braille characters on a whole row, this for all the | |
52 * values line. | |
53 */ | |
54 static time_t | |
55 plot_row(long *out, char *line, double *max, int nrow, int ncol) | |
56 { | |
57 time_t epoch; | |
58 double val; | |
59 int n; | |
60 char *tok; | |
61 | |
62 tok = strsep(&line, "\t"); | |
63 if (!tok) | |
64 err(100, "*** missing epoch value"); | |
65 epoch = strtol(tok, NULL, 10); | |
66 if (errno) | |
67 warn("*** parsing epoch '%s'", tok); | |
68 | |
69 for (n = 0; (tok = strsep(&line, "\t")) != NULL; n++) { | |
70 if (n >= ncol) | |
71 err(100, "too many values"); | |
72 val = atof(tok); | |
73 plot_val(out + n * width, val, max[n], nrow); | |
74 } | |
75 if (n < ncol) | |
76 err(100, "not enough values"); | |
77 | |
78 return epoch; | |
79 } | |
80 | |
81 /* | |
82 * Read enough input in order to print one line and plot it into 'out'. | |
83 */ | |
84 static time_t | |
85 plot_line(long *out, double *max, int ncol) | |
86 { | |
87 time_t epoch; | |
88 int n, nrow; | |
89 long *o, rune; | |
90 char *line; | |
91 size_t sz; | |
92 | |
93 for (rune = BRAILLE_START, o = out, n = ncol * width; n > 0; o++… | |
94 memcpy(o, &rune, sizeof(rune)); | |
95 *o = '\0'; | |
96 for (rune = 0x2502, o = out, n = 0; n < ncol; o += width, n++) | |
97 memcpy(o, &rune, sizeof(rune)); | |
98 out++; | |
99 | |
100 line = NULL, sz = 0; | |
101 for (nrow = 0; nrow < 4; nrow++) { | |
102 if (getline(&line, &sz, stdin) == -1) { | |
103 if (ferror(stdin)) | |
104 err(111, "reading row from stdin"); | |
105 exit(0); | |
106 } | |
107 epoch = plot_row(out, line, max, nrow, ncol); | |
108 } | |
109 | |
110 free(line); | |
111 return epoch; | |
112 } | |
113 | |
114 static void | |
115 put_time(time_t epoch, time_t last, int nline) | |
116 { | |
117 char *out, buf[sizeof("XXxXXxXX ")]; | |
118 | |
119 switch (nline % 3) { | |
120 case 0: | |
121 strftime(buf, sizeof(buf), "%H:%M:%S _", localtime(&epoc… | |
122 out = buf; | |
123 break; | |
124 case 1: | |
125 strftime(buf, sizeof(buf), "%y/%m/%d ", localtime(&last… | |
126 out = buf; | |
127 break; | |
128 case 2: | |
129 out = " "; | |
130 break; | |
131 } | |
132 | |
133 fputs(out, stdout); | |
134 } | |
135 | |
136 static void | |
137 put_line(long *out) | |
138 { | |
139 for (; *out != '\0'; out++) | |
140 put3utf(*out); | |
141 puts("│"); | |
142 } | |
143 | |
144 static void | |
145 plot(char labels[4069], double *max, int ncol) | |
146 { | |
147 time_t epoch, last_epoch; | |
148 long out[WIDTH_MAX + 1]; | |
149 int n; | |
150 | |
151 last_epoch = epoch = 0; | |
152 | |
153 for (n = 0;; n = (n == 25 ? 0 : n + 1)) { | |
154 if (n == 0) { | |
155 put_time(0, 0, 2); | |
156 fputs(labels, stdout); | |
157 puts("│"); | |
158 } | |
159 | |
160 epoch = plot_line(out, max, ncol); | |
161 put_time(epoch, last_epoch, n); | |
162 last_epoch = epoch; | |
163 put_line(out); | |
164 | |
165 fflush(stdout); | |
166 } | |
167 } | |
168 | |
169 /* | |
170 * Label must be able to store all pointers to token buf has to | |
171 * offer: sizeof(*buf / 2). | |
172 */ | |
173 static int | |
174 read_labels(char **labv) | |
175 { | |
176 int ncol; | |
177 char *cp, *line, *tok; | |
178 size_t sz; | |
179 | |
180 line = NULL, sz = 0; | |
181 if (getline(&line, &sz, stdin) == -1) { | |
182 if (ferror(stdin)) | |
183 err(111, "reading labels from stdin"); | |
184 err(100, "missing label line", stderr); | |
185 } | |
186 strchomp(line); | |
187 cp = line; | |
188 | |
189 if (strcmp(strsep(&cp, "\t"), "epoch") != 0) | |
190 err(100, "first label must be 'epoch'"); | |
191 | |
192 for (ncol = 0; (tok = strsep(&cp, "\t")) != NULL; ncol++, labv++) | |
193 *labv = tok; | |
194 *labv = NULL; | |
195 | |
196 if (ncol < 1) | |
197 err(100, "no label found"); | |
198 return ncol; | |
199 } | |
200 | |
201 static void | |
202 fmt_labels(char out[4069], int ncol, char *labels[4069 / 2]) | |
203 { | |
204 int i, n; | |
205 | |
206 for (i = 0; i < ncol; labels++, i++) { | |
207 n = 4069 - (width + sizeof("│")) * i; | |
208 out += snprintf(out, n, "│%-*s", width - 1, *labels); | |
209 } | |
210 } | |
211 | |
212 static void | |
213 usage(void) | |
214 { | |
215 fprintf(stderr, "usage: %s [-w width] maxval... <tsv\n", arg0); | |
216 exit(1); | |
217 } | |
218 | |
219 int | |
220 main(int argc, char **argv) | |
221 { | |
222 double max[4069 / 2], *m; | |
223 int ncol, nmax; | |
224 char *labv[4069 / 2], labels[4069]; | |
225 int c; | |
226 | |
227 if (pledge("stdio", "") < 0) | |
228 err(1, "pledge: %s", strerror(errno)); | |
229 | |
230 arg0 = *argv; | |
231 while ((c = getopt(argc, argv, "w:")) > -1) { | |
232 switch (c) { | |
233 case 'w': | |
234 wflag = atoi(optarg); | |
235 break; | |
236 default: | |
237 usage(); | |
238 } | |
239 } | |
240 argc -= optind; | |
241 argv += optind; | |
242 | |
243 if (argc == 0) | |
244 usage(); | |
245 | |
246 nmax = argc; | |
247 for (m = max; argc > 0; argc--, argv++, m++) { | |
248 *m = strtod(*argv, NULL); | |
249 if (errno) | |
250 warn("*** parsing float '%s'", *argv); | |
251 } | |
252 | |
253 ncol = read_labels(labv); | |
254 width = (wflag - sizeof("XXxXXxXX _")) / ncol - sizeof("|"); | |
255 fmt_labels(labels, ncol, labv); | |
256 if (ncol != nmax) | |
257 err(100, "not as many labels and arguments"); | |
258 plot(labels, max, ncol); | |
259 | |
260 return 0; | |
261 } |