|
|
ploot-feed.c - ploot - simple plotting tools |
|
|
 |
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/ploot (git://bitreich.org) |
|
|
 |
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++, 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 } |
|