initial WIP implementation of plain text version - ploot - simple plotting tools | |
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
commit 817580dbf249b75e747cc81f56f930d80600c59e | |
parent 0f63680382fb6f810f4ac27df9793db7cba292cc | |
Author: Josuah Demangeon <[email protected]> | |
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(-) | |
--- | |
diff --git a/.gitignore b/.gitignore | |
@@ -1,3 +1,4 @@ | |
*.o | |
*.core | |
ploot | |
+plootxt | |
diff --git a/Makefile b/Makefile | |
@@ -1,22 +1,31 @@ | |
CFLAGS = -Wall -Wextra -Werror -std=c89 -pedantic -D_POSIX_C_SOURCE=200… | |
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 | |
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 | |
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; | |
+} | |
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; | |
+} | |
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 *); |