Introduction
Introduction Statistics Contact Development Disclaimer Help
flatten the repository and simplify Makefile - ploot - simple plotting tools
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65…
Log
Files
Refs
Tags
README
LICENSE
---
commit a546b97f9fe7f4a9e30b514bfc257ba85cd9a7f9
parent 1a7e49697644fe2740519b2c5f62a314e675c616
Author: Josuah Demangeon <[email protected]>
Date: Tue, 22 Jun 2021 00:32:54 +0200
flatten the repository and simplify Makefile
Diffstat:
M Makefile | 34 +++++++++++++++++------------…
D README | 60 -----------------------------…
A README.md | 57 +++++++++++++++++++++++++++++…
D config.mk | 4 ----
A csv.c | 132 +++++++++++++++++++++++++++++…
A csv.h | 22 ++++++++++++++++++++++
A drawille.c | 194 ++++++++++++++++++++++++++++++
A drawille.h | 25 +++++++++++++++++++++++++
R test.csv -> example.csv | 0
A ffplot.c | 148 +++++++++++++++++++++++++++++…
A ffplot.h | 34 +++++++++++++++++++++++++++++…
R src/font.c -> font.c | 0
A font.h | 20 ++++++++++++++++++++
R src/font13.c -> font13.c | 0
R src/font8.c -> font8.c | 0
M ploot-braille.c | 36 ++++++++++++++---------------…
M ploot-csv.5 | 6 +++---
M ploot-farbfeld.1 | 16 ++++++++--------
M ploot-farbfeld.c | 67 +++++++++++++++--------------…
M ploot-feed.1 | 2 +-
M ploot-feed.c | 27 ++++++++++++---------------
M ploot-text.c | 19 ++++++++++++-------
D proto.sh | 73 -----------------------------…
A scale.c | 94 +++++++++++++++++++++++++++++…
A scale.h | 14 ++++++++++++++
D src/csv.c | 122 -----------------------------…
D src/csv.h | 23 -----------------------
D src/drawille.c | 196 -----------------------------…
D src/drawille.h | 28 ----------------------------
D src/ffplot.c | 148 -----------------------------…
D src/ffplot.h | 35 -----------------------------…
D src/font.h | 21 ---------------------
D src/log.c | 97 ------------------------------
D src/log.h | 15 ---------------
D src/scale.c | 95 ------------------------------
D src/scale.h | 16 ----------------
D src/util.c | 80 -----------------------------…
D src/util.h | 18 ------------------
A util.c | 124 +++++++++++++++++++++++++++++…
A util.h | 22 ++++++++++++++++++++++
40 files changed, 990 insertions(+), 1134 deletions(-)
---
diff --git a/Makefile b/Makefile
@@ -1,27 +1,31 @@
-include config.mk
+NAME = ploot
+VERSION = v0.1
-src = src/csv.c src/drawille.c src/ffplot.c src/font.c src/font13.c \
- src/font8.c src/log.c src/scale.c src/util.c
-inc = src/csv.h src/drawille.h src/ffplot.h src/font.h src/log.h \
- src/scale.h src/util.h
-bin = ploot-farbfeld ploot-feed ploot-braille ploot-text
-obj = ${src:.c=.o}
-lib = -lm
+D = -D_POSIX_C_SOURCE=200811L -D_BSD_SOURCE
+CFLAGS = -Wall -Wextra -std=c99 -pedantic $W $D -fPIC
+LFLAGS = -static -lm
+PREFIX = /usr/local
+MANOREFIX = $(PREFIX)/share/man
-all: ${bin}
+SRC = csv.c drawille.c ffplot.c font.c font13.c font8.c scale.c util.c
+INC = csv.h drawille.h ffplot.h font.h scale.h util.h
+BIN = ploot-farbfeld ploot-feed ploot-braille ploot-text
+OBJ = ${SRC:.c=.o}
+
+all: ${BIN}
.c.o:
${CC} -c ${CFLAGS} -o $@ $<
-${obj} ${bin:=.o}: ${inc} Makefile
-${bin}: ${obj} ${bin:=.o}
- ${CC} ${LFLAGS} -o $@ [email protected] ${obj} ${lib}
+${OBJ} ${BIN:=.o}: ${INC} Makefile
+${BIN}: ${OBJ} ${BIN:=.o}
+ ${CC} ${LFLAGS} -o $@ [email protected] ${OBJ}
-install: ${bin}
+install: ${BIN}
mkdir -p ${PREFIX}/bin ${MANDIR}/man1 ${MANDIR}/man5
- cp ${bin} ${PREFIX}/bin
+ cp ${BIN} ${PREFIX}/bin
cp *.1 ${MANDIR}/man1
cp *.5 ${MANDIR}/man5
clean:
- rm -f *.o */*.o ${bin}
+ rm -f *.o ${BIN}
diff --git a/README b/README
@@ -1,60 +0,0 @@
-ploot
-=====
-
-
-ploot-farbfeld
---------------
-
-*ploot-farbfeld* reads collectd-style comma separated values (CSV) and produce…
-in the farbfeld [1] image format (pipe it to ff2png). It is an alternative to
-RRDtool [2].
-
-It is targetting at generating monitoring graph, and it always read unix
-timestamp as first column on standard input. The first line determines the
-name of the curves.
-
-[1]: https://tools.suckless.org/farbfeld/
-[2]: https://oss.oetiker.ch/rrdtool/
-
-
-ploot-feed
-----------
-
-*ploot-feed* also reads collectd-style comma separated values (CSV) but produc…
-a plain text continuous waterfall chart for live monitoring in the terminal. it
-is an alternative to grafana [1].
-
- % plootxt 1 1 1 <load-average.csv
-
- │shortterm │midterm │longterm …
- 17:34:00 _│⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/01 │⣟⡁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- │⣛⣂⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 20:34:00 _│⣧⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/01 │⣧⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- │⣟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 23:34:00 _│⣿⡒⠒⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/01 │⡧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- │⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 05:44:41 _│⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/02 │⣛⣁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- │⣷⠶⠶⠶⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 08:44:41 _│⡗⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/02 │⡯⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- │⠗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 11:44:41 _│⠗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/02 │⡿⠶⠒⠒⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- │⠖⠒⠒⠒⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 14:44:41 _│⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/02 │⣿⠟⠓⠒⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- │⣿⠤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 17:44:41 _│⡟⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/02 │⣭⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- │⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 20:51:38 _│⣶⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/02 │⣿⣷⣶⣶⣶⣶⣶⠖⠒⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- │shortterm │midterm │longterm …
- 22:51:38 _│⣿⣿⣿⣟⣛⡋⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
- 18/05/02 │⣿⡿⠍⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀…
-
-[1]: https://grafana.com/
diff --git a/README.md b/README.md
@@ -0,0 +1,57 @@
+ploot
+=====
+
+ploot-ffplot
+--------------
+*ploot-ffplot* reads collectd-style comma separated values (CSV) and produces …
+in the ffplot [1] image format (pipe it to ff2png). It is an alternative to
+RRDtool [2].
+
+It is targetting at generating monitoring graph, and it always read unix
+timestamp as first column on standard input. The first line determines the
+name of the curves.
+
+[1]: https://tools.suckless.org/ffplot/
+[2]: https://oss.oetiker.ch/rrdtool/
+
+ploot-feed
+----------
+*ploot-feed* also reads collectd-style comma separated values (CSV) but produc…
+a plain text continuous waterfall chart for live monitoring in the terminal. it
+is an alternative to grafana [1].
+
+```
+% plootxt 1 1 1 <load-average.csv
+ │shortterm │midterm │longterm …
+17:34:00 _│⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/01 │⣟⡁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+ │⣛⣂⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+20:34:00 _│⣧⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/01 │⣧⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+ │⣟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+23:34:00 _│⣿⡒⠒⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/01 │⡧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+ │⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+05:44:41 _│⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/02 │⣛⣁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+ │⣷⠶⠶⠶⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+08:44:41 _│⡗⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/02 │⡯⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+ │⠗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+11:44:41 _│⠗⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/02 │⡿⠶⠒⠒⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+ │⠖⠒⠒⠒⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+14:44:41 _│⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/02 │⣿⠟⠓⠒⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+ │⣿⠤⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+17:44:41 _│⡟⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/02 │⣭⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+ │⠄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+20:51:38 _│⣶⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/02 │⣿⣷⣶⣶⣶⣶⣶⠖⠒⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+ │shortterm │midterm │longterm …
+22:51:38 _│⣿⣿⣿⣟⣛⡋⠉⠉⠉⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+18/05/02 │⣿⡿⠍⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│�…
+```
+
+[1]: https://grafana.com/
diff --git a/config.mk b/config.mk
@@ -1,4 +0,0 @@
-CFLAGS = -Wall -Wextra -std=c99 -pedantic -fPIC -I"src" -D_POSIX_C_SOUR…
-LFLAGS = -static
-PREFIX = /usr/local
-MANDIR = $(PREFIX)/share/man
diff --git a/csv.c b/csv.c
@@ -0,0 +1,132 @@
+#include "csv.h"
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <time.h>
+#include "util.h"
+
+/*
+ * Read CSV data onto a set of (struct csv).
+ */
+
+static void
+csv_addtime(struct csv *vl, time_t epoch)
+{
+ void *mem;
+
+ debug("csv_addtime %p", vl->t);
+ if ((mem = realloc(vl->t, (vl->n + 1) * sizeof *vl->t)) == NULL)
+ err(1, "realloc: %s", strerror(errno));
+ vl->t = mem;
+ vl->t[vl->n] = epoch;
+}
+
+static void
+csv_addval(struct csv *vl, double field)
+{
+ void *mem;
+
+ debug("csv_addval %p", vl->t);
+ if ((mem = realloc(vl->v, (vl->n + 1) * sizeof *vl->v)) == NULL)
+ err(1, "", strerror(errno));
+ vl->v = mem;
+ vl->v[vl->n] = field;
+}
+
+/*
+ * Add to each column the value on the current row. The time_t
+ * buffer is shared among all fields.
+ */
+void
+csv_addrow(struct csv *vl, size_t ncol, char *line)
+{
+ char *field;
+ time_t *tbuf;
+ long l;
+ double d;
+
+ if ((field = strsep(&line, ",")) == NULL)
+ err(1, "missing epoch at row %zu", vl->n);
+
+ l = strtol(field, NULL, 10);
+ if (errno)
+ err(100, "parsing number '%s'", field);
+
+ csv_addtime(vl, l);
+ tbuf = vl[0].t;
+ for (; (field = strsep(&line, ",")); ncol--, vl->n++, vl++) {
+ if (ncol == 0)
+ err(1, "too many fields at line %zu", vl->n);
+ d = strtod(field, NULL);
+ if (errno)
+ err(100, "parsing double '%s'", field);
+ csv_addval(vl, d);
+ vl->t = tbuf;
+ }
+ if (ncol > 0)
+ err(1, "too few fields at line %zu", vl->n);
+}
+
+/*
+ * < (ncol) >
+ * label1,label2,label3
+ */
+void
+csv_labels(FILE *fp, struct csv **vl, size_t *ncol)
+{
+ char *field, *line, *cp;
+ struct csv *col;
+ size_t sz;
+ ssize_t r;
+
+ sz = 0, line = NULL;
+ r = getline(&line, &sz, fp);
+ if (ferror(fp))
+ err(111, "error while reading from file");
+ if (feof(fp))
+ err(100, "missing label line");
+ strchomp(line);
+
+ cp = line;
+ if (strcmp(strsep(&cp, ","), "epoch") != 0)
+ err(1, "first label must be 'epoch'");
+
+ *vl = NULL;
+ *ncol = 0;
+ while ((field = strsep(&cp, ","))) {
+ if ((*vl = realloc(*vl, sz += sizeof **vl)) == NULL)
+ err(1, "realloc: %s", strerror(errno));
+ col = (*vl) + (*ncol)++;
+ strlcpy(col->label, field, sizeof(col->label));
+ }
+
+ free(line);
+}
+
+/*
+ * < (ncol) >
+ * val1a,val1b,val1c ^
+ * val2a,val2b,val2c |
+ * val3a,val3b,val3c (vl->n)
+ * val4a,val4b,val4c |
+ * val5a,val5b,val5c v
+ */
+void
+csv_values(FILE *fp, struct csv *vl, size_t ncol)
+{
+ char *line;
+ size_t sz;
+
+ sz = 0, line = NULL;
+ while (getline(&line, &sz, fp) > -1)
+ csv_addrow(vl, ncol, line);
+ if (vl->n == 0)
+ err(1, "no value could be read");
+ if (vl->n == 1)
+ err(1, "only one value could be read");
+
+ free(line);
+}
diff --git a/csv.h b/csv.h
@@ -0,0 +1,22 @@
+#ifndef CSV_H
+#define CSV_H
+
+#include <stdio.h>
+#include <time.h>
+
+/*
+ * List of values and timestamps. Both have their dedicated buffer
+ * so that the timestamp buffer can be shared across csv objects.
+ */
+struct csv {
+ time_t *t; /* array of timestamps */
+ double *v; /* array of values */
+ size_t n; /* number of values */
+ char label[64]; /* for the legend */
+};
+
+void csv_addrow(struct csv *, size_t, char *);
+void csv_labels(FILE *, struct csv **, size_t *);
+void csv_values(FILE *, struct csv *, size_t);
+
+#endif
diff --git a/drawille.c b/drawille.c
@@ -0,0 +1,194 @@
+#include "drawille.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "font.h"
+
+/*
+ * Terminal-based plotting using drawille character, aka drawille.
+ */
+
+/* parameters used to draw a line */
+struct line {
+ int x0, y0, x1, y1; /* point of the line */
+ int dx, dy, sx, sy, err; /* parameters for the algorythm */
+};
+
+/*
+ * Turn on the bit at position (row, col) of a single cell. The
+ * pattern is not linear (1-4-2-5-3-6-7-8), because it matches the
+ * drawille pattern.
+ */
+static void
+drawille_cell_dot(uint8_t *cell, int row, int col)
+{
+ uint8_t flags[4][2] = {
+ { 0x01, 0x08 },
+ { 0x02, 0x10 },
+ { 0x04, 0x20 },
+ { 0x40, 0x80 },
+ };
+
+ *cell |= flags[row][col];
+}
+
+static size_t
+drawille_cell_utf(uint8_t cell, char *utf)
+{
+ long rune;
+
+ rune = 10240 + cell;
+ utf[0] = (char)(0xe0 | (0x0f & (rune >> 12))); /* 1110xxxx */
+ utf[1] = (char)(0x80 | (0x3f & (rune >> 6))); /* 10xxxxxx */
+ utf[2] = (char)(0x80 | (0x3f & (rune))); /* 10xxxxxx */
+ return 3;
+}
+
+static uint8_t
+drawille_get(struct drawille *drw, int row, int col)
+{
+ return drw->buf[row * drw->col + col];
+}
+
+size_t
+drawille_put_row(FILE *fp, struct drawille *drw, int row)
+{
+ char txt[] = "xxx";
+ size_t n;
+
+ n = 0;
+ for (int col = 0; col < drw->col; col++) {
+ drawille_cell_utf(drawille_get(drw, row, col), txt);
+ n += fputs(txt, fp);
+ }
+ return n;
+}
+
+/*
+ * Coordinates are passed as (x, y), but the canvas stores bits as
+ * (row, col). Conversion is made by this function.
+ */
+void
+drawille_dot(struct drawille *drw, int x, int y)
+{
+ if (x < 0 || x / 2 >= drw->col || y < 0 || y / 4 >= drw->row)
+ return;
+ drawille_cell_dot(drw->buf + (drw->row - y / 4 - 1) * drw->col + (x / …
+ 3 - y % 4,
+ x % 2);
+}
+
+struct drawille *
+drawille_new(int row, int col)
+{
+ struct drawille *drw;
+
+ if ((drw = calloc(sizeof(struct drawille) + row * col, 1)) == NULL)
+ return NULL;
+ drw->row = row;
+ drw->col = col;
+ return drw;
+}
+
+static void
+drawille_line_init(struct line *l, int x0, int y0, int x1, int y1)
+{
+ l->x0 = x0;
+ l->y0 = y0;
+ l->x1 = x1;
+ l->y1 = y1;
+ l->sx = x0 < x1 ? 1 : -1;
+ l->sy = y0 < y1 ? 1 : -1;
+ l->dx = abs(x1 - x0);
+ l->dy = abs(y1 - y0);
+ l->err = (l->dx > l->dy ? l->dx : -l->dy) / 2;
+}
+
+static int
+drawille_line_next(struct line *l)
+{
+ int e;
+
+ if (l->x0 == l->x1 && l->y0 == l->y1)
+ return 0;
+
+ e = l->err;
+ if (e > -l->dx) {
+ l->x0 += l->sx;
+ l->err -= l->dy;
+ }
+ if (e < l->dy) {
+ l->y0 += l->sy;
+ l->err += l->dx;
+ }
+ return 1;
+}
+
+void
+drawille_line(struct drawille *drw, int x0, int y0, int x1, int y1)
+{
+ struct line l;
+
+ drawille_line_init(&l, x0, y0, x1, y1);
+ do {
+ drawille_dot(drw, l.x0, l.y0);
+ } while (drawille_line_next(&l));
+}
+
+void
+drawille_histogram_dot(struct drawille *drw, int x, int y, int zero)
+{
+ int sign;
+
+ sign = (y > zero) ? (+1) : (-1);
+ for (; y != zero; y -= sign)
+ drawille_dot(drw, x, y);
+ drawille_dot(drw, x, y);
+}
+
+void
+drawille_histogram_line(struct drawille *drw, int x0, int y0, int x1, int y1, …
+{
+ struct line l;
+
+ drawille_line_init(&l, x0, y0, x1, y1);
+ do {
+ drawille_histogram_dot(drw, l.x0, l.y0, zero);
+ } while (drawille_line_next(&l));
+}
+
+static int
+drawille_text_glyph(struct drawille *drw, int x, int y, struct font *font, cha…
+{
+ int width;
+ char *glyph;
+
+ if ((unsigned)c > 127)
+ glyph = font->glyph[0];
+ else
+ glyph = font->glyph[(unsigned)c];
+
+ width = strlen(glyph) / font->height;
+
+ for (int ix = 0; ix < width; ix++)
+ for (int iy = 0; iy < font->height; iy++) {
+ if (glyph[ix + (font->height - 1) * width - iy * width] == 3)
+ drawille_dot(drw, x + ix, y + iy);
+ }
+
+ return width;
+}
+
+char *
+drawille_text(struct drawille *drw, int x, int y, struct font *font, char *s)
+{
+ if (drw->row*4 < font->height)
+ return NULL;
+ for (; *s != '\0' && x < drw->col * 2; s++, x++)
+ x += drawille_text_glyph(drw, x, y, font, *s);
+ return s;
+}
diff --git a/drawille.h b/drawille.h
@@ -0,0 +1,25 @@
+#ifndef DRAWILLE_H
+#define DRAWILLE_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "font.h"
+
+/*
+ * Canvas to draw on with braille characters.
+ */
+struct drawille {
+ int col, row; /* number of dots in total */
+ uint8_t buf[]; /* buffer of size (col * …
+};
+
+size_t drawille_put_row(FILE *, struct drawille *, int);
+void drawille_dot(struct drawille *, int, int);
+struct drawille *drawille_new(int, int);
+void drawille_line(struct drawille *, int, int, int, int);
+void drawille_histogram_dot(struct drawille *, int, int, int);
+void drawille_histogram_line(struct drawille *, int, int, int, int, in…
+char *drawille_text(struct drawille *, int, int, struct font *, char *);
+
+#endif
diff --git a/test.csv b/example.csv
diff --git a/ffplot.c b/ffplot.c
@@ -0,0 +1,148 @@
+#include "ffplot.h"
+
+#include <arpa/inet.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "font.h"
+#include "util.h"
+
+/*
+ * Convert (x,y) coordinates to (row,col) for printing into the buffer.
+ * The buffer only contain one number, so the coordinate is a single integer:
+ * width * y + y.
+ * The coordinates are shifted by offx and offy to permit relative coordinates.
+ *
+ * The convention used: y
+ * - (0,0) is at the lower left corner of the plotvas. |
+ * - (0,1) is above it. +--x
+ */
+void
+ffplot_pixel(struct ffplot *plot, struct ffcolor *color,
+ int x, int y)
+{
+ x += plot->x;
+ y += plot->y;
+ if (x < 0 || x >= plot->w || y < 0 || y >= plot->h)
+ return;
+ memcpy(plot->buf + plot->w * (plot->h - 1 - y) + x, color, sizeof(*plo…
+}
+
+void
+ffplot_rectangle(struct ffplot *plot, struct ffcolor *color,
+ int y1, int x1,
+ int y2, int x2)
+{
+ int x, y, ymin, xmin, ymax, xmax;
+
+ ymin = MIN(y1, y2); ymax = MAX(y1, y2);
+ xmin = MIN(x1, x2); xmax = MAX(x1, x2);
+
+ for (y = ymin; y <= ymax; y++)
+ for (x = xmin; x <= xmax; x++)
+ ffplot_pixel(plot, color, x, y);
+}
+
+/*
+ * From Bresenham's line algorithm and dcat's tplot.
+ */
+void
+ffplot_line(struct ffplot *plot, struct ffcolor *color,
+ int x0, int y0,
+ int x1, int y1)
+{
+ int dy, dx, sy, sx, err, e;
+
+ sx = x0 < x1 ? 1 : -1;
+ sy = y0 < y1 ? 1 : -1;
+ dx = ABS(x1 - x0);
+ dy = ABS(y1 - y0);
+ err = (dy > dx ? dy : -dx) / 2;
+
+ for (;;) {
+ ffplot_pixel(plot, color, x0, y0);
+
+ if (y0 == y1 && x0 == x1)
+ break;
+
+ e = err;
+ if (e > -dy) {
+ y0 += sy;
+ err -= dx;
+ }
+ if (e < dx) {
+ x0 += sx;
+ err += dy;
+ }
+ }
+}
+
+/*
+ * Draw a coloured glyph from font f centered on y.
+ */
+int
+ffplot_char(struct ffplot *plot, struct ffcolor *color, struct font *ft, char …
+ int x, int y)
+{
+ int yf, xf, wf;
+
+ if (c & 0x80)
+ c = '\0';
+ y -= ft->height / 2;
+ wf = font_width(ft, c);
+ for (xf = 0; xf < wf; xf++)
+ for (yf = 0; yf < ft->height; yf++)
+ if (ft->glyph[(int)c][wf * (ft->height - yf) + xf] == …
+ ffplot_pixel(plot, color, x + xf, y + yf);
+ return wf + 1;
+}
+
+/*
+ * Draw a left aligned string without wrapping it.
+ */
+size_t
+ffplot_text_left(struct ffplot *plot, struct ffcolor *color, struct font *ft,
+ char *s, int x, int y)
+{
+ for (; *s != '\0'; s++)
+ x += ffplot_char(plot, color, ft, *s, x, y);
+ return x;
+}
+
+/*
+ * Draw a center aligned string without wrapping it.
+ */
+size_t
+ffplot_text_center(struct ffplot *plot, struct ffcolor *color, struct font *ft,
+ char *s, int x, int y)
+{
+ x -= font_strlen(ft, s) / 2;
+ return ffplot_text_left(plot, color, ft, s, x, y);
+}
+
+/*
+ * Draw a right aligned string without wrapping it.
+ */
+size_t
+ffplot_text_right(struct ffplot *plot, struct ffcolor *color, struct font *ft,
+ char *s, int x, int y)
+{
+ x -= font_strlen(ft, s);
+ return ffplot_text_left(plot, color, ft, s, x, y);
+}
+
+void
+ffplot_print(FILE *fp, struct ffplot *plot)
+{
+ uint32_t w, h;
+
+ w = htonl(plot->w);
+ h = htonl(plot->h);
+
+ fprintf(stdout, "ffplot");
+ fwrite(&w, sizeof(w), 1, fp);
+ fwrite(&h, sizeof(h), 1, fp);
+ fwrite(plot->buf, plot->w * plot->h, sizeof(*plot->buf), fp);
+}
diff --git a/ffplot.h b/ffplot.h
@@ -0,0 +1,34 @@
+#ifndef FFPLOT_H
+#define FFPLOT_H
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "font.h"
+
+struct ffcolor {
+ uint16_t red;
+ uint16_t green;
+ uint16_t blue;
+ uint16_t alpha;
+};
+
+struct ffplot {
+ int w; /* width */
+ int h; /* height */
+ int x; /* x offset */
+ int y; /* y offset */
+ struct ffcolor *buf;
+};
+
+void ffplot_pixel(struct ffplot *, struct ffcolor *, int, int);
+void ffplot_rectangle(struct ffplot *, struct ffcolor *, int, int, int,…
+void ffplot_line(struct ffplot *, struct ffcolor *, int, int, int, int);
+int ffplot_char(struct ffplot *, struct ffcolor *, struct font *, char,…
+size_t ffplot_text_left(struct ffplot *, struct ffcolor *, struct font …
+size_t ffplot_text_center(struct ffplot *, struct ffcolor *, struct fon…
+size_t ffplot_text_right(struct ffplot *, struct ffcolor *, struct font…
+void ffplot_print(FILE *, struct ffplot *);
+
+#endif
diff --git a/src/font.c b/font.c
diff --git a/font.h b/font.h
@@ -0,0 +1,20 @@
+#ifndef FONT_H
+#define FONT_H
+
+#include <stddef.h>
+
+/*
+ * Bitmapped font saved as a '_' and 'X' pattern in a C source file.
+ */
+struct font {
+ int height; /* The width is variable. */
+ char *glyph[128]; /* 0: end, 1: off, 2: on. */
+};
+
+extern struct font font8;
+extern struct font font13;
+
+size_t font_width(struct font *, int);
+size_t font_strlen(struct font *, char *);
+
+#endif
diff --git a/src/font13.c b/font13.c
diff --git a/src/font8.c b/font8.c
diff --git a/ploot-braille.c b/ploot-braille.c
@@ -7,13 +7,9 @@
#include <time.h>
#include <math.h>
#include <unistd.h>
-
#include "drawille.h"
#include "scale.h"
#include "util.h"
-#include "log.h"
-
-char const *arg0 = NULL;
/*
* Plot the body as an histogram interpolating the gaps and include
@@ -46,7 +42,7 @@ braille_histogram(struct csv *vl, struct drawille *drw,
}
static int
-braille_axis_x(FILE *fp, time_t tmin, time_t tmax, time_t tstep, int col)
+braille_axis_x(FILE *fp, time_t tmin, time_t tmax, time_t csvep, int col)
{
int x, o, prec;
char tmp[sizeof("MM/DD HH:MM")], *fmt;
@@ -54,13 +50,13 @@ braille_axis_x(FILE *fp, time_t tmin, time_t tmax, time_t t…
time_t t;
fmt =
- (tstep < 3600 * 12) ? "^%H:%M:%S" :
- (tstep < 3600 * 24) ? "^%m/%d %H:%M" :
+ (csvep < 3600 * 12) ? "^%H:%M:%S" :
+ (csvep < 3600 * 24) ? "^%m/%d %H:%M" :
"^%Y/%m/%d";
n = x = 0;
- t = tmin + tstep - tmin % tstep;
- for (; t < tmax; t += tstep) {
+ t = tmin + csvep - tmin % csvep;
+ for (; t < tmax; t += csvep) {
x = (t - tmin) * col / (tmax - tmin);
strftime(tmp, sizeof tmp, fmt, localtime(&t));
prec = x - n + strlen(tmp);
@@ -107,32 +103,33 @@ static void
plot(struct csv *vl, FILE *fp, size_t ncol, int rows, int cols)
{
double vmin, vmax, vstep;
- time_t tmin, tmax, tstep;
+ time_t tmin, tmax, csvep;
struct drawille *drw;
cols -= 9; /* scale printed at the right */
scale_minmax(vl, ncol, &tmin, &tmax, &vmin, &vmax);
- tstep = scale_tstep(tmin, tmax, cols / 10);
+ csvep = scale_csvep(tmin, tmax, cols / 10);
vstep = scale_vstep(vmin, vmax, rows / 10);
rows -= ncol - 1; /* room for the labels and the scale */
rows /= ncol; /* plot <ncol> times */
rows = MAX(rows, 3); /* readable */
- debug("vstep=%lf vstep=%ld ncol=%zu rows=%zu", vstep, tstep, ncol, row…
+ debug("vstep=%lf vstep=%ld ncol=%zu rows=%zu", vstep, csvep, ncol, row…
for (; ncol > 0; vl++, ncol--) {
- assert(drw = drawille_new(rows, cols));
+ if ((drw = drawille_new(rows, cols)) == NULL)
+ err(1, "drawille_new: %s", strerror(errno));
fprintf(fp, " %s\n", vl->label);
if (braille_histogram(vl, drw, tmin, tmax, vmin, vmax) == -1)
- die(1, "allocating drawille canvas");
+ err(1, "allocating drawille canvas");
if (braille_render(drw, fp, vmin, vmax) == -1)
- die(1, "rendering braille canvas");
+ err(1, "rendering braille canvas");
free(drw);
}
- if (braille_axis_x(fp, tmin, tmax, tstep, cols) == -1)
- die(1, "printing x axis");;
+ if (braille_axis_x(fp, tmin, tmax, csvep, cols) == -1)
+ err(1, "printing x axis");;
}
static void
@@ -151,20 +148,19 @@ main(int argc, char **argv)
rows = 20, cols = 80;
arg0 = *argv;
- optind = 0;
while ((c = getopt(argc, argv, "r:c:")) > -1) {
switch (c) {
case 'r':
rows = atoi(optarg);
if (rows < 1) {
- error("invalid number of rows");
+ warn("invalid number of rows");
usage();
}
break;
case 'c':
cols = atoi(optarg);
if (rows < 1) {
- error("invalid number of columns");
+ warn("invalid number of columns");
usage();
}
break;
diff --git a/ploot-csv.5 b/ploot-csv.5
@@ -15,20 +15,20 @@
epoch,column-name-1,column-name-2
timestamp,value1,value2
timestamp,value1,value2
-…
+\&...
.Ed
.
.
.Sh DESCRIPTION
.
-This is the simple comma-separated format used by the ploot-* programs.
+This is the simple coma-separated format used by the ploot-* programs.
.
.
.Sh INPUT FORMAT
.
.Nm
has a first header line, then zero or more data lines, both
-comma-separated list of values.
+coma-separated list of values.
.
.
.Ss Header line
diff --git a/ploot-farbfeld.1 b/ploot-farbfeld.1
@@ -5,13 +5,13 @@
.
.Sh NAME
.
-.Nm ploot-farbfeld
-.Nd produce a farbfeld image of csv input
+.Nm ploot-ffplot
+.Nd produce a ffplot image of csv input
.
.
.Sh SYNOPSIS
.
-.Nm ploot-farbfeld
+.Nm ploot-ffplot
.Op Fl t Ar title
.Op Fl u Ar unit
.Ar colors...
@@ -21,7 +21,7 @@
.
The
.Nm
-utility plots an image in the farbfeld format out of csv values coming from st…
+utility plots an image in the ffplot format out of csv values coming from stdi…
.
.Bl -tag -width 6n
.
@@ -59,20 +59,20 @@ epoch,used_memory,free_memory
1533752055,301,260
1533752056,303,258
EOF
-$ ploot-farbfeld -t demo -u MB red yellow <sample.txt
+$ ploot-ffplot -t demo -u MB red yellow <sample.txt
.Ed
.
.
.Sh SEE ALSO
.
-.Xr ploot-farbfeld 1 ,
+.Xr ploot-ffplot 1 ,
.Xr ploot-csv 7
.
.Pp
The
-.Xr farbfeld 7
+.Xr ffplot 7
image format:
-.Lk https://tools.suckless.org/farbfeld/
+.Lk https://tools.suckless.org/ffplot/
.
.
.Sh HISTORY
diff --git a/ploot-farbfeld.c b/ploot-farbfeld.c
@@ -1,6 +1,6 @@
#include <arpa/inet.h>
-#include <assert.h>
#include <ctype.h>
+#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <math.h>
@@ -10,11 +10,9 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
-
#include "csv.h"
#include "ffplot.h"
#include "font.h"
-#include "log.h"
#include "util.h"
#include "scale.h"
@@ -53,7 +51,6 @@ struct colorname {
struct ffcolor color;
};
-char const *arg0 = NULL;
static char *tflag = "";
static char *uflag = "";
static struct font *font = &font13;
@@ -70,7 +67,7 @@ static struct colorname colorname[] = {
};
static int
-farbfeld_t2x(time_t t, time_t tmin, time_t tmax)
+ffplot_t2x(time_t t, time_t tmin, time_t tmax)
{
if (tmin == tmax)
return PLOT_W;
@@ -78,7 +75,7 @@ farbfeld_t2x(time_t t, time_t tmin, time_t tmax)
}
static int
-farbfeld_v2y(double v, double vmin, double vmax)
+ffplot_v2y(double v, double vmin, double vmax)
{
if (vmin == vmax)
return PLOT_H;
@@ -86,22 +83,22 @@ farbfeld_v2y(double v, double vmin, double vmax)
}
static void
-farbfeld_xaxis(struct ffplot *plot, struct ffcolor *label, struct ffcolor *gri…
- time_t tmin, time_t tmax, time_t tstep)
+ffplot_xaxis(struct ffplot *plot, struct ffcolor *label, struct ffcolor *grid,
+ time_t tmin, time_t tmax, time_t csvep)
{
time_t t;
int x;
char str[sizeof("MM/DD HH/MM")], *fmt;
- if (tstep < 3600 * 12)
+ if (csvep < 3600 * 12)
fmt = "%H:%M:%S";
- else if (tstep < 3600 * 24)
+ else if (csvep < 3600 * 24)
fmt = "%m/%d %H:%M";
else
fmt = "%X/%m/%d";
- for (t = tmax - tmax % tstep; t >= tmin; t -= tstep) {
- x = farbfeld_t2x(t, tmin, tmax);
+ for (t = tmax - tmax % csvep; t >= tmin; t -= csvep) {
+ x = ffplot_t2x(t, tmin, tmax);
ffplot_line(plot, grid,
x, XLABEL_H,
@@ -114,7 +111,7 @@ farbfeld_xaxis(struct ffplot *plot, struct ffcolor *label, …
}
static void
-farbfeld_yaxis(struct ffplot *plot, struct ffcolor *label, struct ffcolor *gri…
+ffplot_yaxis(struct ffplot *plot, struct ffcolor *label, struct ffcolor *grid,
double vmin, double vmax, double vstep)
{
double v;
@@ -122,7 +119,7 @@ farbfeld_yaxis(struct ffplot *plot, struct ffcolor *label, …
char str[8 + 1];
for (v = vmax - fmod(vmax, vstep); v >= vmin; v -= vstep) {
- y = farbfeld_v2y(v, vmin, vmax);
+ y = ffplot_v2y(v, vmin, vmax);
ffplot_line(plot, grid,
YLABEL_W, y,
@@ -135,7 +132,7 @@ farbfeld_yaxis(struct ffplot *plot, struct ffcolor *label, …
}
static void
-farbfeld_title(struct ffplot *plot,
+ffplot_title(struct ffplot *plot,
struct ffcolor *ct, char *title,
struct ffcolor *cu, char *unit)
{
@@ -144,7 +141,7 @@ farbfeld_title(struct ffplot *plot,
}
static void
-farbfeld_plot(struct ffplot *plot, struct csv *vl, struct ffcolor *color,
+ffplot_plot(struct ffplot *plot, struct csv *vl, struct ffcolor *color,
double vmin, double vmax,
time_t tmin, time_t tmax)
{
@@ -154,8 +151,8 @@ farbfeld_plot(struct ffplot *plot, struct csv *vl, struct f…
first = 1;
for (tp = vl->t, vp = vl->v, n = vl->n; n > 0; n--, vp++, tp++) {
- y = farbfeld_v2y(*vp, vmin, vmax);
- x = farbfeld_t2x(*tp, tmin, tmax);
+ y = ffplot_v2y(*vp, vmin, vmax);
+ x = ffplot_t2x(*tp, tmin, tmax);
if (!first)
ffplot_line(plot, color, xlast, ylast, x, y);
@@ -167,16 +164,16 @@ farbfeld_plot(struct ffplot *plot, struct csv *vl, struct…
}
static void
-farbfeld_values(struct ffplot *plot, struct csv *vl, struct ffcolor **cl, size…
+ffplot_values(struct ffplot *plot, struct csv *vl, struct ffcolor **cl, size_t…
time_t tmin, time_t tmax,
double vmin, double vmax)
{
for (; ncol > 0; ncol--, vl++, cl++)
- farbfeld_plot(plot, vl, *cl, vmin, vmax, tmin, tmax);
+ ffplot_plot(plot, vl, *cl, vmin, vmax, tmin, tmax);
}
static void
-farbfeld_legend(struct ffplot *plot, struct ffcolor *fg, struct csv *vl, struc…
+ffplot_legend(struct ffplot *plot, struct ffcolor *fg, struct csv *vl, struct …
{
size_t x, y;
@@ -209,13 +206,14 @@ plot(struct csv *vl, struct ffcolor **cl, size_t ncol, ch…
struct ffcolor label_fg = { 0x8888, 0x8888, 0x8888, 0xffff };
struct ffcolor title_fg = { 0xdddd, 0xdddd, 0xdddd, 0xffff };
double vmin, vmax, vstep;
- time_t tmin, tmax, tstep;
+ time_t tmin, tmax, csvep;
scale_minmax(vl, ncol, &tmin, &tmax, &vmin, &vmax);
- tstep = scale_tstep(tmin, tmax, 7);
+ csvep = scale_csvep(tmin, tmax, 7);
vstep = scale_vstep(vmin, vmax, 7);
- assert(plot.buf = calloc(IMAGE_H * IMAGE_W, sizeof *plot.buf));
+ if ((plot.buf = calloc(IMAGE_H * IMAGE_W, sizeof *plot.buf)) == NULL)
+ err(1, "calloc: %s", strerror(errno));
plot.y = 0;
plot.x = 0;
@@ -227,23 +225,23 @@ plot(struct csv *vl, struct ffcolor **cl, size_t ncol, ch…
plot.x = XLABEL_X;
plot.y = XLABEL_Y;
- farbfeld_xaxis(&plot, &label_fg, &grid_fg, tmin, tmax, tstep);
+ ffplot_xaxis(&plot, &label_fg, &grid_fg, tmin, tmax, csvep);
plot.x = YLABEL_X;
plot.y = YLABEL_Y;
- farbfeld_yaxis(&plot, &label_fg, &grid_fg, vmin, vmax, vstep);
+ ffplot_yaxis(&plot, &label_fg, &grid_fg, vmin, vmax, vstep);
plot.x = TITLE_X;
plot.y = TITLE_Y;
- farbfeld_title(&plot, &title_fg, name, &label_fg, units);
+ ffplot_title(&plot, &title_fg, name, &label_fg, units);
plot.x = PLOT_X;
plot.y = PLOT_Y;
- farbfeld_values(&plot, vl, cl, ncol, tmin, tmax, vmin, vmax);
+ ffplot_values(&plot, vl, cl, ncol, tmin, tmax, vmin, vmax);
plot.x = LEGEND_X;
plot.y = LEGEND_Y;
- farbfeld_legend(&plot, &label_fg, vl, cl, ncol);
+ ffplot_legend(&plot, &label_fg, vl, cl, ncol);
ffplot_print(stdout, &plot);
}
@@ -264,7 +262,7 @@ argv_to_color(struct ffcolor **cl, char **argv)
{
for (; *argv != NULL; cl++, argv++)
if ((*cl = name_to_color(*argv)) == NULL)
- die(1, "unknown color name: %s", *argv);
+ err(1, "unknown color name: %s", *argv);
}
static void
@@ -286,7 +284,7 @@ main(int argc, char **argv)
size_t ncol;
int c;
- optind = 0;
+ arg0 = *argv;
while ((c = getopt(argc, argv, "t:u:")) > -1) {
switch (c) {
case 't':
@@ -305,13 +303,14 @@ main(int argc, char **argv)
if (argc == 0)
usage();
- assert(cl = calloc(argc, sizeof(*cl)));
+ if ((cl = calloc(argc, sizeof *cl)) == NULL)
+ err(1, "calloc: %s", strerror(errno));
csv_labels(stdin, &vl, &ncol);
if (ncol > (size_t)argc)
- die(1, "too many columns or not enough arguments");
+ err(1, "too many columns or not enough arguments");
else if (ncol < (size_t)argc)
- die(1, "too many arguments or not enough columns");
+ err(1, "too many arguments or not enough columns");
csv_values(stdin, vl, ncol);
argv_to_color(cl, argv);
diff --git a/ploot-feed.1 b/ploot-feed.1
@@ -60,7 +60,7 @@ $ ploot-feed -w 80 1 1 <sample.txt
.
.Sh SEE ALSO
.
-.Xr ploot-farbfeld 1 ,
+.Xr ploot-ffplot 1 ,
.Xr ploot-format 7
.
.
diff --git a/ploot-feed.c b/ploot-feed.c
@@ -8,14 +8,11 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
-
#include "util.h"
-#include "log.h"
#define WIDTH_MAX 1024
#define BRAILLE_START 10240
-char const *arg0 = NULL;
static int wflag = 80;
static int width = 0;
@@ -60,19 +57,19 @@ plot_row(long *out, char *line, double *max, int nrow, int …
tok = strsep(&line, ",");
if (!tok)
- die(100, "*** missing epoch value");
+ err(100, "*** missing epoch value");
epoch = strtol(tok, NULL, 10);
if (errno)
- error("*** parsing epoch '%s'", tok);
+ warn("*** parsing epoch '%s'", tok);
for (n = 0; (tok = strsep(&line, ",")) != NULL; n++) {
if (n >= ncol)
- die(100, "too many values");
+ err(100, "too many values");
val = atof(tok);
plot_val(out + n * width, val, max[n], nrow);
}
if (n < ncol)
- die(100, "not enough values");
+ err(100, "not enough values");
return epoch;
}
@@ -100,7 +97,7 @@ plot_line(long *out, double *max, int ncol)
for (nrow = 0; nrow < 4; nrow++) {
if (getline(&line, &sz, stdin) == -1) {
if (ferror(stdin))
- die(111, "reading row from stdin");
+ err(111, "reading row from stdin");
exit(0);
}
epoch = plot_row(out, line, max, nrow, ncol);
@@ -179,21 +176,21 @@ read_labels(char **labv)
line = NULL, sz = 0;
if (getline(&line, &sz, stdin) == -1) {
if (ferror(stdin))
- die(111, "reading labels from stdin");
- die(100, "missing label line", stderr);
+ err(111, "reading labels from stdin");
+ err(100, "missing label line", stderr);
}
strchomp(line);
cp = line;
if (strcmp(strsep(&cp, ","), "epoch") != 0)
- die(100, "first label must be 'epoch'");
+ err(100, "first label must be 'epoch'");
for (ncol = 0; (tok = strsep(&cp, ",")) != NULL; ncol++, labv++)
*labv = tok;
*labv = NULL;
if (ncol < 1)
- die(100, "no label found");
+ err(100, "no label found");
return ncol;
}
@@ -223,7 +220,7 @@ main(int argc, char **argv)
char *labv[4069 / 2], labels[4069];
int c;
- optind = 0;
+ arg0 = *argv;
while ((c = getopt(argc, argv, "w:")) > -1) {
switch (c) {
case 'w':
@@ -243,14 +240,14 @@ main(int argc, char **argv)
for (m = max; argc > 0; argc--, argv++, m++) {
*m = strtod(*argv, NULL);
if (errno)
- error("*** parsing float '%s'", *argv);
+ warn("*** parsing float '%s'", *argv);
}
ncol = read_labels(labv);
width = (wflag - sizeof("XXxXXxXX _")) / ncol - sizeof("|");
fmt_labels(labels, ncol, labv);
if (ncol != nmax)
- die(100, "not as many labels and arguments");
+ err(100, "not as many labels and arguments");
plot(labels, max, ncol);
return 0;
diff --git a/ploot-text.c b/ploot-text.c
@@ -2,13 +2,13 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
#include "drawille.h"
#include "font.h"
#include "util.h"
-char *arg0 = NULL;
-
void
usage(void)
{
@@ -22,9 +22,11 @@ main(int argc, char **argv)
struct font *ft;
struct drawille *drw;
char *text;
+ size_t h, w;
int c, row;
ft = &font8;
+ arg0 = *argv;
while ((c = getopt(argc, argv, "12")) > -1) {
switch (c) {
case '1':
@@ -37,7 +39,6 @@ main(int argc, char **argv)
usage();
}
}
- arg0 = *argv;
argc -= optind;
argv += optind;
@@ -46,13 +47,17 @@ main(int argc, char **argv)
text = *argv;
- assert(drw = drawille_new((ft->height + 3) / 4, font_strlen(ft, text) …
+ h = (ft->height + 3) / 4;
+ w = font_strlen(ft, text) / 2;
+ if ((drw = drawille_new(h, w)) == NULL)
+ err(1, "drawille_new: %s", strerror(errno));
drawille_text(drw, 0, 0, ft, text);
- for (row = 0; row < drw->row; row++) {
+ for (row = 0; row < drw->row; row++) {
drawille_put_row(stdout, drw, row);
- fprintf(stdout, "\n");
- }
+ fprintf(stdout, "\n");
+ }
free(drw);
+ return 0;
}
diff --git a/proto.sh b/proto.sh
@@ -1,73 +0,0 @@
-#!/bin/sh
-awk='
-BEGIN {
- tab = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
- print "/**/"
-}
-
-END {
- print ""
- print "#endif"
-}
-
-# functions
-
-args {
- sub(/^[ \t]*/, " ")
- args = args $0
-}
-
-/^[a-zA-Z0-9_]+\([][)(a-z_A-Z0-9*,. \t]*$/ {
- if (match(type, "static") || match($0, ";$"))
- next
-
- symbol = $0
- sub(/\(.*/, "", symbol)
- sub(/[a-zA-Z0-9_]*\(/, "", $0)
- if (symbol == "main")
- next
-
- args = $0
- sub(/^[a-z]*\(/, "", args)
-}
-
-args && /\)$/ {
- gsub(/[\n \t]+/, " ", args)
-
- sub(/\)$/, "", args)
-
- gsub(/[a-zA-Z0-9_]+\[[^]]*\]/, "[]", args)
- gsub(/[*][a-zA-Z0-9_]+/, "*", args)
- gsub(/[ ][a-zA-Z0-9_]+,/, ",", args)
- gsub(/[ ][a-zA-Z0-9_]+$/, "", args)
- gsub(/[ ][a-zA-Z0-9_]+\*/, "*", args)
- gsub(/\.\.\.\$/, "...", args)
- gsub(/void\)$/, "void", args)
-
- printf("%s%s%s%s(%s);\n",
- type, substr(tab, 1, 20 / 8 - (length(type) - 3) / 8),
- symbol, substr(tab, 1, 30 / 8 - (length(symbol) - 1) / 8),
- args)
-
- args = ""
-}
-
-!args {
- type = $0
-}
-
-# variables
-
-/^[a-zA-Z][][ \t*a-z_A-Z0-9]*=.*[;{]$/ && $1 != "static" && $1 != "enum" {
- sub(/ *=.*/, ";")
- sub(/[ \t]*;$/, ";");
- print
-}
-'
-
-for file in src/*.c; do file=${file%.c}
- grep -Fq '/**/' "$file.h" 2>/dev/null || continue
- header=$(awk '$0 == "/**/" { exit(0) } 1' "$file.h"
- awk "$awk" "$file.c")
- printf '%s\n' "$header" >"$file.h"
-done
diff --git a/scale.c b/scale.c
@@ -0,0 +1,94 @@
+#include "scale.h"
+
+#include <stddef.h>
+#include <time.h>
+
+#include "util.h"
+
+/*
+ * - <max ^
+ * - | Translate the coordinates between double values
+ * - <val szy and height in the plot of <row> rows.
+ * - |
+ * - <min v
+ */
+int
+scale_ypos(double val, double min, double max, int szy)
+{
+ return szy * (val - min) / (max - min);
+}
+
+/*
+ * <---- szx ----> Translate the coordinates between the…
+ * range and position in the plot of <col> cols.
+ * t1 t t2
+ * | . . | . . |
+ */
+int
+scale_xpos(time_t t, time_t t1, time_t t2, int szx)
+{
+ return szx * (t - t1) / (t2 - t1);
+}
+
+void
+scale_minmax(struct csv *vl, int ncol,
+ time_t *tmin, time_t *tmax,
+ double *vmin, double *vmax)
+{
+ double *v;
+ time_t *t;
+ size_t n;
+
+ *vmin = *vmax = 0;
+ *tmin = *tmax = *vl->t;
+
+ for (; ncol > 0; ncol--, vl++) {
+ for (t = vl->t, v = vl->v, n = vl->n; n > 0; t++, v++, n--) {
+ if (*v < *vmin) *vmin = *v;
+ if (*v > *vmax) *vmax = *v;
+ if (*t < *tmin) *tmin = *t;
+ if (*t > *tmax) *tmax = *t;
+ }
+ }
+
+ if (*tmin == *tmax)
+ err(1, "invalid time scale: min=%lld max=%lld", *tmin, *tmax);
+}
+
+time_t
+scale_csvep(time_t min, time_t max, int nval)
+{
+ time_t dt, *sc, scale[] = {
+ 1, 5, 2, 10, 20, 30, 60, 60*2, 60*5, 60*10, 60*20, 60*30, 3600…
+ 3600*2, 3600*5, 3600*10, 3600*18, 3600*24, 3600*24*2,
+ 3600*24*5, 3600*24*10, 3600*24*20, 3600*24*30, 3600*24*50,
+ 3600*24*100, 3600*24*365, 0
+ };
+
+ dt = max - min;
+
+ for (sc = scale; *sc > 0; sc++)
+ if (dt < *sc * nval)
+ return *sc;
+ return dt / nval;
+}
+
+double
+scale_vstep(double min, double max, int nval)
+{
+ double dv, d, *sc, scale[] = { 1, 2, 3, 5 };
+
+ dv = max - min;
+
+ if (dv > 1)
+ for (d = 1; d != 0; d *= 10)
+ for (sc = scale; sc < scale + LEN(scale); sc++)
+ if (dv < *sc * d * nval)
+ return *sc * d;
+ if (dv < 1)
+ for (d = 1; d != 0; d *= 10)
+ for (sc = scale + LEN(scale) - 1; sc >= scale; sc--)
+ if (dv > *sc / d * nval / 2)
+ return *sc / d;
+ return 0;
+}
diff --git a/scale.h b/scale.h
@@ -0,0 +1,14 @@
+#ifndef SCALE_H
+#define SCALE_H
+
+#include <stddef.h>
+#include <time.h>
+#include "csv.h"
+
+int scale_ypos(double, double, double, int);
+int scale_xpos(time_t, time_t, time_t, int);
+void scale_minmax(struct csv *, int, time_t *, time_t *, double *, doub…
+time_t scale_csvep(time_t, time_t, int);
+double scale_vstep(double, double, int);
+
+#endif
diff --git a/src/csv.c b/src/csv.c
@@ -1,122 +0,0 @@
-#include "csv.h"
-
-#include <errno.h>
-#include <assert.h>
-#include <string.h>
-#include <time.h>
-#include <stdlib.h>
-#include <limits.h>
-#include <time.h>
-
-#include "log.h"
-#include "util.h"
-
-/*
- * Read CSV data onto a set of (struct csv).
- */
-
-static void
-csv_addtime(struct csv *vl, time_t epoch)
-{
- assert(vl->t = realloc(vl->t, (vl->n + 1) * sizeof(*vl->t)));
- vl->t[vl->n] = epoch;
-}
-
-static void
-csv_addval(struct csv *vl, double field)
-{
- assert(vl->v = realloc(vl->v, (vl->n + 1) * sizeof(*vl->v)));
- vl->v[vl->n] = field;
-}
-
-/*
- * Add to each column the value on the current row. The time_t
- * buffer is shared among all fields.
- */
-void
-csv_addrow(struct csv *vl, size_t ncol, char *line)
-{
- char *field;
- time_t *tbuf;
- long l;
- double d;
-
- field = strsep(&line, ",");
- if (!field)
- die(1, "missing epoch at row %zu", vl->n);
-
- l = strtol(field, NULL, 10);
- if (errno)
- die(100, "parsing number '%s'", field);
- csv_addtime(vl, l);
- tbuf = vl[0].t;
- for (; (field = strsep(&line, ",")); ncol--, vl->n++, vl++) {
- if (ncol == 0)
- die(1, "too many fields at line %zu", vl->n);
- d = strtod(field, NULL);
- if (errno)
- die(100, "parsing double '%s'", field);
- csv_addval(vl, d);
- vl->t = tbuf;
- }
- if (ncol > 0)
- die(1, "too few fields at line %zu", vl->n);
-}
-
-/*
- * < *ncol >
- * epoch,label1,label2,label3
- */
-void
-csv_labels(FILE *fp, struct csv **vl, size_t *ncol)
-{
- char *field, *line, *cp;
- struct csv *col;
- size_t sz;
- ssize_t r;
-
- sz = 0, line = NULL;
- r = getline(&line, &sz, fp);
- if (ferror(fp))
- die(111, "error while reading from file");
- if (r == -1)
- die(100, "missing label line");
- strchomp(line);
-
- cp = line;
- if (strcmp(strsep(&cp, ","), "epoch") != 0)
- die(1, "first label must be 'epoch'");
-
- *vl = NULL;
- *ncol = 0;
- while ((field = strsep(&cp, ","))) {
- assert(*vl = realloc(*vl, sz += sizeof(**vl)));
- col = (*vl) + (*ncol)++;
- strlcpy(col->label, field, sizeof(col->label));
- }
-
- free(line);
-}
-
-/*
- * < ncol >
- * epoch,a1,b1,c1 ^
- * epoch,a2,b2,c2 vl->n
- * epoch,a3,b3,c3 v
- */
-void
-csv_values(FILE *fp, struct csv *vl, size_t ncol)
-{
- char *line;
- size_t sz;
-
- sz = 0, line = NULL;
- while (getline(&line, &sz, fp) > -1)
- csv_addrow(vl, ncol, line);
- if (vl->n == 0)
- die(1, "no value could be read");
- if (vl->n == 1)
- die(1, "only one value could be read");
-
- free(line);
-}
diff --git a/src/csv.h b/src/csv.h
@@ -1,23 +0,0 @@
-#ifndef CSV_H
-#define CSV_H
-
-#include <stdio.h>
-#include <time.h>
-
-/*
- * List of values and timestamps. Both have their dedicated buffer
- * so that the timestamp buffer can be shared across csv objects.
- */
-struct csv {
- time_t *t; /* array of timestamps */
- double *v; /* array of values */
- size_t n; /* number of values */
- char label[64]; /* for the legend */
-};
-
-/**/
-void csv_addrow (struct csv *, size_t, char *);
-void csv_labels (FILE *, struct csv **, size_t *…
-void csv_values (FILE *, struct csv *, size_t);
-
-#endif
diff --git a/src/drawille.c b/src/drawille.c
@@ -1,196 +0,0 @@
-#include "drawille.h"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-
-#include "font.h"
-
-#include "log.h" /* XXX */
-
-/*
- * Terminal-based plotting using drawille character, aka drawille.
- */
-
-/* parameters used to draw a line */
-struct line {
- int x0, y0, x1, y1; /* point of the line */
- int dx, dy, sx, sy, err; /* parameters for the algorythm */
-};
-
-/*
- * Turn on the bit at position (row, col) of a single cell. The
- * pattern is not linear (1-4-2-5-3-6-7-8), because it matches the
- * drawille pattern.
- */
-static void
-drawille_cell_dot(uint8_t *cell, int row, int col)
-{
- uint8_t flags[4][2] = {
- { 0x01, 0x08 },
- { 0x02, 0x10 },
- { 0x04, 0x20 },
- { 0x40, 0x80 },
- };
-
- *cell |= flags[row][col];
-}
-
-static size_t
-drawille_cell_utf(uint8_t cell, char *utf)
-{
- long rune;
-
- rune = 10240 + cell;
- utf[0] = (char)(0xe0 | (0x0f & (rune >> 12))); /* 1110xxxx */
- utf[1] = (char)(0x80 | (0x3f & (rune >> 6))); /* 10xxxxxx */
- utf[2] = (char)(0x80 | (0x3f & (rune))); /* 10xxxxxx */
- return 3;
-}
-
-static uint8_t
-drawille_get(struct drawille *drw, int row, int col)
-{
- return drw->buf[row * drw->col + col];
-}
-
-size_t
-drawille_put_row(FILE *fp, struct drawille *drw, int row)
-{
- char txt[] = "xxx";
- size_t n;
-
- n = 0;
- for (int col = 0; col < drw->col; col++) {
- drawille_cell_utf(drawille_get(drw, row, col), txt);
- n += fputs(txt, fp);
- }
- return n;
-}
-
-/*
- * Coordinates are passed as (x, y), but the canvas stores bits as
- * (row, col). Conversion is made by this function.
- */
-void
-drawille_dot(struct drawille *drw, int x, int y)
-{
- if (x < 0 || x / 2 >= drw->col || y < 0 || y / 4 >= drw->row)
- return;
- drawille_cell_dot(drw->buf + (drw->row - y / 4 - 1) * drw->col + (x / …
- 3 - y % 4,
- x % 2);
-}
-
-struct drawille *
-drawille_new(int row, int col)
-{
- struct drawille *drw;
-
- if ((drw = calloc(sizeof(struct drawille) + row * col, 1)) == NULL)
- return NULL;
- drw->row = row;
- drw->col = col;
- return drw;
-}
-
-static void
-drawille_line_init(struct line *l, int x0, int y0, int x1, int y1)
-{
- l->x0 = x0;
- l->y0 = y0;
- l->x1 = x1;
- l->y1 = y1;
- l->sx = x0 < x1 ? 1 : -1;
- l->sy = y0 < y1 ? 1 : -1;
- l->dx = abs(x1 - x0);
- l->dy = abs(y1 - y0);
- l->err = (l->dx > l->dy ? l->dx : -l->dy) / 2;
-}
-
-static int
-drawille_line_next(struct line *l)
-{
- int e;
-
- if (l->x0 == l->x1 && l->y0 == l->y1)
- return 0;
-
- e = l->err;
- if (e > -l->dx) {
- l->x0 += l->sx;
- l->err -= l->dy;
- }
- if (e < l->dy) {
- l->y0 += l->sy;
- l->err += l->dx;
- }
- return 1;
-}
-
-void
-drawille_line(struct drawille *drw, int x0, int y0, int x1, int y1)
-{
- struct line l;
-
- drawille_line_init(&l, x0, y0, x1, y1);
- do {
- drawille_dot(drw, l.x0, l.y0);
- } while (drawille_line_next(&l));
-}
-
-void
-drawille_histogram_dot(struct drawille *drw, int x, int y, int zero)
-{
- int sign;
-
- sign = (y > zero) ? (+1) : (-1);
- for (; y != zero; y -= sign)
- drawille_dot(drw, x, y);
- drawille_dot(drw, x, y);
-}
-
-void
-drawille_histogram_line(struct drawille *drw, int x0, int y0, int x1, int y1, …
-{
- struct line l;
-
- drawille_line_init(&l, x0, y0, x1, y1);
- do {
- drawille_histogram_dot(drw, l.x0, l.y0, zero);
- } while (drawille_line_next(&l));
-}
-
-static int
-drawille_text_glyph(struct drawille *drw, int x, int y, struct font *font, cha…
-{
- int width;
- char *glyph;
-
- if ((unsigned)c > 127)
- glyph = font->glyph[0];
- else
- glyph = font->glyph[(unsigned)c];
-
- width = strlen(glyph) / font->height;
-
- for (int ix = 0; ix < width; ix++)
- for (int iy = 0; iy < font->height; iy++) {
- if (glyph[ix + (font->height - 1) * width - iy * width] == 3)
- drawille_dot(drw, x + ix, y + iy);
- }
-
- return width;
-}
-
-char *
-drawille_text(struct drawille *drw, int x, int y, struct font *font, char *s)
-{
- if (drw->row*4 < font->height)
- return NULL;
- for (; *s != '\0' && x < drw->col * 2; s++, x++)
- x += drawille_text_glyph(drw, x, y, font, *s);
- return s;
-}
diff --git a/src/drawille.h b/src/drawille.h
@@ -1,28 +0,0 @@
-#ifndef DRAWILLE_H
-#define DRAWILLE_H
-
-#include <stddef.h>
-#include <stdint.h>
-#include <stdio.h>
-
-#include "csv.h"
-#include "font.h"
-
-/*
- * Canvas to draw on with braille characters.
- */
-struct drawille {
- int col, row; /* number of dots in total */
- uint8_t buf[]; /* buffer of size (col * …
-};
-
-/**/
-size_t drawille_put_row (FILE *, struct drawille *, int);
-void drawille_dot (struct drawille *, int, int);
-struct drawille *drawille_new (int, int);
-void drawille_line (struct drawille *, int, int,…
-void drawille_histogram_dot (struct drawille *, int, int…
-void drawille_histogram_line (struct drawille *, int, in…
-char * drawille_text (struct drawille *, int, in…
-
-#endif
diff --git a/src/ffplot.c b/src/ffplot.c
@@ -1,148 +0,0 @@
-#include "ffplot.h"
-
-#include <arpa/inet.h>
-#include <stddef.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdint.h>
-
-#include "font.h"
-#include "util.h"
-
-/*
- * Convert (x,y) coordinates to (row,col) for printing into the buffer.
- * The buffer only contain one number, so the coordinate is a single integer:
- * width * y + y.
- * The coordinates are shifted by offx and offy to permit relative coordinates.
- *
- * The convention used: y
- * - (0,0) is at the lower left corner of the plotvas. |
- * - (0,1) is above it. +--x
- */
-void
-ffplot_pixel(struct ffplot *plot, struct ffcolor *color,
- int x, int y)
-{
- x += plot->x;
- y += plot->y;
- if (x < 0 || x >= plot->w || y < 0 || y >= plot->h)
- return;
- memcpy(plot->buf + plot->w * (plot->h - 1 - y) + x, color, sizeof(*plo…
-}
-
-void
-ffplot_rectangle(struct ffplot *plot, struct ffcolor *color,
- int y1, int x1,
- int y2, int x2)
-{
- int x, y, ymin, xmin, ymax, xmax;
-
- ymin = MIN(y1, y2); ymax = MAX(y1, y2);
- xmin = MIN(x1, x2); xmax = MAX(x1, x2);
-
- for (y = ymin; y <= ymax; y++)
- for (x = xmin; x <= xmax; x++)
- ffplot_pixel(plot, color, x, y);
-}
-
-/*
- * From Bresenham's line algorithm and dcat's tplot.
- */
-void
-ffplot_line(struct ffplot *plot, struct ffcolor *color,
- int x0, int y0,
- int x1, int y1)
-{
- int dy, dx, sy, sx, err, e;
-
- sx = x0 < x1 ? 1 : -1;
- sy = y0 < y1 ? 1 : -1;
- dx = ABS(x1 - x0);
- dy = ABS(y1 - y0);
- err = (dy > dx ? dy : -dx) / 2;
-
- for (;;) {
- ffplot_pixel(plot, color, x0, y0);
-
- if (y0 == y1 && x0 == x1)
- break;
-
- e = err;
- if (e > -dy) {
- y0 += sy;
- err -= dx;
- }
- if (e < dx) {
- x0 += sx;
- err += dy;
- }
- }
-}
-
-/*
- * Draw a coloured glyph from font f centered on y.
- */
-int
-ffplot_char(struct ffplot *plot, struct ffcolor *color, struct font *ft, char …
- int x, int y)
-{
- int yf, xf, wf;
-
- if (c & 0x80)
- c = '\0';
- y -= ft->height / 2;
- wf = font_width(ft, c);
- for (xf = 0; xf < wf; xf++)
- for (yf = 0; yf < ft->height; yf++)
- if (ft->glyph[(int)c][wf * (ft->height - yf) + xf] == …
- ffplot_pixel(plot, color, x + xf, y + yf);
- return wf + 1;
-}
-
-/*
- * Draw a left aligned string without wrapping it.
- */
-size_t
-ffplot_text_left(struct ffplot *plot, struct ffcolor *color, struct font *ft,
- char *s, int x, int y)
-{
- for (; *s != '\0'; s++)
- x += ffplot_char(plot, color, ft, *s, x, y);
- return x;
-}
-
-/*
- * Draw a center aligned string without wrapping it.
- */
-size_t
-ffplot_text_center(struct ffplot *plot, struct ffcolor *color, struct font *ft,
- char *s, int x, int y)
-{
- x -= font_strlen(ft, s) / 2;
- return ffplot_text_left(plot, color, ft, s, x, y);
-}
-
-/*
- * Draw a right aligned string without wrapping it.
- */
-size_t
-ffplot_text_right(struct ffplot *plot, struct ffcolor *color, struct font *ft,
- char *s, int x, int y)
-{
- x -= font_strlen(ft, s);
- return ffplot_text_left(plot, color, ft, s, x, y);
-}
-
-void
-ffplot_print(FILE *fp, struct ffplot *plot)
-{
- uint32_t w, h;
-
- w = htonl(plot->w);
- h = htonl(plot->h);
-
- fprintf(stdout, "farbfeld");
- fwrite(&w, sizeof(w), 1, fp);
- fwrite(&h, sizeof(h), 1, fp);
- fwrite(plot->buf, plot->w * plot->h, sizeof(*plot->buf), fp);
-}
diff --git a/src/ffplot.h b/src/ffplot.h
@@ -1,35 +0,0 @@
-#ifndef FFPLOT_H
-#define FFPLOT_H
-
-#include <stdio.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#include "font.h"
-
-struct ffcolor {
- uint16_t red;
- uint16_t green;
- uint16_t blue;
- uint16_t alpha;
-};
-
-struct ffplot {
- int w; /* width */
- int h; /* height */
- int x; /* x offset */
- int y; /* y offset */
- struct ffcolor *buf;
-};
-
-/**/
-void ffplot_pixel (struct ffplot *, struct ffcol…
-void ffplot_rectangle (struct ffplot *, struct ffcolor *…
-void ffplot_line (struct ffplot *, struct ffcolo…
-int ffplot_char (struct ffplot *, struct ffcolor…
-size_t ffplot_text_left (struct ffplot *, struct ffcolor…
-size_t ffplot_text_center (struct ffplot *, struct ffcol…
-size_t ffplot_text_right (struct ffplot *, struct ffcolo…
-void ffplot_print (FILE *, struct ffplot *);
-
-#endif
diff --git a/src/font.h b/src/font.h
@@ -1,21 +0,0 @@
-#ifndef FONT_H
-#define FONT_H
-
-#include <stddef.h>
-
-/*
- * Bitmapped font saved as a '_' and 'X' pattern in a C source file.
- */
-struct font {
- int height; /* The width is variable. */
- char *glyph[128]; /* 0: end, 1: off, 2: on. */
-};
-
-extern struct font font8;
-extern struct font font13;
-
-/**/
-size_t font_width (struct font *, int);
-size_t font_strlen (struct font *, char *);
-
-#endif
diff --git a/src/log.c b/src/log.c
@@ -1,97 +0,0 @@
-#include "log.h"
-
-#include <string.h>
-
-/*
- * log.c - log to standard error according to the log level
- *
- * Instead of logging to syslog, delegate logging to a separate
- * tool, such as FreeBSD's daemon(8), POSIX's logger(1).
- *
- * log_init() sets the log level to the "LOG" environment variable
- * if set, or to 4 (log down to info included) otherwise.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#define LOG_DEFAULT 2 /* info */
-
-int log_level = -1;
-
-void
-vlogf(int level, char const *flag, char const *fmt, va_list va)
-{
- char *env;
-
- if (log_level == -1) {
- env = getenv("LOG");
- log_level = env ? atoi(env) : 0;
- log_level = log_level > 0 ? log_level : LOG_DEFAULT;
- }
-
- if (log_level < level)
- return;
-
- fprintf(stderr, "%s: ", flag);
- vfprintf(stderr, fmt, va);
-
- if (errno)
- fprintf(stderr, ": %s", strerror(errno));
- errno = 0;
-
- fprintf(stderr, "\n");
- fflush(stderr);
-}
-
-void
-die(int exitcode, char const *fmt, ...)
-{
- va_list va;
-
- va_start(va, fmt);
- vlogf(0, "error", fmt, va);
- va_end(va);
- exit(exitcode);
-}
-
-void
-error(char const *fmt, ...)
-{
- va_list va;
-
- va_start(va, fmt);
- vlogf(0, "error", fmt, va);
- va_end(va);
-}
-
-void
-warn(char const *fmt, ...)
-{
- va_list va;
-
- va_start(va, fmt);
- vlogf(1, "warn", fmt, va);
- va_end(va);
-}
-
-void
-info(char const *fmt, ...)
-{
- va_list va;
-
- va_start(va, fmt);
- vlogf(2, "info", fmt, va);
- va_end(va);
-}
-
-void
-debug(char const *fmt, ...)
-{
- va_list va;
-
- va_start(va, fmt);
- vlogf(3, "debug", fmt, va);
- va_end(va);
-}
diff --git a/src/log.h b/src/log.h
@@ -1,15 +0,0 @@
-#ifndef LOG_H
-#define LOG_H
-
-#include <stdarg.h>
-
-/**/
-extern int log_level;
-void vlogf (int, char const *, char cons…
-void die (int, char const *, ...);
-void error (char const *, ...);
-void warn (char const *, ...);
-void info (char const *, ...);
-void debug (char const *, ...);
-
-#endif
diff --git a/src/scale.c b/src/scale.c
@@ -1,95 +0,0 @@
-#include "scale.h"
-
-#include <stddef.h>
-#include <time.h>
-
-#include "util.h"
-#include "log.h"
-
-/*
- * - <max ^
- * - | Translate the coordinates between double values
- * - <val szy and height in the plot of <row> rows.
- * - |
- * - <min v
- */
-int
-scale_ypos(double val, double min, double max, int szy)
-{
- return szy * (val - min) / (max - min);
-}
-
-/*
- * <---- szx ----> Translate the coordinates between the…
- * range and position in the plot of <col> cols.
- * t1 t t2
- * | . . | . . |
- */
-int
-scale_xpos(time_t t, time_t t1, time_t t2, int szx)
-{
- return szx * (t - t1) / (t2 - t1);
-}
-
-void
-scale_minmax(struct csv *vl, int ncol,
- time_t *tmin, time_t *tmax,
- double *vmin, double *vmax)
-{
- double *v;
- time_t *t;
- size_t n;
-
- *vmin = *vmax = 0;
- *tmin = *tmax = *vl->t;
-
- for (; ncol > 0; ncol--, vl++) {
- for (t = vl->t, v = vl->v, n = vl->n; n > 0; t++, v++, n--) {
- if (*v < *vmin) *vmin = *v;
- if (*v > *vmax) *vmax = *v;
- if (*t < *tmin) *tmin = *t;
- if (*t > *tmax) *tmax = *t;
- }
- }
-
- if (*tmin == *tmax)
- die(1, "invalid time scale: min=%lld max=%lld", *tmin, *tmax);
-}
-
-time_t
-scale_tstep(time_t min, time_t max, int nval)
-{
- time_t dt, *sc, scale[] = {
- 1, 5, 2, 10, 20, 30, 60, 60*2, 60*5, 60*10, 60*20, 60*30, 3600…
- 3600*2, 3600*5, 3600*10, 3600*18, 3600*24, 3600*24*2,
- 3600*24*5, 3600*24*10, 3600*24*20, 3600*24*30, 3600*24*50,
- 3600*24*100, 3600*24*365, 0
- };
-
- dt = max - min;
-
- for (sc = scale; *sc > 0; sc++)
- if (dt < *sc * nval)
- return *sc;
- return dt / nval;
-}
-
-double
-scale_vstep(double min, double max, int nval)
-{
- double dv, d, *sc, scale[] = { 1, 2, 3, 5 };
-
- dv = max - min;
-
- if (dv > 1)
- for (d = 1; d != 0; d *= 10)
- for (sc = scale; sc < scale + LEN(scale); sc++)
- if (dv < *sc * d * nval)
- return *sc * d;
- if (dv < 1)
- for (d = 1; d != 0; d *= 10)
- for (sc = scale + LEN(scale) - 1; sc >= scale; sc--)
- if (dv > *sc / d * nval / 2)
- return *sc / d;
- return 0;
-}
diff --git a/src/scale.h b/src/scale.h
@@ -1,16 +0,0 @@
-#ifndef SCALE_H
-#define SCALE_H
-
-#include <stddef.h>
-#include <time.h>
-
-#include "csv.h"
-
-/**/
-int scale_ypos (double, double, double, int);
-int scale_xpos (time_t, time_t, time_t, int);
-void scale_minmax (struct csv *, int, time_t *, …
-time_t scale_tstep (time_t, time_t, int);
-double scale_vstep (double, double, int);
-
-#endif
diff --git a/src/util.c b/src/util.c
@@ -1,80 +0,0 @@
-#include "util.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-size_t
-strlcpy(char *buf, const char *str, size_t sz)
-{
- size_t len, cpy;
-
- cpy = ((len = strlen(str)) > sz) ? (sz) : (len);
- memcpy(buf, str, cpy);
- buf[sz - 1] = '\0';
- return len;
-}
-
-void
-put3utf(long rune)
-{
- putchar((char)(0xe0 | (0x0f & (rune >> 12)))); /* 1110xxxx */
- putchar((char)(0x80 | (0x3f & (rune >> 6)))); /* 10xxxxxx */
- putchar((char)(0x80 | (0x3f & (rune)))); /* 10xxxxxx */
-}
-
-char *
-strsep(char **strp, const char *sep)
-{
- char *s, *prev;
-
- if (*strp == NULL)
- return NULL;
- for (s = prev = *strp; strchr(sep, *s) == NULL; s++);
- if (*s == '\0') {
- *strp = NULL;
- return prev;
- }
- *s = '\0';
- *strp = s + 1;
-
- return prev;
-}
-
-void
-strchomp(char *s)
-{
- char *x = s + strlen(s);
-
- while (--x >= s && (*x == '\r' || *x == '\n'))
- *x = '\0';
-}
-
-/*
- * Set 'str' to a human-readable form of 'num' with always a width of 8 (+1 for
- * the '\0' terminator). Buffer overflow is ensured not to happen due to the
- * max size of a double. Return the exponent.
- */
-int
-humanize(char *str, double val)
-{
- int exp, precision;
- char label[] = { '\0', 'M', 'G', 'T', 'E' };
-
- for (exp = 0; ABS(val) > 1000; exp++)
- val /= 1000;
-
- precision = (ABS(val) < 10) ? 2 : (ABS(val) < 100) ? 1 : 0;
- precision += (exp == 0);
-
- snprintf(str, 9, "%+.*f %c", precision, val, label[exp]);
- str[8] = '\0';
- if (val >= 0)
- str[0] = ' ';
-
- return exp * 3;
-}
diff --git a/src/util.h b/src/util.h
@@ -1,18 +0,0 @@
-#ifndef TOOL_H
-#define TOOL_H
-
-#include <stddef.h>
-
-#define LEN(x) (sizeof(x) / sizeof(*x))
-#define MAX(x, y) ((x) > (y) ? (x) : (y))
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
-#define ABS(x) ((x) < 0 ? -(x) : (x))
-
-/**/
-size_t strlcpy (char *, const char *, si…
-void put3utf (long);
-char * strsep (char **, const char *);
-void strchomp (char *);
-int humanize (char *, double);
-
-#endif
diff --git a/util.c b/util.c
@@ -0,0 +1,124 @@
+#include "util.h"
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+char const *arg0;
+
+static void
+_log(char const *fmt, va_list va)
+{
+ if (arg0 != NULL)
+ fprintf(stderr, "%s: ", arg0);
+ vfprintf(stderr, fmt, va);
+ fprintf(stderr, "\n");
+ fflush(stderr);
+}
+
+void
+err(int e, char const *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ _log( fmt, va);
+ exit(e);
+}
+
+void
+warn(char const *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ _log(fmt, va);
+}
+
+void
+debug(char const *fmt, ...)
+{
+ static int verbose = -1;
+ va_list va;
+
+ if (verbose < 0)
+ verbose = (getenv("DEBUG") != NULL);
+ if (!verbose)
+ return;
+ va_start(va, fmt);
+ _log(fmt, va);
+}
+
+size_t
+strlcpy(char *buf, const char *str, size_t sz)
+{
+ size_t len, cpy;
+
+ cpy = ((len = strlen(str)) > sz) ? (sz) : (len);
+ memcpy(buf, str, cpy);
+ buf[sz - 1] = '\0';
+ return len;
+}
+
+void
+put3utf(long rune)
+{
+ putchar((char)(0xe0 | (0x0f & (rune >> 12)))); /* 1110xxxx */
+ putchar((char)(0x80 | (0x3f & (rune >> 6)))); /* 10xxxxxx */
+ putchar((char)(0x80 | (0x3f & (rune)))); /* 10xxxxxx */
+}
+
+char *
+strsep(char **strp, const char *sep)
+{
+ char *s, *prev;
+
+ if (*strp == NULL)
+ return NULL;
+ for (s = prev = *strp; strchr(sep, *s) == NULL; s++);
+ if (*s == '\0') {
+ *strp = NULL;
+ return prev;
+ }
+ *s = '\0';
+ *strp = s + 1;
+
+ return prev;
+}
+
+void
+strchomp(char *s)
+{
+ char *x = s + strlen(s);
+
+ while (--x >= s && (*x == '\r' || *x == '\n'))
+ *x = '\0';
+}
+
+/*
+ * Set 'str' to a human-readable form of 'num' with always a width of 8 (+1 for
+ * the '\0' terminator). Buffer overflow is ensured not to happen due to the
+ * max size of a double. Return the exponent.
+ */
+int
+humanize(char *str, double val)
+{
+ int exp, precision;
+ char label[] = { '\0', 'M', 'G', 'T', 'E' };
+
+ for (exp = 0; ABS(val) > 1000; exp++)
+ val /= 1000;
+
+ precision = (ABS(val) < 10) ? 2 : (ABS(val) < 100) ? 1 : 0;
+ precision += (exp == 0);
+
+ snprintf(str, 9, "%+.*f %c", precision, val, label[exp]);
+ str[8] = '\0';
+ if (val >= 0)
+ str[0] = ' ';
+
+ return exp * 3;
+}
diff --git a/util.h b/util.h
@@ -0,0 +1,22 @@
+#ifndef TOOL_H
+#define TOOL_H
+
+#include <stddef.h>
+
+#define LEN(x) (sizeof(x) / sizeof(*x))
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+
+extern char const *arg0;
+
+void err(int, char const *fmt, ...);
+void warn(char const *fmt, ...);
+void debug(char const *fmt, ...);
+size_t strlcpy(char *, const char *, size_t);
+void put3utf(long);
+char *strsep(char **, const char *);
+void strchomp(char *);
+int humanize(char *, double);
+
+#endif
You are viewing proxied material from bitreich.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.