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