Introduction
Introduction Statistics Contact Development Disclaimer Help
csv: fix use of uninitialized memory - ploot - simple plotting tools
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65…
Log
Files
Refs
Tags
README
LICENSE
---
commit f7f88c2ee5573abff4c44c36bf7b2e705081b2ed
parent c3fcef87d156b02a9ad8ca7cd47fee4a826534f4
Author: Josuah Demangeon <[email protected]>
Date: Sun, 27 Jun 2021 01:04:39 +0200
csv: fix use of uninitialized memory
Diffstat:
M Makefile | 6 +++---
M csv.c | 33 ++++++++++++++---------------…
M csv.h | 1 -
M ploot-braille.c | 157 ++++++++++++++++++++++-------…
M ploot-farbfeld.c | 14 +++++++-------
D scale.c | 94 -----------------------------…
D scale.h | 14 --------------
7 files changed, 140 insertions(+), 179 deletions(-)
---
diff --git a/Makefile b/Makefile
@@ -7,9 +7,9 @@ LFLAGS = -static -lm
PREFIX = /usr/local
MANOREFIX = $(PREFIX)/share/man
-SRC = csv.c drawille.c font.c font13.c font8.c scale.c util.c
-INC = csv.h drawille.h font.h scale.h util.h
-BIN = ploot-farbfeld ploot-feed ploot-braille ploot-text
+SRC = csv.c drawille.c font.c font13.c font8.c util.c
+INC = csv.h drawille.h font.h util.h
+BIN = ploot-feed ploot-braille ploot-text # ploot-farbfeld
OBJ = ${SRC:.c=.o}
all: ${BIN}
diff --git a/csv.c b/csv.c
@@ -13,11 +13,10 @@
*/
static void
-csv_addtime(struct csv *vl, time_t epoch)
+csv_add_time(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;
@@ -25,11 +24,10 @@ csv_addtime(struct csv *vl, time_t epoch)
}
static void
-csv_addval(struct csv *vl, double field)
+csv_add_val(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;
@@ -40,8 +38,8 @@ csv_addval(struct csv *vl, double 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)
+static void
+csv_add_row(struct csv *vl, size_t ncol, char *line)
{
char *field;
time_t *tbuf;
@@ -55,7 +53,7 @@ csv_addrow(struct csv *vl, size_t ncol, char *line)
if (errno)
err(100, "parsing number '%s'", field);
- csv_addtime(vl, l);
+ csv_add_time(vl, l);
tbuf = vl[0].t;
for (; (field = strsep(&line, ",")); ncol--, vl->n++, vl++) {
if (ncol == 0)
@@ -63,7 +61,7 @@ csv_addrow(struct csv *vl, size_t ncol, char *line)
d = strtod(field, NULL);
if (errno)
err(100, "parsing double '%s'", field);
- csv_addval(vl, d);
+ csv_add_val(vl, d);
vl->t = tbuf;
}
if (ncol > 0)
@@ -75,10 +73,10 @@ csv_addrow(struct csv *vl, size_t ncol, char *line)
* label1,label2,label3
*/
void
-csv_labels(FILE *fp, struct csv **vl, size_t *ncol)
+csv_labels(FILE *fp, struct csv **vlp, size_t *ncol)
{
char *field, *line, *cp;
- struct csv *col;
+ struct csv *vl, *col;
size_t sz;
ssize_t r;
@@ -94,16 +92,16 @@ csv_labels(FILE *fp, struct csv **vl, size_t *ncol)
if (strcmp(strsep(&cp, ","), "epoch") != 0)
err(1, "first label must be 'epoch'");
- *vl = NULL;
- *ncol = 0;
+ sz = 0, vl = NULL, *ncol = 0;
while ((field = strsep(&cp, ","))) {
- if ((*vl = realloc(*vl, sz += sizeof **vl)) == NULL)
+ if ((vl = realloc(vl, sz += sizeof *vl)) == NULL)
err(1, "realloc: %s", strerror(errno));
- col = (*vl) + (*ncol)++;
- strlcpy(col->label, field, sizeof(col->label));
+ memset(vl, 0, sizeof *vl);
+ col = vl + (*ncol)++;
+ strlcpy(col->label, field, sizeof col->label);
}
-
free(line);
+ *vlp = vl;
}
/*
@@ -122,11 +120,10 @@ csv_values(FILE *fp, struct csv *vl, size_t ncol)
sz = 0, line = NULL;
while (getline(&line, &sz, fp) > -1)
- csv_addrow(vl, ncol, line);
+ csv_add_row(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
@@ -15,7 +15,6 @@ struct csv {
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);
diff --git a/ploot-braille.c b/ploot-braille.c
@@ -8,13 +8,90 @@
#include <math.h>
#include <unistd.h>
#include "drawille.h"
-#include "scale.h"
#include "util.h"
+#include "csv.h"
#ifndef __OpenBSD__
#define pledge(...) 0
#endif
+static int
+get_min_max(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; /* always show 0 on the scale */
+ *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)
+ return -1;
+ return 0;
+}
+
+static time_t
+time_mark_step(time_t min, time_t max, int dots)
+{
+ time_t dt, scale[] = {
+ 1, 5, 2, 10, 20, 30, 60, 60*2, 60*5, 60*10, 60*20, 60*30, 3600…
+ 3600*2, 3600*6, 3600*12, 3600*24, 3600*24*2,
+ 3600*24*7, 3600*24*14, 3600*24*20, 3600*24*21, 3600*24*28, 360…
+ 3600*24*100, 3600*24*365, 0
+ };
+
+ dt = max - min;
+ for (time_t *sc = scale; *sc > 0; sc++)
+ if (dt < *sc * dots)
+ return *sc;
+ return dt / dots;
+}
+
+/*
+ * Make the value scale aligned with round values by changing the
+ * minimal and maximal values.
+ */
+static void
+adjust_scale(double *min, double *max, int rows)
+{
+ double dv, step, scale[] = { 1, 2, 2.5, 5, };
+
+ dv = *max - *min;
+
+ if (dv > 1) {
+ for (double mant = 1;; mant *= 10) {
+ double *sc = scale;
+ for (; sc < scale + LEN(scale); sc++) {
+ step = mant * *sc;
+ if (dv < (rows - 2) * step)
+ goto end;
+ }
+ }
+ } else {
+ for (double mant = 1;; mant /= 10) {
+ double *sc = scale + LEN(scale) - 1;
+ for (; sc >= scale; sc--) {
+ step = mant * *sc;
+ if (dv > (rows - 2) * step)
+ goto end;
+ }
+ }
+ }
+end:
+ *min = (int)(*min / step) * step;
+ *max = *min + step * rows;
+}
+
/*
* Plot the body as an histogram interpolating the gaps and include
* a vertical and horizontal axis.
@@ -28,25 +105,31 @@ braille_histogram(struct csv *vl, struct drawille *drw,
time_t *t;
size_t n;
- zero = scale_ypos(0, vmin, vmax, drw->row*4);
+#define SHIFT (4 / 2)
+#define POSITION(val, min, max, sz) ((sz) * ((val) - (min)) / ((max) - (min)) …
+
+ zero = POSITION(0, vmin, vmax, drw->row*4);
v = vl->v;
t = vl->t;
n = vl->n;
for (; n > 0; n--, t++, v++) {
- if (isnan(*v)) /* XXX: better handling? */
+ if (isnan(*v)) /* XXX: better handling? */
continue;
- y = scale_ypos(*v, vmin, vmax, drw->row * 4);
- x = scale_xpos(*t, tmin, tmax, drw->col * 2);
- if (n < vl->n) /* only plot when xprev, yprev are set */
+ y = POSITION(*v, vmin, vmax, drw->row * 4);
+ x = POSITION(*t, tmin, tmax, drw->col * 2);
+ if (n < vl->n) /* only plot when xprev, yprev are set */
drawille_histogram_line(drw, xprev, yprev, x, y, zero);
xprev = x;
yprev = y;
}
+
+#undef POSITION
+
return 0;
}
static int
-braille_axis_x(FILE *fp, time_t tmin, time_t tmax, time_t csvep, int col)
+braille_axis_x(FILE *fp, time_t tmin, time_t tmax, time_t tstep, int col)
{
int x, o, prec;
char tmp[sizeof("MM/DD HH:MM")], *fmt;
@@ -54,13 +137,13 @@ braille_axis_x(FILE *fp, time_t tmin, time_t tmax, time_t …
time_t t;
fmt =
- (csvep < 3600 * 12) ? "^%H:%M:%S" :
- (csvep < 3600 * 24) ? "^%m/%d %H:%M" :
- "^%Y/%m/%d";
+ (tstep < 3600 * 12) ? "^%H:%M:%S" :
+ (tstep < 3600 * 24) ? "^%m/%d %H:%M" :
+ "^%Y/%m/%d";
n = x = 0;
- t = tmin + csvep - tmin % csvep;
- for (; t < tmax; t += csvep) {
+ t = tmin + tstep - tmin % tstep;
+ for (; t < tmax; t += tstep) {
x = (t - tmin) * col / (tmax - tmin);
strftime(tmp, sizeof tmp, fmt, localtime(&t));
prec = x - n + strlen(tmp);
@@ -76,51 +159,41 @@ braille_axis_x(FILE *fp, time_t tmin, time_t tmax, time_t …
* Plot a single line out of the y axis, at row <r> out of <rows>.
*/
static void
-braille_axis_y(FILE *fp, double vmin, double vmax, int r, int rows)
+braille_axis_y(FILE *fp, double min, double max, int r, int rows)
{
- char tmp[10] = "", *s;
- double val;
-
- val = (rows - r) * (vmax - vmin) / rows;
- humanize(tmp, val);
- s =
- (r == 0) ? "┌" :
- (r == rows - 1) ? "└" :
- "├";
- fprintf(fp, "%s%-6s ", s, tmp);
+ char buf[10] = "";
+
+ humanize(buf, (rows - 1 - r) * (max - min) / rows);
+ fprintf(fp, "├%s ", buf);
}
static int
-braille_render(struct drawille *drw, FILE *fp, double vmin, double vmax)
+braille_render(struct drawille *drw, FILE *fp, double min, double max)
{
int row;
for (row = 0; row < drw->row; row++) {
drawille_put_row(fp, drw, row);
- braille_axis_y(fp, vmin, vmax, row, drw->row);
+ braille_axis_y(fp, min, max, row, drw->row);
fprintf(fp, "\n");
}
return 0;
}
static void
-plot(struct csv *vl, FILE *fp, size_t ncol, int rows, int cols)
+plot(struct csv *vl, size_t ncol, int rows, int cols, FILE *fp)
{
- double vmin, vmax, vstep;
- time_t tmin, tmax, csvep;
+ double vmin, vmax;
+ time_t tmin, tmax, tstep;
struct drawille *drw;
- cols -= 9; /* scale printed at the right */
-
- scale_minmax(vl, ncol, &tmin, &tmax, &vmin, &vmax);
- csvep = scale_csvep(tmin, tmax, cols / 10);
- vstep = scale_vstep(vmin, vmax, rows / 10);
+ rows = MAX(rows, 2); /* readable */
- 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, csvep, ncol, row…
+ if (get_min_max(vl, ncol, &tmin, &tmax, &vmin, &vmax) < 0)
+ err(1, "invalid scale: tmin=%lld tmax=%lld vmin=%fd vmax=%fd",
+ (long long)tmin, (long long)tmax, vmin, vmax);
+ adjust_scale(&vmin, &vmax, rows);
+ tstep = time_mark_step(tmin, tmax, cols);
for (; ncol > 0; vl++, ncol--) {
if ((drw = drawille_new(rows, cols)) == NULL)
@@ -132,7 +205,7 @@ plot(struct csv *vl, FILE *fp, size_t ncol, int rows, int c…
err(1, "rendering braille canvas");
free(drw);
}
- if (braille_axis_x(fp, tmin, tmax, csvep, cols) == -1)
+ if (braille_axis_x(fp, tmin, tmax, tstep * 10, cols) == -1)
err(1, "printing x axis");;
}
@@ -153,7 +226,7 @@ main(int argc, char **argv)
if (pledge("stdio", "") < 0)
err(1, "pledge: %s", strerror(errno));
- rows = 20, cols = 80;
+ rows = 4, cols = 60;
arg0 = *argv;
while ((c = getopt(argc, argv, "r:c:")) > -1) {
switch (c) {
@@ -185,8 +258,8 @@ main(int argc, char **argv)
csv_labels(stdin, &vl, &ncol);
csv_values(stdin, vl, ncol);
- plot(vl, stdout, ncol, rows, cols);
+ plot(vl, ncol, rows, cols, stdout);
free(vl);
- return 1;
+ return 0;
}
diff --git a/ploot-farbfeld.c b/ploot-farbfeld.c
@@ -236,20 +236,20 @@ ffplot_v2y(double v, double vmin, double vmax)
static void
ffplot_xaxis(struct ffplot *plot, struct ffcolor *label, struct ffcolor *grid,
- time_t tmin, time_t tmax, time_t csvep)
+ time_t tmin, time_t tmax, time_t tstep)
{
time_t t;
int x;
char str[sizeof("MM/DD HH/MM")], *fmt;
- if (csvep < 3600 * 12)
+ if (tstep < 3600 * 12)
fmt = "%H:%M:%S";
- else if (csvep < 3600 * 24)
+ else if (tstep < 3600 * 24)
fmt = "%m/%d %H:%M";
else
fmt = "%X/%m/%d";
- for (t = tmax - tmax % csvep; t >= tmin; t -= csvep) {
+ for (t = tmax - tmax % tstep; t >= tmin; t -= tstep) {
x = ffplot_t2x(t, tmin, tmax);
ffplot_line(plot, grid,
@@ -358,10 +358,10 @@ 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, csvep;
+ time_t tmin, tmax, tstep;
scale_minmax(vl, ncol, &tmin, &tmax, &vmin, &vmax);
- csvep = scale_csvep(tmin, tmax, 7);
+ tstep = scale_tstep(tmin, tmax, 7);
vstep = scale_vstep(vmin, vmax, 7);
if ((plot.buf = calloc(IMAGE_H * IMAGE_W, sizeof *plot.buf)) == NULL)
@@ -377,7 +377,7 @@ plot(struct csv *vl, struct ffcolor **cl, size_t ncol, char…
plot.x = XLABEL_X;
plot.y = XLABEL_Y;
- ffplot_xaxis(&plot, &label_fg, &grid_fg, tmin, tmax, csvep);
+ ffplot_xaxis(&plot, &label_fg, &grid_fg, tmin, tmax, tstep);
plot.x = YLABEL_X;
plot.y = YLABEL_Y;
diff --git a/scale.c b/scale.c
@@ -1,94 +0,0 @@
-#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
@@ -1,14 +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 *, doub…
-time_t scale_csvep(time_t, time_t, int);
-double scale_vstep(double, double, int);
-
-#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.