refactor a bit - 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 a2f50e1cb8af6ef5571c142b93b8ade388e0bfa5
 (DIR) parent 1f4e757723ea483ab2c60c8fec2937569441af9e
 (HTM) Author: Josuah Demangeon <me@josuah.net>
       Date:   Tue, 18 Feb 2020 08:33:24 +0100
       
       refactor a bit
       
       Diffstat:
         M def.h                               |      48 +++++++------------------------
         M drawille.c                          |      58 +++++++++++++++++++++++--------
         M ploot-braille.c                     |     106 +++++++++----------------------
         M ploot-farbfeld.c                    |       8 ++++----
         M ploot-feed.c                        |       6 +++---
         M test.csv                            |       1 +
         M util.c                              |      46 -------------------------------
       
       7 files changed, 90 insertions(+), 183 deletions(-)
       ---
 (DIR) diff --git a/def.h b/def.h
       @@ -35,62 +35,34 @@ struct vlist {
                char                *label;                /* for the legend */
        };
        
       -/* csv.c */
       -
       +/**/
        void                csv_addrow                (struct vlist *, size_t, char *);
        void                csv_labels                (FILE *, char *, struct vlist **, size_t *);
        void                csv_values                (FILE *, struct vlist *, size_t);
       -
       -/* drawille.c */
       -
       -size_t                drawille_fmt_row        (struct drawille *, char *, size_t, int);
       +size_t                drawille_put_row        (struct drawille *, FILE *, 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_line_hist        (struct drawille *, int, int, int, int, int);
       -void                drawille_dot_hist        (struct drawille *, int, int, int);
       +void                drawille_histogram_dot        (struct drawille *, int, int, int);
       +void                drawille_histogram_line        (struct drawille *, int, int, int, int, int);
       +int                drawille_histogram        (struct vlist *, struct drawille *, time_t, time_t, double, double);
        char *                drawille_text                (struct drawille *, int, int, struct font *, char *);
       -
       -/* font.c */
       -
        size_t                font_width                (struct font *, int);
        size_t                font_strlen                (struct font *, char *);
       -
       -/* font*.c */
       -
       -struct font font13;
       -struct font font7;
       -struct font font8;
       -
       -/* ploot-braille.c */
       -
       +struct font        font13;
       +struct font        font7;
       +struct font        font8;
        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 *, time_t *, time_t *, double *, double *, double *);
       -
       -/* util.c */
       -
        size_t                strlcpy                        (char *, const char *, size_t);
        void                put3utf                        (long);
        char *                strsep                        (char **, const char *);
        void                estriplf                (char *);
        double                eatof                        (char *);
        long                eatol                        (char *);
       -char *                esfgets                        (char *, size_t, FILE *);
        int                humanize                (char *, double);
       -void                vlog                        (char const *, char const *, va_list);
       -void                warn                        (char const *, ...);
       -void                err                        (int, char const *, ...);
       +
       +#endif
 (DIR) diff --git a/drawille.c b/drawille.c
       @@ -6,6 +6,7 @@
        #include <stdio.h>
        #include <stdlib.h>
        #include <string.h>
       +#include <math.h>
        
        #include "def.h"
        
       @@ -52,7 +53,7 @@ drawille_get(struct drawille *drw, int row, int col)
        }
        
        size_t
       -drawille_fmt_row(struct drawille *drw, char *buf, size_t sz, int row)
       +drawille_put_row(struct drawille *drw, FILE *fp, int row)
        {
                char                txt[] = "xxx";
                size_t                n;
       @@ -60,7 +61,7 @@ drawille_fmt_row(struct drawille *drw, char *buf, size_t sz, int row)
                n = 0;
                for (int col = 0; col < drw->col; col++) {
                        drawille_cell_utf(drawille_get(drw, row, col), txt);
       -                n += snprintf(buf+n, sz-n, "%s", txt);
       +                n += fputs(txt, fp);
                }
                return n;
        }
       @@ -111,7 +112,7 @@ drawille_line_next(struct line *l)
                int                e;
        
                if (l->x0 == l->x1 && l->y0 == l->y1)
       -                return -1;
       +                return 0;
        
                e = l->err;
                if (e > -l->dx) {
       @@ -122,7 +123,7 @@ drawille_line_next(struct line *l)
                        l->y0 += l->sy;
                        l->err += l->dx;
                }
       -        return 0;
       +        return 1;
        }
        
        void
       @@ -137,27 +138,54 @@ drawille_line(struct drawille *drw, int x0, int y0, int x1, int y1)
        }
        
        void
       -drawille_line_hist(struct drawille *drw, int x0, int y0, int x1, int y1, int zero)
       +drawille_histogram_dot(struct drawille *drw, int x, int y, int zero)
        {
       -        struct line        l;
                int                sign;
        
       +        sign = (y > zero) ? (+1) : (-1);
       +        for (; y != zero + sign; y -= sign)
       +                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 {
       -                sign = (l.y0 > zero) ? (-1) : (+1);
       -                for (int y = l.y0; y != zero + sign; y += sign)
       -                        drawille_dot(drw, l.x0, y);
       +                drawille_histogram_dot(drw, l.x0, l.y0, zero);
                } while (drawille_line_next(&l));
        }
        
       -void
       -drawille_dot_hist(struct drawille *drw, int x, int y, int zero)
       +/*
       + * Plot the body as an histogram interpolating the gaps and include
       + * a vertical and horizontal axis.
       + */
       +int
       +drawille_histogram(struct vlist *vl, struct drawille *drw,
       +        time_t tmin, time_t tmax, double vmin, double vmax)
        {
       -        int                sign;
       +        int                x, xprev, y, yprev, zero;
       +        double                *v;
       +        time_t                *t;
       +        size_t                n;
        
       -        sign = (y > zero) ? (-1) : (+1);
       -        for (; y != zero + sign; y += sign)
       -                drawille_dot(drw, x, y);
       +        zero = scale_ypos(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? */
       +                        continue;
       +                y = scale_ypos(*v, vmin, vmax, drw->row * 4);
       +                x = scale_xpos(*t, tmin, tmax, drw->col * 2);
       +                if (n < vl->n)
       +                        drawille_histogram_line(drw, xprev, yprev, x, y, zero);
       +                xprev = x;
       +                yprev = y;
       +        }
       +        return 0;
        }
        
        static int
 (DIR) diff --git a/ploot-braille.c b/ploot-braille.c
       @@ -12,61 +12,43 @@
        
        char const        *arg0 = NULL;
        
       -/*
       - * Return the step between two values.
       - */
        static int
       -braille_time_interval(time_t step)
       +braille_axis_x(FILE *fp, time_t tmin, time_t tmax, time_t tstep, int col)
        {
       -        time_t                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
       -        };
       -
       -        for (time_t *s = scale; *s != 0; s++)
       -                if (*s >= 20 * step)
       -                        return *s;
       -        return 1;
       -}
       -
       -static size_t
       -braille_axis_x(FILE *fp, time_t step, time_t tmax, int col)
       -{
       -        int                x, prec;
       +        int                x, o, prec;
                char                tmp[sizeof("MM/DD HH:MM")], *fmt;
                size_t                n;
       -        time_t                t, interval;
       +        time_t                t;
        
       -        interval = braille_time_interval(step);
       -        fmt = (step < 3600 * 12) ? "^%H:%M:%S" :
       -            (step < 3600 * 24) ? "^%m/%d %H:%M" :
       +        fmt = (tstep < 3600 * 12) ? "^%H:%M:%S" :
       +            (tstep < 3600 * 24) ? "^%m/%d %H:%M" :
                    "^%Y/%m/%d";
                n = x = 0;
        
       -        t = tmax - col * 2 * step;
       -        t += interval - t % interval;
       -        for (; t < tmax; t += interval) {
       +        t = tmin;
       +        t += tstep - t % tstep;
       +        for (; t < tmax; t += tstep) {
       +                x = (t - tmin) * col / (tmax - tmin);
                        strftime(tmp, sizeof tmp, fmt, localtime(&t));
       -                x = ((t - tmax) / 2 + col * step) / step;
                        prec = x - n + strlen(tmp);
       -                fprintf(fp, "%*s", prec, tmp);
       +                if ((o = fprintf(fp, "%*s", prec, tmp)) < 0)
       +                        return -1;
       +                n += o;
                }
                fputc('\n', fp);
       -        return 1;
       +        return 0;
        }
        
        /*
         * Plot a single line out of the y axis, at row <r> out of <rows>.
         */
        static void
       -braille_axis_y(FILE *fp, double min, double max, int r, int rows)
       +braille_axis_y(FILE *fp, double vmin, double vmax, int r, int rows)
        {
                char                tmp[10] = "", *s;
                double                val;
        
       -        val = (max - min) * (rows - r) / rows + min;
       +        val = (rows - r) * (vmax - vmin) / rows;
                humanize(tmp, val);
                s = (r == 0) ? "┌" :
                    (r == rows - 1) ? "└" :
       @@ -75,70 +57,40 @@ braille_axis_y(FILE *fp, double min, double max, int r, int rows)
        }
        
        static int
       -braille_render(struct drawille *drw, FILE *fp, time_t tmin, time_t tmax)
       +braille_render(struct drawille *drw, FILE *fp, double vmin, double vmax)
        {
       -        char                buf[LINE_MAX];
       -
                /* Render the plot line by line. */
                for (int row = 0; row < drw->row; row++) {
       -                drawille_fmt_row(drw, buf, sizeof buf, row);
       -                braille_axis_y(fp, tmin, tmax, row, drw->row);
       +                drawille_put_row(drw, fp, row);
       +                braille_axis_y(fp, vmin, vmax, row, drw->row);
                        fputc('\n', fp);
                }
                return 0;
        }
        
       -/*
       - * Plot the body as an histogram interpolating the gaps and include
       - * a vertical and horizontal axis.
       - */
       -static int
       -braille_hist(struct vlist *vl, FILE *fp, time_t tmin, time_t tmax, int row, int col)
       -{
       -        int                x, y, zero, shift;
       -        double                *v, vmin, vmax;
       -        time_t                *t;
       -        size_t                n;
       -        struct drawille        *drw;
       -
       -        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 int
       +static void
        plot(struct vlist *vl, FILE *fp, size_t ncol, int row, int col)
        {
                size_t                len;
                double                vmin, vmax, vstep;
                time_t                tmin, tmax, tstep;
       +        struct drawille        *drw;
        
                len = 500;
                col -= 8;
        
                scale(vl, ncol, &tmin, &tmax, &tstep, &vmin, &vmax, &vstep);
       +        warn("vstep=%lf vstep=%ld", vstep, tstep);
        
       -        if (braille_hist(vl, fp, tmin, tmax, row, col) == -1)
       +        if ((drw = drawille_new(row, col)) == NULL)
                        err(1, "allocating drawille canvas");
       -        braille_axis_x(fp, tstep, tmax, col);
       -        return 0;
       +        if (drawille_histogram(vl, drw, tmin, tmax, vmin, vmax) == -1)
       +                err(1, "allocating drawille canvas");
       +        if (braille_render(drw, fp, vmin, vmax) == -1)
       +                err(1, "rendering braille canvas");
       +        if (braille_axis_x(fp, tmin, tmax, tstep, col) == -1)
       +                err(1, "printing x axis");;
       +        free(drw);
        }
        
        static void
 (DIR) diff --git a/ploot-farbfeld.c b/ploot-farbfeld.c
       @@ -65,10 +65,10 @@ struct canvas {
                struct color        *buf;
        };
        
       -char const                *arg0 = NULL;
       -static char                *tflag = "";
       -static char                *uflag = "";
       -static struct font        *font = &font13;
       +char const        *arg0 = NULL;
       +static char        *tflag = "";
       +static char        *uflag = "";
       +static struct font *font = &font13;
        
        static struct cname cname[] = {
                /* name       red     green   blue    alpha */
 (DIR) diff --git a/ploot-feed.c b/ploot-feed.c
       @@ -13,9 +13,9 @@
        #define WIDTH_MAX 1024
        #define BRAILLE_START        10240
        
       -char const                *arg0 = NULL;
       -static int                wflag = 80;
       -static int                width = 0;
       +char const        *arg0 = NULL;
       +static int        wflag = 80;
       +static int        width = 0;
        
        /*
         * Turn the bit at position (row, col) on in the .
 (DIR) diff --git a/test.csv b/test.csv
       @@ -109,5 +109,6 @@ epoch,shortterm,midterm,longterm
        1525294298,0.278198,0.260864,0.242920
        1525295198,0.192505,0.183716,0.200806
        1525296098,0.109375,0.185669,0.207153
       +1525296098,-0.109375,0.185669,0.207153
        1525296998,0.137085,0.126221,0.138184
        1525297898,0.077881,0.092529,0.109619
 (DIR) diff --git a/util.c b/util.c
       @@ -77,19 +77,6 @@ eatol(char *str)
                return atol(str);
        }
        
       -char *
       -esfgets(char *buf, size_t n, FILE *file)
       -{
       -        if (fgets(buf, n, file) == NULL) {
       -                if (ferror(stdin))
       -                        perror("fread from stdin"), exit(1);
       -                else
       -                        return NULL;
       -        }
       -        estriplf(buf);
       -        return buf;
       -}
       -
        /*
         * 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
       @@ -114,36 +101,3 @@ 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);
       -}