ploot-feed.c - ploot - simple plotting tools HTML 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 }