flatten the repository and simplify Makefile - 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 a546b97f9fe7f4a9e30b514bfc257ba85cd9a7f9
(DIR) parent 1a7e49697644fe2740519b2c5f62a314e675c616
(HTM) Author: Josuah Demangeon <me@josuah.net>
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(-)
---
(DIR) 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 $@ $@.o ${obj} ${lib}
+${OBJ} ${BIN:=.o}: ${INC} Makefile
+${BIN}: ${OBJ} ${BIN:=.o}
+ ${CC} ${LFLAGS} -o $@ $@.o ${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}
(DIR) diff --git a/README b/README
@@ -1,60 +0,0 @@
-ploot
-=====
-
-
-ploot-farbfeld
---------------
-
-*ploot-farbfeld* reads collectd-style comma separated values (CSV) and produces a plot
-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 produces
-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/
(DIR) 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 a plot
+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 produces
+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/
(DIR) diff --git a/config.mk b/config.mk
@@ -1,4 +0,0 @@
-CFLAGS = -Wall -Wextra -std=c99 -pedantic -fPIC -I"src" -D_POSIX_C_SOURCE=200811L
-LFLAGS = -static
-PREFIX = /usr/local
-MANDIR = $(PREFIX)/share/man
(DIR) 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);
+}
(DIR) 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
(DIR) 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 / 2),
+ 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, int zero)
+{
+ 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, char c)
+{
+ 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;
+}
(DIR) 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 * row) */
+};
+
+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, int);
+char *drawille_text(struct drawille *, int, int, struct font *, char *);
+
+#endif
(DIR) diff --git a/test.csv b/example.csv
(DIR) 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(*plot->buf));
+}
+
+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 c,
+ 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] == 3)
+ 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);
+}
(DIR) 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, int);
+void ffplot_line(struct ffplot *, struct ffcolor *, int, int, int, int);
+int ffplot_char(struct ffplot *, struct ffcolor *, struct font *, char, int, int);
+size_t ffplot_text_left(struct ffplot *, struct ffcolor *, struct font *, char *, int, int);
+size_t ffplot_text_center(struct ffplot *, struct ffcolor *, struct font *, char *, int, int);
+size_t ffplot_text_right(struct ffplot *, struct ffcolor *, struct font *, char *, int, int);
+void ffplot_print(FILE *, struct ffplot *);
+
+#endif
(DIR) diff --git a/src/font.c b/font.c
(DIR) 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
(DIR) diff --git a/src/font13.c b/font13.c
(DIR) diff --git a/src/font8.c b/font8.c
(DIR) 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 tstep, int col)
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, rows);
+ debug("vstep=%lf vstep=%ld ncol=%zu rows=%zu", vstep, csvep, ncol, rows);
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;
(DIR) 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
(DIR) 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 stdin.
+utility plots an image in the ffplot format out of csv values coming from stdin.
.
.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
(DIR) 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 *grid,
- 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, struct ffcolor *grid,
}
static void
-farbfeld_yaxis(struct ffplot *plot, struct ffcolor *label, struct ffcolor *grid,
+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, struct ffcolor *grid,
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, struct ffcolor *grid,
}
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 ffcolor *color,
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 ffcolor *color,
}
static void
-farbfeld_values(struct ffplot *plot, struct csv *vl, struct ffcolor **cl, size_t ncol,
+ffplot_values(struct ffplot *plot, struct csv *vl, struct ffcolor **cl, size_t ncol,
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, struct ffcolor **cl, size_t ncol)
+ffplot_legend(struct ffplot *plot, struct ffcolor *fg, struct csv *vl, struct ffcolor **cl, size_t ncol)
{
size_t x, y;
@@ -209,13 +206,14 @@ plot(struct csv *vl, struct ffcolor **cl, size_t ncol, char *name, char *units)
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, char *name, char *units)
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);
(DIR) 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
.
.
(DIR) 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 ncol)
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;
(DIR) 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) / 2));
+ 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;
}
(DIR) 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
(DIR) 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 time
+ * 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;
+}
(DIR) 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 *, double *);
+time_t scale_csvep(time_t, time_t, int);
+double scale_vstep(double, double, int);
+
+#endif
(DIR) 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);
-}
(DIR) 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
(DIR) 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 / 2),
- 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, int zero)
-{
- 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, char c)
-{
- 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;
-}
(DIR) 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 * row) */
-};
-
-/**/
-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, int);
-char * drawille_text (struct drawille *, int, int, struct font *, char *);
-
-#endif
(DIR) 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(*plot->buf));
-}
-
-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 c,
- 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] == 3)
- 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);
-}
(DIR) 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 ffcolor *, int, int);
-void ffplot_rectangle (struct ffplot *, struct ffcolor *, int, int, int, int);
-void ffplot_line (struct ffplot *, struct ffcolor *, int, int, int, int);
-int ffplot_char (struct ffplot *, struct ffcolor *, struct font *, char, int, int);
-size_t ffplot_text_left (struct ffplot *, struct ffcolor *, struct font *, char *, int, int);
-size_t ffplot_text_center (struct ffplot *, struct ffcolor *, struct font *, char *, int, int);
-size_t ffplot_text_right (struct ffplot *, struct ffcolor *, struct font *, char *, int, int);
-void ffplot_print (FILE *, struct ffplot *);
-
-#endif
(DIR) 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
(DIR) 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);
-}
(DIR) 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 const *, va_list);
-void die (int, char const *, ...);
-void error (char const *, ...);
-void warn (char const *, ...);
-void info (char const *, ...);
-void debug (char const *, ...);
-
-#endif
(DIR) 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 time
- * 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;
-}
(DIR) 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 *, double *, double *);
-time_t scale_tstep (time_t, time_t, int);
-double scale_vstep (double, double, int);
-
-#endif
(DIR) 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;
-}
(DIR) 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 *, size_t);
-void put3utf (long);
-char * strsep (char **, const char *);
-void strchomp (char *);
-int humanize (char *, double);
-
-#endif
(DIR) 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;
+}
(DIR) 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