auto-scale - ploot - simple plotting tools | |
git clone git://bitreich.org/ploot git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65… | |
Log | |
Files | |
Refs | |
Tags | |
README | |
LICENSE | |
--- | |
commit c3911021718dc5e5b2dd6469495e7f3bc4befdd2 | |
parent d97badd46c19a6903a589c41b8b87d044f48f8dc | |
Author: Josuah Demangeon <[email protected]> | |
Date: Wed, 2 May 2018 06:37:05 +0200 | |
auto-scale | |
Diffstat: | |
M Makefile | 2 +- | |
M ffplot.c | 66 +++++++++++++++++++++++++++++… | |
D main.c | 191 -----------------------------… | |
M ploot.c | 364 +++++++++++------------------… | |
M ploot.h | 3 +-- | |
5 files changed, 186 insertions(+), 440 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
@@ -1,7 +1,7 @@ | |
CFLAGS = -Wall -Wextra -Werror -std=c89 -pedantic -D_POSIX_C_SOURCE=200… | |
LDFLAGS = -static | |
-SRC = main.c ffplot.c ffdraw.c font_14x7.c | |
+SRC = ploot.c ffplot.c ffdraw.c font_14x7.c | |
OBJ = $(SRC:.c=.o) | |
LIB = -lm | |
diff --git a/ffplot.c b/ffplot.c | |
@@ -18,6 +18,7 @@ | |
#include "font_14x7.h" | |
#define ABS(x) ((x) < 0 ? -(x) : (x)) | |
+#define LEN(x) (sizeof(x) / sizeof(*x)) | |
#define MARGIN 4 | |
@@ -42,7 +43,7 @@ | |
#define PLOT_X (YLABEL_H) | |
#define PLOT_Y (XLABEL_W) | |
#define PLOT_W 700 | |
-#define PLOT_H 200 | |
+#define PLOT_H 160 | |
#define LEGEND_X (YLABEL_H) | |
#define LEGEND_Y (IMAGE_W - LEGEND_W) | |
@@ -198,9 +199,60 @@ legend(Canvas *can, Color *label_fg, Vlist *v, int n) | |
} | |
void | |
-ffdraw(char *name, char *units, Vlist *v, int n, | |
- double vmin, double vmax, double vstep, | |
- time_t tmin, time_t tmax, time_t tstep) | |
+find_scales(Vlist *v, int n, | |
+ double *vmin, double *vmax, double *vstep, | |
+ time_t *tmin, time_t *tmax, time_t *tstep) | |
+{ | |
+ double dv, *vs, vscale[] = { 5, 2, 1 }; | |
+ time_t dt, *ts, tscale[] = { | |
+ 3600*24*30, 3600*24*5, 3600*24*2, 3600*24, 3600*18, 3600*10, | |
+ 3600*5, 3600*2, 3600, 60*30, 60*20, 60*10, 60*5, 60*2, 60, 30, | |
+ 20, 10, 5, 2, 1 | |
+ }; | |
+ int i; | |
+ | |
+ *vmin = *vmax = *tmin = *tmax = 0; | |
+ | |
+ for (; n-- > 0; v++) { | |
+ for (i = 0; i < v->n; i++) { | |
+ if (v->v[i] < *vmin) | |
+ *vmin = v->v[i]; | |
+ if (v->v[i] > *vmax) | |
+ *vmax = v->v[i]; | |
+ if (v->t[i] < *tmin) | |
+ *tmin = v->t[i]; | |
+ if (v->t[i] > *tmax) | |
+ *tmax = v->t[i]; | |
+ } | |
+ } | |
+ | |
+ dv = *vmax - *vmin; | |
+ dt = *tmax - *tmin; | |
+ | |
+ for (ts = tscale; ts < tscale + LEN(tscale); ts++) { | |
+ if (dt > *ts * 5) { | |
+ *tstep = *ts; | |
+ break; | |
+ } | |
+ } | |
+ | |
+ for (i = 1; i != 0; i *= 10) { | |
+ for (vs = vscale; vs < vscale + LEN(vscale); vs++) { | |
+ if (dv > *vs * i * 1) { | |
+ *vstep = *vs * i * 10; | |
+ i = 0; | |
+ break; | |
+ } | |
+ } | |
+ } | |
+} | |
+ | |
+/* | |
+ * Plot the 'n' values list of the 'v' array with title 'name' and | |
+ * 'units' label. | |
+ */ | |
+void | |
+ffplot(Vlist *v, int n, char *name, char *units) | |
{ | |
Canvas can = { IMAGE_W, IMAGE_H, buffer, 0, 0 }; | |
Color plot_bg = { 0x2222, 0x2222, 0x2222, 0xffff }; | |
@@ -208,6 +260,12 @@ ffdraw(char *name, char *units, Vlist *v, int n, | |
Color grid_fg = { 0x3737, 0x3737, 0x3737, 0xffff }; | |
Color label_fg = { 0x8888, 0x8888, 0x8888, 0xffff }; | |
Color title_fg = { 0xdddd, 0xdddd, 0xdddd, 0xffff }; | |
+ double vmin, vmax, vstep = 30; | |
+ time_t tmin, tmax, tstep = 30; | |
+ | |
+ find_scales(v, n, &vmin, &vmax, &vstep, &tmin, &tmax, &tstep); | |
+ | |
+ fprintf(stderr, "%f %f %lld %lld\n", vmin, vmax, tmin, tmax); | |
can.x = 0; | |
can.y = 0; | |
diff --git a/main.c b/main.c | |
@@ -1,191 +0,0 @@ | |
-#include <time.h> | |
-#include <stdlib.h> | |
-#include <stdio.h> | |
-#include <fcntl.h> | |
-#include <limits.h> | |
-#include <string.h> | |
-#include <ctype.h> | |
- | |
-#include "arg.h" | |
-#include "ploot.h" | |
-#include "config.h" /* after ploot.h for type definitions */ | |
- | |
-#define LEN(x) (sizeof(x) / sizeof(*x)) | |
- | |
-char *argv0; | |
-char *tflag = ""; | |
-char *uflag = ""; | |
- | |
-static int | |
-color(Color *col, char *name) | |
-{ | |
- ColorList *c; | |
- | |
- for (c = colorlist; c->name != NULL; c++) { | |
- if (strcmp(name, c->name) == 0) { | |
- memcpy(col, &c->col, sizeof(*col)); | |
- return 0; | |
- } | |
- } | |
- | |
- return -1; | |
-} | |
- | |
-void | |
-estriplf(char *line) | |
-{ | |
- char *lf; | |
- | |
- if ((lf = strchr(line, '\n')) == NULL || lf[1] != '\0') | |
- fputs("invalid input\n", stderr), exit(1); | |
- *lf = '\0'; | |
-} | |
- | |
-static void | |
-read_labels(Vlist *v, char **argv, char *buf) | |
-{ | |
- if (fgets(buf, LINE_MAX, stdin) == NULL) { | |
- if (ferror(stdin)) | |
- perror("fread from stdin"); | |
- else | |
- fputs("missing label line\n", stderr); | |
- exit(1); | |
- } | |
- estriplf(buf); | |
- | |
- if (strcmp(strsep(&buf, ","), "epoch") != 0) | |
- fputs("first label must be \"epoch\"\n", stderr), exit(1); | |
- | |
- for (; *argv != NULL; v++, argv++) | |
- if ((v->label = strsep(&buf, ",")) == NULL) | |
- fputs("more arguments than columns\n", stderr), exit(1… | |
- else if (color(&v->col, *argv) == -1) | |
- fprintf(stderr, "unknown color: %s\n", *argv), exit(1); | |
- | |
- if (strsep(&buf, ",") != NULL) | |
- fputs("more columns than arguments\n", stderr), exit(1); | |
-} | |
- | |
-double | |
-eatof(char *str) | |
-{ | |
- char *s; | |
- | |
- for (s = str; *s != '\0'; s++) | |
- if (!isdigit(*s) && *s != '.') | |
- fputs("invalid floatrformat", stderr), exit(0); | |
- return atof(str); | |
-} | |
- | |
-long | |
-eatol(char *str) | |
-{ | |
- char *s; | |
- | |
- for (s = str; *s != '\0'; s++) | |
- if (!isdigit(*s)) | |
- fputs("invalid number format", stderr), exit(0); | |
- return atol(str); | |
-} | |
- | |
-void | |
-add_val(Vlist *v, int *bufsiz, int nval, double field, time_t epoch) | |
-{ | |
- if (nval >= *bufsiz) { | |
- *bufsiz = *bufsiz * 2 + 1; | |
- if ((v->v = realloc(v->v, *bufsiz * sizeof(*v->v))) == NULL) | |
- perror("reallocating values buffer"), exit(1); | |
- if ((v->t = realloc(v->t, *bufsiz * sizeof(*v->t))) == NULL) | |
- perror("reallocating values buffer"), exit(1); | |
- } | |
- v->v[nval] = field; | |
- v->t[nval] = epoch; | |
- v->n = nval + 1; | |
-} | |
- | |
-/* | |
- * Add to each column the value on the current row. | |
- */ | |
-void | |
-add_row(Vlist *v, int *bufsiz, int ncol, int nval, char *line) | |
-{ | |
- time_t epoch; | |
- int n; | |
- char *field; | |
- | |
- if ((field = strsep(&line, ",")) == NULL) | |
- fprintf(stderr, "%d: missing epoch\n", nval), exit(0); | |
- | |
- epoch = eatol(field); | |
- for (n = 0; (field = strsep(&line, ",")) != NULL; n++, v++) { | |
- if (n > ncol) | |
- fprintf(stderr, "%d: too many fields\n", nval), exit(0… | |
- add_val(v, bufsiz, nval, eatof(field), epoch); | |
- } | |
- if (n < ncol) | |
- fprintf(stderr, "%d: too few fields\n", nval), exit(0); | |
-} | |
- | |
-/* | |
- * < ncol > | |
- * epoch,a1,b1,c1 ^ | |
- * epoch,a2,b2,c2 nval | |
- * epoch,a3,b3,c3 v | |
- */ | |
-void | |
-read_values(Vlist *v, int ncol) | |
-{ | |
- int nval, bufsiz; | |
- char line[LINE_MAX]; | |
- | |
- bufsiz = 0; | |
- for (nval = 0; fgets(line, sizeof(line), stdin); nval++) { | |
- estriplf(line); | |
- add_row(v, &bufsiz, ncol, nval, line); | |
- } | |
-} | |
- | |
-static void | |
-usage(void) | |
-{ | |
- ColorList *c; | |
- | |
- fprintf(stderr, "usage: %s [-t title] [-u unit] color...\n" | |
- "available colors as defined by \"config.h\":\n", argv0); | |
- for (c = colorlist; c->name != NULL; c++) | |
- fprintf(stderr, "- %s\n", c->name); | |
- exit(1); | |
-} | |
- | |
-int | |
-main(int argc, char **argv) | |
-{ | |
- Vlist *v; | |
- double vmin, vmax, vstep; | |
- time_t tmin, tmax, tstep; | |
- char labels[LINE_MAX]; | |
- | |
- ARGBEGIN { | |
- case 't': | |
- tflag = EARGF(usage()); | |
- break; | |
- case 'u': | |
- uflag = EARGF(usage()); | |
- break; | |
- } ARGEND; | |
- | |
- if ((v = calloc(argc, sizeof(*v))) == NULL) | |
- perror("calloc value list"), exit(1); | |
- | |
- vmin = -30; vmax = 700; vstep = 120; | |
- tmin = 0; tmax = 2000; tstep = 300; | |
- | |
- read_labels(v, argv, labels); | |
- read_values(v, argc); | |
- | |
- ffdraw(tflag, uflag, v, argc, | |
- vmin, vmax, vstep, | |
- tmin, tmax, tstep); | |
- | |
- return 0; | |
-} | |
diff --git a/ploot.c b/ploot.c | |
@@ -1,304 +1,184 @@ | |
-#include <sys/time.h> | |
- | |
-#include <stdio.h> | |
+#include <time.h> | |
#include <stdlib.h> | |
+#include <stdio.h> | |
+#include <fcntl.h> | |
+#include <limits.h> | |
#include <string.h> | |
-#include <unistd.h> | |
-#include <time.h> | |
+#include <ctype.h> | |
#include "arg.h" | |
-#include "config.h" | |
+#include "ploot.h" | |
+#include "config.h" /* after ploot.h for type definitions */ | |
-#define ABS(x) ((x) < 0 ? -(x) : (x)) | |
-#define MIN(x, y) ((x) < (y) ? (x) : (y)) | |
-#define MAX(x, y) ((x) > (y) ? (x) : (y)) | |
-#define LEN(buf) (sizeof(buf) / sizeof(*(buf))) | |
+#define LEN(x) (sizeof(x) / sizeof(*x)) | |
char *argv0; | |
+char *tflag = ""; | |
+char *uflag = ""; | |
-/* | |
-** Add 'val' at the current position 'pos' of the 'ring' buffer and set pos to | |
-** the next postion. | |
-*/ | |
-#define RING_ADD(rbuf, len, pos, val) \ | |
-do { \ | |
- rbuf[pos] = val; \ | |
- pos = (pos + 1 < len) ? (pos + 1) : (0); \ | |
-} while (0) | |
- | |
-/* | |
-** Copy the ring buffer 'rbuf' content with current position 'pos' into the | |
-** buffer 'buf'. Both buffer of length 'len'. | |
-*/ | |
-#define RING_COPY(buf, rbuf, len, pos) \ | |
-do { \ | |
- memcpy(buf, rbuf + pos, (len - pos) * sizeof(*rbuf)); \ | |
- memcpy(buf + (len - pos), rbuf, pos * sizeof(*rbuf)); \ | |
-} while (0) | |
- | |
-#define MAX_VAL 80 | |
-#define MARGIN 7 | |
- | |
-int hflag = 20; | |
-char *tflag = NULL; | |
-time_t oflag = 0; | |
- | |
-/* | |
-** Set 'str' to a human-readable form of 'num' with always a width of 7 (+ 1 | |
-** the '\0' terminator). Buffer overflow is ensured not to happen due to the | |
-** max size of a double. | |
-*/ | |
-void | |
-humanize(char *str, double val) | |
+static int | |
+color(Color *col, char *name) | |
{ | |
- int exp, precision; | |
- char *label = "\0kMGTE"; | |
+ ColorList *c; | |
- for (exp = 0; ABS(val) > 1000; exp++) | |
- val /= 1000; | |
+ for (c = colorlist; c->name != NULL; c++) { | |
+ if (strcmp(name, c->name) == 0) { | |
+ memcpy(col, &c->col, sizeof(*col)); | |
+ return 0; | |
+ } | |
+ } | |
- precision = (ABS(val) < 10) ? (3) : (ABS(val) < 100) ? (2) : (1); | |
- if (exp == 0) | |
- precision++; | |
- snprintf(str, 8, "%+.*f%c", precision, val, label[exp]); | |
- str[7] = '\0'; | |
- if (val >= 0) | |
- str[0] = ' '; | |
+ return -1; | |
} | |
-/* | |
-** Returns the maximal double of values between 'beg' and 'end'. | |
-*/ | |
-double | |
-maxdv(double *beg, double *end) | |
+static void | |
+estriplf(char *line) | |
{ | |
- double *val, max; | |
+ char *lf; | |
- max = *beg; | |
- for (val = beg; val < end; val++) { | |
- if (*val > max) | |
- max = *val; | |
- } | |
- return max; | |
+ if ((lf = strchr(line, '\n')) == NULL || lf[1] != '\0') | |
+ fputs("invalid input\n", stderr), exit(1); | |
+ *lf = '\0'; | |
} | |
-/* | |
-** If not null, print the title 'str' centered on width. | |
-*/ | |
-void | |
-title(char *str, int width) | |
+static void | |
+read_labels(Vlist *v, char **argv, char *buf) | |
{ | |
- if (str == NULL) | |
- return; | |
- printf("%*s\n", (int)(width + strlen(str)) / 2 + MARGIN + 3, str); | |
-} | |
- | |
-/* | |
-** Print vertical axis with humanized number from time to time, with occurences | |
-** determined after the position on the vertical axis from the bottom 'pos'. | |
-*/ | |
-void | |
-vaxis(double val, int pos) | |
-{ | |
- char label[10]; | |
- | |
- if (pos % 4 == 0) { | |
- humanize(label, val); | |
- printf("%*s -", MARGIN, label); | |
- } else { | |
- printf("%*c ", MARGIN, ' '); | |
+ if (fgets(buf, LINE_MAX, stdin) == NULL) { | |
+ if (ferror(stdin)) | |
+ perror("fread from stdin"); | |
+ else | |
+ fputs("missing label line\n", stderr); | |
+ exit(1); | |
} | |
-} | |
+ estriplf(buf); | |
-/* | |
-** Print horizontal axis for up to 'col' values along with dates if reading ti… | |
-** series. | |
-*/ | |
-void | |
-haxis(double *beg, double *end, time_t time) | |
-{ | |
- double *tp; | |
- char buf[9], dbeg[11], dend[11]; | |
+ if (strcmp(strsep(&buf, ","), "epoch") != 0) | |
+ fputs("first label must be \"epoch\"\n", stderr), exit(1); | |
- printf("%*d -+", MARGIN, 0); | |
- for (tp = beg; tp < end; tp++) | |
- putchar((*tp < 0) ? ('x') : ('-')); | |
- putchar('\n'); | |
- if (oflag > 0) { | |
- printf("%*c", MARGIN - 1, ' '); | |
- strftime(dbeg, sizeof(dbeg), "%Y/%m/%d", localtime(&time)); | |
- for (tp = beg; tp < end; tp += 7) { | |
- strftime(buf, sizeof(buf), " %H:%M", localtime(&time)… | |
- fputs(buf, stdout); | |
- time += oflag * 7; | |
- } | |
- strftime(dend, sizeof(dend), "%Y/%m/%d", localtime(&time)); | |
- printf("\n %-*s %s\n", (int)(beg - end) + 4, dbeg, dend); | |
- } | |
+ for (; *argv != NULL; v++, argv++) | |
+ if ((v->label = strsep(&buf, ",")) == NULL) | |
+ fputs("more arguments than columns\n", stderr), exit(1… | |
+ else if (color(&v->col, *argv) == -1) | |
+ fprintf(stderr, "unknown color: %s\n", *argv), exit(1); | |
+ | |
+ if (strsep(&buf, ",") != NULL) | |
+ fputs("more columns than arguments\n", stderr), exit(1); | |
} | |
-/* | |
-** Print two rows of a plot into a single line using ' ', '.' and ':'. | |
-*/ | |
-void | |
-line(double *beg, double *end, double top, double bot) | |
+static double | |
+eatof(char *str) | |
{ | |
- double *val; | |
+ char *s; | |
- putchar('|'); | |
- for (val = beg; val != end; val++) | |
- putchar((*val < bot) ? ' ' : (*val < top) ? '.' : ':'); | |
- putchar('\n'); | |
+ for (s = str; *s != '\0'; s++) | |
+ if (!isdigit(*s) && *s != '-' && *s != '.') | |
+ fputs("invalid floatrformat", stderr), exit(0); | |
+ return atof(str); | |
} | |
-/* | |
-** Plot values between 'beg' and 'end' in a plot of height 'height'. | |
-** If 'str' is not NULL, it is set as a title above the graph. | |
-*/ | |
-void | |
-plot(double *beg, double *end, int height, char *str, time_t start) | |
+static long | |
+eatol(char *str) | |
{ | |
- double top, bot, max; | |
- int h; | |
+ char *s; | |
- putchar('\n'); | |
- | |
- max = maxdv(beg, end); | |
- for (h = height + height % 2; h > 0; h -= 2) { | |
- top = h * max / height; | |
- bot = (h - 1) * max / height; | |
- | |
- vaxis(top, h); | |
- line(beg, end, top, bot); | |
- } | |
- | |
- haxis(beg, end, start); | |
- | |
- if (str != NULL) | |
- title(str, end - beg); | |
- | |
- putchar('\n'); | |
+ for (s = str; *s != '\0'; s++) | |
+ if (!isdigit(*s) && *s != '-') | |
+ fputs("invalid number format", stderr), exit(0); | |
+ return atol(str); | |
} | |
-/* | |
-** Read a simple format with one double per line and save the last 'MAX_WIDTH' | |
-** values into 'buf' which must be at least MAX_VAL wide and return a pointer | |
-** to the last element or NULL if the input contains error. | |
-*/ | |
-double * | |
-read_simple(double buf[MAX_VAL]) | |
+static void | |
+add_val(Vlist *v, int *bufsiz, int nval, double field, time_t epoch) | |
{ | |
- double rbuf[MAX_VAL], val; | |
- size_t p, pos, len; | |
- | |
- len = LEN(rbuf); | |
- for (p = pos = 0; scanf("%lf\n", &val) > 0; p++) | |
- RING_ADD(rbuf, len, pos, val); | |
- len = MIN(len, p); | |
- | |
- RING_COPY(buf, rbuf, len, pos); | |
- | |
- return buf + len; | |
+ if (nval >= *bufsiz) { | |
+ *bufsiz = *bufsiz * 2 + 1; | |
+ if ((v->v = realloc(v->v, *bufsiz * sizeof(*v->v))) == NULL) | |
+ perror("reallocating values buffer"), exit(1); | |
+ if ((v->t = realloc(v->t, *bufsiz * sizeof(*v->t))) == NULL) | |
+ perror("reallocating values buffer"), exit(1); | |
+ } | |
+ v->v[nval] = field; | |
+ v->t[nval] = epoch; | |
+ v->n = nval + 1; | |
} | |
/* | |
-** Read a format with blank separated time_t-double pairs, one per line and sa… | |
-** the last 'MAX_WIDTH' values into 'tbuf' and 'vbuf' which must both be at | |
-** least MAX_VAL wide and return a pointer to the last element of 'vbuf' or | |
-** NULL if the input contains error. | |
-*/ | |
-time_t * | |
-read_time_series(double *vbuf, time_t *tbuf) | |
+ * Add to each column the value on the current row. | |
+ */ | |
+static void | |
+add_row(Vlist *v, int *bufsiz, int ncol, int nval, char *line) | |
{ | |
- size_t p, pos, nul, len; | |
- double vrbuf[MAX_VAL], vval, dval; | |
- time_t trbuf[MAX_VAL], tval; | |
- | |
- len = LEN(vrbuf); | |
- for (p = pos = 0; scanf("%lf %lf\n", &dval, &vval) > 0; p++) { | |
- tval = (time_t)dval; | |
- RING_ADD(trbuf, len, pos, tval); | |
- RING_ADD(vrbuf, len, nul, vval); | |
+ time_t epoch; | |
+ int n; | |
+ char *field; | |
+ | |
+ if ((field = strsep(&line, ",")) == NULL) | |
+ fprintf(stderr, "%d: missing epoch\n", nval), exit(0); | |
+ | |
+ epoch = eatol(field); | |
+ for (n = 0; (field = strsep(&line, ",")) != NULL; n++, v++) { | |
+ if (n > ncol) | |
+ fprintf(stderr, "%d: too many fields\n", nval), exit(0… | |
+ add_val(v, bufsiz, nval, eatof(field), epoch); | |
} | |
- len = MIN(len, p); | |
- | |
- RING_COPY(tbuf, trbuf, len, pos); | |
- RING_COPY(vbuf, vrbuf, len, pos); | |
- | |
- return tbuf + len; | |
+ if (n < ncol) | |
+ fprintf(stderr, "%d: too few fields\n", nval), exit(0); | |
} | |
/* | |
-** Walk from 'tbeg' and 'tend' and add offset in 'tbuf' every time there is no | |
-** value in 'step' amount of time, by setting a value to -1. | |
-*/ | |
-double * | |
-skip_gaps(time_t *tbeg, time_t *tend, double *vbuf, time_t step) | |
+ * < ncol > | |
+ * epoch,a1,b1,c1 ^ | |
+ * epoch,a2,b2,c2 nval | |
+ * epoch,a3,b3,c3 v | |
+ */ | |
+static void | |
+read_values(Vlist *v, int ncol) | |
{ | |
- size_t p, pos, len; | |
- time_t *tp, toff; | |
- double *vp, vrbuf[MAX_VAL]; | |
- | |
- /* Compute the average alignment of the timestamps values according to | |
- ** the step size. */ | |
- toff = 0; | |
- for (tp = tbeg; tp < tend; tp++) | |
- toff += *tp % step; | |
- toff = *tbeg + toff / (tend - tbeg) + step / 2; | |
+ int nval, bufsiz; | |
+ char line[LINE_MAX]; | |
- /* Fill 'vbuf' with gap added at each time gap using vrbuf as | |
- ** intermediate ring buffer. */ | |
- len = LEN(vrbuf); | |
- for (p = pos = 0, tp = tbeg, vp = vbuf; tp < tend; p++, vp++, tp++) { | |
- for (; toff < *tp; toff += step) | |
- RING_ADD(vrbuf, len, pos, -1); | |
- RING_ADD(vrbuf, len, pos, *vp); | |
- toff += step; | |
+ bufsiz = 0; | |
+ for (nval = 0; fgets(line, sizeof(line), stdin); nval++) { | |
+ estriplf(line); | |
+ add_row(v, &bufsiz, ncol, nval, line); | |
} | |
- len = MAX(MIN(p, len), pos); | |
- | |
- RING_COPY(vbuf, vrbuf, len, pos); | |
- | |
- return vbuf + len; | |
} | |
-void | |
+static void | |
usage(void) | |
{ | |
- printf("usage: ploot [-h <height>] [-o <offset>] [-t <title>]\n"); | |
+ ColorList *c; | |
+ | |
+ fprintf(stderr, "usage: %s [-t title] [-u unit] color...\n" | |
+ "available colors as defined by \"config.h\":\n", argv0); | |
+ for (c = colorlist; c->name != NULL; c++) | |
+ fprintf(stderr, "- %s\n", c->name); | |
exit(1); | |
} | |
int | |
main(int argc, char **argv) | |
{ | |
- time_t tbuf[MAX_VAL], *tend, start; | |
- double vbuf[MAX_VAL], *vend; | |
+ Vlist *v; | |
+ char labels[LINE_MAX]; | |
- ARGBEGIN(argc, argv) { | |
- case 'h': | |
- if ((hflag = atoi(EARGF(usage()))) <= 0) | |
- usage(); | |
- break; | |
+ ARGBEGIN { | |
case 't': | |
tflag = EARGF(usage()); | |
break; | |
- case 'o': | |
- oflag = atol(EARGF(usage())); | |
+ case 'u': | |
+ uflag = EARGF(usage()); | |
break; | |
- default: | |
- usage(); | |
- } ARGEND | |
+ } ARGEND; | |
- if (oflag == 0) { | |
- vend = read_simple(vbuf); | |
- start = 0; | |
- } else { | |
- tend = read_time_series(vbuf, tbuf); | |
- vend = skip_gaps(tbuf, tend, vbuf, oflag); | |
- start = *tbuf; | |
- } | |
+ if ((v = calloc(argc, sizeof(*v))) == NULL) | |
+ perror("calloc value list"), exit(1); | |
+ | |
+ read_labels(v, argv, labels); | |
+ read_values(v, argc); | |
+ | |
+ ffplot(v, argc, tflag, uflag); | |
- plot(vbuf, vend, hflag, tflag, start); | |
return 0; | |
} | |
diff --git a/ploot.h b/ploot.h | |
@@ -45,8 +45,7 @@ void ffdraw_fill (Canvas *, Color *); | |
void ffdraw_print (Canvas *); | |
/* ffplot.c */ | |
-void ffdraw (char *, char *, Vlist *, int, doub… | |
- double, time_t, time_t, time_t); | |
+void ffplot (Vlist *, int, char *, char *); | |
/* util.c */ | |
char *strsep (char **, const char *); |