Introduction
Introduction Statistics Contact Development Disclaimer Help
add an experimental ploot-braille tool - ploot - simple plotting tools
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65…
Log
Files
Refs
Tags
README
LICENSE
---
commit 1f4e757723ea483ab2c60c8fec2937569441af9e
parent ffb9fc9caeaf3a79f5ab4c7fcbbf4994c1037582
Author: Josuah Demangeon <[email protected]>
Date: Sat, 15 Feb 2020 15:23:03 +0100
add an experimental ploot-braille tool
Diffstat:
M .gitignore | 1 +
M Makefile | 4 ++--
M arg.h | 2 --
A csv.c | 95 ++++++++++++++++++++++++++++++
M def.h | 24 ++++++++++++++++++++++--
M drawille.c | 39 +++++++++++++++--------------…
D log.h | 45 -----------------------------…
M ploot-braille.c | 201 +++++++++++++----------------…
M ploot-farbfeld.c | 7 +++----
M ploot-feed.c | 14 ++++++++------
A scale.c | 139 ++++++++++++++++++++++++++++++
M util.c | 53 ++++++++++++++++++++++++++++-…
12 files changed, 425 insertions(+), 199 deletions(-)
---
diff --git a/.gitignore b/.gitignore
@@ -1,4 +1,5 @@
*.o
*.core
+ploot-braille
ploot-farbfeld
ploot-feed
diff --git a/Makefile b/Makefile
@@ -1,5 +1,4 @@
-CFLAGS = -Wall -Wextra -std=c99 -pedantic -fPIC \
- -D_POSIX_C_SOURCE=200809L
+CFLAGS = -Wall -Wextra -std=c99 -pedantic -fPIC
LFLAGS = -static
BIN = ploot-farbfeld ploot-feed ploot-braille
LIB = -lm
@@ -9,6 +8,7 @@ SRC = csv.c drawille.c font.c font7.c font8.c font13.c u…
all: $(BIN)
+${SRC:.c=.o} ${BIN:=.o}: arg.h def.h Makefile
${BIN}: ${SRC:.c=.o} ${BIN:=.o}
${CC} $(LFLAGS) -o $@ [email protected] ${SRC:.c=.o} $(LIB)
diff --git a/arg.h b/arg.h
@@ -1,8 +1,6 @@
#ifndef ARG_H
#define ARG_H
-extern char const *arg0;
-
#define ARG_SWITCH(argc, argv) \
arg0 = *argv; \
while (++argv && --argc && **argv == '-' && (*argv)[1]) …
diff --git a/csv.c b/csv.c
@@ -0,0 +1,95 @@
+/*
+ * Read CSV data onto a set of (struct vlist).
+ */
+
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include "def.h"
+
+static void
+csv_addtime(struct vlist *vl, time_t epoch)
+{
+ if ((vl->t = realloc(vl->t, (vl->n + 1) * sizeof(*vl->t))) == NULL)
+ err(1, "reallocating values buffer");
+ vl->t[vl->n] = epoch;
+}
+
+static void
+csv_addval(struct vlist *vl, double field)
+{
+ if ((vl->v = realloc(vl->v, (vl->n + 1) * sizeof(*vl->v))) == NULL)
+ err(1, "reallocating values buffer");
+ vl->v[vl->n] = field;
+}
+
+/*
+ * Add to each column the value on the current row.
+ */
+void
+csv_addrow(struct vlist *vl, size_t ncol, char *line)
+{
+ char *field;
+
+ if ((field = strsep(&line, ",")) == NULL)
+ err(1, "missing epoch at row %zu", vl->n);
+
+ csv_addtime(vl, eatol(field));
+ for (; (field = strsep(&line, ",")) != NULL; ncol--, vl->n++, vl++) {
+ if (ncol == 0)
+ err(1, "too many fields at line %zu", vl->n);
+ csv_addval(vl, eatof(field));
+ }
+ if (ncol > 0)
+ err(1, "too few fields at line %zu", vl->n);
+}
+
+/*
+ * < *ncol >
+ * epoch,label1,label2,label3
+ */
+void
+csv_labels(FILE *fp, char *buf, struct vlist **vl, size_t *ncol)
+{
+ char *field;
+ size_t sz;
+
+ if (esfgets(buf, LINE_MAX, fp) == NULL)
+ err(1, "missing label line");
+
+ if (strcmp(strsep(&buf, ","), "epoch") != 0)
+ err(1, "first label must be \"epoch\"");
+
+ *vl = NULL;
+ for (*ncol = 0; (field = strsep(&buf, ",")) != NULL; ++*ncol) {
+ sz = (*ncol + 1) * sizeof **vl;
+ if ((*vl = realloc(*vl, sz)) == NULL)
+ err(1, "realloc");
+ (*vl)[*ncol].label = field;
+ }
+}
+
+/*
+ * < ncol >
+ * epoch,a1,b1,c1 ^
+ * epoch,a2,b2,c2 vl->n
+ * epoch,a3,b3,c3 v
+ */
+void
+csv_values(FILE *fp, struct vlist *vl, size_t ncol)
+{
+ char line[LINE_MAX];
+ time_t *tbuf;
+
+ while (esfgets(line, sizeof(line), fp) != NULL)
+ 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");
+
+ /* The same time buffer can be used for all. */
+ for (tbuf = vl->t; ncol > 0; ncol--, vl++)
+ vl->t = tbuf;
+}
diff --git a/def.h b/def.h
@@ -1,4 +1,5 @@
#include <limits.h>
+#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
@@ -37,8 +38,8 @@ struct vlist {
/* csv.c */
void csv_addrow (struct vlist *, size_t, char *);
-void csv_values (struct vlist *, size_t);
-void csv_labels (struct vlist *, char **, char *…
+void csv_labels (FILE *, char *, struct vlist **…
+void csv_values (FILE *, struct vlist *, size_t);
/* drawille.c */
@@ -61,12 +62,28 @@ struct font font13;
struct font font7;
struct font font8;
+/* ploot-braille.c */
+
+char const *arg0;
+
+/* ploot-farbfeld.c */
+
+char const *arg0;
+
+/* ploot-feed.c */
+
+char const *arg0;
+
/* scale.c */
+int scale_ypos (double, double, double, int);
+int scale_xpos (time_t, time_t, time_t, int);
+void scale_vminmax (double *, double *, int);
void scale (struct vlist *, int, time_t …
/* util.c */
+size_t strlcpy (char *, const char *, si…
void put3utf (long);
char * strsep (char **, const char *);
void estriplf (char *);
@@ -74,3 +91,6 @@ double eatof (char *);
long eatol (char *);
char * esfgets (char *, size_t, FILE *);
int humanize (char *, double);
+void vlog (char const *, char const *, v…
+void warn (char const *, ...);
+void err (int, char const *, ...);
diff --git a/drawille.c b/drawille.c
@@ -1,3 +1,7 @@
+/*
+ * Terminal-based plotting using drawille character, aka drawille.
+ */
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -5,14 +9,10 @@
#include "def.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 */
+ int x0, y0, x1, y1; /* point of the line…
+ int dx, dy, sx, sy, err; /* parameters for the a…
};
/*
@@ -36,7 +36,7 @@ drawille_cell_dot(uint8_t *cell, int row, int col)
static size_t
drawille_cell_utf(uint8_t cell, char *utf)
{
- long rune;
+ long rune;
rune = 10240 + cell;
utf[0] = (char)(0xe0 | (0x0f & (rune >> 12))); /* 1110xxxx */
@@ -54,8 +54,8 @@ drawille_get(struct drawille *drw, int row, int col)
size_t
drawille_fmt_row(struct drawille *drw, char *buf, size_t sz, int row)
{
- char txt[] = "xxx";
- size_t n;
+ char txt[] = "xxx";
+ size_t n;
n = 0;
for (int col = 0; col < drw->col; col++) {
@@ -82,7 +82,7 @@ drawille_dot(struct drawille *drw, int x, int y)
struct drawille *
drawille_new(int row, int col)
{
- struct drawille *drw;
+ struct drawille *drw;
if ((drw = calloc(sizeof(struct drawille) + row * col, 1)) == NULL)
return NULL;
@@ -108,10 +108,10 @@ drawille_line_init(struct line *l, int x0, int y0, int x1…
static int
drawille_line_next(struct line *l)
{
- int e;
+ int e;
if (l->x0 == l->x1 && l->y0 == l->y1)
- return 0;
+ return -1;
e = l->err;
if (e > -l->dx) {
@@ -122,13 +122,13 @@ drawille_line_next(struct line *l)
l->y0 += l->sy;
l->err += l->dx;
}
- return 1;
+ return 0;
}
void
drawille_line(struct drawille *drw, int x0, int y0, int x1, int y1)
{
- struct line l;
+ struct line l;
drawille_line_init(&l, x0, y0, x1, y1);
do {
@@ -139,8 +139,8 @@ drawille_line(struct drawille *drw, int x0, int y0, int x1,…
void
drawille_line_hist(struct drawille *drw, int x0, int y0, int x1, int y1, int z…
{
- struct line l;
- int sign;
+ struct line l;
+ int sign;
drawille_line_init(&l, x0, y0, x1, y1);
do {
@@ -153,7 +153,7 @@ drawille_line_hist(struct drawille *drw, int x0, int y0, in…
void
drawille_dot_hist(struct drawille *drw, int x, int y, int zero)
{
- int sign;
+ int sign;
sign = (y > zero) ? (-1) : (+1);
for (; y != zero + sign; y += sign)
@@ -163,8 +163,8 @@ drawille_dot_hist(struct drawille *drw, int x, int y, int z…
static int
drawille_text_glyph(struct drawille *drw, int x, int y, struct font *font, cha…
{
- int width;
- char *glyph;
+ int width;
+ char *glyph;
if ((unsigned)c > 127)
glyph = font->glyph[0];
@@ -187,7 +187,6 @@ drawille_text(struct drawille *drw, int x, int y, struct fo…
{
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/log.h b/log.h
@@ -1,45 +0,0 @@
-#ifndef LOG_H
-#define LOG_H
-
-#include <errno.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-char const *arg0; /* Should be set by the library caller. */
-
-static inline void
-vlog(char const *base, char const *fmt, va_list va)
-{
- fprintf(stderr, "%s: ", base);
- vfprintf(stderr, fmt, va);
- if (errno)
- fprintf(stderr, ": %s", strerror(errno));
- fputc('\n', stderr);
- fflush(stderr);
- errno = 0; /* avoid repeating the error in loop */
-}
-
-static inline void
-warn(char const *fmt, ...)
-{
- va_list va;
-
- va_start(va, fmt);
- vlog(arg0, fmt, va);
- va_end(va);
-}
-
-static inline void
-err(int e, char const *fmt, ...)
-{
- va_list va;
-
- va_start(va, fmt);
- vlog(arg0, fmt, va);
- va_end(va);
- exit(e);
-}
-
-#endif
diff --git a/ploot-braille.c b/ploot-braille.c
@@ -8,48 +8,15 @@
#include <math.h>
#include "def.h"
+#include "arg.h"
-/*
- * Adjust the vertical scale so that it gets possible to
- */
-static void
-plot_scale(double *min, double *max, int row)
-{
- double unit, range, mi;
-
- range = *max - *min;
- unit = 1;
-
- /* Zoom until it fills the canvas. */
- for (; (row - 1) * unit > range; unit /= 10)
- continue;
-
- /* Dezoom until it fits the canvas. */
- for (; (row - 1) * unit < range; unit *= 10)
- continue;
-
- /* Fine tune. */
- if ((row - 1) * unit / 5 > range)
- unit /= 5;
- if ((row - 1) * unit / 4 > range)
- unit /= 4;
- if ((row - 1) * unit / 2 > range)
- unit /= 2;
-
- /* Align the minimum (and the zero). */
- for (mi = 0; mi > *min - unit; mi -= unit)
- continue;
-
- /* Update the displayed minimal and maximal. */
- *min = mi;
- *max = mi + unit * row;
-}
+char const *arg0 = NULL;
/*
* Return the step between two values.
*/
static int
-plot_time_interval(time_t step)
+braille_time_interval(time_t step)
{
time_t scale[] = {
1, 5, 2, 10, 20, 30, 60, 60*2, 60*5, 60*10, 60*20, 60*30,
@@ -65,136 +32,142 @@ plot_time_interval(time_t step)
}
static size_t
-plot_axis_x(char *buf, size_t sz, time_t step, time_t t2, int col)
+braille_axis_x(FILE *fp, time_t step, time_t tmax, int col)
{
int x, prec;
char tmp[sizeof("MM/DD HH:MM")], *fmt;
size_t n;
time_t t, interval;
- interval = plot_time_interval(step);
+ interval = braille_time_interval(step);
fmt = (step < 3600 * 12) ? "^%H:%M:%S" :
(step < 3600 * 24) ? "^%m/%d %H:%M" :
"^%Y/%m/%d";
n = x = 0;
- t = t2 - col * 2 * step;
+ t = tmax - col * 2 * step;
t += interval - t % interval;
- for (; t < t2; t += interval) {
+ for (; t < tmax; t += interval) {
strftime(tmp, sizeof tmp, fmt, localtime(&t));
- x = ((t - t2) / 2 + col * step) / step;
+ x = ((t - tmax) / 2 + col * step) / step;
prec = x - n + strlen(tmp);
- assert((n += snprintf(buf+n, sz-n, "%*s", prec, tmp)) <= sz);
+ fprintf(fp, "%*s", prec, tmp);
}
- assert((n += strlcpy(buf+n, "\n", sz-n)) < sz);
- return n;
+ fputc('\n', fp);
+ return 1;
}
/*
* Plot a single line out of the y axis, at row <r> out of <rows>.
*/
-static size_t
-plot_axis_y(char *buf, size_t sz, double min, double max, int r, int rows)
+static void
+braille_axis_y(FILE *fp, double min, double max, int r, int rows)
{
- size_t i;
char tmp[10] = "", *s;
double val;
val = (max - min) * (rows - r) / rows + min;
- humanize(tmp, sizeof tmp, val);
+ humanize(tmp, val);
s = (r == 0) ? "┌" :
(r == rows - 1) ? "└" :
"├";
- i = snprintf(buf, sz, "%s%-6s ", s, tmp);
- return (i > sz) ? (sz) : (i);
+ fprintf(fp, "%s%-6s ", s, tmp);
}
-static char *
-plot_render(struct drawille *drw, double min, double max, time_t step, time_t …
+static int
+braille_render(struct drawille *drw, FILE *fp, time_t tmin, time_t tmax)
{
- char *buf;
- size_t sz;
- size_t n;
+ char buf[LINE_MAX];
/* Render the plot line by line. */
- sz = drw->row * (20 + drw->col * 3 + 1) + 1;
- sz += drw->col + 1 + 100000;
- if ((buf = calloc(sz, 1)) == NULL)
- goto err;
- n = 0;
for (int row = 0; row < drw->row; row++) {
- n += drawille_fmt_row(drw, buf+n, sz-n, row);
- n += plot_axis_y(buf+n, sz-n, min, max, row, drw->row);
- n += strlcpy(buf+n, "\n", sz-n);
+ drawille_fmt_row(drw, buf, sizeof buf, row);
+ braille_axis_y(fp, tmin, tmax, row, drw->row);
+ fputc('\n', fp);
}
- plot_axis_x(buf+n, sz-n, step, t2, drw->col);
- return buf;
-err:
- errno = ENOBUFS;
- free(buf);
- return NULL;
+ return 0;
}
/*
* Plot the body as an histogram interpolating the gaps and include
* a vertical and horizontal axis.
*/
-static char *
-plot_hist(struct vlist *vl, time_t t2, struct drawille *drw)
+static int
+braille_hist(struct vlist *vl, FILE *fp, time_t tmin, time_t tmax, int row, in…
{
int x, y, zero, shift;
- double min, max, val;
- time_t t1, t;
-
- /* Adjust the y scale. */
- shift = min = max = 0;
- timeserie_stats(vl, &min, &max);
- if (drw->row > 1) {
- shift = 2; /* Align values to the middle of the scale: |- */
- plot_scale(&min, &max, drw->row);
- }
- zero = timeserie_ypos(0, min, max, drw->row*4) - shift;
-
- /* Adjust the x scale. */
- t2 = t2 + vl->step - t2 % vl->step;
- t1 = t2 - vl->step * vl->len;
-
- /* Plot the data in memory in <drw> starting from the end (t2). */
- t = t2;
- for (x = drw->col * 2; x > 0; x--) {
- val = timeserie_get(vl, t);
- if (!isnan(val)) {
- y = timeserie_ypos(val, min, max, drw->row*4) - shift;
- drawille_dot_hist(drw, x, y, zero);
- }
- t -= vl->step;
- }
+ double *v, vmin, vmax;
+ time_t *t;
+ size_t n;
+ struct drawille *drw;
- return plot_render(drw, min, max, vl->step, t2);
+ if ((drw = drawille_new(row, col)) == NULL)
+ err(1, "allocating drawille canvas");
+
+ shift = (drw->row > 1) ? (2) : (0); /* center values on "|-" marks */
+ vmin = vmax = 0;
+ zero = scale_ypos(0, vmin, vmax, drw->row*4) - shift;
+ v = vl->v;
+ t = vl->t;
+ n = vl->n;
+ for (; n > 0; n--, t++, v++) {
+ if (isnan(*v)) /* XXX: better handling? */
+ continue;
+ y = scale_ypos(*v, vmin, vmax, drw->row * 4) - shift;
+ x = scale_xpos(*t, tmin, tmax, drw->col * 2);
+ drawille_dot_hist(drw, x, y, zero);
+ }
+ if (braille_render(drw, fp, tmin, tmax) == -1)
+ err(1, "rendering braille canvas");
+ free(drw);
+ return 0;
}
-static char *
-plot(struct vlist *vl, time_t t2, int row, int col)
+static int
+plot(struct vlist *vl, FILE *fp, size_t ncol, int row, int col)
{
- struct drawille *drw;
size_t len;
- char *buf;
+ double vmin, vmax, vstep;
+ time_t tmin, tmax, tstep;
len = 500;
- buf = NULL;
- drw = NULL;
col -= 8;
- if (timeserie_read(vl) == -1)
- goto err;
+ scale(vl, ncol, &tmin, &tmax, &tstep, &vmin, &vmax, &vstep);
- if ((drw = drawille_new(row, col)) == NULL)
- goto err;
+ if (braille_hist(vl, fp, tmin, tmax, row, col) == -1)
+ err(1, "allocating drawille canvas");
+ braille_axis_x(fp, tstep, tmax, col);
+ return 0;
+}
- buf = plot_hist(vl, t2, drw);
-err:
- if (buf == NULL)
- timedb_close(&vl->db);
- free(drw);
- return buf;
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s\n", arg0);
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ struct vlist *vl;
+ char labels[LINE_MAX];
+ size_t ncol;
+
+ ARG_SWITCH(argc, argv) {
+ default:
+ usage();
+ }
+
+ if (argc > 0)
+ usage();
+
+ csv_labels(stdin, labels, &vl, &ncol);
+ csv_values(stdin, vl, ncol);
+
+ plot(vl, stdout, ncol, 20, 80);
+
+ free(vl);
+ return 1;
}
diff --git a/ploot-farbfeld.c b/ploot-farbfeld.c
@@ -13,7 +13,6 @@
#include <math.h>
#include "arg.h"
-#include "log.h"
#include "def.h"
#define MARGIN 4
@@ -66,9 +65,9 @@ struct canvas {
struct color *buf;
};
-char const *arg0;
-static char *tflag = "";
-static char *uflag = "";
+char const *arg0 = NULL;
+static char *tflag = "";
+static char *uflag = "";
static struct font *font = &font13;
static struct cname cname[] = {
diff --git a/ploot-feed.c b/ploot-feed.c
@@ -13,9 +13,9 @@
#define WIDTH_MAX 1024
#define BRAILLE_START 10240
-int wflag = 80;
-int width = 0;
-char const *arg0 = NULL;
+char const *arg0 = NULL;
+static int wflag = 80;
+static int width = 0;
/*
* Turn the bit at position (row, col) on in the .
@@ -139,8 +139,11 @@ plot(char labels[LINE_MAX], double *max, int ncol)
last_epoch = epoch = 0;
for (n = 0;; n = (n == 25 ? 0 : n + 1)) {
- if (n == 0)
- put_time(0, 0, 2), fputs(labels, stdout), puts("│");
+ if (n == 0) {
+ put_time(0, 0, 2);
+ fputs(labels, stdout);
+ puts("│");
+ }
epoch = plot_line(out, max, ncol);
put_time(epoch, last_epoch, n);
@@ -224,7 +227,6 @@ main(int argc, char **argv)
int ncol, nmax;
char *labv[LINE_MAX / 2], labels[LINE_MAX];
- setvbuf(stdin, NULL, _IOLBF, 0);
nmax = parse_args(argc, argv, max);
ncol = read_labels(labv);
width = (wflag - sizeof("XXxXXxXX _")) / ncol - sizeof("|");
diff --git a/scale.c b/scale.c
@@ -0,0 +1,139 @@
+#include "def.h"
+#include "err.h"
+
+#define XDENSITY 7 /* nb of values on x axis */
+#define YDENSITY 7 /* nb of values on y axis */
+
+/*
+ * - <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);
+}
+
+static void
+scale_minmax(struct vlist *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);
+}
+
+static time_t
+scale_tstep(time_t min, time_t max, int density)
+{
+ time_t dt, *s, 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 (s = scale; s < scale + LEN(scale); s++)
+ if (dt < *s * density)
+ return *s;
+ return 0;
+}
+
+static double
+scale_vstep(double min, double max, int density)
+{
+ double dv, d, *s, scale[] = { 1, 2, 3, 5 };
+
+ dv = max - min;
+
+ if (dv > 1)
+ for (d = 1; d != 0; d *= 10)
+ for (s = scale; s < scale + LEN(scale); s++)
+ if (dv < *s * d * density)
+ return *s * d;
+ if (dv < 1)
+ for (d = 1; d != 0; d *= 10)
+ for (s = scale + LEN(scale) - 1; s >= scale; s--)
+ if (dv > *s / d * density / 2)
+ return *s / d;
+ return 0;
+}
+
+/*
+ * Adjust the vertical scale so that everything fits, with nice
+ * scale values.
+ */
+void
+scale_vminmax(double *min, double *max, int row)
+{
+ double unit, range, mi;
+
+ range = *max - *min;
+ unit = 1;
+
+ /* Zoom until it fills the canvas. */
+ for (; (row - 1) * unit > range; unit /= 10)
+ continue;
+
+ /* Dezoom until it fits the canvas. */
+ for (; (row - 1) * unit < range; unit *= 10)
+ continue;
+
+ /* Fine tune. */
+ if ((row - 1) * unit / 5 > range)
+ unit /= 5;
+ if ((row - 1) * unit / 4 > range)
+ unit /= 4;
+ if ((row - 1) * unit / 2 > range)
+ unit /= 2;
+
+ /* Align the minimum (and the zero). */
+ for (mi = 0; mi > *min - unit; mi -= unit)
+ continue;
+
+ /* Update the displayed minimal and maximal. */
+ *min = mi;
+ *max = mi + unit * row;
+}
+
+void
+scale(struct vlist *vl, int ncol,
+ time_t *tmin, time_t *tmax, time_t *tstep,
+ double *vmin, double *vmax, double *vstep)
+{
+ scale_minmax(vl, ncol, tmin, tmax, vmin, vmax);
+ *tstep = scale_tstep(*tmin, *tmax, XDENSITY);
+ *vstep = scale_vstep(*vmin, *vmax, YDENSITY);
+}
diff --git a/util.c b/util.c
@@ -1,12 +1,24 @@
-#include <string.h>
+#include <ctype.h>
#include <errno.h>
-#include <stdio.h>
#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <ctype.h>
+#include <string.h>
#include "def.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)
{
@@ -79,7 +91,7 @@ esfgets(char *buf, size_t n, FILE *file)
}
/*
- * Set 'str' to a human-readable form of 'num' with always a width of 8 (+ 1
+ * 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.
*/
@@ -102,3 +114,36 @@ humanize(char *str, double val)
return exp * 3;
}
+
+void
+vlog(char const *base, char const *fmt, va_list va)
+{
+ fprintf(stderr, "%s: ", base);
+ vfprintf(stderr, fmt, va);
+ if (errno)
+ fprintf(stderr, ": %s", strerror(errno));
+ fputc('\n', stderr);
+ fflush(stderr);
+ errno = 0; /* avoid repeating the error in loop */
+}
+
+void
+warn(char const *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ vlog(arg0, fmt, va);
+ va_end(va);
+}
+
+void
+err(int e, char const *fmt, ...)
+{
+ va_list va;
+
+ va_start(va, fmt);
+ vlog(arg0, fmt, va);
+ va_end(va);
+ exit(e);
+}
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.