]> git.ipfire.org Git - thirdparty/rrdtool-1.x.git/blame - src/rrd_graph_helper.c
Constify argv, fix warnings. (#1242)
[thirdparty/rrdtool-1.x.git] / src / rrd_graph_helper.c
CommitLineData
0516711e 1/****************************************************************************
e839e17c 2 * RRDtool 1.8.0 Copyright by Tobi Oetiker, 1997-2022
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;
254e4e44
JB
1029 if (gdp->xrule == 0) {
1030 /* distinguish from uninitialized */
1031 gdp->xrule++;
1032 }
53dc677d
WS
1033 } else {
1034 gdp->yrule = val;
1035 }
1036 } else {
1037 rrd_set_error("vname %s not found", vname);
1038 return NULL;
1039 }
1040 }
1041 }
1042 }
1043
1044 /* and assign it */
1045 if (vname) {
1046 strncpy(gdp->vname, vname, MAX_VNAME_LEN);
1047 gdp->vname[MAX_VNAME_LEN] = '\0';
1048 }
1049 if (rrd) {
1050 strncpy(gdp->rrd, rrd, 1023);
1051 gdp->rrd[1023] = '\0';
1052 }
1053 if (ds) {
1054 strncpy(gdp->ds_nam, ds, DS_NAM_SIZE - 1);
1055 gdp->ds_nam[DS_NAM_SIZE - 1] = '\0';
1056 }
1057 if (cf) {
1058 gdp->cf = rrd_cf_conv(cf);
1059 if (((int) gdp->cf) == -1) {
1060 rrd_set_error("bad CF: %s", cf);
1061 return NULL;
1062 }
1ace8365 1063 } else {
53dc677d
WS
1064 if (bitscmp(PARSE_CF)) {
1065 gdp->cf = (enum cf_en) -1;
1066 }
1067 }
1068 if ((color) && (parse_color(color, &(gdp->col)))) {
1069 return NULL;
1070 }
1071 if ((color2) && (parse_color(color2, &(gdp->col2)))) {
1072 return NULL;
1073 }
1074 if (rpn) {
1075 gdp->rpn = rpn;
1076 }
1077 if ((legend) && (*legend != 0)) {
1078 /* and copy it into place */
1079 strncpy(gdp->legend, legend, FMT_LEG_LEN);
1080 }
1081 if (fraction) {
1082 if (strcmp(fraction, "vname") == 0) {
1083 /* check that vname is really a DEF|CDEF */
1084 if (im->gdes[gdp->vidx].gf != GF_DEF
1085 && im->gdes[gdp->vidx].gf != GF_CDEF) {
1086 rrd_set_error
1087 ("variable '%s' not DEF nor CDEF when using dynamic fractions",
1088 gdp->vname);
1089 return NULL;
1090 }
1091 /* add as flag to use (c)?def */
1092 gdp->cf = CF_LAST;
1093 gdp->yrule = 0.5;
1094 } else {
1095 /* parse number */
1096 double val;
1097 char *x;
1098 int f = getDouble(fraction, &val, &x);
1099
1100 if (f) {
1101 rrd_set_error("error parsing number %s", vname);
1102 return NULL;
1103 }
1104 gdp->yrule = val;
1105 }
1106 }
1107 /* remember the index for faster varfind */
1108 char *key = gdes_fetch_key((*gdp));
1109
1110 if (gdp->gf == GF_DEF
1111 && !g_hash_table_lookup_extended(im->rrd_map, key, NULL, NULL)) {
1112 dprintfhash("ins key %s - %ld\n", key, im->gdes_c - 1);
1113 g_hash_table_insert(im->gdef_map, g_strdup(key),
1114 GINT_TO_POINTER(im->gdes_c - 1));
1115 }
1116 free(key);
1117 if (gdp->gf == GF_DEF || gdp->gf == GF_VDEF || gdp->gf == GF_CDEF) {
1118 dprintfhash("ins vname %s - %ld\n", gdp->vname, im->gdes_c - 1);
1119 g_hash_table_insert(im->gdef_map, g_strdup(gdp->vname),
1120 GINT_TO_POINTER(im->gdes_c - 1));
1121 }
1122 return gdp;
6465207c
AB
1123}
1124
1ace8365
TO
1125/* and some defines */
1126#define set_match(str,pat,cmd) if (strcmp(pat, str) == 0) { cmd ;}
1127
1128/* prototypes */
53dc677d
WS
1129static int parse_axis(
1130 enum gf_en,
1131 parsedargs_t *,
1132 image_desc_t *const);
1133static int parse_def(
1134 enum gf_en,
1135 parsedargs_t *,
1136 image_desc_t *const);
1137static int parse_cvdef(
1138 enum gf_en,
1139 parsedargs_t *,
1140 image_desc_t *const);
1141static int parse_line(
1142 enum gf_en,
1143 parsedargs_t *,
1144 image_desc_t *const);
1145static int parse_area(
1146 enum gf_en,
1147 parsedargs_t *,
1148 image_desc_t *const);
1149static int parse_stack(
1150 enum gf_en,
1151 parsedargs_t *,
1152 image_desc_t *const);
1153static int parse_gprint(
1154 enum gf_en,
1155 parsedargs_t *,
1156 image_desc_t *const);
1157static int parse_comment(
1158 enum gf_en,
1159 parsedargs_t *,
1160 image_desc_t *const);
1161static int parse_hvrule(
1162 enum gf_en,
1163 parsedargs_t *,
1164 image_desc_t *const);
1165static int parse_tick(
1166 enum gf_en,
1167 parsedargs_t *,
1168 image_desc_t *const);
1169static int parse_textalign(
1170 enum gf_en,
1171 parsedargs_t *,
1172 image_desc_t *const);
1173static int parse_shift(
1174 enum gf_en,
1175 parsedargs_t *,
1176 image_desc_t *const);
1177static int parse_xport(
1178 enum gf_en,
1179 parsedargs_t *,
1180 image_desc_t *const);
1ace8365 1181
fe1fd85f 1182/* this is needed for LINE,AREA,STACK so that the labels get done correctly... */
53dc677d
WS
1183static void legend_shift(
1184 char *legend)
129d1f40 1185{
53dc677d
WS
1186 if (!legend || !legend[0]) {
1187 return;
1188 }
1189 memmove(legend + 2, legend, strlen(legend));
1190 legend[0] = ' ';
1191 legend[1] = ' ';
129d1f40
MS
1192}
1193
1ace8365 1194/* implementations */
53dc677d
WS
1195static int parse_axis(
1196 enum gf_en gf,
1197 parsedargs_t *pa,
1198 image_desc_t *const im)
1199{
d093a1d3 1200
1ace8365 1201#if 0
53dc677d
WS
1202 /* define X or y axis */
1203 axis_t *a = im->xaxis;
1204
1205 if (gf == GF_YAXIS) {
1206 a = im->yaxis;
1207 }
1208 /* try to parse the number */
1209 char *cmd = getKeyValueArgument("cmd", 1, pa);
1210
1211 if (cmd[5]) {
1212 int num = atoi(cmd + 5);
1213
1214 if ((num < 1) || (num > MAX_AXIS)) {
1215 rrd_set_error
1216 ("invalid axis ID %i in %s - should be in range [1:%i]", num,
1217 cmd, MAX_AXIS);
1218 return 1;
1219 }
1220 /* and forward by that much */
1221 a = a + (num - 1);
1222 }
1223
1224 /* and set type */
1225 char *t = getKeyValueArgument("type", 1, pa);
1226
1227 if (t) {
1228 set_match(t, "TIME", a->type = AXIS_TYPE_TIME)
1229 else
1230 set_match(t, "LINEAR", a->type = AXIS_TYPE_LINEAR)
1231 else
1232 set_match(t, "LOGARITHMIC", a->type = AXIS_TYPE_LOGARITHMIC)
1233 else {
1234 rrd_set_error("unsupported axis type %s", t);
1235 return 1;
1236 }
1237 }
1238 /* and other stuff */
1239 a->bounds.lowertxt = getKeyValueArgument("min", 1, pa);
1240 a->bounds.uppertxt = getKeyValueArgument("max", 1, pa);
c5794b2d 1241#else
53dc677d
WS
1242 /* prevent unused warnings */
1243 (void) gf;
1244 (void) pa;
1245 (void) im;
1ace8365 1246#endif
d093a1d3 1247
53dc677d
WS
1248 /* and return */
1249 return 0;
1ace8365 1250}
adb27eb6 1251
53dc677d
WS
1252static int parse_def(
1253 enum gf_en gf,
1254 parsedargs_t *pa,
1255 image_desc_t *const im)
1256{
1257 /* get new graph that we fill */
1258 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1259 PARSE_VNAMERRDDSCF
1260 | PARSE_START
1261 | PARSE_STEP
1262 | PARSE_END
1263 | PARSE_REDUCE | PARSE_DAEMON);
1264 /* retry in case of errors modifying the name */
1265 if (!gdp) {
1266 /* restart from scratch */
1267 resetParsedArguments(pa);
1268 /* get the first parameter */
1269 keyvalue_t *first = getFirstUnusedArgument(0, pa);
1270
1271 /* if it is any of the "original" positional args, then we terminate immediately */
1272 for (int i = 0; i < 10; i++) {
1273 if (poskeys[i] == first->key) {
1274 return -1;
1275 }
1276 }
1277 /* otherwise we patch the key */
1278 *(first->key) += 128;
1279
1280 /* and keep a copy of the error */
1281 char original_error[4096];
1282
1283 strncpy(original_error, rrd_get_error(), sizeof(original_error) - 1);
1284 /* and clear the error */
1285 rrd_clear_error();
1286
1287 /* now run it */
1288 gdp = newGraphDescription(im, gf, pa,
1289 PARSE_VNAMERRDDSCF
1290 | PARSE_START
1291 | PARSE_STEP
1292 | PARSE_END
1293 | PARSE_REDUCE
1294 | PARSE_DAEMON | PARSE_RETRY);
1295 /* on error, we restore the original error and return */
1296 if (!gdp) {
1297 rrd_set_error(original_error);
1298 return 1;
1299 }
1300 }
1301
1302 if (gdp->step == 0) {
1303 gdp->step = im->step; /* initialize with image wide step */
1304 }
1305
1306 /* debugging output */
1307 dprintf("=================================\n");
1308 dprintf("DEF : %s\n", pa->arg_orig);
1309 dprintf("VNAME : %s\n", gdp->vname);
1310 dprintf("RRD : %s\n", gdp->rrd);
1311 dprintf("DS : %s\n", gdp->ds_nam);
1312 dprintf("CF : %i\n", gdp->cf);
1313 dprintf("START : (%lld)\n", (long long int) gdp->start);
1314 dprintf("STEP : (%lld)\n", (long long int) gdp->step);
1315 dprintf("END : (%lld)\n", (long long int) gdp->end);
1316 dprintf("REDUCE: (%i)\n", gdp->cf_reduce);
1317 dprintf("DAEMON: %s\n", gdp->daemon);
1318 dprintf("=================================\n");
1319
1320 /* and return fine */
1321 return 0;
aa70e348 1322}
1ace8365 1323
53dc677d
WS
1324static int parse_cvdef(
1325 enum gf_en gf,
1326 parsedargs_t *pa,
1327 image_desc_t *const im)
1328{
1329 /* get new graph that we fill */
1330 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1331 PARSE_VNAMERPN);
1332
1333 if (!gdp) {
1334 return 1;
1335 }
1336
1337 /* handle RPN parsing */
1338 if (gf == GF_CDEF) {
1339 /* parse rpn */
1340 if ((gdp->rpnp =
1341 rpn_parse((void *) im, gdp->rpn, &find_var_wrapper)) == NULL) {
1342 return 1;
1343 }
1344 } else { /* VDEF */
1345 /* parse vdef, as vdef_parse is a bit "stupid" right now we have to touch things here */
1346 /* so find first , */
1347 char *c = strchr(gdp->rpn, ',');
1348 char vname[MAX_VNAME_LEN + 1];
1349
1350 if (!c) {
1351 rrd_set_error("Comma expected in VDEF definition %s", gdp->rpn);
1352 return 1;
1353 }
1354 /* found a comma, so copy the first part to ds_nam (re/abusing it) */
1355 *c = 0; /* yes now it seems as if the string ended here */
1356 strncpy(vname, gdp->rpn, MAX_VNAME_LEN);
1357 *c = ','; /* and now all is back to normal ... shudder */
1358 /* trying to find the vidx for that name */
1359 gdp->vidx = find_var(im, vname);
1360 if (gdp->vidx < 0) {
1361 *c = ',';
1362 rrd_set_error("Not a valid vname: %s in line %s", vname,
1363 gdp->rpn);
1364 return 1;
1365 }
1366 if (im->gdes[gdp->vidx].gf != GF_DEF
1367 && im->gdes[gdp->vidx].gf != GF_CDEF) {
1368 rrd_set_error("variable '%s' not DEF nor " "CDEF in VDEF '%s'",
1369 vname, gdp->rpn);
1370 return 1;
1371 }
1372 /* and parsing the rpn */
1373 int r = vdef_parse(gdp, c + 1);
1374
1375 /* original code does not check here for some reason */
1376 if (r) {
1377 return 1;
1378 }
1379 }
1380
1381 /* debugging output */
1382 dprintf("=================================\n");
1383 if (gf == GF_CDEF) {
1384 dprintf("CDEF : %s\n", pa->arg_orig);
1385 } else {
1386 dprintf("VDEF : %s\n", pa->arg_orig);
1387 }
1388 dprintf("VNAME : %s\n", gdp->vname);
1389 dprintf("RPN : %s\n", gdp->rpn);
1390 dprintf("=================================\n");
1391
1392 /* and return fine */
1393 return 0;
aa70e348 1394}
1ace8365
TO
1395
1396
53dc677d
WS
1397static int parse_line(
1398 enum gf_en gf,
1399 parsedargs_t *pa,
1400 image_desc_t *const im)
1401{
1402 /* get new graph that we fill */
1403 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1404 PARSE_VNAMECOLORLEGEND
1405 | PARSE_STACK
1406 | PARSE_SKIPSCALE
1407 | PARSE_LINEWIDTH
1408 | PARSE_DASHES
1409 | PARSE_XAXIS | PARSE_YAXIS);
1410 if (!gdp) {
1411 return 1;
1412 }
1413
1414 /* debug output */
1415 dprintf("=================================\n");
1416 dprintf("LINE : %s\n", pa->arg_orig);
1417 if (gdp->vidx < 0) {
1418 dprintf("VAL : %g\n", gdp->yrule);
1419 } else {
1420 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1421 }
1422 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1423 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1424 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
1425 gdp->col2.red, gdp->col2.green, gdp->col2.blue, gdp->col2.alpha);
1426 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1427 dprintf("STACK : %i\n", gdp->stack);
1428 dprintf("SKIPSCALE : %i\n", gdp->skipscale);
1429 dprintf("WIDTH : %g\n", gdp->linewidth);
1430 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1431 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1432 if (gdp->ndash) {
1433 dprintf("DASHES: %i - %g", gdp->ndash, gdp->p_dashes[0]);
1434 for (int i = 1; i < gdp->ndash; i++) {
1435 dprintf(", %g", gdp->p_dashes[i]);
1436 }
1437 dprintf("\n");
1438 }
1439 dprintf("=================================\n");
1440
1441 /* shift the legend by 2 spaces for the "coloured-box" */
1442 legend_shift(gdp->legend);
1443
1444 /* and return fine */
1445 return 0;
adb27eb6
AB
1446}
1447
53dc677d
WS
1448static int parse_area(
1449 enum gf_en gf,
1450 parsedargs_t *pa,
1451 image_desc_t *const im)
1452{
1453 /* get new graph that we fill */
1454 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1455 PARSE_VNAMECOLORLEGEND
1456 | PARSE_STACK
1457 | PARSE_SKIPSCALE
1458 | PARSE_XAXIS
1459 | PARSE_YAXIS | PARSE_GRADHEIGHT);
1460 if (!gdp) {
1461 return 1;
1462 }
1463
1464 /* debug output */
1465 dprintf("=================================\n");
1466 dprintf("AREA : %s\n", pa->arg_orig);
1467 if (gdp->vidx < 0) {
1468 dprintf("VAL : %g\n", gdp->yrule);
1469 } else {
1470 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1471 }
1472 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1473 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1474 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
1475 gdp->col2.red, gdp->col2.green, gdp->col2.blue, gdp->col2.alpha);
1476 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1477 dprintf("STACK : %i\n", gdp->stack);
1478 dprintf("SKIPSCALE : %i\n", gdp->skipscale);
1479 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1480 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1481 dprintf("=================================\n");
1482
1483 /* shift the legend by 2 spaces for the "coloured-box" */
1484 legend_shift(gdp->legend);
1485
1486 /* and return fine */
1487 return 0;
1ace8365 1488}
6465207c 1489
53dc677d
WS
1490static int parse_stack(
1491 enum gf_en gf,
1492 parsedargs_t *pa,
1493 image_desc_t *const im)
1494{
1495 /* get new graph that we fill */
1496 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1497 PARSE_VNAMECOLORLEGEND
1498 | PARSE_XAXIS | PARSE_YAXIS);
1499 if (!gdp) {
1500 return 1;
1501 }
1502
1503 gdp->stack = 1;
1504 /* and try to get the one index before ourselves */
1505 long i;
1506
1507 for (i = im->gdes_c - 1; (gdp->gf == gf) && (i >= 0); i--) {
1508 dprintfparsed("trying to process entry %li with type %u\n", i,
cb7a4bec 1509 (unsigned int) im->gdes[i].gf);
53dc677d
WS
1510 switch (im->gdes[i].gf) {
1511 case GF_LINE:
1512 case GF_AREA:
1513 gdp->gf = im->gdes[i].gf;
1514 gdp->linewidth = im->gdes[i].linewidth;
1515 dprintfparsed("found matching LINE/AREA at %li with type %u\n", i,
cb7a4bec 1516 (unsigned int) im->gdes[i].gf);
53dc677d
WS
1517 break;
1518 default:
1519 break;
1520 }
1521 }
1522 /* error the unhandled */
1523 if (gdp->gf == gf) {
1524 rrd_set_error("No previous LINE or AREA found for %s", pa->arg_orig);
1525 return 1;
1526 }
1527
1528 /* debug output */
1529 dprintf("=================================\n");
1530 dprintf("STACK : %s\n", pa->arg_orig);
1531 if (gdp->vidx < 0) {
1532 dprintf("VAL : %g\n", gdp->yrule);
1533 } else {
1534 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1535 }
1536 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1537 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1538 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
1539 gdp->col2.red, gdp->col2.green, gdp->col2.blue, gdp->col2.alpha);
1540 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1541 dprintf("STACK : %i\n", gdp->stack);
1542 dprintf("WIDTH : %g\n", gdp->linewidth);
1543 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1544 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1545 dprintf("DASHES: TODI\n");
1546 dprintf("=================================\n");
1547
1548 /* shift the legend by 2 spaces for the "coloured-box" */
1549 legend_shift(gdp->legend);
1550
1551 /* and return fine */
1552 return 0;
1ace8365 1553}
6465207c 1554
53dc677d
WS
1555static int parse_hvrule(
1556 enum gf_en gf,
1557 parsedargs_t *pa,
1558 image_desc_t *const im)
1559{
1560 /* get new graph that we fill */
1561 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1562 PARSE_VNAMECOLORLEGEND
1563 | PARSE_VNAMEREFNUM
1564 | PARSE_XAXIS
1565 | PARSE_YAXIS | PARSE_DASHES);
1566 if (!gdp) {
1567 return 1;
1568 }
1569
1570 /* debug output */
1571 dprintf("=================================\n");
1572 if (gf == GF_VRULE) {
1573 dprintf("VRULE : %s\n", pa->arg_orig);
1ace8365 1574 } else {
53dc677d
WS
1575 dprintf("HRULE : %s\n", pa->arg_orig);
1576 }
1577 if (gdp->vidx < 0) {
1578 if (gf == GF_VRULE) {
1579 dprintf("VAL : %lld\n", (long long) gdp->xrule);
1580 } else {
1581 dprintf("VAL : %g\n", gdp->yrule);
1582 }
1583 } else {
1584 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1585 }
1586 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1587 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1588 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
1589 gdp->col2.red, gdp->col2.green, gdp->col2.blue, gdp->col2.alpha);
1590 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1591 dprintf("DASHES: TODO\n");
1592 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1593 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1594 dprintf("=================================\n");
1595
1596 /* shift the legend by 2 spaces for the "coloured-box" */
1597 legend_shift(gdp->legend);
1598
1599 /* check that vidx is of type VDEF */
1600 if (gdp->vidx != -1 && im->gdes[gdp->vidx].gf != GF_VDEF) {
1601 rrd_set_error("Using vname %s of wrong type in line %s\n",
1602 gdp->vname, pa->arg_orig);
1603 return 1;
1604 }
1fe48b55
TO
1605
1606
53dc677d
WS
1607 /* and return fine */
1608 return 0;
1ace8365 1609}
6465207c 1610
53dc677d
WS
1611static int parse_gprint(
1612 enum gf_en gf,
1613 parsedargs_t *pa,
1614 image_desc_t *const im)
1615{
1616 /* get new graph that we fill */
1617 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1618 PARSE_VNAMEREF
1619 | PARSE_CF
1620 | PARSE_FORMAT
1621 | PARSE_STRFTIMEVFMT);
1622 if (!gdp) {
1623 return 1;
1624 }
1625 /* here we parse pos arguments locally */
1626 /* vname */
1627 if (gdp->vname[0] == 0) {
1628 dprintfparsed("Processing positional vname\n");
1629 keyvalue_t *first = getFirstUnusedArgument(1, pa);
1630
1631 if (first) {
1632 strncpy(gdp->vname, first->keyvalue, MAX_VNAME_LEN);
1633 gdp->vname[MAX_VNAME_LEN] = '\0';
1634 /* get type of reference */
1635 gdp->vidx = find_var(im, gdp->vname);
1636 if (gdp->vidx < 0) {
1637 rrd_set_error("undefined vname %s", gdp->vname);
1638 return 1;
1639 }
1640 } else {
1641 rrd_set_error("No positional VNAME");
1642 return 1;
1643 }
1644 }
1645 /* check type of ref in general */
1646 enum gf_en vnamegf = im->gdes[gdp->vidx].gf;
1647
1648 dprintfparsed("Processing referenced type %i\n", vnamegf);
1649 switch (vnamegf) {
1650 /* deprecated */
1651 case GF_DEF:
1652 case GF_CDEF:
1653 dprintfparsed("Processing positional CF\n");
1654 /* look for CF if not given */
1655 if (((int) gdp->cf) == -1) {
1656 keyvalue_t *first = getFirstUnusedArgument(1, pa);
1657
1658 if (first) {
1659 gdp->cf = rrd_cf_conv(first->value);
1660 if (((int) gdp->cf) == -1) {
1661 rrd_set_error("bad CF for DEF/CDEF: %s", first->value);
1662 return 1;
1663 }
1664 } else {
1665 rrd_set_error("No positional CDEF");
1666 return 1;
1667 }
1668 }
1669 break;
1670 case GF_VDEF:
1671 break;
1672 default:
1673 rrd_set_error("Encountered unknown type variable '%s'",
1674 im->gdes[gdp->vidx].vname);
1675 return 1;
1676 }
1677 /* and get positional format */
1678 if (gdp->format[0] == 0) {
1679 dprintfparsed("Processing positional format\n");
1680 keyvalue_t *first = getFirstUnusedArgument(1, pa);
1681
1682 if (first) {
1683 strncpy(gdp->format, first->keyvalue, FMT_LEG_LEN);
1684 dprintfparsed("got positional format: %s\n", gdp->format);
1685 } else {
1686 rrd_set_error("No positional CF/FORMAT");
1687 return 1;
1688 }
1689 }
1690 /* debug output */
1691 dprintf("=================================\n");
1692 if (gf == GF_GPRINT) {
1693 dprintf("GPRINT : %s\n", pa->arg_orig);
1694 } else {
1695 dprintf("PRINT : %s\n", pa->arg_orig);
1696 }
1697 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1698 if ((int) gdp->cf > -1) {
cb7a4bec 1699 dprintf("CF : (%u)\n", (unsigned int) gdp->cf);
53dc677d
WS
1700 }
1701 dprintf("FORMAT: \"%s\"\n", gdp->legend);
1702 dprintf("=================================\n");
1703
1704 /* and return */
1705 return 0;
1ace8365 1706}
6465207c 1707
53dc677d
WS
1708static int parse_comment(
1709 enum gf_en gf,
1710 parsedargs_t *pa,
1711 image_desc_t *const im)
1712{
1713 /* get new graph that we fill */
1714 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1715 PARSE_LEGEND);
1716
1717 if (!gdp) {
1718 return 1;
1719 }
1720
1721 /* and if we have no legend, then use the first positional one */
1722 if (gdp->legend[0] == 0) {
1723 keyvalue_t *first = getFirstUnusedArgument(1, pa);
1724
1725 if (first) {
1726 strncpy(gdp->legend, first->keyvalue, FMT_LEG_LEN);
1727 } else {
1728 rrd_set_error("No positional CF/FORMAT");
1729 return 1;
1730 }
1731 }
1732 /* debug output */
1733 dprintf("=================================\n");
1734 dprintf("COMMENT : %s\n", pa->arg_orig);
1735 dprintf("LEGEND : \"%s\"\n", gdp->legend);
1736
1737 /* and return */
1738 return 0;
6465207c 1739}
adb27eb6 1740
53dc677d
WS
1741static int parse_tick(
1742 enum gf_en gf,
1743 parsedargs_t *pa,
1744 image_desc_t *const im)
1745{
1746 /* get new graph that we fill */
1747 graph_desc_t *gdp = newGraphDescription(im, gf, pa,
1748 PARSE_VNAMECOLORFRACTIONLEGEND);
1749
1750 if (!gdp) {
1751 return 1;
1752 }
1753 /* debug output */
1754 dprintf("=================================\n");
1755 dprintf("TICK : %s\n", pa->arg_orig);
1756 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1757 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1758 gdp->col.red, gdp->col.green, gdp->col.blue, gdp->col.alpha);
1759 if (gdp->cf == CF_LAST) {
1760 dprintf("FRAC : %s\n", gdp->vname);
1761 } else {
1762 dprintf("FRAC : %g\n", gdp->yrule);
1763 }
1764 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1765 dprintf("XAXIS : %i\n", gdp->xaxisidx);
1766 dprintf("YAXIS : %i\n", gdp->yaxisidx);
1767 dprintf("=================================\n");
1768 /* and return */
1769 return 0;
1ace8365 1770}
6465207c 1771
53dc677d
WS
1772static int parse_textalign(
1773 enum gf_en gf,
1774 parsedargs_t *pa,
1775 image_desc_t *const im)
1776{
1777 keyvalue_t *kv;
1778
1779 /* get new graph that we fill */
1780 graph_desc_t *gdp = newGraphDescription(im, gf, pa, 0);
1781
1782 if (!gdp) {
1783 return 1;
1784 }
1785
1786 /* get align */
1787 char *align = getKeyValueArgument("align", 1, pa);
1788
1789 if (!align) {
1790 kv = getFirstUnusedArgument(1, pa);
1791 if (kv)
1792 align = kv->value;
1793 }
1794 if (!align) {
1795 rrd_set_error("No alignment given");
1796 return 1;
1797 }
1798
1799 /* parse align */
1800 if (strcmp(align, "left") == 0) {
1801 gdp->txtalign = TXA_LEFT;
1802 } else if (strcmp(align, "right") == 0) {
1803 gdp->txtalign = TXA_RIGHT;
1804 } else if (strcmp(align, "justified") == 0) {
1805 gdp->txtalign = TXA_JUSTIFIED;
1806 } else if (strcmp(align, "center") == 0) {
1807 gdp->txtalign = TXA_CENTER;
1808 } else {
1809 rrd_set_error("Unknown alignment type '%s'", align);
1810 return 1;
1811 }
1812
1813 /* debug output */
1814 dprintf("=================================\n");
1815 dprintf("TEXTALIGN : %s\n", pa->arg_orig);
cb7a4bec 1816 dprintf("ALIGNMENT : %s (%u)\n", align, (unsigned int) gdp->txtalign);
53dc677d
WS
1817 dprintf("=================================\n");
1818 /* and return */
1819 return 0;
1ace8365 1820}
6465207c 1821
53dc677d
WS
1822static int parse_shift(
1823 enum gf_en gf,
1824 parsedargs_t *pa,
1825 image_desc_t *const im)
1826{
1827 keyvalue_t *kv;
1828
1829 /* get new graph that we fill */
1830 graph_desc_t *gdp = newGraphDescription(im, gf, pa, PARSE_VNAMEREFPOS);
1831
1832 if (!gdp) {
1833 return 1;
1834 }
1835 /* and check that it is a CDEF */
1836 switch (im->gdes[gdp->vidx].gf) {
1ace8365
TO
1837 case GF_DEF:
1838 case GF_CDEF:
53dc677d
WS
1839 dprintf("- vname is of type DEF or CDEF, OK\n");
1840 break;
1ace8365 1841 case GF_VDEF:
53dc677d
WS
1842 rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n",
1843 im->gdes[gdp->vidx].vname, pa->arg_orig);
1844 return 1;
1ace8365 1845 default:
53dc677d
WS
1846 rrd_set_error("Encountered unknown type variable '%s' in line '%s'",
1847 im->gdes[gdp->vidx].vname, pa->arg_orig);
1848 return 1;
1849 }
1850
1851 /* now parse the "shift" */
1852 char *shift = getKeyValueArgument("shift", 1, pa);
1853
1854 if (!shift) {
1855 kv = getFirstUnusedArgument(1, pa);
1856 if (kv)
1857 shift = kv->value;
1858 }
1859 if (!shift) {
1860 rrd_set_error("No shift given");
1861 return 1;
1862 }
1863 /* identify shift */
1864 gdp->shidx = find_var(im, shift);
1865 if (gdp->shidx >= 0) {
1866 /* it is a def, so let us check its type */
1867 switch (im->gdes[gdp->shidx].gf) {
1868 case GF_DEF:
1869 case GF_CDEF:
1870 rrd_set_error("Offset cannot be a (C)DEF: '%s' in line '%s'\n",
1871 im->gdes[gdp->shidx].vname, pa->arg_orig);
1872 return 1;
1873 case GF_VDEF:
1874 dprintf("- vname is of type VDEF, OK\n");
1875 break;
1876 default:
1ace8365 1877 rrd_set_error
53dc677d
WS
1878 ("Encountered unknown type variable '%s' in line '%s'",
1879 im->gdes[gdp->vidx].vname, pa->arg_orig);
1880 return 1;
1881 }
1882 } else {
1883 /* it is no def, so parse as number */
1884 long val;
1885 char *x;
1886 int f = getLong(shift, &val, &x, 10);
1887
1888 if (f) {
1889 rrd_set_error("error parsing number %s", shift);
1ace8365 1890 return 1;
53dc677d
WS
1891 }
1892 gdp->shval = val;
1893 gdp->shidx = -1;
6465207c 1894 }
53dc677d
WS
1895
1896 /* debug output */
1897 dprintf("=================================\n");
1898 dprintf("SHIFT : %s\n", pa->arg_orig);
1899 dprintf("VNAME : %s (%li)\n", im->gdes[gdp->vidx].vname, gdp->vidx);
1900 if (gdp->shidx >= 0) {
1901 dprintf("SHIFTBY : %s (%i)\n", im->gdes[gdp->shidx].vname,
1902 gdp->shidx);
1903 } else {
59d21dcd 1904#if defined _WIN32 && SIZEOF_TIME_T == 8 /* in case of __MINGW64__, _WIN64 and _MSC_VER >= 1400 (ifndef _USE_32BIT_TIME_T) */
53dc677d 1905 dprintf("SHIFTBY : %lli\n", gdp->shval); /* argument 3 has type 'time_t {aka long long int}' */
f79c1d56 1906#else
53dc677d 1907 dprintf("SHIFTBY : %li\n", gdp->shval);
f79c1d56 1908#endif
53dc677d
WS
1909 }
1910 dprintf("=================================\n");
1911 /* and return */
1912 return 0;
6465207c 1913}
1ace8365 1914
53dc677d
WS
1915static int parse_xport(
1916 enum gf_en gf,
1917 parsedargs_t *pa,
1918 image_desc_t *const im)
1919{
1920 /* get new graph that we fill */
1921 graph_desc_t *gdp =
1922 newGraphDescription(im, gf, pa, PARSE_VNAMECOLORLEGEND);
1923 if (!gdp) {
1924 return 1;
1925 }
1926 /* check for cdef */
1927 /* and check that it is a CDEF */
1928 switch (im->gdes[gdp->vidx].gf) {
1929 case GF_DEF:
1930 case GF_CDEF:
1931 dprintf("- vname is of type DEF or CDEF, OK\n");
1932 break;
1933 case GF_VDEF:
1934 rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n",
1935 im->gdes[gdp->vidx].vname, pa->arg_orig);
1936 return 1;
1937 default:
1938 rrd_set_error("Encountered unknown type variable '%s' in line '%s'",
1939 im->gdes[gdp->vidx].vname, pa->arg_orig);
1940 return 1;
1941 }
1942
1943 /* debug output */
1944 dprintf("=================================\n");
1945 dprintf("LINE : %s\n", pa->arg_orig);
1946 dprintf("VNAME : %s (%li)\n", gdp->vname, gdp->vidx);
1947 dprintf("LEGEND: \"%s\"\n", gdp->legend);
1948 dprintf("=================================\n");
1ace8365 1949
53dc677d 1950 return 0;
6465207c
AB
1951}
1952
18cadd88
TO
1953void rrd_graph_script(
1954 int argc,
b76e3c57 1955 const char **argv,
c4e8c1ea 1956 image_desc_t *const im,
18cadd88
TO
1957 int optno)
1958{
1959 int i;
1960
53dc677d 1961 /* and now handle the things */
1ace8365 1962 parsedargs_t pa;
53dc677d 1963
1ace8365 1964 initParsedArguments(&pa);
6465207c 1965
1ace8365 1966 /* loop arguments */
ed031af0 1967 for (i = optno; i < argc; i++) {
53dc677d
WS
1968 /* release parsed args - avoiding late cleanups */
1969 freeParsedArguments(&pa);
1970 /* processed parsed args */
1971 if (parseArguments(argv[i], &pa)) {
1972 return;
1973 }
1ace8365 1974
e111de44 1975 /* dumpArguments(&pa); */
53dc677d
WS
1976 /* now let us handle the field based on the first command or cmd=... */
1977 char *cmd = NULL;
1978
1979 /* and try to get via cmd */
1980 char *t = getKeyValueArgument("cmd", 255, &pa);
1981
1982 if (t) {
1983 cmd = t;
1984 } else if ((t = getKeyValueArgument("pos0", 255, &pa))) {
1985 cmd = t;
1986 } else {
1987 rrd_set_error("no command set in argument %s", pa.arg_orig);
1988 freeParsedArguments(&pa);
1989 return;
1990 }
1991
1992 /* convert to enum but handling LINE special */
1993 enum gf_en gf = (enum gf_en) -1;
1994
1995 gf = gf_conv(cmd);
1996 if ((int) gf == -1) {
1997 if (strncmp("LINE", cmd, 4) == 0) {
1998 gf = GF_LINE;
1999 addToArguments(&pa, NULL, "linewidth", cmd + 4, 0);
2000 } else {
2001 rrd_set_error("'%s' is not a valid function name in %s", cmd,
2002 pa.arg_orig);
2003 return;
2004 }
2005 }
2006 /* now we can handle the commands */
2007 int r = 0;
2008
2009 switch (gf) {
2010 case GF_XAXIS:
2011 r = parse_axis(gf, &pa, im);
2012 break;
2013 case GF_YAXIS:
2014 r = parse_axis(gf, &pa, im);
2015 break;
2016 case GF_DEF:
2017 r = parse_def(gf, &pa, im);
2018 break;
2019 case GF_CDEF:
2020 r = parse_cvdef(gf, &pa, im);
2021 break;
2022 case GF_VDEF:
2023 r = parse_cvdef(gf, &pa, im);
2024 break;
2025 case GF_LINE:
2026 r = parse_line(gf, &pa, im);
2027 break;
2028 case GF_AREA:
2029 r = parse_area(gf, &pa, im);
2030 break;
2031 case GF_PRINT:
2032 r = parse_gprint(gf, &pa, im);
2033 break;
2034 case GF_GPRINT:
2035 r = parse_gprint(gf, &pa, im);
2036 break;
2037 case GF_COMMENT:
2038 r = parse_comment(gf, &pa, im);
2039 break;
2040 case GF_HRULE:
2041 r = parse_hvrule(gf, &pa, im);
2042 break;
2043 case GF_VRULE:
2044 r = parse_hvrule(gf, &pa, im);
2045 break;
2046 case GF_STACK:
2047 r = parse_stack(gf, &pa, im);
2048 break;
2049 case GF_TICK:
2050 r = parse_tick(gf, &pa, im);
2051 break;
2052 case GF_TEXTALIGN:
2053 r = parse_textalign(gf, &pa, im);
2054 break;
2055 case GF_SHIFT:
2056 r = parse_shift(gf, &pa, im);
2057 break;
2058 case GF_XPORT:
2059 r = parse_xport(gf, &pa, im);
2060 break;
2061 /* unsupported types right now */
2062 }
2063 /* handle the return error case */
2064 if (r) {
2065 freeParsedArguments(&pa);
2066 return;
2067 }
2068 /* check for unprocessed keyvalue args */
2069 char *s;
2070
2071 if ((s = checkUnusedValues(&pa))) {
2072 /* set error message */
2073 rrd_set_error("Unused Arguments \"%s\" in command : %s", s,
2074 pa.arg_orig);
2075 free(s);
2076 /* exit early */
2077 freeParsedArguments(&pa);
2078 return;
2079 }
6465207c 2080 }
1ace8365
TO
2081 /* finally free arguments */
2082 freeParsedArguments(&pa);
6465207c 2083}