URI: 
       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 }