]> git.ipfire.org Git - thirdparty/rrdtool-1.x.git/blame - src/rrd_graph_helper.c
New rrd_update switch --skip-past-updates
[thirdparty/rrdtool-1.x.git] / src / rrd_graph_helper.c
CommitLineData
0516711e 1/****************************************************************************
36400d5b 2 * RRDtool 1.4.3 Copyright by Tobi Oetiker, 1997-2010
0516711e
TO
3 ****************************************************************************
4 * rrd_graph_helper.c commandline parser functions
054f4ff3 5 * this code initially written by Alex van den Bogaerdt
0516711e
TO
6 ****************************************************************************/
7
adb27eb6 8#include "rrd_graph.h"
1ace8365
TO
9#define dprintf(...) if (gdp->debug&1) fprintf(stderr,__VA_ARGS__);
10#define dprintfparsed(...) if (gdp->debug&2) fprintf(stderr,__VA_ARGS__);
11
12void initParsedArguments(parsedargs_t* pa) {
13 /* initialize */
14 pa->arg=NULL;
15 pa->arg_orig=NULL;
16 pa->kv_args=NULL;
17 pa->kv_cnt=0;
6465207c 18}
adb27eb6 19
1ace8365
TO
20void freeParsedArguments(parsedargs_t* pa) {
21 if (pa->arg) {free(pa->arg);}
22 if (pa->kv_args) {free(pa->kv_args);}
23 initParsedArguments(pa);
24}
6465207c 25
1ace8365
TO
26void dumpKeyValue(char* pre,keyvalue_t* t) {
27 if (t) {
28 fprintf(stderr,"%s%i: '%s' = '%s' %i\n",
29 pre,
30 t->pos,
31 t->key,
32 t->value,
33 t->flag
34 );
35 } else {
36 fprintf(stderr,"%sNULL\n",pre);
37 }
38}
6465207c 39
1ace8365
TO
40void dumpArguments(parsedargs_t* pa) {
41 fprintf(stderr,"====================\nParsed Arguments of: %s\n",pa->arg_orig);
42 for(int i=0;i<pa->kv_cnt;i++) {
43 dumpKeyValue(" ",&(pa->kv_args[i]));
44 }
45 fprintf(stderr,"---------------\n");
46}
3da125e9 47
1ace8365
TO
48char* getKeyValueArgument(const char* key,int flag, parsedargs_t* pa) {
49 /* we count backwords for "overwrites" */
50 for(int i=pa->kv_cnt-1;i>=0;i--) {
51 char* akey=(pa->kv_args[i]).key;
52 if (strcmp(akey,key)==0) {
53 /* set flag */
54 if (flag) {pa->kv_args[i].flag=flag;}
55 /* return value */
56 return pa->kv_args[i].value;
adb27eb6 57 }
1ace8365
TO
58 }
59 return NULL;
6465207c
AB
60}
61
1ace8365
TO
62keyvalue_t* getFirstUnusedArgument(int flag, parsedargs_t* pa) {
63 for(int i=0;i<pa->kv_cnt;i++) {
64 if (! pa->kv_args[i].flag) {
65 pa->kv_args[i].flag=flag;
66 return &(pa->kv_args[i]);
18cadd88 67 }
1ace8365
TO
68 }
69 return NULL;
6465207c
AB
70}
71
1ace8365
TO
72char* checkUnusedValues(parsedargs_t* pa){
73 char *res=NULL;
74 for(int i=0;i<pa->kv_cnt;i++) {
75 if (!pa->kv_args[i].flag) {
ef7231f1
TO
76 const size_t klen = strlen(pa->kv_args[i].key);
77 const size_t vlen = strlen(pa->kv_args[i].value);
78 const size_t len = res ? strlen(res) : 0;
79
80 char *t = realloc(res,len + 3 + klen + vlen);
1ace8365
TO
81 if (! t) { return res; }
82 res=t;
ef7231f1 83 strncat(res,pa->kv_args[i].key, klen);
1ace8365 84 strcat(res,"=");
ef7231f1 85 strncat(res,pa->kv_args[i].value, vlen);
1ace8365 86 strcat(res,":");
6465207c 87 }
1ace8365
TO
88 }
89 /* if we got one, then strip the final : */
90 if (res) { res[strlen(res)-1]=0; }
91 /* and return res */
92 return res;
93}
adb27eb6 94
1ace8365
TO
95int getMappedKeyValueArgument(const char* key,int flag, parsedargs_t* pa,
96 int* val,keyint_t** transpose) {
97 /* get the value itself as string */
98 char* v=getKeyValueArgument(key,flag,pa);
99 /* now try to parse the value */
100 if (v) {
101 for(;(*transpose)->key;transpose++) {
102 if (strcmp((*transpose)->key,v)==0) {
103 *val=(*transpose)->value;
104 return 0;
105 }
6465207c 106 }
1ace8365
TO
107 }
108 /* not found, so return error */
109 return 1;
6465207c
AB
110}
111
1ace8365
TO
112int getLong(const char* v,long *val,char**extra,int base) {
113 /* try to execute the parser */
114 /* NOTE that this may be a bit different from the original parser */
115 *extra=NULL;
116 *val=strtol(v,extra,base);
117 /* and error handling */
118 if (extra==NULL) {
119 return 0;
120 } else {
121 if (*extra==v) {
122 return -1; /* failed miserably */
123 } else {
124 if ((*extra)[0]==0) { return 0; }
125 return 1; /* got extra bytes */
7d0bd260 126 }
1ace8365
TO
127 }
128 /* not found, so return error */
129 return -2;
130}
131
132int getDouble(const char* v, double *val,char**extra) {
133 /* try to execute the parser */
134 /* NOTE that this may be a bit different from the original parser */
135 *extra=NULL;
136 *val=strtod(v,extra);
137 /* and error handling */
138 if (extra==NULL) {
139 return 0;
140 } else {
141 if (*extra==v) {
142 return -1; /* failed miserably */
143 } else {
144 if ((*extra)[0]==0) { return 0; }
145 return 1; /* got extra bytes */
6465207c 146 }
1ace8365
TO
147 }
148 /* not found, so return error */
149 return -2;
7d0bd260
TO
150}
151
1ace8365
TO
152int addToArguments(parsedargs_t* pa, char*key, char*value, int cnt) {
153 /* resize the field */
154 keyvalue_t* t=realloc(pa->kv_args,(pa->kv_cnt+1)*sizeof(keyvalue_t));
155 if (!t) {
156 rrd_set_error("could not realloc memory");
157 return -1;
158 } else {
159 /* assign pointer */
160 pa->kv_args=t;
161 }
162 /* fill in data */
163 pa->kv_args[pa->kv_cnt].key=key;
164 pa->kv_args[pa->kv_cnt].value=value;
165 pa->kv_args[pa->kv_cnt].pos=cnt;
166 pa->kv_args[pa->kv_cnt].flag=0;
167 pa->kv_cnt++;
168 /* and return ok */
169 return 0;
170}
18cadd88 171
1ace8365
TO
172char *poskeys[]={"pos0","pos1","pos2","pos3","pos4","pos5","pos6","pos7","pos8","pos9"};
173int parseArguments(const char* origarg, parsedargs_t* pa) {
174 initParsedArguments(pa);
175 /* now assign a copy */
176 pa->arg=strdup(origarg);
177 if (!pa->arg) { rrd_set_error("Could not allocate memory");return -1; }
178 pa->arg_orig=origarg;
179
180 /* first split arg into : */
181 char last=1;
182 char c;
183 int cnt=0;
184 int poscnt=0;
185 char* pos=pa->arg;
186 char* field=pos;
187 do {
188 c=*pos;
189 if (! field) { field=pos;cnt++;}
190 switch (c) {
191 /* if the char is a backslash, then this escapes the next one */
192 case '\\':
193 if (pos[1]) { pos++; }
194 break;
195 case 0:
196 case ':':
197 /* null and : separate the string */
198 *pos=0;
199 /* handle the case where we have got an = */
200 /* find equal sign */
201 char* equal=field;
202 for (equal=field;(*equal)&&(*equal!='=');equal++) { ; }
203 /* if we are on position 1 then check for position 0 to be [CV]?DEV */
204 int checkforkeyvalue=1;
205 /* nw define key to use */
206 char *key,*value;
207 if ((*equal=='=') && (checkforkeyvalue)) {
208 *equal=0;
209 key=field;
210 value=equal+1;
211 } else {
212 if ((poscnt>0)&&(strcmp(field,"STACK")==0)) {
213 key="stack";
214 value="1";
215 } else if ((poscnt>0)&&(strcmp(field,"strftime")==0)) {
216 key="strftime";
217 value="1";
218 } else {
219 if (poscnt>9) {
220 rrd_set_error("too many positional arguments");
221 freeParsedArguments(pa);
222 return -1;
223 }
224 key=poskeys[poscnt];
225 poscnt++;
226 value=field;
227 }
228 }
229 /* do some synonym translations */
230 if (strcmp(key,"label")==0) { key="legend"; }
231 if (strcmp(key,"colour")==0) { key="color"; }
232 if (strcmp(key,"colour2")==0) { key="color2"; }
233
234 /* add to fields */
235 if (addToArguments(pa,key,value,cnt)) {
236 freeParsedArguments(pa);
237 return -1;
238 }
239
240 /* and reset field */
241 field=NULL;
242 break;
18cadd88 243 default:
1ace8365 244 break;
5e01c4f7 245 }
1ace8365
TO
246 /* assign last */
247 last=c;
248 /* and step to next one byte */
249 pos++;
250 } while (c);
251 /* and return OK */
252 return 0;
6465207c
AB
253}
254
1ace8365
TO
255int parse_color( const char *const, struct gfx_color_t *);
256int parse_color( const char *const string, struct gfx_color_t *c)
18cadd88 257{
1ace8365
TO
258 unsigned int r = 0, g = 0, b = 0, a = 0, i;
259
260 /* matches the following formats:
261 ** RGB
262 ** RGBA
263 ** RRGGBB
264 ** RRGGBBAA
265 */
266
267 i = 0;
268 while (string[i] && isxdigit((unsigned int) string[i]))
269 i++;
270 if (string[i] != '\0')
271 return 1; /* garbage follows hexdigits */
272 switch (i) {
273 case 3:
274 case 4:
275 sscanf(string, "%1x%1x%1x%1x", &r, &g, &b, &a);
276 r *= 0x11;
277 g *= 0x11;
278 b *= 0x11;
279 a *= 0x11;
280 if (i == 3)
281 a = 0xFF;
282 break;
283 case 6:
284 case 8:
285 sscanf(string, "%02x%02x%02x%02x", &r, &g, &b, &a);
286 if (i == 6)
287 a = 0xFF;
288 break;
289 default:
290 return 1; /* wrong number of digits */
291 }
292 /* I wonder how/why this works... */
293 *c=gfx_hex_to_col(r << 24 | g << 16 | b << 8 | a);
294 return 0;
295}
7d0bd260 296
1ace8365
TO
297/* this would allow for 240 different values */
298#define PARSE_FIELD1 (1L<<60)
299#define PARSE_FIELD2 (1L<<61)
300#define PARSE_FIELD3 (1L<<62)
301#define PARSE_FIELD4 (1L<<63)
302#define PARSE_POSITIONAL (1L<<59)
303#define PARSE_ONYAXIS (1L<<58)
304#define PARSE_VNAME (PARSE_FIELD1|(1L<< 0))
305#define PARSE_RRD (PARSE_FIELD1|(1L<< 1))
306#define PARSE_DS (PARSE_FIELD1|(1L<< 2))
307#define PARSE_CF (PARSE_FIELD1|(1L<< 3))
308#define PARSE_COLOR (PARSE_FIELD1|(1L<< 4))
309#define PARSE_COLOR2 (PARSE_FIELD1|(1L<< 5))
310#define PARSE_LEGEND (PARSE_FIELD1|(1L<< 6))
311#define PARSE_RPN (PARSE_FIELD1|(1L<< 7))
312#define PARSE_START (PARSE_FIELD1|(1L<< 8))
313#define PARSE_STEP (PARSE_FIELD1|(1L<< 9))
314#define PARSE_END (PARSE_FIELD1|(1L<<10))
315#define PARSE_STACK (PARSE_FIELD1|(1L<<11))
316#define PARSE_LINEWIDTH (PARSE_FIELD1|(1L<<12))
317#define PARSE_XAXIS (PARSE_FIELD1|(1L<<13))
318#define PARSE_YAXIS (PARSE_FIELD1|(1L<<14))
319#define PARSE_REDUCE (PARSE_FIELD1|(1L<<15))
320#define PARSE_DASHES (PARSE_FIELD1|(1L<<20))
321#define PARSE_HEIGHT (PARSE_FIELD1|(1L<<21))
322#define PARSE_FORMAT (PARSE_FIELD1|(1L<<22))
323#define PARSE_STRFTIME (PARSE_FIELD1|(1L<<23))
324#define PARSE_FRACTION (PARSE_FIELD1|(1L<<24))
325/* VNAME Special cases for generic parsing */
326#define PARSE_VNAMEDEF (PARSE_VNAME|(1L<<57))
327#define PARSE_VNAMEREF (PARSE_VNAME|(1L<<56))
328#define PARSE_VNAMEREFNUM (PARSE_VNAMEREF|(1L<<55))
329#define PARSE_VNAMEREFNUMNOPARSE (PARSE_FIELD1|(1L<<54))
330/* special positional cases */
331#define PARSE_VNAMERRDDSCF (PARSE_POSITIONAL|PARSE_VNAMEDEF|PARSE_RRD|PARSE_DS|PARSE_CF)
332#define PARSE_VNAMECOLORLEGEND (PARSE_POSITIONAL|PARSE_VNAMEREFNUM|PARSE_COLOR|PARSE_COLOR2|PARSE_LEGEND)
333#define PARSE_VNAMECOLORFRACTIONLEGEND (PARSE_VNAMECOLORLEGEND|PARSE_FRACTION)
334#define PARSE_VNAMERPN (PARSE_POSITIONAL|PARSE_VNAMEDEF|PARSE_RPN)
335#define PARSE_VNAMEREFPOS (PARSE_POSITIONAL|PARSE_VNAMEREF)
336
337graph_desc_t* newGraphDescription(image_desc_t *const,enum gf_en,parsedargs_t*,unsigned long);
338graph_desc_t* newGraphDescription(image_desc_t *const im,enum gf_en gf,parsedargs_t* pa,unsigned long bits) {
339 /* check that none of the othe bitfield marker is set */
340 if ((bits&PARSE_FIELD1)&&((bits&(PARSE_FIELD2|PARSE_FIELD3|PARSE_FIELD4)))) {
341 rrd_set_error("newGraphDescription: bad bitfield1 value %08x",bits);return NULL; }
342 /* the normal handler that adds to img */
343 if (gdes_alloc(im)) { return NULL; }
344 /* set gdp */
345 graph_desc_t *gdp= &im->gdes[im->gdes_c - 1];
346
347 /* set some generic things */
348 gdp->gf=gf;
349 if (1) {
350 char *t,*x;
351 long debug=0;
352 if ((t=getKeyValueArgument("debug",1,pa)) && ((getLong(t,&debug,&x,10)))) {
353 rrd_set_error("Bad debug value: %s",t); return NULL; }
354 gdp->debug=debug;
355 }
356
357 /* and the "flagged" parser implementation
358 *
359 * first the fields with legacy positional args
360 */
361#define bitscmp(v) ((bits&v)==v)
362 char* vname=NULL;
363 if (bitscmp(PARSE_VNAME)) { vname=getKeyValueArgument("vname",1,pa);
364 dprintfparsed("got vname: %s\n",vname);}
365 char *rrd=NULL;
366 if (bitscmp(PARSE_RRD)) { rrd=getKeyValueArgument("rrd",1,pa);
367 dprintfparsed("got rrd: %s\n",rrd);}
368 char *ds=NULL;
369 if (bitscmp(PARSE_DS)) { ds=getKeyValueArgument("ds",1,pa);
370 dprintfparsed("got ds: %s\n",ds);}
371 char *cf=NULL;
372 if (bitscmp(PARSE_CF)) { cf=getKeyValueArgument("cf",1,pa);
373 dprintfparsed("got cf: %s\n",cf);}
374 char *color=NULL;
375 if (bitscmp(PARSE_COLOR)) { color=getKeyValueArgument("color",1,pa);
376 dprintfparsed("got color: %s\n",color);}
377 char *color2=NULL;
378 if (bitscmp(PARSE_COLOR2)) { color2=getKeyValueArgument("color2",1,pa);
379 dprintfparsed("got color2: %s\n",color2);}
380 char *rpn=NULL;
381 if (bitscmp(PARSE_RPN)) { rpn=getKeyValueArgument("rpn",1,pa);
382 dprintfparsed("got rpn: %s\n",rpn);}
383 char *legend=NULL;
384 if (bitscmp(PARSE_LEGEND)) { legend=getKeyValueArgument("legend",1,pa);
385 dprintfparsed("got legend: %s\n",legend);}
386 char *fraction=NULL;
387 if (bitscmp(PARSE_FRACTION)) { fraction=getKeyValueArgument("fraction",1,pa);
388 dprintfparsed("got fraction: %s\n",fraction);}
389 /*
390 * here the ones without delayed assigns (which are for positional parsers)
391 */
392 if (bitscmp(PARSE_FORMAT)) {
393 char *format=getKeyValueArgument("format",1,pa);
394 if(format) {
395 strncpy(gdp->format,format,FMT_LEG_LEN);
396 dprintfparsed("got format: %s\n",format);
18cadd88 397 }
1ace8365
TO
398 }
399 if (bitscmp(PARSE_STRFTIME)) {
400 char *strft=getKeyValueArgument("strftime",1,pa);
401 gdp->strftm=(strft)?1:0;
402 dprintfparsed("got strftime: %s\n",strft);
403 }
404 if (bitscmp(PARSE_STACK)) {
405 char *stack=getKeyValueArgument("stack",1,pa);
406 gdp->stack=(stack)?1:0;
407 dprintfparsed("got stack: %s\n",stack);
408 }
409 if (bitscmp(PARSE_REDUCE)) {
410 char *reduce=getKeyValueArgument("reduce",1,pa);
411 if (reduce) {
412 gdp->cf_reduce=cf_conv(reduce);
413 dprintfparsed("got reduce: %s (%i)\n",reduce,gdp->cf_reduce);
414 if (((int)gdp->cf_reduce)==-1) { rrd_set_error("bad reduce CF: %s",reduce); return NULL; }
7d0bd260 415 }
1ace8365
TO
416 }
417 if (bitscmp(PARSE_XAXIS)) {
418 long xaxis=0;
419 char *t,*x;
420 if ((t=getKeyValueArgument("xaxis",1,pa)) && ((getLong(t,&xaxis,&x,10))||(xaxis<1)||(xaxis>MAX_AXIS))) {
421 rrd_set_error("Bad xaxis value: %s",t); return NULL; }
422 dprintfparsed("got xaxis: %s (%li)\n",t,xaxis);
423 gdp->xaxisidx=xaxis;
424 }
425 if (bitscmp(PARSE_YAXIS)) {
426 long yaxis=0;
427 char *t,*x;
428 if ((t=getKeyValueArgument("yaxis",1,pa)) && ((getLong(t,&yaxis,&x,10))||(yaxis<1)||(yaxis>MAX_AXIS))) {
429 rrd_set_error("Bad yaxis value: %s",t); return NULL; }
430 dprintfparsed("got yaxis: %s (%li)\n",t,yaxis);
431 gdp->yaxisidx=yaxis;
432 }
433 if (bitscmp(PARSE_LINEWIDTH)) {
434 double linewidth=0;
435 char *t,*x;
436 if ((t=getKeyValueArgument("linewidth",1,pa))&&(*t!=0)) {
437 if ((getDouble(t,&linewidth,&x))||(linewidth<=0)) {
438 rrd_set_error("Bad line width: %s",t); return NULL;
439 }
440 dprintfparsed("got linewidth: %s (%g)\n",t,linewidth);
441 gdp->linewidth=linewidth;
18cadd88 442 }
1ace8365
TO
443 }
444 if (bitscmp(PARSE_HEIGHT)) {
445 double height=0;
446 char *t,*x;
447 if ((t=getKeyValueArgument("height",1,pa))&&(*t!=0)) {
448 if (getDouble(t,&height,&x)) {
449 rrd_set_error("Bad height: %s",t); return NULL;
450 }
451 dprintfparsed("got height: %s (%g)\n",t,height);
452 gdp->gradheight=height;
01496ecb 453 }
1ace8365
TO
454 }
455 if (bitscmp(PARSE_STEP)) {
456 long step=0;
457 char *t,*x;
458 if ((t=getKeyValueArgument("step",1,pa)) && ((getLong(t,&step,&x,10))||(step<1))) {
459 rrd_set_error("Bad step value: %s",t); return NULL; }
460 dprintfparsed("got step: %s (%li)\n",t,step);
461 gdp->step=step;
462 }
463 if ((bitscmp(PARSE_START)||bitscmp(PARSE_END))) {
464 /* these should get done together to use the start/end code correctly*/
465 char* parsetime_error;
466 /* first start */
467 char* start;
468 rrd_time_value_t start_tv;
469 start_tv.type = ABSOLUTE_TIME;
470 start_tv.offset = 0;
471 localtime_r(&gdp->start, &start_tv.tm);
472 if (bitscmp(PARSE_START)) {
473 start=getKeyValueArgument("start",1,pa);
474 if ((start)&&(parsetime_error = rrd_parsetime(start, &start_tv))) {
475 rrd_set_error("start time: %s", parsetime_error);return NULL; }
476 dprintfparsed("got start: %s\n",start);
15dbcb6e 477 }
1ace8365
TO
478 /* now end */
479 char* end;
480 rrd_time_value_t end_tv;
481 end_tv.type = ABSOLUTE_TIME;
482 end_tv.offset = 0;
483 localtime_r(&gdp->end, &end_tv.tm);
484 if (bitscmp(PARSE_END)) {
485 end=getKeyValueArgument("end",1,pa);
486 if ((end)&&(parsetime_error = rrd_parsetime(end, &end_tv))) {
487 rrd_set_error("end time: %s", parsetime_error); return NULL; }
488 dprintfparsed("got end: %s\n",end);
2cbe4e85 489 }
1ace8365
TO
490 /* and now put the pieces together (relative times like start=end-2days) */
491 time_t start_tmp = 0, end_tmp = 0;
492 if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) {
493 return NULL;
6465207c 494 }
1ace8365
TO
495 dprintfparsed("got start %s translated to: %lld\n",start,(long long int)start_tmp);
496 dprintfparsed("got end %s translated to: %lld\n",end,(long long int)end_tmp);
497
498 /* check some ranges */
499 if (start_tmp < 3600 * 24 * 365 * 10) {
500 rrd_set_error("the first entry to fetch should be "
501 "after 1980 (%ld)", start_tmp);
502 return NULL; }
503 if (end_tmp < start_tmp) {
504 rrd_set_error("start (%ld) should be less than end (%ld)",
505 start_tmp, end_tmp);
506 return NULL; }
58e13ed8 507
1ace8365
TO
508 /* and finally set it irrespectively of if it has been set or not
509 * it may have been a relative time and if you just set it partially
510 * then that is wrong...
511 */
512 gdp->start = start_tmp;
513 gdp->start_orig = start_tmp;
514 gdp->end = end_tmp;
515 gdp->end_orig = end_tmp;
516 }
517 if (bitscmp(PARSE_DASHES)) {
518 char* dashes=getKeyValueArgument("dashes",1,pa);
519 /* if we got dashes */
520 if (dashes) {
521 gdp->offset = 0;
522 /* count the , in dashes */
523 int cnt=0;for(char*t=dashes;(*t)&&(t=strchr(t,','));t++,cnt++) {;}
524 dprintfparsed("Got dashes argument: %s with %i comma\n",dashes,cnt);
525 /* now handle */
526 gdp->ndash = cnt+1;
527 gdp->p_dashes = (double *) malloc(sizeof(double)*(gdp->ndash+1));
528 /* now loop dashes */
529 for(int i=0;i<gdp->ndash;i++) {
530 char *x;
531 int f=getDouble(dashes,&gdp->p_dashes[i],&x);
532 if(f<0) {
533 rrd_set_error("Could not parse number: %s",dashes); return NULL;
58e13ed8 534 }
1ace8365
TO
535 /* we should have this most of the time */
536 dprintfparsed("Processed %s to %g at index %i\n",dashes,gdp->p_dashes[i],i);
537 if (f>0) {
538 if (*x!=',') {
539 rrd_set_error("expected a ',' at : %s",x); return NULL;}
540 dashes=x+1;
541 }
542 if ((f==0)&&(i!=gdp->ndash-1)) {
543 rrd_set_error("unexpected end at : %s",dashes); return NULL;}
544 }
6465207c 545 }
1ace8365
TO
546 char* dashoffset=getKeyValueArgument("dash-offset",1,pa);
547 if (dashoffset) {
548 char* x;
549 if (getDouble(dashes,&gdp->offset,&x)) {
550 rrd_set_error("Could not parse dash-offset: %s",dashoffset); return NULL; }
6465207c 551 }
1ace8365
TO
552 }
553
554 /* here now the positional(=legacy) parsers which are EXCLUSIVE - SO ELSE IF !!!
555 * we also only parse the extra here and assign just further down
556 * TODO maybe we can generalize this a bit more...
557 */
558 if (bitscmp(PARSE_VNAMERRDDSCF)) {
559 if ((!vname)||(!rrd)) {
560 /* get the first unused argument */
561 keyvalue_t* first=getFirstUnusedArgument(1,pa);
562 if (!first) { rrd_set_error("No argument for definition of vdef/rrd in %s",pa->arg_orig); return NULL; }
563 dprintfparsed("got positional vname and rrd: %s - %s\n",first->key,first->value);
564 if (!vname) {vname=first->key;}
565 if (!rrd) {rrd=first->value; }
6465207c 566 }
1ace8365
TO
567 /* and now look for datasource */
568 if (!ds) {
569 /* get the first unused argument */
570 keyvalue_t* first=getFirstUnusedArgument(1,pa);
571 if (!first) { rrd_set_error("No argument for definition of DS in %s",pa->arg_orig); return NULL; }
572 dprintfparsed("got positional ds: %s - \n",first->value);
573 ds=first->value;
3da125e9 574 }
1ace8365
TO
575 /* and for CF */
576 if (!cf) {
577 /* get the first unused argument */
578 keyvalue_t* first=getFirstUnusedArgument(1,pa);
579 if (!first) { rrd_set_error("No argument for definition of CF in %s",pa->arg_orig); return NULL; }
580 dprintfparsed("got positional cf: %s - \n",first->value);
581 cf=first->value;
582 }
583 } else if (bitscmp(PARSE_VNAMECOLORLEGEND)) {
584 /* vname */
585 if (!vname) {
586 keyvalue_t* first=getFirstUnusedArgument(1,pa);
587 if (first) { vname=first->value;
588 } else { rrd_set_error("No positional VNAME"); return NULL; }
3da125e9 589 }
1ace8365
TO
590 /* fraction added into the parsing mix for TICK */
591 if ((bitscmp(PARSE_VNAMECOLORFRACTIONLEGEND))&&(!fraction)) {
592 keyvalue_t* first=getFirstUnusedArgument(1,pa);
593 if (first) { fraction=first->value;
594 } else { rrd_set_error("No positional FRACTION"); return NULL; }
595 }
596 /* legend */
597 if (!legend) {
598 keyvalue_t* first=getFirstUnusedArgument(1,pa);
599 if (first) { legend=first->value;
600 dprintfparsed("got positional legend: %s - \n",first->value);
601 } else { rrd_set_error("No positional legend found"); return NULL; }
6465207c 602 }
1ace8365
TO
603 } else if (bitscmp(PARSE_VNAMERPN)) {
604 if ((!vname)||(!rpn)) {
605 /* get the first unused argument */
606 keyvalue_t* first=getFirstUnusedArgument(1,pa);
607 if (!first) { rrd_set_error("No argument for definition of vdef/rrd in %s",pa->arg_orig); return NULL; }
608 dprintfparsed("got positional vname and rpn: %s - %s\n",first->key,first->value);
609 if (!vname) {vname=first->key;}
610 if (!rpn) {rpn=first->value; }
3da125e9 611 }
1ace8365
TO
612 } else if (bitscmp(PARSE_VNAMEREFPOS)) {
613 if ((!vname)) {
614 /* get the first unused argument */
615 keyvalue_t* first=getFirstUnusedArgument(1,pa);
616 if (!first) { rrd_set_error("No argument for definition of vdef/rrd in %s",pa->arg_orig); return NULL; }
617 dprintfparsed("got positional vname and rrd: %s - %s\n",first->key,first->value);
618 if (!vname) {vname=first->value;}
c79bd073 619 }
1ace8365
TO
620 }
621
622 /* and set some of those late assignments to accomodate the legacy parser*/
623 /* first split vname into color */
624 if (vname) {
625 /* check for color */
626 char *h1=strchr(vname,'#');
627 char* h2=NULL;
628 if (h1) {
629 *h1=0;h1++;
630 dprintfparsed("got positional color: %s - \n",h1);
631 h2=strchr(h1,'#');
632 if (h2) {
633 *h2=0;h2++;
634 dprintfparsed("got positional color2: %s - \n",h2);
635 }
636 }
637 if (bitscmp(PARSE_COLOR) && (! color) && (h1)) { color=h1;}
638 if (bitscmp(PARSE_COLOR2) && (! color2) && (h2)) { color2=h2;}
639 }
640
641 /* check if we are reusing the vname */
642 if (vname) {
643 int idx=find_var(im, vname);
644 dprintfparsed("got positional index %i for %s - \n",idx,vname);
645
646 /* some handling */
647 if (bitscmp(PARSE_VNAMEDEF)) {
648 if (idx>=0) {
649 rrd_set_error("trying to reuse vname %s",vname); return NULL; }
650 } else if (bitscmp(PARSE_VNAMEREF)) {
651 if (idx>=0) {
652 gdp->vidx=idx;
653 } else if (bitscmp(PARSE_VNAMEREFNUM)) {
654 if (!bitscmp(PARSE_VNAMEREFNUMNOPARSE)) {
655 double val;
656 char *x;
657 int f=getDouble(vname,&val,&x);
658 if (f) {
659 rrd_set_error("error parsing number %s",vname); return NULL;
660 }
661 gdp->yrule=val;
662 } else {
663 rrd_set_error("vname %s not found",vname); return NULL;
664 }
665 } else {
666 gdp->vidx=-1;
667 }
18cadd88 668 }
1ace8365
TO
669 }
670
671 /* and assign it */
672 if (vname) { strncpy(gdp->vname,vname,MAX_VNAME_LEN + 1); }
673 if (rrd) { strncpy(gdp->rrd,rrd,1024); }
674 if (ds) { strncpy(gdp->ds_nam,ds,DS_NAM_SIZE); }
675 if (cf) {
676 gdp->cf=cf_conv(cf);
677 if (((int)gdp->cf)==-1) {
678 rrd_set_error("bad CF: %s",cf); return NULL; }
679 } else { if (bitscmp(PARSE_CF)) {gdp->cf=-1;}}
680 if ((color)&&(parse_color(color,&(gdp->col)))) { return NULL; }
681 if ((color2)&&(parse_color(color2,&(gdp->col2)))) { return NULL; }
682 if (rpn) {gdp->rpn=rpn;}
683 if ((legend)&&(*legend!=0)) {
684 /* some spacing before we really start with the legend - needed for some reason */
685 char* t=gdp->legend;
686 *t=' ';t++;
687 *t=' ';t++;
688 /* and copy it into place */
689 strncpy(t,legend,FMT_LEG_LEN);
690 }
691 if (fraction) {
692 if (strcmp(fraction,"vname")==0) {
693 /* check that vname is really a DEF|CDEF */
694 if (im->gdes[gdp->vidx].gf != GF_DEF && im->gdes[gdp->vidx].gf != GF_CDEF) {
695 rrd_set_error("variable '%s' not DEF nor CDEF when using dynamic fractions", gdp->vname);
696 return NULL;
697 }
698 /* add as flag to use (c)?def */
699 gdp->cf=CF_LAST;
700 gdp->yrule=0.5;
701 } else {
702 /* parse number */
703 double val;
704 char *x;
705 int f=getDouble(fraction,&val,&x);
706 if (f) {
707 rrd_set_error("error parsing number %s",vname); return NULL;
708 }
709 gdp->yrule=val;
3da125e9 710 }
1ace8365
TO
711 }
712 /* and return it */
713 return gdp;
6465207c
AB
714}
715
1ace8365
TO
716/* and some defines */
717#define set_match(str,pat,cmd) if (strcmp(pat, str) == 0) { cmd ;}
718
719/* prototypes */
720int parse_axis(enum gf_en,parsedargs_t*,image_desc_t *const);
721int parse_def(enum gf_en,parsedargs_t*,image_desc_t *const);
722int parse_cvdef(enum gf_en,parsedargs_t*,image_desc_t *const);
723int parse_line(enum gf_en,parsedargs_t*,image_desc_t *const);
724int parse_area(enum gf_en,parsedargs_t*,image_desc_t *const);
725int parse_stack(enum gf_en,parsedargs_t*,image_desc_t *const);
726int parse_print(enum gf_en,parsedargs_t*,image_desc_t *const);
727int parse_gprint(enum gf_en,parsedargs_t*,image_desc_t *const);
728int parse_comment(enum gf_en,parsedargs_t*,image_desc_t *const);
729int parse_hvrule(enum gf_en,parsedargs_t*,image_desc_t *const);
730int parse_grad(enum gf_en,parsedargs_t*,image_desc_t *const);
731int parse_tick(enum gf_en,parsedargs_t*,image_desc_t *const);
732int parse_textalign(enum gf_en,parsedargs_t*,image_desc_t *const);
733int parse_shift(enum gf_en,parsedargs_t*,image_desc_t *const);
734int parse_xport(enum gf_en,parsedargs_t*,image_desc_t *const);
735
736/* implementations */
737int parse_axis(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im){
738#if 0
739 /* define X or y axis */
740 axis_t *a=im->xaxis;
741 if (gf == GF_YAXIS) { a=im->yaxis; }
742 /* try to parse the number */
743 char* cmd=getKeyValueArgument("cmd",1,pa);
744 if (cmd[5]) {
745 int num=atoi(cmd+5);
746 if ((num<1)||(num>MAX_AXIS)) {
747 rrd_set_error("invalid axis ID %i in %s - should be in range [1:%i]",num,cmd,MAX_AXIS);
748 return 1;
d2dadad0 749 }
1ace8365
TO
750 /* and forward by that much */
751 a=a+(num-1);
752 }
753
754 /* and set type */
755 char* t=getKeyValueArgument("type",1,pa);
756 if (t) {
757 set_match(t,"TIME",a->type=AXIS_TYPE_TIME)
758 else
759 set_match(t,"LINEAR",a->type=AXIS_TYPE_LINEAR)
760 else
761 set_match(t,"LOGARITHMIC",a->type=AXIS_TYPE_LOGARITHMIC)
762 else {
763 rrd_set_error("unsupported axis type %s",t);
764 return 1;
765 }
766 }
767 /* and other stuff */
768 a->bounds.lowertxt=getKeyValueArgument("min",1,pa);
769 a->bounds.uppertxt=getKeyValueArgument("max",1,pa);
770#endif
771 /* and return */
772 return 0;
773}
adb27eb6 774
1ace8365
TO
775int parse_def(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im){
776 /* get new graph that we fill */
777 graph_desc_t *gdp=newGraphDescription(im,gf,pa,
778 PARSE_VNAMERRDDSCF
779 |PARSE_START
780 |PARSE_STEP
781 |PARSE_END
782 |PARSE_REDUCE
783 );
784 if (!gdp) { return -1;}
785
786 /* debugging output */
787 dprintf("=================================\n");
788 dprintf("DEF : %s\n",pa->arg_orig);
789 dprintf("VNAME : %s\n",gdp->vname);
790 dprintf("RRD : %s\n",gdp->rrd);
791 dprintf("DS : %s\n",gdp->ds_nam);
792 dprintf("CF : %i\n",gdp->cf);
793 dprintf("START : (%lld)\n",(long long int)gdp->start);
794 dprintf("STEP : (%lld)\n",(long long int)gdp->step);
795 dprintf("END : (%lld)\n",(long long int)gdp->end);
796 dprintf("REDUCE: (%i)\n",gdp->cf_reduce);
797 dprintf("=================================\n");
798
799 /* and return fine */
800 return 0;
801}
802
803int parse_cvdef(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im){
804 /* get new graph that we fill */
805 graph_desc_t *gdp=newGraphDescription(im,gf,pa,
806 PARSE_VNAMERPN
807 );
808 if (!gdp) { return -1;}
809
810 /* handle RPN parsing */
811 if (gf==GF_CDEF) {
812 /* parse rpn */
813 if ((gdp->rpnp= rpn_parse((void *) im, gdp->rpn, &find_var_wrapper)) == NULL) {
814 return -1; }
815 } else {
816 /* parse vdef, as vdef_parse is a bit "stupid" right now we have to touch things here */
817 /* so find first , */
818 char*c=strchr(gdp->rpn,',');
819 if (! c) { rrd_set_error("Comma expected in VDEF definition %s",gdp->rpn); return -1;}
820 /* found a comma, so copy the first part to ds_name (re/abusing it) */
821 *c=0;
822 strncpy(gdp->ds_nam,gdp->rpn,DS_NAM_SIZE);
823 *c=',';
824 /* trying to find the vidx for that name */
825 gdp->vidx = find_var(im, gdp->ds_nam);
826 if (gdp->vidx<0) { *c=',';
827 rrd_set_error("Not a valid vname: %s in line %s", gdp->ds_nam, gdp->rpn);
828 return -1;}
829 if (im->gdes[gdp->vidx].gf != GF_DEF && im->gdes[gdp->vidx].gf != GF_CDEF) {
830 rrd_set_error("variable '%s' not DEF nor "
831 "CDEF in VDEF '%s'", gdp->ds_nam, gdp->rpn);
832 return 1;
6465207c 833 }
1ace8365
TO
834 /* and parsing the rpn */
835 int r=vdef_parse(gdp, c+1);
836 /* original code does not check here for some reason */
837 if (r) { return -1; }
838 }
839
840 /* debugging output */
841 dprintf("=================================\n");
842 if (gf==GF_CDEF) {
843 dprintf("CDEF : %s\n",pa->arg_orig);
844 } else {
845 dprintf("VDEF : %s\n",pa->arg_orig);
846 }
847 dprintf("VNAME : %s\n",gdp->vname);
848 dprintf("RPN : %s\n",gdp->rpn);
849 dprintf("=================================\n");
850
851 /* and return fine */
852 return 0;
853}
854
855
856int parse_line(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im){
857 /* get new graph that we fill */
858 graph_desc_t *gdp=newGraphDescription(im,gf,pa,
859 PARSE_VNAMECOLORLEGEND
860 |PARSE_STACK
861 |PARSE_LINEWIDTH
862 |PARSE_DASHES
863 |PARSE_XAXIS
864 |PARSE_YAXIS
865 );
866 if (!gdp) { return -1;}
867
868 /* debug output */
869 dprintf("=================================\n");
870 dprintf("LINE : %s\n",pa->arg_orig);
871 if (gdp->vidx<0) {
872 dprintf("VAL : %g\n",gdp->yrule);
873 } else {
874 dprintf("VNAME : %s (%li)\n",gdp->vname,gdp->vidx);
875 }
876 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
877 gdp->col.red,gdp->col.green,gdp->col.blue,gdp->col.alpha);
878 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
879 gdp->col2.red,gdp->col2.green,gdp->col2.blue,gdp->col2.alpha);
880 dprintf("LEGEND: %s\n",gdp->legend);
881 dprintf("STACK : %i\n",gdp->stack);
882 dprintf("WIDTH : %g\n",gdp->linewidth);
883 dprintf("XAXIS : %i\n",gdp->xaxisidx);
884 dprintf("YAXIS : %i\n",gdp->yaxisidx);
885 if (gdp->ndash) {
886 dprintf("DASHES: %i - %g",gdp->ndash,gdp->p_dashes[0]);
887 for(int i=1;i<gdp->ndash;i++){dprintf(", %g",gdp->p_dashes[i]);}
888 dprintf("\n");
889 }
890 dprintf("=================================\n");
891
892 /* and return fine */
893 return 0;
adb27eb6
AB
894}
895
1ace8365
TO
896int parse_area(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im){
897 /* get new graph that we fill */
898 graph_desc_t *gdp=newGraphDescription(im,gf,pa,
899 PARSE_VNAMECOLORLEGEND
900 |PARSE_STACK
901 |PARSE_XAXIS
902 |PARSE_YAXIS
903 |PARSE_HEIGHT
904 );
905 if (!gdp) { return -1;}
906
907 /* debug output */
908 dprintf("=================================\n");
909 dprintf("AREA : %s\n",pa->arg_orig);
910 if (gdp->vidx<0) {
911 dprintf("VAL : %g\n",gdp->yrule);
912 } else {
913 dprintf("VNAME : %s (%li)\n",gdp->vname,gdp->vidx);
914 }
915 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
916 gdp->col.red,gdp->col.green,gdp->col.blue,gdp->col.alpha);
917 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
918 gdp->col2.red,gdp->col2.green,gdp->col2.blue,gdp->col2.alpha);
919 dprintf("LEGEND: %s\n",gdp->legend);
920 dprintf("STACK : %i\n",gdp->stack);
921 dprintf("XAXIS : %i\n",gdp->xaxisidx);
922 dprintf("YAXIS : %i\n",gdp->yaxisidx);
923 dprintf("=================================\n");
924
925 /* and return fine */
926 return 0;
927}
6465207c 928
1ace8365
TO
929int parse_stack(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im){
930 /* get new graph that we fill */
931 graph_desc_t *gdp=newGraphDescription(im,gf,pa,
932 PARSE_VNAMECOLORLEGEND
933 |PARSE_XAXIS
934 |PARSE_YAXIS
935 );
936 if (!gdp) { return -1;}
937 gdp->stack=1;
938 /* and try to get the one index before ourselves */
939 long i;
940 for (i=im->gdes_c;(gdp->gf==gf)&&(i>=0);i--) {
941 dprintfparsed("trying to process entry %li with type %u\n",i,im->gdes[i].gf);
942 switch (im->gdes[i].gf) {
943 case GF_LINE:
944 case GF_AREA:
945 gdp->gf=im->gdes[i].gf;
946 gdp->linewidth=im->gdes[i].linewidth;
947 dprintfparsed("found matching LINE/AREA at %li with type %u\n",i,im->gdes[i].gf);
948 break;
949 default: break;
6465207c 950 }
1ace8365
TO
951 }
952 /* error the unhandled */
953 if (gdp->gf==gf) {
954 rrd_set_error("No previous LINE or AREA found for %s",pa->arg_orig); return -1;}
955
956 /* debug output */
957 dprintf("=================================\n");
958 dprintf("STACK : %s\n",pa->arg_orig);
959 if (gdp->vidx<0) {
960 dprintf("VAL : %g\n",gdp->yrule);
961 } else {
962 dprintf("VNAME : %s (%li)\n",gdp->vname,gdp->vidx);
963 }
964 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
965 gdp->col.red,gdp->col.green,gdp->col.blue,gdp->col.alpha);
966 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
967 gdp->col2.red,gdp->col2.green,gdp->col2.blue,gdp->col2.alpha);
968 dprintf("LEGEND: %s\n",gdp->legend);
969 dprintf("STACK : %i\n",gdp->stack);
970 dprintf("WIDTH : %g\n",gdp->linewidth);
971 dprintf("XAXIS : %i\n",gdp->xaxisidx);
972 dprintf("YAXIS : %i\n",gdp->yaxisidx);
973 dprintf("DASHES: TODI\n");
974 dprintf("=================================\n");
975
976 /* and return fine */
977 return 0;
978}
6465207c 979
1ace8365
TO
980int parse_hvrule(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im){
981 /* get new graph that we fill */
982 graph_desc_t *gdp=newGraphDescription(im,gf,pa,
983 PARSE_VNAMECOLORLEGEND
984 |PARSE_VNAMEREFNUMNOPARSE
985 |PARSE_XAXIS
986 |PARSE_YAXIS
987 |PARSE_DASHES
988 );
989 if (!gdp) { return -1;}
990
991 /* check that vidx is of type VDEF */
992 if (im->gdes[gdp->vidx].gf != GF_VDEF) {
993 rrd_set_error("Using vname %s of wrong type in line %s\n",
994 gdp->vname,pa->arg_orig);
995 return -1;
996 }
997
998 /* and here we place number parsing - depends on axis in the long-run*/
999 if (gdp->vidx<0) {
1000 rrd_set_error("TODO: NOT SUPPORTED: Need to add number handler here for %s\n",
1001 gdp->vname); return -1;
1002 /* depending on axis type this is either number or time
1003 essentially becoming generic when we get axis support
1004 */
1005 }
1006
1007 /* debug output */
1008 dprintf("=================================\n");
1009 if (gf==GF_VRULE) {
1010 dprintf("VRULE : %s\n",pa->arg_orig);
1011 } else {
1012 dprintf("HRULE : %s\n",pa->arg_orig);
1013 }
1014 if (gdp->vidx<0) {
1015 if (gf==GF_VRULE) {
1016 dprintf("VAL : %g\n",gdp->yrule);
1017 } else {
1018 dprintf("VAL : %g\n",gdp->yrule);
1019 }
1020 } else {
1021 dprintf("VNAME : %s (%li)\n",gdp->vname,gdp->vidx);
1022 }
1023 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1024 gdp->col.red,gdp->col.green,gdp->col.blue,gdp->col.alpha);
1025 dprintf("COLOR2: r=%g g=%g b=%g a=%g\n",
1026 gdp->col2.red,gdp->col2.green,gdp->col2.blue,gdp->col2.alpha);
1027 dprintf("LEGEND: %s\n",gdp->legend);
1028 dprintf("DASHES: TODO\n");
1029 dprintf("XAXIS : %i\n",gdp->xaxisidx);
1030 dprintf("YAXIS : %i\n",gdp->yaxisidx);
1031 dprintf("=================================\n");
1032
1033 /* and return fine */
1034 return 0;
1035}
6465207c 1036
1ace8365
TO
1037int parse_gprint(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im) {
1038 /* get new graph that we fill */
1039 graph_desc_t *gdp=newGraphDescription(im,gf,pa,
1040 PARSE_VNAMEREF
1041 |PARSE_CF
1042 |PARSE_FORMAT
1043 |PARSE_STRFTIME
1044 );
1045 if (!gdp) { return -1;}
1046 /* here we parse pos arguments locally */
1047 /* vname */
1048 if (gdp->vname[0]==0) {
1049 dprintfparsed("Processing postitional vname\n");
1050 keyvalue_t* first=getFirstUnusedArgument(1,pa);
1051 if (first) {
1052 strncpy(gdp->vname,first->value,MAX_VNAME_LEN + 1);
1053 /* get type of reference */
1054 gdp->vidx=find_var(im, gdp->vname);
1055 if (gdp->vidx<0) {
1056 rrd_set_error("undefined vname %s",gdp->vname); return -1; }
1057 } else { rrd_set_error("No positional VNAME"); return -1; }
1058 }
1059 /* check type of ref in general */
1060 enum gf_en vnamegf=im->gdes[gdp->vidx].gf;
1061 dprintfparsed("Processing referenced type %i\n",vnamegf);
1062 switch (vnamegf) {
1063 /* depreciated */
1064 case GF_DEF:
1065 case GF_CDEF:
1066 dprintfparsed("Processing postitional CF\n");
1067 /* look for CF if not given */
1068 if (((int)gdp->cf)==-1) {
1069 keyvalue_t* first=getFirstUnusedArgument(1,pa);
1070 if (first) {
1071 gdp->cf=cf_conv(first->value);
1072 if (((int)gdp->cf)==-1) {
1073 rrd_set_error("bad CF: %s",first->value); return -1; }
1074 } else { rrd_set_error("No positional CDEF"); return -1; }
1075 }
1076 break;
1077 case GF_VDEF:
1078 break;
1079 default:
1080 rrd_set_error("Encountered unknown type variable '%s'",
1081 im->gdes[gdp->vidx].vname);
1082 return -1;
1083 }
1084 /* and get positional format */
1085 if (gdp->format[0]==0) {
1086 dprintfparsed("Processing postitional format\n");
1087 keyvalue_t* first=getFirstUnusedArgument(1,pa);
1088 if (first) {
1089 strncpy(gdp->format,first->value,FMT_LEG_LEN);
1090 dprintfparsed("got positional format: %s\n",gdp->format);
1091 } else { rrd_set_error("No positional CF/FORMAT"); return -1; }
1092 }
1093 /* debug output */
1094 dprintf("=================================\n");
1095 if (gf==GF_GPRINT) {
1096 dprintf("GPRINT : %s\n",pa->arg_orig);
1097 } else {
1098 dprintf("PRINT : %s\n",pa->arg_orig);
1099 }
1100 dprintf("VNAME : %s (%li)\n",gdp->vname,gdp->vidx);
1101 if ((int)gdp->cf>-1) {
1102 dprintf("CF : (%u)\n",gdp->cf);
1103 }
1104 dprintf("FORMAT: %s\n",gdp->legend);
1105 dprintf("=================================\n");
1106
1107 /* and return */
1108 return 0;
1109}
6465207c 1110
1ace8365
TO
1111int parse_comment(enum gf_en gf,parsedargs_t*pa,image_desc_t *const im){
1112 /* get new graph that we fill */
1113 graph_desc_t *gdp=newGraphDescription(im,gf,pa,
1114 PARSE_LEGEND
1115 );
1116 if (!gdp) { return -1;}
1117
1118 /* and if we have no legend, then use the first positional one */
1119 if (gdp->legend[0]==0) {
1120 keyvalue_t* first=getFirstUnusedArgument(1,pa);
1121 if (first) {
1122 strncpy(gdp->legend,first->value,FMT_LEG_LEN);
1123 } else { rrd_set_error("No positional CF/FORMAT"); return -1; }
1124 }
1125 /* debug output */
1126 dprintf("=================================\n");
1127 dprintf("COMMENT : %s\n",pa->arg_orig);
1128 dprintf("LEGEND : %s\n",gdp->legend);
1129 /* and return */
1130 return 0;
6465207c 1131}
adb27eb6 1132
1ace8365
TO
1133int parse_tick(enum gf_en gf,parsedargs_t* pa,image_desc_t *const im) {
1134 /* get new graph that we fill */
1135 graph_desc_t *gdp=newGraphDescription(im,gf,pa,
1136 PARSE_VNAMECOLORFRACTIONLEGEND
1137 );
1138 if (!gdp) { return -1;}
1139 /* debug output */
1140 dprintf("=================================\n");
1141 dprintf("TICK : %s\n",pa->arg_orig);
1142 dprintf("VNAME : %s (%li)\n",gdp->vname,gdp->vidx);
1143 dprintf("COLOR : r=%g g=%g b=%g a=%g\n",
1144 gdp->col.red,gdp->col.green,gdp->col.blue,gdp->col.alpha);
1145 if (gdp->cf==CF_LAST) {
1146 dprintf("FRAC : %s\n",gdp->vname);
1147 } else {
1148 dprintf("FRAC : %g\n",gdp->yrule);
1149 }
1150 dprintf("LEGEND: %s\n",gdp->legend);
1151 dprintf("XAXIS : %i\n",gdp->xaxisidx);
1152 dprintf("YAXIS : %i\n",gdp->yaxisidx);
1153 dprintf("=================================\n");
1154 /* and return */
1155 return 0;
1156}
6465207c 1157
1ace8365
TO
1158int parse_textalign(enum gf_en gf,parsedargs_t* pa,image_desc_t *const im) {
1159 /* get new graph that we fill */
1160 graph_desc_t *gdp=newGraphDescription(im,gf,pa,0);
1161 if (!gdp) { return -1;}
1162
1163 /* get align */
1164 char* align=getKeyValueArgument("align",1,pa);
1165 if (!align) align=getFirstUnusedArgument(1,pa)->value;
1166 if (!align) { rrd_set_error("No alignment given"); return -1; }
1167
1168 /* parse align */
1169 if (strcmp(align, "left") == 0) {
1170 gdp->txtalign = TXA_LEFT;
1171 } else if (strcmp(align, "right") == 0) {
1172 gdp->txtalign = TXA_RIGHT;
1173 } else if (strcmp(align, "justified") == 0) {
1174 gdp->txtalign = TXA_JUSTIFIED;
1175 } else if (strcmp(align, "center") == 0) {
1176 gdp->txtalign = TXA_CENTER;
1177 } else {
1178 rrd_set_error("Unknown alignement type '%s'", align);
1179 return 1;
1180 }
1181
1182 /* debug output */
1183 dprintf("=================================\n");
1184 dprintf("TEXTALIGN : %s\n",pa->arg_orig);
1185 dprintf("ALIGNMENT : %s (%u)\n",align,gdp->txtalign);
1186 dprintf("=================================\n");
1187 /* and return */
1188 return 0;
1189}
6465207c 1190
1ace8365
TO
1191int parse_shift(enum gf_en gf,parsedargs_t* pa,image_desc_t *const im) {
1192 /* get new graph that we fill */
1193 graph_desc_t *gdp=newGraphDescription(im,gf,pa,PARSE_VNAMEREFPOS);
1194 if (!gdp) { return -1;}
1195 /* and check that it is a CDEF */
1196 switch (im->gdes[gdp->vidx].gf) {
1197 case GF_DEF:
1198 case GF_CDEF:
1199 dprintf("- vname is of type DEF or CDEF, OK\n");
1200 break;
1201 case GF_VDEF:
1202 rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n",
1203 im->gdes[gdp->vidx].vname, pa->arg_orig);
1204 return 1;
1205 default:
1206 rrd_set_error("Encountered unknown type variable '%s' in line '%s'",
1207 im->gdes[gdp->vidx].vname, pa->arg_orig);
1208 return 1;
1209 }
1210
1211 /* now parse the "shift" */
1212 char* shift=getKeyValueArgument("shift",1,pa);
1213 if (!shift) {shift=getFirstUnusedArgument(1,pa)->value;}
1214 if (!shift) { rrd_set_error("No shift given"); return -1; }
1215 /* identify shift */
1216 gdp->shidx=find_var(im, shift);
1217 if (gdp->shidx>=0) {
1218 /* it is a def, so let us check its type*/
1219 switch (im->gdes[gdp->shidx].gf) {
1220 case GF_DEF:
1221 case GF_CDEF:
1222 rrd_set_error("Offset cannot be a (C)DEF: '%s' in line '%s'\n",
1223 im->gdes[gdp->shidx].vname, pa->arg_orig);
1224 return 1;
1225 case GF_VDEF:
1226 dprintf("- vname is of type VDEF, OK\n");
1227 break;
1228 default:
1229 rrd_set_error
1230 ("Encountered unknown type variable '%s' in line '%s'",
1231 im->gdes[gdp->vidx].vname, pa->arg_orig);
1232 return 1;
6465207c 1233 }
1ace8365
TO
1234 } else {
1235 /* it is no def, so parse as number */
1236 long val;
1237 char *x;
1238 int f=getLong(shift,&val,&x,10);
1239 if (f) { rrd_set_error("error parsing number %s",shift); return -1; }
1240 gdp->shval = val;
1241 gdp->shidx = -1;
1242 }
1243
1244 /* debug output */
1245 dprintf("=================================\n");
1246 dprintf("SHIFT : %s\n",pa->arg_orig);
1247 dprintf("VNAME : %s (%li)\n",im->gdes[gdp->vidx].vname,gdp->vidx);
1248 if (gdp->shidx>=0) {
1249 dprintf("SHIFTBY : %s (%i)\n",im->gdes[gdp->shidx].vname,gdp->shidx);
1250 } else {
1251 dprintf("SHIFTBY : %li\n",gdp->shval);
1252 }
1253 dprintf("=================================\n");
1254 /* and return */
1255 return 0;
6465207c 1256}
1ace8365
TO
1257int parse_xport(enum gf_en gf,parsedargs_t* pa,image_desc_t *const im) {
1258 /* get new graph that we fill */
1259 graph_desc_t *gdp=newGraphDescription(im,gf,pa,PARSE_VNAMECOLORLEGEND);
1260 if (!gdp) { return -1;}
1261 /* check for cdef */
1262 /* and check that it is a CDEF */
1263 switch (im->gdes[gdp->vidx].gf) {
1264 case GF_DEF:
1265 case GF_CDEF:
1266 dprintf("- vname is of type DEF or CDEF, OK\n");
1267 break;
1268 case GF_VDEF:
1269 rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n",
1270 im->gdes[gdp->vidx].vname, pa->arg_orig);
1271 return 1;
1272 default:
1273 rrd_set_error("Encountered unknown type variable '%s' in line '%s'",
1274 im->gdes[gdp->vidx].vname, pa->arg_orig);
1275 return 1;
1276 }
1277
1278 /* debug output */
1279 dprintf("=================================\n");
1280 dprintf("LINE : %s\n",pa->arg_orig);
1281 dprintf("VNAME : %s (%li)\n",gdp->vname,gdp->vidx);
1282 dprintf("LEGEND: %s\n",gdp->legend);
1283 dprintf("=================================\n");
1284
1285 return 0;
6465207c
AB
1286}
1287
18cadd88
TO
1288void rrd_graph_script(
1289 int argc,
1290 char *argv[],
c4e8c1ea 1291 image_desc_t *const im,
18cadd88
TO
1292 int optno)
1293{
1294 int i;
1295
1ace8365
TO
1296 /* and now handle the things*/
1297 parsedargs_t pa;
1298 initParsedArguments(&pa);
6465207c 1299
1ace8365 1300 /* loop arguments */
18cadd88 1301 for (i = optind + optno; i < argc; i++) {
1ace8365
TO
1302 /* release parsed args - avoiding late cleanups*/
1303 freeParsedArguments(&pa);
1304 /* processed parsed args */
1305 if (parseArguments(argv[i],&pa)) {
1306 return; }
1307
1308 /* now let us handle the field based on the first command or cmd=...*/
1309 char*cmd=NULL;
1310 /* and try to get via cmd */
1311 char* t=getKeyValueArgument("cmd",1,&pa);
1312 if (t) {
1313 cmd=t;
1314 } else if ((t=getKeyValueArgument("pos0",1,&pa))) {
1315 cmd=t;
1316 } else {
1317 rrd_set_error("no command set in argument %s",pa.arg_orig);
1318 freeParsedArguments(&pa);
1319 return;
1320 }
6465207c 1321
1ace8365
TO
1322 /* convert to enum but handling LINE special*/
1323 enum gf_en gf=-1;
1324 gf=gf_conv(cmd);
1325 if ((int)gf == -1) {
1326 if (strncmp("LINE",cmd,4)==0) {
1327 gf=GF_LINE;
1328 addToArguments(&pa,"linewidth",cmd+4,0);
1329 } else {
1330 rrd_set_error("'%s' is not a valid function name in %s", cmd,pa.arg_orig );
1331 return;
1332 }
1333 }
1334 /* now we can handle the commands */
1335 int r=0;
1336 switch (gf) {
1337 case GF_XAXIS: r=parse_axis(gf,&pa,im); break;
1338 case GF_YAXIS: r=parse_axis(gf,&pa,im); break;
1339 case GF_DEF: r=parse_def(gf,&pa,im); break;
1340 case GF_CDEF: r=parse_cvdef(gf,&pa,im); break;
1341 case GF_VDEF: r=parse_cvdef(gf,&pa,im); break;
1342 case GF_LINE: r=parse_line(gf,&pa,im); break;
1343 case GF_AREA: r=parse_area(gf,&pa,im); break;
1344 case GF_PRINT: r=parse_gprint(gf,&pa,im); break;
1345 case GF_GPRINT: r=parse_gprint(gf,&pa,im); break;
1346 case GF_COMMENT: r=parse_comment(gf,&pa,im); break;
1347 case GF_HRULE: r=parse_hvrule(gf,&pa,im); break;
1348 case GF_VRULE: r=parse_hvrule(gf,&pa,im); break;
1349 case GF_STACK: r=parse_stack(gf,&pa,im); break;
1350 case GF_TICK: r=parse_tick(gf,&pa,im); break;
1351 case GF_TEXTALIGN: r=parse_textalign(gf,&pa,im); break;
1352 case GF_SHIFT: r=parse_shift(gf,&pa,im); break;
1353 case GF_XPORT: r=parse_xport(gf,&pa,im); break;
1354 /* unsupported types right now */
1355 case GF_GRAD:
1356 rrd_set_error("GRAD unsupported - use AREA instead");
1357 break;
1358 }
1359 /* handle the return error case */
1360 if (r) { freeParsedArguments(&pa); return;}
1361 /* check for unprocessed keyvalue args */
1362 char *s;
1363 if ((s=checkUnusedValues(&pa))) {
1364 rrd_set_error("Unused Arguments in %s: %s",pa.arg_orig,s);
1365 freeParsedArguments(&pa);
1366 free(s);
1367 return;
1368 }
6465207c 1369 }
1ace8365
TO
1370 /* finally free arguments */
1371 freeParsedArguments(&pa);
6465207c 1372}