]>
Commit | Line | Data |
---|---|---|
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 | ||
12 | void 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 |
20 | void 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 |
26 | void 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 |
40 | void 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 |
48 | char* 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 |
62 | keyvalue_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 |
72 | char* 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 |
95 | int 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 |
112 | int 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 | ||
132 | int 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 |
152 | int 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 |
172 | char *poskeys[]={"pos0","pos1","pos2","pos3","pos4","pos5","pos6","pos7","pos8","pos9"}; |
173 | int 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 |
255 | int parse_color( const char *const, struct gfx_color_t *); |
256 | int 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 | ||
337 | graph_desc_t* newGraphDescription(image_desc_t *const,enum gf_en,parsedargs_t*,unsigned long); | |
338 | graph_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 */ | |
720 | int parse_axis(enum gf_en,parsedargs_t*,image_desc_t *const); | |
721 | int parse_def(enum gf_en,parsedargs_t*,image_desc_t *const); | |
722 | int parse_cvdef(enum gf_en,parsedargs_t*,image_desc_t *const); | |
723 | int parse_line(enum gf_en,parsedargs_t*,image_desc_t *const); | |
724 | int parse_area(enum gf_en,parsedargs_t*,image_desc_t *const); | |
725 | int parse_stack(enum gf_en,parsedargs_t*,image_desc_t *const); | |
726 | int parse_print(enum gf_en,parsedargs_t*,image_desc_t *const); | |
727 | int parse_gprint(enum gf_en,parsedargs_t*,image_desc_t *const); | |
728 | int parse_comment(enum gf_en,parsedargs_t*,image_desc_t *const); | |
729 | int parse_hvrule(enum gf_en,parsedargs_t*,image_desc_t *const); | |
730 | int parse_grad(enum gf_en,parsedargs_t*,image_desc_t *const); | |
731 | int parse_tick(enum gf_en,parsedargs_t*,image_desc_t *const); | |
732 | int parse_textalign(enum gf_en,parsedargs_t*,image_desc_t *const); | |
733 | int parse_shift(enum gf_en,parsedargs_t*,image_desc_t *const); | |
734 | int parse_xport(enum gf_en,parsedargs_t*,image_desc_t *const); | |
735 | ||
736 | /* implementations */ | |
737 | int 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 |
775 | int 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 | ||
803 | int 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 | ||
856 | int 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 |
896 | int 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 |
929 | int 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 |
980 | int 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 |
1037 | int 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 |
1111 | int 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 |
1133 | int 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 |
1158 | int 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 |
1191 | int 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 |
1257 | int 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 |
1288 | void 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 | } |