]> git.ipfire.org Git - thirdparty/rrdtool-1.x.git/blame - src/rrd_graph_helper.c
Merge pull request #1072 from SuperHeron/acinclude-python3
[thirdparty/rrdtool-1.x.git] / src / rrd_graph_helper.c
CommitLineData
0516711e 1/****************************************************************************
bfa56b52 2 * RRDtool 1.7.2 Copyright by Tobi Oetiker, 1997-2019
0516711e 3 ****************************************************************************
aa70e348 4 * rrd_graph_helper.c commandline parser functions
054f4ff3 5 * this code initially written by Alex van den Bogaerdt
0516711e
TO
6 ****************************************************************************/
7
f79c1d56
WS
8#ifdef __MINGW64__
9#define __USE_MINGW_ANSI_STDIO 1 /* for %lli */
10#endif
11
e111de44 12#include <locale.h>
c5794b2d
SH
13#include "rrd_config.h"
14#ifdef HAVE_STDINT_H
1a9c6fc4 15#include <stdint.h>
c5794b2d 16#endif
e111de44 17
adb27eb6 18#include "rrd_graph.h"
22550a23 19#include "rrd_strtod.h"
e111de44 20
1ace8365
TO
21#define dprintf(...) if (gdp->debug&1) fprintf(stderr,__VA_ARGS__);
22#define dprintfparsed(...) if (gdp->debug&2) fprintf(stderr,__VA_ARGS__);
8b1d02ad 23#define dprintfhash(...) if (gdp->debug&4) fprintf(stderr,__VA_ARGS__);
1ace8365 24
53dc677d
WS
25void initParsedArguments(
26 parsedargs_t *pa)
27{
28 /* initialize */
29 pa->arg = NULL;
30 pa->arg_orig = NULL;
31 pa->kv_args = NULL;
32 pa->kv_cnt = 0;
6465207c 33}
adb27eb6 34
53dc677d
WS
35void freeParsedArguments(
36 parsedargs_t *pa)
37{
38 if (pa->arg) {
39 free(pa->arg);
40 }
41 if (pa->kv_args) {
42 for (int i = 0; i < pa->kv_cnt; i++) {
43 free(pa->kv_args[i].keyvalue);
44 }
45 free(pa->kv_args);
129d1f40 46 }
53dc677d 47 initParsedArguments(pa);
1ace8365 48}
6465207c 49
53dc677d
WS
50void resetParsedArguments(
51 parsedargs_t *pa)
52{
53 if (pa->kv_args) {
54 for (int i = 0; i < pa->kv_cnt; i++) {
55 if (pa->kv_args[i].flag != 255) {
56 pa->kv_args[i].flag = 0;
57 }
58 }
beeb3140 59 }
beeb3140
MS
60}
61
53dc677d
WS
62void dumpKeyValue(
63 char *pre,
64 keyvalue_t *t)
65{
66 if (t) {
67 fprintf(stderr, "%s%i: '%s' = '%s' %i\n",
68 pre, t->pos, t->key, t->value, t->flag);
69 } else {
70 fprintf(stderr, "%sNULL\n", pre);
71 }
1ace8365 72}
6465207c 73
53dc677d
WS
74void dumpArguments(
75 parsedargs_t *pa)
76{
77 fprintf(stderr, "====================\nParsed Arguments of: %s\n",
78 pa->arg_orig);
79 for (int i = 0; i < pa->kv_cnt; i++) {
80 dumpKeyValue(" ", &(pa->kv_args[i]));
81 }
82 fprintf(stderr, "---------------\n");
1ace8365 83}
3da125e9 84
53dc677d
WS
85char *getKeyValueArgument(
86 const char *key,
87 int flag,
88 parsedargs_t *pa)
89{
90 /* we count backwards for "overwrites" */
91 for (int i = pa->kv_cnt - 1; i >= 0; i--) {
92 char *akey = (pa->kv_args[i]).key;
93
94 if (strcmp(akey, key) == 0) {
95 /* set flag */
96 if (flag) {
97 pa->kv_args[i].flag = flag;
98 }
99 /* return value */
100 return pa->kv_args[i].value;
101 }
102 }
103 return NULL;
6465207c
AB
104}
105
53dc677d
WS
106keyvalue_t *getFirstUnusedArgument(
107 int flag,
108 parsedargs_t *pa)
109{
110 for (int i = 0; i < pa->kv_cnt; i++) {
111 if (!pa->kv_args[i].flag) {
112 pa->kv_args[i].flag = flag;
113 return &(pa->kv_args[i]);
114 }
18cadd88 115 }
53dc677d 116 return NULL;
6465207c
AB
117}
118
53dc677d
WS
119char *checkUnusedValues(
120 parsedargs_t *pa)
121{
122 char *res = NULL;
123 size_t len = 0;
124
125 for (int i = 0; i < pa->kv_cnt; i++) {
126 if (!pa->kv_args[i].flag) {
127 const size_t kvlen = strlen(pa->kv_args[i].keyvalue);
128
129 len += kvlen + 1;
130
131 /* alloc/realloc if necessary and set to 0 */
132 if (res) {
133 char *t = (char *) realloc(res, len);
134
135 if (!t) {
136 return res;
137 }
138 res = t;
139 } else {
140 res = malloc(len);
141 if (!res) {
142 return NULL;
143 }
144 *res = 0;
145 }
146 /* add key = value as originally given */
147 strncat(res, pa->kv_args[i].keyvalue, kvlen);
148 strcat(res, ":");
149 }
150 }
151 /* if we got one, then strip the final : */
152 if (res) {
153 res[len - 1] = 0;
154 }
155 /* and return res */
156 return res;
1ace8365 157}
adb27eb6 158
53dc677d
WS
159int getMappedKeyValueArgument(
160 const char *key,
161 int flag,
162 parsedargs_t *pa,
163 int *val,
164 keyint_t **transpose)
165{
166 /* get the value itself as string */
167 char *v = getKeyValueArgument(key, flag, pa);
168
169 /* now try to parse the value */
170 if (v) {
171 for (; (*transpose)->key; transpose++) {
172 if (strcmp((*transpose)->key, v) == 0) {
173 *val = (*transpose)->value;
174 return 0;
175 }
176 }
177 }
178 /* not found, so return error */
179 return 1;
6465207c
AB
180}
181
53dc677d
WS
182int getLong(
183 const char *v,
184 long *val,
185 char **extra,
186 int base)
187{
188 if (extra == NULL) {
189 return 0;
190 }
191
192 /* try to execute the parser */
193 /* NOTE that this may be a bit different from the original parser */
194 *extra = NULL;
195 *val = strtol(v, extra, base);
196 /* and error handling */
197 if (*extra == v) {
198 return -1; /* failed miserably */
199 } else {
200 if ((*extra)[0] == 0) {
201 return 0;
202 }
203 return 1; /* got extra bytes */
204 }
205 /* not found, so return error */
206 return -2;
aa70e348 207}
1ace8365 208
53dc677d
WS
209int getDouble(
210 const char *v,
211 double *val,
212 char **extra)
213{
214 /* try to execute the parser */
215 /* NOTE that this may be a bit different from the original parser */
216 *extra = NULL;
7a47523f 217
53dc677d
WS
218 /* see rrd_strtodbl's return values for more information */
219 switch (rrd_strtodbl(v, extra, val, NULL)) {
fd1aab0c
TO
220 case 0:
221 return -1;
222 break;
223 case 1:
224 return 1;
225 break;
226 case 2:
227 return 0;
228 break;
229 default:
230 return -2;
231 break;
53dc677d 232 }
7d0bd260
TO
233}
234
53dc677d
WS
235int addToArguments(
236 parsedargs_t *pa,
237 char *keyvalue,
238 char *key,
239 char *value,
240 int pos)
241{
242 /* resize the field */
243 keyvalue_t *t = (keyvalue_t *) realloc(pa->kv_args,
244 (pa->kv_cnt +
245 1) * sizeof(keyvalue_t));
246 if (!t) {
247 rrd_set_error("could not realloc memory");
248 return -1;
249 } else {
250 /* assign pointer */
251 pa->kv_args = t;
252 }
253 /* fill in data */
254 pa->kv_args[pa->kv_cnt].keyvalue = keyvalue;
255 pa->kv_args[pa->kv_cnt].key = key;
256 pa->kv_args[pa->kv_cnt].value = value;
257 pa->kv_args[pa->kv_cnt].pos = pos;
258 pa->kv_args[pa->kv_cnt].flag = 0;
259 pa->kv_cnt++;
260 /* and return ok */
261 return 0;
1ace8365 262}
18cadd88 263
53dc677d
WS
264char *poskeys[] =
265 { "pos0", "pos1", "pos2", "pos3", "pos4", "pos5", "pos6", "pos7", "pos8",
266 "pos9"
267};
268
269int parseArguments(
270 const char *origarg,
271 parsedargs_t *pa)
272{
273 initParsedArguments(pa);
274 /* now assign a copy */
275 pa->arg = strdup(origarg);
276 if (!pa->arg) {
277 rrd_set_error("Could not allocate memory");
278 return -1;
5e01c4f7 279 }
53dc677d
WS
280 pa->arg_orig = origarg;
281
282 /* first split arg into : */
283 char c;
284 int cnt = 0;
285 int poscnt = 0;
286 char *pos = pa->arg;
287 char *field = pos;
288
289 do {
290 c = *pos;
291 if (!field) {
292 field = pos;
293 cnt++;
294 }
295 switch (c) {
296 /* if the char is a backslash, then this escapes the next one */
297 case '\\':
298 if (pos[1] == ':') {
299 /* move up the rest of the string to eat the backslash */
300 memmove(pos, pos + 1, strlen(pos + 1) + 1);
301 }
302 break;
303 case 0:
304 case ':':{
305 /* null and : separate the string */
306 *pos = 0;
307 /* flag to say we are positional */
308 //int ispos=0;
309 /* handle the case where we have got an = */
310 /* find equal sign */
311 char *equal = field;
312
313 for (equal = field; (*equal) && (*equal != '='); equal++) {;
314 }
315 /* if we are on position 1 then check for position 0 to be [CV]?DEV */
316 int checkforkeyvalue = 1;
317
318 /* nw define key to use */
319 char *keyvalue = strdup(field);
320 char *key, *value;
321
322 if ((*equal == '=') && (checkforkeyvalue)) {
323 *equal = 0;
324 key = field;
325 value = equal + 1;
326 } else {
327 if ((poscnt > 0) && (strcmp(field, "STACK") == 0)) {
328 key = "stack";
329 value = "1";
330 } else if ((poscnt > 0) && (strcmp(field, "strftime") == 0)) {
331 key = "strftime";
332 value = "1";
333 } else if ((poscnt > 0) && (strcmp(field, "dashes") == 0)) {
334 key = "dashes";
335 value = "5,5";
336 } else if ((poscnt > 0)
337 && (strcmp(field, "valstrftime") == 0)) {
338 key = "vformatter";
339 value = "timestamp";
340 } else if ((poscnt > 0)
341 && (strcmp(field, "valstrfduration") == 0)) {
342 key = "vformatter";
343 value = "duration";
344 } else if ((poscnt > 0) && (strcmp(field, "skipscale") == 0)) {
345 key = "skipscale";
346 value = "1";
347 } else {
348 if (poscnt > 9) {
349 rrd_set_error("too many positional arguments");
350 freeParsedArguments(pa);
351 return -1;
352 }
353 key = poskeys[poscnt];
354 poscnt++;
355 //ispos=poscnt;
356 value = field;
357 }
358 }
359 /* do some synonym translations */
360 if (strcmp(key, "label") == 0) {
361 key = "legend";
362 }
363 if (strcmp(key, "colour") == 0) {
364 key = "color";
365 }
366 if (strcmp(key, "colour2") == 0) {
367 key = "color2";
368 }
369
370 /* add to fields */
371 if (addToArguments(pa, keyvalue, key, value, cnt)) {
372 freeParsedArguments(pa);
373 return -1;
374 }
375
376 /* and reset field */
377 field = NULL;
378 }
379 break;
380 default:
381 break;
382 }
383 /* and step to next one byte */
384 pos++;
385 } while (c);
386 /* and return OK */
387 return 0;
6465207c
AB
388}
389
53dc677d
WS
390static int parse_color(
391 const char *const string,
392 struct gfx_color_t *c)
18cadd88 393{
53dc677d
WS
394 unsigned int r = 0, g = 0, b = 0, a = 0, i;
395
396 /* matches the following formats:
397 ** RGB
398 ** RGBA
399 ** RRGGBB
400 ** RRGGBBAA
401 */
402
403 i = 0;
404 while (string[i] && isxdigit((unsigned int) string[i]))
405 i++;
406 if (string[i] != '\0')
407 return 1; /* garbage follows hexdigits */
408 switch (i) {
409 case 3:
410 case 4:
411 sscanf(string, "%1x%1x%1x%1x", &r, &g, &b, &a);
412 r *= 0x11;
413 g *= 0x11;
414 b *= 0x11;
415 a *= 0x11;
416 if (i == 3)
417 a = 0xFF;
418 break;
419 case 6:
420 case 8:
421 sscanf(string, "%02x%02x%02x%02x", &r, &g, &b, &a);
422 if (i == 6)
423 a = 0xFF;
424 break;
425 default:
426 return 1; /* wrong number of digits */
427 }
428 /* I wonder how/why this works... */
429 *c = gfx_hex_to_col(r << 24 | g << 16 | b << 8 | a);
430 return 0;
1ace8365 431}
7d0bd260 432
1ace8365 433/* this would allow for 240 different values */
1a9c6fc4
TO
434#define PARSE_FIELD1 (1ULL<<60)
435#define PARSE_FIELD2 (1ULL<<61)
436#define PARSE_FIELD3 (1ULL<<62)
437#define PARSE_FIELD4 (1ULL<<63)
438#define PARSE_POSITIONAL (1ULL<<59)
439#define PARSE_ONYAXIS (1ULL<<58)
440#define PARSE_VNAME (PARSE_FIELD1|(1ULL<< 0))
441#define PARSE_RRD (PARSE_FIELD1|(1ULL<< 1))
442#define PARSE_DS (PARSE_FIELD1|(1ULL<< 2))
443#define PARSE_CF (PARSE_FIELD1|(1ULL<< 3))
444#define PARSE_COLOR (PARSE_FIELD1|(1ULL<< 4))
445#define PARSE_COLOR2 (PARSE_FIELD1|(1ULL<< 5))
446#define PARSE_LEGEND (PARSE_FIELD1|(1ULL<< 6))
447#define PARSE_RPN (PARSE_FIELD1|(1ULL<< 7))
448#define PARSE_START (PARSE_FIELD1|(1ULL<< 8))
449#define PARSE_STEP (PARSE_FIELD1|(1ULL<< 9))
450#define PARSE_END (PARSE_FIELD1|(1ULL<<10))
451#define PARSE_STACK (PARSE_FIELD1|(1ULL<<11))
452#define PARSE_LINEWIDTH (PARSE_FIELD1|(1ULL<<12))
453#define PARSE_XAXIS (PARSE_FIELD1|(1ULL<<13))
454#define PARSE_YAXIS (PARSE_FIELD1|(1ULL<<14))
455#define PARSE_REDUCE (PARSE_FIELD1|(1ULL<<15))
456#define PARSE_SKIPSCALE (PARSE_FIELD1|(1ULL<<16))
6011ea0d 457#define PARSE_DAEMON (PARSE_FIELD1|(1ULL<<17))
e111de44 458
1a9c6fc4 459#define PARSE_DASHES (PARSE_FIELD1|(1ULL<<20))
c8cb208a 460#define PARSE_GRADHEIGHT (PARSE_FIELD1|(1ULL<<21))
1a9c6fc4 461#define PARSE_FORMAT (PARSE_FIELD1|(1ULL<<22))
f0cc37d1 462#define PARSE_STRFTIMEVFMT (PARSE_FIELD1|(1ULL<<23))
1a9c6fc4 463#define PARSE_FRACTION (PARSE_FIELD1|(1ULL<<24))
1ace8365 464/* VNAME Special cases for generic parsing */
1a9c6fc4
TO
465#define PARSE_VNAMEDEF (PARSE_VNAME|(1ULL<<57))
466#define PARSE_VNAMEREF (PARSE_VNAME|(1ULL<<56))
467#define PARSE_VNAMEREFNUM (PARSE_VNAMEREF|(1ULL<<55))
1ace8365
TO
468/* special positional cases */
469#define PARSE_VNAMERRDDSCF (PARSE_POSITIONAL|PARSE_VNAMEDEF|PARSE_RRD|PARSE_DS|PARSE_CF)
470#define PARSE_VNAMECOLORLEGEND (PARSE_POSITIONAL|PARSE_VNAMEREFNUM|PARSE_COLOR|PARSE_COLOR2|PARSE_LEGEND)
471#define PARSE_VNAMECOLORFRACTIONLEGEND (PARSE_VNAMECOLORLEGEND|PARSE_FRACTION)
472#define PARSE_VNAMERPN (PARSE_POSITIONAL|PARSE_VNAMEDEF|PARSE_RPN)
473#define PARSE_VNAMEREFPOS (PARSE_POSITIONAL|PARSE_VNAMEREF)
beeb3140
MS
474/* a retry parsing */
475#define PARSE_RETRY (1ULL<<54)
1ace8365 476
37092fc2
TO
477/* find gdes containing var*/
478static long find_var(
479 image_desc_t *im,
480 char *key)
481{
482 /* this makes only sense for a sufficient number of items */
53dc677d
WS
483 long match = -1;
484 gpointer value;
485 gboolean ok =
486 g_hash_table_lookup_extended(im->gdef_map, key, NULL, &value);
487 if (ok) {
8b1d02ad 488 match = GPOINTER_TO_INT(value);
37092fc2 489 }
d093a1d3
TO
490
491 /* printf("%s -> %ld\n",key,match); */
492
37092fc2
TO
493 return match;
494
495}
496
497static long find_var_wrapper(
498 void *arg1,
499 char *key)
500{
501 return find_var((image_desc_t *) arg1, key);
502}
503
504
53dc677d
WS
505static graph_desc_t *newGraphDescription(
506 image_desc_t *const,
507 enum gf_en,
508 parsedargs_t *,
509 uint64_t);
510static graph_desc_t *newGraphDescription(
511 image_desc_t *const im,
512 enum gf_en gf,
513 parsedargs_t *pa,
514 uint64_t bits)
515{
516 /* check that none of the other bitfield marker is set */
517 if ((bits & PARSE_FIELD1)
518 && ((bits & (PARSE_FIELD2 | PARSE_FIELD3 | PARSE_FIELD4)))) {
519 rrd_set_error("newGraphDescription: bad bitfield1 value %08llx",
520 bits);
f0cc37d1 521 return NULL;
53dc677d
WS
522 }
523 /* the normal handler that adds to img */
524 if ((!(bits & PARSE_RETRY)) && (gdes_alloc(im))) {
525 return NULL;
526 }
527 /* set gdp */
528 graph_desc_t *gdp = &im->gdes[im->gdes_c - 1];
529
530 /* set some generic things */
531 gdp->gf = gf;
532 {
533 char *t, *x;
534 long debug = 0;
535
536 if ((t = getKeyValueArgument("debug", 1, pa))
537 && ((getLong(t, &debug, &x, 10)))) {
538 rrd_set_error("Bad debug value: %s", t);
539 return NULL;
540 }
541 gdp->debug = debug;
542 }
543
544 /* and the "flagged" parser implementation
545 *
546 * first the fields with legacy positional args
1ace8365 547 */
53dc677d
WS
548#define bitscmp(v) ((bits&v)==v)
549 char *vname = NULL;
550
551 if (bitscmp(PARSE_VNAME)) {
552 vname = getKeyValueArgument("vname", 1, pa);
553 dprintfparsed("got vname: %s\n", vname);
554 }
555 char *rrd = NULL;
556
557 if (bitscmp(PARSE_RRD)) {
558 rrd = getKeyValueArgument("rrd", 1, pa);
559 dprintfparsed("got rrd: %s\n", rrd);
560 }
561 char *ds = NULL;
562
563 if (bitscmp(PARSE_DS)) {
564 ds = getKeyValueArgument("ds", 1, pa);
565 dprintfparsed("got ds: %s\n", ds);
566 }
567 char *cf = NULL;
568
569 if (bitscmp(PARSE_CF)) {
570 cf = getKeyValueArgument("cf", 1, pa);
571 dprintfparsed("got cf: %s\n", cf);
572 }
573 char *color = NULL;
574
575 if (bitscmp(PARSE_COLOR)) {
576 color = getKeyValueArgument("color", 1, pa);
577 dprintfparsed("got color: %s\n", color);
578 }
579 char *color2 = NULL;
580
581 if (bitscmp(PARSE_COLOR2)) {
582 color2 = getKeyValueArgument("color2", 1, pa);
583 dprintfparsed("got color2: %s\n", color2);
584 }
585 char *rpn = NULL;
586
587 if (bitscmp(PARSE_RPN)) {
588 rpn = getKeyValueArgument("rpn", 1, pa);
589 dprintfparsed("got rpn: %s\n", rpn);
590 }
591 char *legend = NULL;
592
593 if (bitscmp(PARSE_LEGEND)) {
594 legend = getKeyValueArgument("legend", 1, pa);
595 dprintfparsed("got legend: \"%s\"\n", legend);
596 }
597 char *fraction = NULL;
598
599 if (bitscmp(PARSE_FRACTION)) {
600 fraction = getKeyValueArgument("fraction", 1, pa);
601 dprintfparsed("got fraction: %s\n", fraction);
602 }
603 /*
604 * here the ones without delayed assigns (which are for positional parsers)
605 */
606 if (bitscmp(PARSE_FORMAT)) {
607 char *format = getKeyValueArgument("format", 1, pa);
608
609 if (format) {
610 strncpy(gdp->format, format, FMT_LEG_LEN);
611 dprintfparsed("got format: %s\n", format);
612 }
613 }
614 if (bitscmp(PARSE_STRFTIMEVFMT)) {
615 char *strft = getKeyValueArgument("strftime", 1, pa);
616 char *frmtr = getKeyValueArgument("vformatter", 1, pa);
617
618 gdp->strftm = (strft) ? 1 : 0;
619 if (frmtr != NULL) {
620 if (strcmp(frmtr, "timestamp") == 0) {
621 gdp->vformatter = VALUE_FORMATTER_TIMESTAMP;
622 } else if (strcmp(frmtr, "duration") == 0) {
623 gdp->vformatter = VALUE_FORMATTER_DURATION;
624 } else {
625 rrd_set_error("Unsupported vformatter: %s", frmtr);
626 return NULL;
627 }
628 }
629 dprintfparsed("got strftime: %s\n", strft);
630 }
631 if (bitscmp(PARSE_STACK)) {
632 char *stack = getKeyValueArgument("stack", 1, pa);
633
634 gdp->stack = (stack) ? 1 : 0;
635 dprintfparsed("got stack: %s\n", stack);
636 }
637 if (bitscmp(PARSE_SKIPSCALE)) {
638 char *skipscale = getKeyValueArgument("skipscale", 1, pa);
639
640 gdp->skipscale = (skipscale) ? 1 : 0;
641 dprintfparsed("got skipscale: %s\n", skipscale);
642 }
643 if (bitscmp(PARSE_REDUCE)) {
644 char *reduce = getKeyValueArgument("reduce", 1, pa);
645
646 if (reduce) {
647 gdp->cf_reduce = rrd_cf_conv(reduce);
648 gdp->cf_reduce_set = 1;
649 dprintfparsed("got reduce: %s (%i)\n", reduce, gdp->cf_reduce);
650 if (((int) gdp->cf_reduce) == -1) {
651 rrd_set_error("bad reduce CF: %s", reduce);
652 return NULL;
653 }
654 }
655 }
656 if (bitscmp(PARSE_DAEMON)) {
657 char *daemon = getKeyValueArgument("daemon", 1, pa);
658
659 if (daemon) {
660 /* graph_desc_t: char daemon[256] */
661 strncpy(gdp->daemon, daemon, 255);
662 gdp->daemon[255] = '\0';
663 dprintfparsed("got daemon: %s\n", gdp->daemon);
664 }
665 }
666 if (bitscmp(PARSE_XAXIS)) {
667 long xaxis = 0;
668 char *t, *x;
669
670 if ((t = getKeyValueArgument("xaxis", 1, pa))
671 && ((getLong(t, &xaxis, &x, 10)) || (xaxis < 1)
672 || (xaxis > MAX_AXIS))) {
673 rrd_set_error("Bad xaxis value: %s", t);
674 return NULL;
675 }
676 dprintfparsed("got xaxis: %s (%li)\n", t, xaxis);
677 gdp->xaxisidx = xaxis;
678 }
679 if (bitscmp(PARSE_YAXIS)) {
680 long yaxis = 0;
681 char *t, *x;
682
683 if ((t = getKeyValueArgument("yaxis", 1, pa))
684 && ((getLong(t, &yaxis, &x, 10)) || (yaxis < 1)
685 || (yaxis > MAX_AXIS))) {
686 rrd_set_error("Bad yaxis value: %s", t);
687 return NULL;
688 }
689 dprintfparsed("got yaxis: %s (%li)\n", t, yaxis);
690 gdp->yaxisidx = yaxis;
691 }
692 if (bitscmp(PARSE_LINEWIDTH)) {
693 double linewidth = 1;
694 char *t, *x;
695
696 if ((t = getKeyValueArgument("linewidth", 1, pa)) && (*t != 0)) {
697 if ((getDouble(t, &linewidth, &x)) || (linewidth < 0)) {
698 rrd_set_error("Bad line width: %s", t);
699 return NULL;
700 }
701 }
702 dprintfparsed("got linewidth: %s (%g)\n", t, linewidth);
703 gdp->linewidth = linewidth;
704 }
705 if (bitscmp(PARSE_GRADHEIGHT)) {
706 double gradheight = 0;
707 char *t, *x;
708
709 if ((t = getKeyValueArgument("gradheight", 1, pa)) && (*t != 0)) {
710 if (getDouble(t, &gradheight, &x)) {
711 rrd_set_error("Bad gradheight: %s", t);
712 return NULL;
713 }
714 dprintfparsed("got gradheight: %s (%g)\n", t, gradheight);
715 gdp->gradheight = gradheight;
716 }
717 }
718 if (bitscmp(PARSE_STEP)) {
719 long step = 0;
720 char *t, *x;
721
722 if ((t = getKeyValueArgument("step", 1, pa))
723 && ((getLong(t, &step, &x, 10)) || (step < 1))) {
724 rrd_set_error("Bad step value: %s", t);
725 return NULL;
726 }
727 dprintfparsed("got step: %s (%li)\n", t, step);
728 gdp->step = step;
729 }
730 if ((bitscmp(PARSE_START) || bitscmp(PARSE_END))) {
731 /* these should get done together to use the start/end code correctly */
732 char *parsetime_error;
733
734 /* first start */
735 char *start;
736 rrd_time_value_t start_tv;
737
738 start_tv.type = ABSOLUTE_TIME;
739 start_tv.offset = 0;
740 localtime_r(&gdp->start, &start_tv.tm);
741
742 if (bitscmp(PARSE_START)) {
743 start = getKeyValueArgument("start", 1, pa);
744 if ((start)
745 && (parsetime_error = rrd_parsetime(start, &start_tv))) {
746 rrd_set_error("start time: %s", parsetime_error);
747 return NULL;
748 }
749 dprintfparsed("got start: %s\n", start);
750 } else {
751 start = NULL;
752 }
753 /* now end */
754 char *end;
755 rrd_time_value_t end_tv;
756
757 end_tv.type = ABSOLUTE_TIME;
758 end_tv.offset = 0;
759 localtime_r(&gdp->end, &end_tv.tm);
760
761 if (bitscmp(PARSE_END)) {
762 end = getKeyValueArgument("end", 1, pa);
763 if ((end) && (parsetime_error = rrd_parsetime(end, &end_tv))) {
764 rrd_set_error("end time: %s", parsetime_error);
765 return NULL;
766 }
767 dprintfparsed("got end: %s\n", end);
768 } else {
769 end = NULL;
770 }
771 /* and now put the pieces together (relative times like start=end-2days) */
772 time_t start_tmp = 0, end_tmp = 0;
773
774 if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) ==
775 -1) {
776 return NULL;
777 }
778 dprintfparsed("got start %s translated to: %lld\n", start,
779 (long long int) start_tmp);
780 dprintfparsed("got end %s translated to: %lld\n", end,
781 (long long int) end_tmp);
782
783 /* check some ranges */
784 if (start_tmp < 3600 * 24 * 365 * 10) {
785 rrd_set_error("the first entry to fetch should be "
786 "after 1980 (%ld)", start_tmp);
787 return NULL;
788 }
789 if (end_tmp < start_tmp) {
790 rrd_set_error("start (%ld) should be less than end (%ld)",
791 start_tmp, end_tmp);
792 return NULL;
793 }
794
795 /* and finally set it irrespectively of if it has been set or not
796 * it may have been a relative time and if you just set it partially
797 * then that is wrong...
798 */
799 gdp->start = start_tmp;
800 gdp->start_orig = start_tmp;
801 gdp->end = end_tmp;
802 gdp->end_orig = end_tmp;
803 }
804 if (bitscmp(PARSE_DASHES)) {
805 char *dashes = getKeyValueArgument("dashes", 1, pa);
806
807 /* if we got dashes */
808 if (dashes) {
809 gdp->dash = 1;
810 gdp->offset = 0;
811 /* count the , in dashes */
812 int cnt = 0;
813
814 for (char *t = dashes; (*t) && (t = strchr(t, ','));
815 t++, cnt++) {;
816 }
817 dprintfparsed("Got dashes argument: %s with %i comma\n", dashes,
818 cnt);
819 /* now handle */
820 gdp->ndash = cnt + 1;
821 gdp->p_dashes =
822 (double *) malloc(sizeof(double) * (gdp->ndash + 1));
823 /* now loop dashes */
824 for (int i = 0; i < gdp->ndash; i++) {
825 char *x;
826 int f = getDouble(dashes, &gdp->p_dashes[i], &x);
827
828 if (f < 0) {
829 rrd_set_error("Could not parse number: %s", dashes);
830 return NULL;
831 }
832 /* we should have this most of the time */
833 dprintfparsed("Processed %s to %g at index %i\n", dashes,
834 gdp->p_dashes[i], i);
835 if (f > 0) {
836 if (*x != ',') {
837 rrd_set_error("expected a ',' at : %s", x);
838 return NULL;
839 }
840 dashes = x + 1;
841 }
842 if ((f == 0) && (i != gdp->ndash - 1)) {
843 rrd_set_error("unexpected end at : %s", dashes);
844 return NULL;
845 }
846 }
847 }
848 char *dashoffset = getKeyValueArgument("dash-offset", 1, pa);
849
850 if (dashoffset) {
851 char *x;
852
853 if (getDouble(dashoffset, &gdp->offset, &x)) {
854 rrd_set_error("Could not parse dash-offset: %s", dashoffset);
855 return NULL;
856 }
857 }
858 }
859
860 /* here now the positional(=legacy) parsers which are EXCLUSIVE - SO ELSE IF !!!
861 * we also only parse the extra here and assign just further down
862 * TODO maybe we can generalize this a bit more...
863 */
864 if (bitscmp(PARSE_VNAMERRDDSCF)) {
865 if ((!vname) || (!rrd)) {
866 /* get the first unused argument */
867 keyvalue_t *first = getFirstUnusedArgument(1, pa);
868
869 if (!first) {
870 rrd_set_error("No argument for definition of vdef/rrd in %s",
871 pa->arg_orig);
872 return NULL;
873 }
874 dprintfparsed("got positional vname and rrd: %s - %s\n",
875 first->key, first->value);
876 if (!vname) {
877 vname = first->key;
878 }
879 if (!rrd) {
880 rrd = first->value;
881 }
882 }
883 /* and now look for datasource */
884 if (!ds) {
885 /* get the first unused argument */
886 keyvalue_t *first = getFirstUnusedArgument(1, pa);
887
888 if (!first) {
889 rrd_set_error("No argument for definition of DS in %s",
890 pa->arg_orig);
891 return NULL;
892 }
893 dprintfparsed("got positional ds: %s - \n", first->value);
894 ds = first->value;
895 }
896 /* and for CF */
897 if (!cf) {
898 /* get the first unused argument */
899 keyvalue_t *first = getFirstUnusedArgument(1, pa);
900
901 if (!first) {
902 rrd_set_error("No argument for definition of CF in %s",
903 pa->arg_orig);
904 return NULL;
905 }
906 dprintfparsed("got positional cf: %s - \n", first->value);
907 cf = first->value;
908 }
909 } else if (bitscmp(PARSE_VNAMECOLORLEGEND)) {
910 /* vname */
911 if (!vname) {
912 keyvalue_t *first = getFirstUnusedArgument(1, pa);
913
914 if (first) {
915 vname = first->value;
916 } else {
917 rrd_set_error("No positional VNAME");
918 return NULL;
919 }
920 }
921 /* fraction added into the parsing mix for TICK */
922 if ((bitscmp(PARSE_VNAMECOLORFRACTIONLEGEND)) && (!fraction)) {
923 keyvalue_t *first = getFirstUnusedArgument(1, pa);
924
925 if (first) {
926 fraction = first->value;
927 } else {
928 rrd_set_error("No positional FRACTION");
929 return NULL;
930 }
931 }
932 /* legend (it's optional if no other arguments follow) */
933 if (!legend) {
934 keyvalue_t *first = getFirstUnusedArgument(1, pa);
935
936 if (first) {
937 legend = first->keyvalue;
938 dprintfparsed("got positional legend: %s - \n", legend);
939 }
940 }
941 } else if (bitscmp(PARSE_VNAMERPN)) {
942 if ((!vname) || (!rpn)) {
943 /* get the first unused argument */
944 keyvalue_t *first = getFirstUnusedArgument(1, pa);
945
946 if (!first) {
947 rrd_set_error("No argument for definition of vdef/rrd in %s",
948 pa->arg_orig);
949 return NULL;
950 }
951 dprintfparsed("got positional vname and rpn: %s - %s\n",
952 first->key, first->value);
953 if (!vname) {
954 vname = first->key;
955 }
956 if (!rpn) {
957 rpn = first->value;
958 }
959 }
960 } else if (bitscmp(PARSE_VNAMEREFPOS)) {
961 if ((!vname)) {
962 /* get the first unused argument */
963 keyvalue_t *first = getFirstUnusedArgument(1, pa);
964
965 if (!first) {
966 rrd_set_error("No argument for definition of vdef/rrd in %s",
967 pa->arg_orig);
968 return NULL;
969 }
970 dprintfparsed("got positional vname and rrd: %s - %s\n",
971 first->key, first->value);
2e356b25 972 vname = first->value;
53dc677d
WS
973 }
974 }
975
976 /* and set some of those late assignments to accommodate the legacy parser */
977 /* first split vname into color */
978 if (vname) {
979 /* check for color */
980 char *h1 = strchr(vname, '#');
981 char *h2 = NULL;
982
983 if (h1) {
984 *h1 = 0;
985 h1++;
986 dprintfparsed("got positional color: %s - \n", h1);
987 h2 = strchr(h1, '#');
988 if (h2) {
989 *h2 = 0;
990 h2++;
991 dprintfparsed("got positional color2: %s - \n", h2);
992 }
993 }
994 if (bitscmp(PARSE_COLOR) && (!color) && (h1)) {
995 color = h1;
996 }
997 if (bitscmp(PARSE_COLOR2) && (!color2) && (h2)) {
998 color2 = h2;
999 }
1000 }
1001
1002 /* check if we are reusing the vname */
1003 if (vname) {
1004 int idx = find_var(im, vname);
1005
1006 dprintfparsed("got positional index %i for %s - \n", idx, vname);
1007
1008 /* some handling */
1009 if (bitscmp(PARSE_VNAMEDEF)) {
1010 if (idx >= 0) {
1011 rrd_set_error("trying to reuse vname %s", vname);
1012 return NULL;
1013 }
1014 } else if (bitscmp(PARSE_VNAMEREF)) {
1015 gdp->vidx = idx;
1016 if (idx < 0) {
1017 if (bitscmp(PARSE_VNAMEREFNUM)) {
1018 double val;
1019 char *x;
1020 int f = getDouble(vname, &val, &x);
1021
1022 if (f) {
1023 rrd_set_error("%s is not a vname nor a number",
1024 vname);
1025 return NULL;
1026 }
1027 if (gf == GF_VRULE) {
1028 gdp->xrule = val;
1029 } else {
1030 gdp->yrule = val;
1031 }
1032 } else {
1033 rrd_set_error("vname %s not found", vname);
1034 return NULL;
1035 }
1036 }
1037 }
1038 }
1039
1040 /* and assign it */
1041 if (vname) {
1042 strncpy(gdp->vname, vname, MAX_VNAME_LEN);
1043 gdp->vname[MAX_VNAME_LEN] = '\0';
1044 }
1045 if (rrd) {
1046 strncpy(gdp->rrd, rrd, 1023);
1047 gdp->rrd[1023] = '\0';
1048 }
1049 if (ds) {
1050 strncpy(gdp->ds_nam, ds, DS_NAM_SIZE - 1);
1051 gdp->ds_nam[DS_NAM_SIZE - 1] = '\0';
1052 }
1053 if (cf) {
1054 gdp->cf = rrd_cf_conv(cf);
1055 if (((int) gdp->cf) == -1) {
1056 rrd_set_error("bad CF: %s", cf);
1057 return NULL;
1058 }
1ace8365 1059 } else {
53dc677d
WS
1060 if (bitscmp(PARSE_CF)) {
1061 gdp->cf = (enum cf_en) -1;
1062 }
1063 }
1064 if ((color) && (parse_color(color, &(gdp->col)))) {
1065 return NULL;
1066 }
1067 if ((color2) && (parse_color(color2, &(gdp->col2)))) {
1068 return NULL;
1069 }
1070 if (rpn) {
1071 gdp->rpn = rpn;
1072 }
1073 if ((legend) && (*legend != 0)) {
1074 /* and copy it into place */
1075 strncpy(gdp->legend, legend, FMT_LEG_LEN);
1076 }
1077 if (fraction) {
1078 if (strcmp(fraction, "vname") == 0) {
1079 /* check that vname is really a DEF|CDEF */
1080 if (im->gdes[gdp->vidx].gf != GF_DEF
1081 && im->gdes[gdp->vidx].gf != GF_CDEF) {
1082 rrd_set_error
1083 ("variable '%s' not DEF nor CDEF when using dynamic fractions",
1084 gdp->vname);
1085 return NULL;
1086 }
1087 /* add as flag to use (c)?def */
1088 gdp->cf = CF_LAST;
1089 gdp->yrule = 0.5;
1090 } else {
1091 /* parse number */
1092 double val;
1093 char *x;
1094 int f = getDouble(fraction, &val, &x);
1095
1096 if (f) {
1097 rrd_set_error("error parsing number %s", vname);
1098 return NULL;
1099 }
1100 gdp->yrule = val;
1101 }
1102 }
1103 /* remember the index for faster varfind */
1104 char *key = gdes_fetch_key((*gdp));
1105
1106 if (gdp->gf == GF_DEF
1107 && !g_hash_table_lookup_extended(im->rrd_map, key, NULL, NULL)) {
1108 dprintfhash("ins key %s - %ld\n", key, im->gdes_c - 1);
1109 g_hash_table_insert(im->gdef_map, g_strdup(key),
1110 GINT_TO_POINTER(im->gdes_c - 1));
1111 }
1112 free(key);
1113 if (gdp->gf == GF_DEF || gdp->gf == GF_VDEF || gdp->gf == GF_CDEF) {
1114 dprintfhash("ins vname %s - %ld\n", gdp->vname, im->gdes_c - 1);
1115 g_hash_table_insert(im->gdef_map, g_strdup(gdp->vname),
1116 GINT_TO_POINTER(im->gdes_c - 1));
1117 }
1118 return gdp;
6465207c
AB
1119}
1120
1ace8365
TO
1121/* and some defines */
1122#define set_match(str,pat,cmd) if (strcmp(pat, str) == 0) { cmd ;}
1123
1124/* prototypes */
53dc677d
WS
1125static int parse_axis(
1126 enum gf_en,
1127 parsedargs_t *,
1128 image_desc_t *const);
1129static int parse_def(
1130 enum gf_en,
1131 parsedargs_t *,
1132 image_desc_t *const);
1133static int parse_cvdef(
1134 enum gf_en,
1135 parsedargs_t *,
1136 image_desc_t *const);
1137static int parse_line(
1138 enum gf_en,
1139 parsedargs_t *,
1140 image_desc_t *const);
1141static int parse_area(
1142 enum gf_en,
1143 parsedargs_t *,
1144 image_desc_t *const);
1145static int parse_stack(
1146 enum gf_en,
1147 parsedargs_t *,
1148 image_desc_t *const);
1149static int parse_gprint(
1150 enum gf_en,
1151 parsedargs_t *,
1152 image_desc_t *const);
1153static int parse_comment(
1154 enum gf_en,
1155 parsedargs_t *,
1156 image_desc_t *const);
1157static int parse_hvrule(
1158 enum gf_en,
1159 parsedargs_t *,
1160 image_desc_t *const);
1161static int parse_tick(
1162 enum gf_en,
1163 parsedargs_t *,
1164 image_desc_t *const);
1165static int parse_textalign(
1166 enum gf_en,
1167 parsedargs_t *,
1168 image_desc_t *const);
1169static int parse_shift(
1170 enum gf_en,
1171 parsedargs_t *,
1172 image_desc_t *const);
1173static int parse_xport(
1174 enum gf_en,
1175 parsedargs_t *,
1176 image_desc_t *const);
1ace8365 1177
fe1fd85f 1178/* this is needed for LINE,AREA,STACK so that the labels get done correctly... */
53dc677d
WS
1179static void legend_shift(
1180 char *legend)
129d1f40 1181{
53dc677d
WS
1182 if (!legend || !legend[0]) {
1183 return;
1184 }
1185 memmove(legend + 2, legend, strlen(legend));
1186 legend[0] = ' ';
1187 legend[1] = ' ';
129d1f40
MS
1188}
1189
1ace8365 1190/* implementations */
53dc677d
WS
1191static int parse_axis(
1192 enum gf_en gf,
1193 parsedargs_t *pa,
1194 image_desc_t *const im)
1195{
d093a1d3 1196
1ace8365 1197#if 0
53dc677d
WS
1198 /* define X or y axis */
1199 axis_t *a = im->xaxis;
1200
1201 if (gf == GF_YAXIS) {
1202 a = im->yaxis;
1203 }
1204 /* try to parse the number */
1205 char *cmd = getKeyValueArgument("cmd", 1, pa);
1206
1207 if (cmd[5]) {
1208 int num = atoi(cmd + 5);
1209
1210 if ((num < 1) || (num > MAX_AXIS)) {
1211 rrd_set_error
1212 ("invalid axis ID %i in %s - should be in range [1:%i]", num,
1213 cmd, MAX_AXIS);
1214 return 1;
1215 }
1216 /* and forward by that much */
1217 a = a + (num - 1);
1218 }
1219
1220 /* and set type */
1221 char *t = getKeyValueArgument("type", 1, pa);
1222
1223 if (t) {
1224 set_match(t, "TIME", a->type = AXIS_TYPE_TIME)
1225 else
1226 set_match(t, "LINEAR", a->type = AXIS_TYPE_LINEAR)
1227 else
1228 set_match(t, "LOGARITHMIC", a->type = AXIS_TYPE_LOGARITHMIC)
1229 else {
1230 rrd_set_error("unsupported axis type %s", t);
1231 return 1;
1232 }
1233 }
1234 /* and other stuff */
1235 a->bounds.lowertxt = getKeyValueArgument("min", 1, pa);
1236 a->bounds.uppertxt = getKeyValueArgument("max", 1, pa);
c5794b2d 1237#else
53dc677d
WS
1238 /* prevent unused warnings */
1239 (void) gf;
1240 (void) pa;
1241 (void) im;
1ace8365 1242#endif
d093a1d3 1243
53dc677d
WS
1244 /* and return */
1245 return 0;
1ace8365 1246}
adb27eb6 1247
53dc677d
WS
1248static int parse_def(
1249 enum gf_en gf,
1250 parsedargs_t *pa,
1251 image_desc_t *const im)
1252{
1253 /* get new graph that we fill */
1254 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1255 PARSE_VNAMERRDDSCF
1256 | PARSE_START
1257 | PARSE_STEP
1258 | PARSE_END
1259 | PARSE_REDUCE | PARSE_DAEMON);
1260 /* retry in case of errors modifying the name */
1261 if (!gdp) {
1262 /* restart from scratch */
1263 resetParsedArguments(pa);
1264 /* get the first parameter */
1265 keyvalue_t *first = getFirstUnusedArgument(0, pa);
1266
1267 /* if it is any of the "original" positional args, then we terminate immediately */
1268 for (int i = 0; i < 10; i++) {
1269 if (poskeys[i] == first->key) {
1270 return -1;
1271 }
1272 }
1273 /* otherwise we patch the key */
1274 *(first->key) += 128;
1275
1276 /* and keep a copy of the error */
1277 char original_error[4096];
1278
1279 strncpy(original_error, rrd_get_error(), sizeof(original_error) - 1);
1280 /* and clear the error */
1281 rrd_clear_error();
1282
1283 /* now run it */
1284 gdp = newGraphDescription(im, gf, pa,
1285 PARSE_VNAMERRDDSCF
1286 | PARSE_START
1287 | PARSE_STEP
1288 | PARSE_END
1289 | PARSE_REDUCE
1290 | PARSE_DAEMON | PARSE_RETRY);
1291 /* on error, we restore the original error and return */
1292 if (!gdp) {
1293 rrd_set_error(original_error);
1294 return 1;
1295 }
1296 }
1297
1298 if (gdp->step == 0) {
1299 gdp->step = im->step; /* initialize with image wide step */
1300 }
1301
1302 /* debugging output */
1303 dprintf("=================================\n");
1304 dprintf("DEF : %s\n", pa->arg_orig);
1305 dprintf("VNAME : %s\n", gdp->vname);
1306 dprintf("RRD : %s\n", gdp->rrd);
1307 dprintf("DS : %s\n", gdp->ds_nam);
1308 dprintf("CF : %i\n", gdp->cf);
1309 dprintf("START : (%lld)\n", (long long int) gdp->start);
1310 dprintf("STEP : (%lld)\n", (long long int) gdp->step);
1311 dprintf("END : (%lld)\n", (long long int) gdp->end);
1312 dprintf("REDUCE: (%i)\n", gdp->cf_reduce);
1313 dprintf("DAEMON: %s\n", gdp->daemon);
1314 dprintf("=================================\n");
1315
1316 /* and return fine */
1317 return 0;
aa70e348 1318}
1ace8365 1319
53dc677d
WS
1320static int parse_cvdef(
1321 enum gf_en gf,
1322 parsedargs_t *pa,
1323 image_desc_t *const im)
1324{
1325 /* get new graph that we fill */
1326 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1327 PARSE_VNAMERPN);
1328
1329 if (!gdp) {
1330 return 1;
1331 }
1332
1333 /* handle RPN parsing */
1334 if (gf == GF_CDEF) {
1335 /* parse rpn */
1336 if ((gdp->rpnp =
1337 rpn_parse((void *) im, gdp->rpn, &find_var_wrapper)) == NULL) {
1338 return 1;
1339 }
1340 } else { /* VDEF */
1341 /* parse vdef, as vdef_parse is a bit "stupid" right now we have to touch things here */
1342 /* so find first , */
1343 char *c = strchr(gdp->rpn, ',');
1344 char vname[MAX_VNAME_LEN + 1];
1345
1346 if (!c) {
1347 rrd_set_error("Comma expected in VDEF definition %s", gdp->rpn);
1348 return 1;
1349 }
1350 /* found a comma, so copy the first part to ds_nam (re/abusing it) */
1351 *c = 0; /* yes now it seems as if the string ended here */
1352 strncpy(vname, gdp->rpn, MAX_VNAME_LEN);
1353 *c = ','; /* and now all is back to normal ... shudder */
1354 /* trying to find the vidx for that name */
1355 gdp->vidx = find_var(im, vname);
1356 if (gdp->vidx < 0) {
1357 *c = ',';
1358 rrd_set_error("Not a valid vname: %s in line %s", vname,
1359 gdp->rpn);
1360 return 1;
1361 }
1362 if (im->gdes[gdp->vidx].gf != GF_DEF
1363 && im->gdes[gdp->vidx].gf != GF_CDEF) {
1364 rrd_set_error("variable '%s' not DEF nor " "CDEF in VDEF '%s'",
1365 vname, gdp->rpn);
1366 return 1;
1367 }
1368 /* and parsing the rpn */
1369 int r = vdef_parse(gdp, c + 1);
1370
1371 /* original code does not check here for some reason */
1372 if (r) {
1373 return 1;
1374 }
1375 }
1376
1377 /* debugging output */
1378 dprintf("=================================\n");
1379 if (gf == GF_CDEF) {
1380 dprintf("CDEF : %s\n", pa->arg_orig);
1381 } else {
1382 dprintf("VDEF : %s\n", pa->arg_orig);
1383 }
1384 dprintf("VNAME : %s\n", gdp->vname);
1385 dprintf("RPN : %s\n", gdp->rpn);
1386 dprintf("=================================\n");
1387
1388 /* and return fine */
1389 return 0;
aa70e348 1390}
1ace8365
TO
1391
1392
53dc677d
WS
1393static int parse_line(
1394 enum gf_en gf,
1395 parsedargs_t *pa,
1396 image_desc_t *const im)
1397{
1398 /* get new graph that we fill */
1399 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1400 PARSE_VNAMECOLORLEGEND
1401 | PARSE_STACK
1402 | PARSE_SKIPSCALE
1403 | PARSE_LINEWIDTH
1404 | PARSE_DASHES
1405 | PARSE_XAXIS | PARSE_YAXIS);
1406 if (!gdp) {
1407 return 1;
1408 }
1409
1410 /* debug output */
1411 dprintf("=================================\n");
1412 dprintf("LINE : %s\n", pa->arg_orig);
1413 if (gdp->vidx < 0) {
1414 dprintf("VAL : %g\n", gdp->yrule);
1415 } else {
1416 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1417 }
1418 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1419 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1420 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
1421 gdp->col2.red, gdp->col2.green, gdp->col2.blue, gdp->col2.alpha);
1422 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1423 dprintf("STACK : %i\n", gdp->stack);
1424 dprintf("SKIPSCALE : %i\n", gdp->skipscale);
1425 dprintf("WIDTH : %g\n", gdp->linewidth);
1426 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1427 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1428 if (gdp->ndash) {
1429 dprintf("DASHES: %i - %g", gdp->ndash, gdp->p_dashes[0]);
1430 for (int i = 1; i < gdp->ndash; i++) {
1431 dprintf(", %g", gdp->p_dashes[i]);
1432 }
1433 dprintf("\n");
1434 }
1435 dprintf("=================================\n");
1436
1437 /* shift the legend by 2 spaces for the "coloured-box" */
1438 legend_shift(gdp->legend);
1439
1440 /* and return fine */
1441 return 0;
adb27eb6
AB
1442}
1443
53dc677d
WS
1444static int parse_area(
1445 enum gf_en gf,
1446 parsedargs_t *pa,
1447 image_desc_t *const im)
1448{
1449 /* get new graph that we fill */
1450 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1451 PARSE_VNAMECOLORLEGEND
1452 | PARSE_STACK
1453 | PARSE_SKIPSCALE
1454 | PARSE_XAXIS
1455 | PARSE_YAXIS | PARSE_GRADHEIGHT);
1456 if (!gdp) {
1457 return 1;
1458 }
1459
1460 /* debug output */
1461 dprintf("=================================\n");
1462 dprintf("AREA : %s\n", pa->arg_orig);
1463 if (gdp->vidx < 0) {
1464 dprintf("VAL : %g\n", gdp->yrule);
1465 } else {
1466 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1467 }
1468 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1469 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1470 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
1471 gdp->col2.red, gdp->col2.green, gdp->col2.blue, gdp->col2.alpha);
1472 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1473 dprintf("STACK : %i\n", gdp->stack);
1474 dprintf("SKIPSCALE : %i\n", gdp->skipscale);
1475 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1476 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1477 dprintf("=================================\n");
1478
1479 /* shift the legend by 2 spaces for the "coloured-box" */
1480 legend_shift(gdp->legend);
1481
1482 /* and return fine */
1483 return 0;
1ace8365 1484}
6465207c 1485
53dc677d
WS
1486static int parse_stack(
1487 enum gf_en gf,
1488 parsedargs_t *pa,
1489 image_desc_t *const im)
1490{
1491 /* get new graph that we fill */
1492 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1493 PARSE_VNAMECOLORLEGEND
1494 | PARSE_XAXIS | PARSE_YAXIS);
1495 if (!gdp) {
1496 return 1;
1497 }
1498
1499 gdp->stack = 1;
1500 /* and try to get the one index before ourselves */
1501 long i;
1502
1503 for (i = im->gdes_c - 1; (gdp->gf == gf) && (i >= 0); i--) {
1504 dprintfparsed("trying to process entry %li with type %u\n", i,
cb7a4bec 1505 (unsigned int) im->gdes[i].gf);
53dc677d
WS
1506 switch (im->gdes[i].gf) {
1507 case GF_LINE:
1508 case GF_AREA:
1509 gdp->gf = im->gdes[i].gf;
1510 gdp->linewidth = im->gdes[i].linewidth;
1511 dprintfparsed("found matching LINE/AREA at %li with type %u\n", i,
cb7a4bec 1512 (unsigned int) im->gdes[i].gf);
53dc677d
WS
1513 break;
1514 default:
1515 break;
1516 }
1517 }
1518 /* error the unhandled */
1519 if (gdp->gf == gf) {
1520 rrd_set_error("No previous LINE or AREA found for %s", pa->arg_orig);
1521 return 1;
1522 }
1523
1524 /* debug output */
1525 dprintf("=================================\n");
1526 dprintf("STACK : %s\n", pa->arg_orig);
1527 if (gdp->vidx < 0) {
1528 dprintf("VAL : %g\n", gdp->yrule);
1529 } else {
1530 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1531 }
1532 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1533 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1534 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
1535 gdp->col2.red, gdp->col2.green, gdp->col2.blue, gdp->col2.alpha);
1536 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1537 dprintf("STACK : %i\n", gdp->stack);
1538 dprintf("WIDTH : %g\n", gdp->linewidth);
1539 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1540 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1541 dprintf("DASHES: TODI\n");
1542 dprintf("=================================\n");
1543
1544 /* shift the legend by 2 spaces for the "coloured-box" */
1545 legend_shift(gdp->legend);
1546
1547 /* and return fine */
1548 return 0;
1ace8365 1549}
6465207c 1550
53dc677d
WS
1551static int parse_hvrule(
1552 enum gf_en gf,
1553 parsedargs_t *pa,
1554 image_desc_t *const im)
1555{
1556 /* get new graph that we fill */
1557 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1558 PARSE_VNAMECOLORLEGEND
1559 | PARSE_VNAMEREFNUM
1560 | PARSE_XAXIS
1561 | PARSE_YAXIS | PARSE_DASHES);
1562 if (!gdp) {
1563 return 1;
1564 }
1565
1566 /* debug output */
1567 dprintf("=================================\n");
1568 if (gf == GF_VRULE) {
1569 dprintf("VRULE : %s\n", pa->arg_orig);
1ace8365 1570 } else {
53dc677d
WS
1571 dprintf("HRULE : %s\n", pa->arg_orig);
1572 }
1573 if (gdp->vidx < 0) {
1574 if (gf == GF_VRULE) {
1575 dprintf("VAL : %lld\n", (long long) gdp->xrule);
1576 } else {
1577 dprintf("VAL : %g\n", gdp->yrule);
1578 }
1579 } else {
1580 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1581 }
1582 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1583 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1584 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
1585 gdp->col2.red, gdp->col2.green, gdp->col2.blue, gdp->col2.alpha);
1586 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1587 dprintf("DASHES: TODO\n");
1588 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1589 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1590 dprintf("=================================\n");
1591
1592 /* shift the legend by 2 spaces for the "coloured-box" */
1593 legend_shift(gdp->legend);
1594
1595 /* check that vidx is of type VDEF */
1596 if (gdp->vidx != -1 && im->gdes[gdp->vidx].gf != GF_VDEF) {
1597 rrd_set_error("Using vname %s of wrong type in line %s\n",
1598 gdp->vname, pa->arg_orig);
1599 return 1;
1600 }
1fe48b55
TO
1601
1602
53dc677d
WS
1603 /* and return fine */
1604 return 0;
1ace8365 1605}
6465207c 1606
53dc677d
WS
1607static int parse_gprint(
1608 enum gf_en gf,
1609 parsedargs_t *pa,
1610 image_desc_t *const im)
1611{
1612 /* get new graph that we fill */
1613 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1614 PARSE_VNAMEREF
1615 | PARSE_CF
1616 | PARSE_FORMAT
1617 | PARSE_STRFTIMEVFMT);
1618 if (!gdp) {
1619 return 1;
1620 }
1621 /* here we parse pos arguments locally */
1622 /* vname */
1623 if (gdp->vname[0] == 0) {
1624 dprintfparsed("Processing positional vname\n");
1625 keyvalue_t *first = getFirstUnusedArgument(1, pa);
1626
1627 if (first) {
1628 strncpy(gdp->vname, first->keyvalue, MAX_VNAME_LEN);
1629 gdp->vname[MAX_VNAME_LEN] = '\0';
1630 /* get type of reference */
1631 gdp->vidx = find_var(im, gdp->vname);
1632 if (gdp->vidx < 0) {
1633 rrd_set_error("undefined vname %s", gdp->vname);
1634 return 1;
1635 }
1636 } else {
1637 rrd_set_error("No positional VNAME");
1638 return 1;
1639 }
1640 }
1641 /* check type of ref in general */
1642 enum gf_en vnamegf = im->gdes[gdp->vidx].gf;
1643
1644 dprintfparsed("Processing referenced type %i\n", vnamegf);
1645 switch (vnamegf) {
1646 /* deprecated */
1647 case GF_DEF:
1648 case GF_CDEF:
1649 dprintfparsed("Processing positional CF\n");
1650 /* look for CF if not given */
1651 if (((int) gdp->cf) == -1) {
1652 keyvalue_t *first = getFirstUnusedArgument(1, pa);
1653
1654 if (first) {
1655 gdp->cf = rrd_cf_conv(first->value);
1656 if (((int) gdp->cf) == -1) {
1657 rrd_set_error("bad CF for DEF/CDEF: %s", first->value);
1658 return 1;
1659 }
1660 } else {
1661 rrd_set_error("No positional CDEF");
1662 return 1;
1663 }
1664 }
1665 break;
1666 case GF_VDEF:
1667 break;
1668 default:
1669 rrd_set_error("Encountered unknown type variable '%s'",
1670 im->gdes[gdp->vidx].vname);
1671 return 1;
1672 }
1673 /* and get positional format */
1674 if (gdp->format[0] == 0) {
1675 dprintfparsed("Processing positional format\n");
1676 keyvalue_t *first = getFirstUnusedArgument(1, pa);
1677
1678 if (first) {
1679 strncpy(gdp->format, first->keyvalue, FMT_LEG_LEN);
1680 dprintfparsed("got positional format: %s\n", gdp->format);
1681 } else {
1682 rrd_set_error("No positional CF/FORMAT");
1683 return 1;
1684 }
1685 }
1686 /* debug output */
1687 dprintf("=================================\n");
1688 if (gf == GF_GPRINT) {
1689 dprintf("GPRINT : %s\n", pa->arg_orig);
1690 } else {
1691 dprintf("PRINT : %s\n", pa->arg_orig);
1692 }
1693 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1694 if ((int) gdp->cf > -1) {
cb7a4bec 1695 dprintf("CF : (%u)\n", (unsigned int) gdp->cf);
53dc677d
WS
1696 }
1697 dprintf("FORMAT: \"%s\"\n", gdp->legend);
1698 dprintf("=================================\n");
1699
1700 /* and return */
1701 return 0;
1ace8365 1702}
6465207c 1703
53dc677d
WS
1704static int parse_comment(
1705 enum gf_en gf,
1706 parsedargs_t *pa,
1707 image_desc_t *const im)
1708{
1709 /* get new graph that we fill */
1710 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1711 PARSE_LEGEND);
1712
1713 if (!gdp) {
1714 return 1;
1715 }
1716
1717 /* and if we have no legend, then use the first positional one */
1718 if (gdp->legend[0] == 0) {
1719 keyvalue_t *first = getFirstUnusedArgument(1, pa);
1720
1721 if (first) {
1722 strncpy(gdp->legend, first->keyvalue, FMT_LEG_LEN);
1723 } else {
1724 rrd_set_error("No positional CF/FORMAT");
1725 return 1;
1726 }
1727 }
1728 /* debug output */
1729 dprintf("=================================\n");
1730 dprintf("COMMENT : %s\n", pa->arg_orig);
1731 dprintf("LEGEND : \"%s\"\n", gdp->legend);
1732
1733 /* and return */
1734 return 0;
6465207c 1735}
adb27eb6 1736
53dc677d
WS
1737static int parse_tick(
1738 enum gf_en gf,
1739 parsedargs_t *pa,
1740 image_desc_t *const im)
1741{
1742 /* get new graph that we fill */
1743 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1744 PARSE_VNAMECOLORFRACTIONLEGEND);
1745
1746 if (!gdp) {
1747 return 1;
1748 }
1749 /* debug output */
1750 dprintf("=================================\n");
1751 dprintf("TICK : %s\n", pa->arg_orig);
1752 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1753 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1754 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1755 if (gdp->cf == CF_LAST) {
1756 dprintf("FRAC : %s\n", gdp->vname);
1757 } else {
1758 dprintf("FRAC : %g\n", gdp->yrule);
1759 }
1760 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1761 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1762 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1763 dprintf("=================================\n");
1764 /* and return */
1765 return 0;
1ace8365 1766}
6465207c 1767
53dc677d
WS
1768static int parse_textalign(
1769 enum gf_en gf,
1770 parsedargs_t *pa,
1771 image_desc_t *const im)
1772{
1773 keyvalue_t *kv;
1774
1775 /* get new graph that we fill */
1776 graph_desc_t *gdp = newGraphDescription(im, gf, pa, 0);
1777
1778 if (!gdp) {
1779 return 1;
1780 }
1781
1782 /* get align */
1783 char *align = getKeyValueArgument("align", 1, pa);
1784
1785 if (!align) {
1786 kv = getFirstUnusedArgument(1, pa);
1787 if (kv)
1788 align = kv->value;
1789 }
1790 if (!align) {
1791 rrd_set_error("No alignment given");
1792 return 1;
1793 }
1794
1795 /* parse align */
1796 if (strcmp(align, "left") == 0) {
1797 gdp->txtalign = TXA_LEFT;
1798 } else if (strcmp(align, "right") == 0) {
1799 gdp->txtalign = TXA_RIGHT;
1800 } else if (strcmp(align, "justified") == 0) {
1801 gdp->txtalign = TXA_JUSTIFIED;
1802 } else if (strcmp(align, "center") == 0) {
1803 gdp->txtalign = TXA_CENTER;
1804 } else {
1805 rrd_set_error("Unknown alignment type '%s'", align);
1806 return 1;
1807 }
1808
1809 /* debug output */
1810 dprintf("=================================\n");
1811 dprintf("TEXTALIGN : %s\n", pa->arg_orig);
cb7a4bec 1812 dprintf("ALIGNMENT : %s (%u)\n", align, (unsigned int) gdp->txtalign);
53dc677d
WS
1813 dprintf("=================================\n");
1814 /* and return */
1815 return 0;
1ace8365 1816}
6465207c 1817
53dc677d
WS
1818static int parse_shift(
1819 enum gf_en gf,
1820 parsedargs_t *pa,
1821 image_desc_t *const im)
1822{
1823 keyvalue_t *kv;
1824
1825 /* get new graph that we fill */
1826 graph_desc_t *gdp = newGraphDescription(im, gf, pa, PARSE_VNAMEREFPOS);
1827
1828 if (!gdp) {
1829 return 1;
1830 }
1831 /* and check that it is a CDEF */
1832 switch (im->gdes[gdp->vidx].gf) {
1ace8365
TO
1833 case GF_DEF:
1834 case GF_CDEF:
53dc677d
WS
1835 dprintf("- vname is of type DEF or CDEF, OK\n");
1836 break;
1ace8365 1837 case GF_VDEF:
53dc677d
WS
1838 rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n",
1839 im->gdes[gdp->vidx].vname, pa->arg_orig);
1840 return 1;
1ace8365 1841 default:
53dc677d
WS
1842 rrd_set_error("Encountered unknown type variable '%s' in line '%s'",
1843 im->gdes[gdp->vidx].vname, pa->arg_orig);
1844 return 1;
1845 }
1846
1847 /* now parse the "shift" */
1848 char *shift = getKeyValueArgument("shift", 1, pa);
1849
1850 if (!shift) {
1851 kv = getFirstUnusedArgument(1, pa);
1852 if (kv)
1853 shift = kv->value;
1854 }
1855 if (!shift) {
1856 rrd_set_error("No shift given");
1857 return 1;
1858 }
1859 /* identify shift */
1860 gdp->shidx = find_var(im, shift);
1861 if (gdp->shidx >= 0) {
1862 /* it is a def, so let us check its type */
1863 switch (im->gdes[gdp->shidx].gf) {
1864 case GF_DEF:
1865 case GF_CDEF:
1866 rrd_set_error("Offset cannot be a (C)DEF: '%s' in line '%s'\n",
1867 im->gdes[gdp->shidx].vname, pa->arg_orig);
1868 return 1;
1869 case GF_VDEF:
1870 dprintf("- vname is of type VDEF, OK\n");
1871 break;
1872 default:
1ace8365 1873 rrd_set_error
53dc677d
WS
1874 ("Encountered unknown type variable '%s' in line '%s'",
1875 im->gdes[gdp->vidx].vname, pa->arg_orig);
1876 return 1;
1877 }
1878 } else {
1879 /* it is no def, so parse as number */
1880 long val;
1881 char *x;
1882 int f = getLong(shift, &val, &x, 10);
1883
1884 if (f) {
1885 rrd_set_error("error parsing number %s", shift);
1ace8365 1886 return 1;
53dc677d
WS
1887 }
1888 gdp->shval = val;
1889 gdp->shidx = -1;
6465207c 1890 }
53dc677d
WS
1891
1892 /* debug output */
1893 dprintf("=================================\n");
1894 dprintf("SHIFT : %s\n", pa->arg_orig);
1895 dprintf("VNAME : %s (%li)\n", im->gdes[gdp->vidx].vname, gdp->vidx);
1896 if (gdp->shidx >= 0) {
1897 dprintf("SHIFTBY : %s (%i)\n", im->gdes[gdp->shidx].vname,
1898 gdp->shidx);
1899 } else {
59d21dcd 1900#if defined _WIN32 && SIZEOF_TIME_T == 8 /* in case of __MINGW64__, _WIN64 and _MSC_VER >= 1400 (ifndef _USE_32BIT_TIME_T) */
53dc677d 1901 dprintf("SHIFTBY : %lli\n", gdp->shval); /* argument 3 has type 'time_t {aka long long int}' */
f79c1d56 1902#else
53dc677d 1903 dprintf("SHIFTBY : %li\n", gdp->shval);
f79c1d56 1904#endif
53dc677d
WS
1905 }
1906 dprintf("=================================\n");
1907 /* and return */
1908 return 0;
6465207c 1909}
1ace8365 1910
53dc677d
WS
1911static int parse_xport(
1912 enum gf_en gf,
1913 parsedargs_t *pa,
1914 image_desc_t *const im)
1915{
1916 /* get new graph that we fill */
1917 graph_desc_t *gdp =
1918 newGraphDescription(im, gf, pa, PARSE_VNAMECOLORLEGEND);
1919 if (!gdp) {
1920 return 1;
1921 }
1922 /* check for cdef */
1923 /* and check that it is a CDEF */
1924 switch (im->gdes[gdp->vidx].gf) {
1925 case GF_DEF:
1926 case GF_CDEF:
1927 dprintf("- vname is of type DEF or CDEF, OK\n");
1928 break;
1929 case GF_VDEF:
1930 rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n",
1931 im->gdes[gdp->vidx].vname, pa->arg_orig);
1932 return 1;
1933 default:
1934 rrd_set_error("Encountered unknown type variable '%s' in line '%s'",
1935 im->gdes[gdp->vidx].vname, pa->arg_orig);
1936 return 1;
1937 }
1938
1939 /* debug output */
1940 dprintf("=================================\n");
1941 dprintf("LINE : %s\n", pa->arg_orig);
1942 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1943 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1944 dprintf("=================================\n");
1ace8365 1945
53dc677d 1946 return 0;
6465207c
AB
1947}
1948
18cadd88
TO
1949void rrd_graph_script(
1950 int argc,
1951 char *argv[],
c4e8c1ea 1952 image_desc_t *const im,
18cadd88
TO
1953 int optno)
1954{
1955 int i;
1956
53dc677d 1957 /* and now handle the things */
1ace8365 1958 parsedargs_t pa;
53dc677d 1959
1ace8365 1960 initParsedArguments(&pa);
6465207c 1961
1ace8365 1962 /* loop arguments */
ed031af0 1963 for (i = optno; i < argc; i++) {
53dc677d
WS
1964 /* release parsed args - avoiding late cleanups */
1965 freeParsedArguments(&pa);
1966 /* processed parsed args */
1967 if (parseArguments(argv[i], &pa)) {
1968 return;
1969 }
1ace8365 1970
e111de44 1971 /* dumpArguments(&pa); */
53dc677d
WS
1972 /* now let us handle the field based on the first command or cmd=... */
1973 char *cmd = NULL;
1974
1975 /* and try to get via cmd */
1976 char *t = getKeyValueArgument("cmd", 255, &pa);
1977
1978 if (t) {
1979 cmd = t;
1980 } else if ((t = getKeyValueArgument("pos0", 255, &pa))) {
1981 cmd = t;
1982 } else {
1983 rrd_set_error("no command set in argument %s", pa.arg_orig);
1984 freeParsedArguments(&pa);
1985 return;
1986 }
1987
1988 /* convert to enum but handling LINE special */
1989 enum gf_en gf = (enum gf_en) -1;
1990
1991 gf = gf_conv(cmd);
1992 if ((int) gf == -1) {
1993 if (strncmp("LINE", cmd, 4) == 0) {
1994 gf = GF_LINE;
1995 addToArguments(&pa, NULL, "linewidth", cmd + 4, 0);
1996 } else {
1997 rrd_set_error("'%s' is not a valid function name in %s", cmd,
1998 pa.arg_orig);
1999 return;
2000 }
2001 }
2002 /* now we can handle the commands */
2003 int r = 0;
2004
2005 switch (gf) {
2006 case GF_XAXIS:
2007 r = parse_axis(gf, &pa, im);
2008 break;
2009 case GF_YAXIS:
2010 r = parse_axis(gf, &pa, im);
2011 break;
2012 case GF_DEF:
2013 r = parse_def(gf, &pa, im);
2014 break;
2015 case GF_CDEF:
2016 r = parse_cvdef(gf, &pa, im);
2017 break;
2018 case GF_VDEF:
2019 r = parse_cvdef(gf, &pa, im);
2020 break;
2021 case GF_LINE:
2022 r = parse_line(gf, &pa, im);
2023 break;
2024 case GF_AREA:
2025 r = parse_area(gf, &pa, im);
2026 break;
2027 case GF_PRINT:
2028 r = parse_gprint(gf, &pa, im);
2029 break;
2030 case GF_GPRINT:
2031 r = parse_gprint(gf, &pa, im);
2032 break;
2033 case GF_COMMENT:
2034 r = parse_comment(gf, &pa, im);
2035 break;
2036 case GF_HRULE:
2037 r = parse_hvrule(gf, &pa, im);
2038 break;
2039 case GF_VRULE:
2040 r = parse_hvrule(gf, &pa, im);
2041 break;
2042 case GF_STACK:
2043 r = parse_stack(gf, &pa, im);
2044 break;
2045 case GF_TICK:
2046 r = parse_tick(gf, &pa, im);
2047 break;
2048 case GF_TEXTALIGN:
2049 r = parse_textalign(gf, &pa, im);
2050 break;
2051 case GF_SHIFT:
2052 r = parse_shift(gf, &pa, im);
2053 break;
2054 case GF_XPORT:
2055 r = parse_xport(gf, &pa, im);
2056 break;
2057 /* unsupported types right now */
2058 }
2059 /* handle the return error case */
2060 if (r) {
2061 freeParsedArguments(&pa);
2062 return;
2063 }
2064 /* check for unprocessed keyvalue args */
2065 char *s;
2066
2067 if ((s = checkUnusedValues(&pa))) {
2068 /* set error message */
2069 rrd_set_error("Unused Arguments \"%s\" in command : %s", s,
2070 pa.arg_orig);
2071 free(s);
2072 /* exit early */
2073 freeParsedArguments(&pa);
2074 return;
2075 }
6465207c 2076 }
1ace8365
TO
2077 /* finally free arguments */
2078 freeParsedArguments(&pa);
6465207c 2079}