ploot-feed.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
---
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++, n--)
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(&epoch));
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 }