initial WIP implementation of plain text version - 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
---
(DIR) commit 817580dbf249b75e747cc81f56f930d80600c59e
(DIR) parent 0f63680382fb6f810f4ac27df9793db7cba292cc
(HTM) Author: Josuah Demangeon <mail@josuah.net>
Date: Sun, 6 May 2018 23:11:07 +0200
initial WIP implementation of plain text version
Diffstat:
M .gitignore | 1 +
M Makefile | 29 +++++++++++++++++++----------
M ploot.c | 47 +++----------------------------
A plootxt.c | 188 +++++++++++++++++++++++++++++++
M util.c | 50 +++++++++++++++++++++++++++++++
A util.h | 6 ++++++
6 files changed, 268 insertions(+), 53 deletions(-)
---
(DIR) diff --git a/.gitignore b/.gitignore
@@ -1,3 +1,4 @@
*.o
*.core
ploot
+plootxt
(DIR) diff --git a/Makefile b/Makefile
@@ -1,22 +1,31 @@
CFLAGS = -Wall -Wextra -Werror -std=c89 -pedantic -D_POSIX_C_SOURCE=200809L
LDFLAGS = -static
-SRC = ploot.c ffplot.c ffdraw.c font_14x7.c
-OBJ = $(SRC:.c=.o)
+PLOOT_SRC = ploot.c ffplot.c ffdraw.c font_14x7.c util.c
+PLOOT_OBJ = $(PLOOT_SRC:.c=.o)
+
+PLOOTXT_SRC = plootxt.c util.c
+PLOOTXT_OBJ = $(PLOOTXT_SRC:.c=.o)
+
LIB = -lm
-all:x ploot
+all:V ploot plootxt
-ploot: $(OBJ)
- ${CC} $(LDFLAGS) -o $@ $(OBJ) $(LIB)
+ploot: $(PLOOT_OBJ)
+ ${CC} $(LDFLAGS) -o $@ $(PLOOT_OBJ) $(LIB)
-install:x ploot
+plootxt: $(PLOOTXT_OBJ)
+ ${CC} $(LDFLAGS) -o $@ $(PLOOTXT_OBJ) $(LIB)
+
+install:V ploot plootxt
mkdir -p ${PREFIX}/bin
- cp ploot ${PREFIX}/bin/ploot
+ cp ploot plootxt ${PREFIX}/bin
-clean:x
+clean:V
rm -f *.o ploot
-x:
+V: # :V acts like .PHONY:
+
+$(PLOOT_SRC) $(PLOOTXT_SRC): \
+arg.h ploot.h util.h font.h font_14x7.h
-$(SRC): arg.h ploot.h font.h font_14x7.h
(DIR) diff --git a/ploot.c b/ploot.c
@@ -8,6 +8,7 @@
#include "arg.h"
#include "ploot.h"
+#include "util.h"
#include "config.h" /* after ploot.h for type definitions */
#define LEN(x) (sizeof(x) / sizeof(*x))
@@ -32,26 +33,10 @@ color(Color *col, char *name)
}
static void
-estriplf(char *line)
-{
- char *lf;
-
- if ((lf = strchr(line, '\n')) == NULL || lf[1] != '\0')
- fputs("invalid input\n", stderr), exit(1);
- *lf = '\0';
-}
-
-static void
read_labels(Vlist *v, char **argv, char *buf)
{
- if (fgets(buf, LINE_MAX, stdin) == NULL) {
- if (ferror(stdin))
- perror("fread from stdin");
- else
- fputs("missing label line\n", stderr);
- exit(1);
- }
- estriplf(buf);
+ if (esfgets(buf, LINE_MAX, stdin) == NULL)
+ fputs("missing label line\n", stderr), exit(1);
if (strcmp(strsep(&buf, ","), "epoch") != 0)
fputs("first label must be \"epoch\"\n", stderr), exit(1);
@@ -66,28 +51,6 @@ read_labels(Vlist *v, char **argv, char *buf)
fputs("more columns than arguments\n", stderr), exit(1);
}
-static double
-eatof(char *str)
-{
- char *s;
-
- for (s = str; *s != '\0'; s++)
- if (!isdigit(*s) && *s != '-' && *s != '.')
- fputs("invalid float format\n", stderr), exit(0);
- return atof(str);
-}
-
-static long
-eatol(char *str)
-{
- char *s;
-
- for (s = str; *s != '\0'; s++)
- if (!isdigit(*s) && *s != '-')
- fputs("invalid number format\n", stderr), exit(0);
- return atol(str);
-}
-
static int
add_val(Vlist *v, int bufsize, int nval, double field, time_t epoch)
{
@@ -145,10 +108,8 @@ read_values(Vlist *v, int ncol)
char line[LINE_MAX];
bufsize = 0;
- for (nval = 0; fgets(line, sizeof(line), stdin); nval++) {
- estriplf(line);
+ for (nval = 0; esfgets(line, sizeof(line), stdin) != NULL; nval++)
bufsize = add_row(v, bufsize, ncol, nval, line);
- }
}
static void
(DIR) diff --git a/plootxt.c b/plootxt.c
@@ -0,0 +1,188 @@
+#include <time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "arg.h"
+#include "util.h"
+
+#define LEN(x) (sizeof(x) / sizeof(*x))
+
+#define WIDTH_MAX 1024
+
+int screenwidth = 80;
+
+char *argv0;
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s <csv\n", argv0);
+ exit(1);
+}
+
+void
+fmt_labels(char out[LINE_MAX], int ncol, char *labels[LINE_MAX / 2])
+{
+ int i, w;
+
+ w = screenwidth / ncol;
+ for (i = 0; i < ncol; labels++, i++)
+ out += snprintf(out, w - 1, " %.*s", w - 1, *labels);
+}
+
+/*
+ * Label must be able to store all pointers to token buf has to
+ * offer: sizeof(*buf / 2).
+ */
+static int
+read_labels(char out[LINE_MAX])
+{
+ int ncol;
+ char *l, line[LINE_MAX], *labels[LINE_MAX / 2], *tok;
+
+ l = line;
+ if (esfgets(line, LINE_MAX, stdin) == NULL)
+ fputs("missing label line\n", stderr), exit(1);
+
+ if (strcmp(strsep(&l, ","), "epoch") != 0)
+ fputs("first label must be \"epoch\"\n", stderr), exit(1);
+
+ for (ncol = 1; (tok = strsep(&l, ",")) != NULL; ncol++)
+ *labels = tok;
+ *labels = NULL;
+
+ if (ncol < 2)
+ fputs("no label found\n", stderr), exit(1);
+
+ fmt_labels(out, ncol, labels);
+
+ return ncol;
+}
+
+void
+plot_val(char *out, double val, int nrow, int width)
+{
+ (void)val;
+ (void)out;
+ (void)nrow;
+ (void)width;
+}
+
+/*
+ * Change the braille characters on a whole row, this for all the
+ * values line.
+ */
+time_t
+plot_row(char *out, char *line, int nrow, int ncol, int width)
+{
+ time_t epoch;
+ double val;
+ int n;
+ char *tok;
+
+ if ((tok = strsep(&line, ",")) == NULL)
+ fputs("*** missing epoch value\n", stderr), exit(1);
+ epoch = eatol(tok);
+
+ for (n = 1; (tok = strsep(&line, ",")) != NULL; n++) {
+ if (n >= ncol)
+ fputs("too many values\n", stderr), exit(1);
+ val = eatof(tok);
+ plot_val(out + n * width, nrow, val, width);
+ }
+ if (n < ncol)
+ fputs("not enough values\n", stderr), exit(1);
+
+ return epoch;
+}
+
+/*
+ * Read enough input in order to print one line and plot it into 'out'.
+ */
+time_t
+plot_line(char *out, int ncol, int width)
+{
+ time_t epoch;
+ int nrow;
+ char line[LINE_MAX];
+
+ for (nrow = 0; nrow < 4; nrow++) {
+ if ((esfgets(line, LINE_MAX, stdin)) == NULL)
+ exit(0);
+ epoch = plot_row(out, line, nrow, ncol, width);
+ }
+
+ return epoch;
+}
+
+void
+put_time(time_t epoch, time_t last, int nline)
+{
+ char *out, buf[sizeof("XXxXXxXX |")];
+
+ switch (nline % 3) {
+ case 0:
+ strftime(buf, sizeof(buf), "%H:%M:%S _|", localtime(&epoch));
+ out = buf;
+ break;
+ case 1:
+ strftime(buf, sizeof(buf), "%y/%m/%d |", localtime(&last));
+ out = buf;
+ break;
+ case 2:
+ out = " |";
+ break;
+ }
+
+ fputs(out, stdout);
+}
+
+void
+plot(char labels[LINE_MAX], int ncol)
+{
+ time_t epoch, last_epoch;
+ int n, width;
+ char out[WIDTH_MAX * 3 + 1];
+
+ width = screenwidth / ncol;
+ last_epoch = epoch = 0;
+
+ for (n = 0;; n++) {
+ if (n >= 20) {
+ puts(labels);
+ n = 0;
+ }
+
+ epoch = plot_line(out, ncol, width);
+ put_time(epoch, last_epoch, n);
+ last_epoch = epoch;
+ puts(out);
+
+ fflush(stdout);
+ }
+}
+
+void
+parse_args(int argc, char **argv)
+{
+ argv0 = *argv;
+ if (argc != 1)
+ usage();
+}
+
+int
+main(int argc, char **argv)
+{
+ char labels[LINE_MAX];
+ int ncol;
+
+ parse_args(argc, argv);
+ ncol = read_labels(labels);
+ plot(labels, ncol);
+
+ return 0;
+}
(DIR) diff --git a/util.c b/util.c
@@ -1,4 +1,9 @@
#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <ctype.h>
#include "ploot.h"
@@ -19,3 +24,48 @@ strsep(char **strp, const char *sep)
return prev;
}
+
+void
+estriplf(char *line)
+{
+ char *lf;
+
+ if ((lf = strchr(line, '\n')) == NULL || lf[1] != '\0')
+ fputs("invalid input\n", stderr), exit(1);
+ *lf = '\0';
+}
+
+double
+eatof(char *str)
+{
+ char *s;
+
+ for (s = str; *s != '\0'; s++)
+ if (!isdigit(*s) && *s != '-' && *s != '.')
+ fputs("invalid float format\n", stderr), exit(0);
+ return atof(str);
+}
+
+long
+eatol(char *str)
+{
+ char *s;
+
+ for (s = str; *s != '\0'; s++)
+ if (!isdigit(*s) && *s != '-')
+ fputs("invalid number format\n", stderr), exit(0);
+ return atol(str);
+}
+
+char *
+esfgets(char *buf, size_t n, FILE *file)
+{
+ if (fgets(buf, n, file) == NULL) {
+ if (ferror(stdin))
+ perror("fread from stdin"), exit(1);
+ else
+ return NULL;
+ }
+ estriplf(buf);
+ return buf;
+}
(DIR) diff --git a/util.h b/util.h
@@ -0,0 +1,6 @@
+/* util.c */
+char *strsep (char **, const char *);
+void estriplf (char *);
+double eatof (char *);
+long eatol (char *);
+char *esfgets (char *, size_t, FILE *);