]>
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" |
6465207c AB |
9 | |
10 | #define dprintf if (gdp->debug) printf | |
11 | ||
7d0bd260 TO |
12 | /* NOTE ON PARSING: |
13 | * | |
14 | * we use the following: | |
15 | * | |
16 | * i=0; sscanf(&line[*eaten], "what to find%n", variables, &i) | |
17 | * | |
18 | * Usually you want to find a separator as well. Example: | |
19 | * i=0; sscanf(&line[*eaten], "%li:%n", &someint, &i) | |
20 | * | |
21 | * When the separator is not found, i is not set and thus remains zero. | |
22 | * Another way would be to compare strlen() to i | |
23 | * | |
24 | * Why is this important? Because 12345abc should not be matched as | |
25 | * integer 12345 ... | |
26 | */ | |
27 | ||
28 | /* NOTE ON VNAMES: | |
29 | * | |
30 | * "if ((gdp->vidx=find_var(im, l))!=-1)" is not good enough, at least | |
31 | * not by itself. | |
32 | * | |
33 | * A vname as a result of a VDEF is quite different from a vname | |
34 | * resulting of a DEF or CDEF. | |
35 | */ | |
36 | ||
37 | /* NOTE ON VNAMES: | |
38 | * | |
39 | * A vname called "123" is not to be parsed as the number 123 | |
40 | */ | |
41 | ||
42 | ||
b8d04741 TO |
43 | /* Define prototypes for the parsing methods. |
44 | Inputs: | |
7d0bd260 TO |
45 | const char *const line - a fixed pointer to a fixed string |
46 | unsigned int *const eaten - a fixed pointer to a changing index in that line | |
47 | graph_desc_t *const gdp - a fixed pointer to a changing graph description | |
48 | image_desc_t *const im - a fixed pointer to a changing image description | |
b8d04741 TO |
49 | */ |
50 | ||
18cadd88 TO |
51 | int rrd_parse_find_gf( |
52 | const char *const, | |
53 | unsigned int *const, | |
c4e8c1ea | 54 | graph_desc_t *const); |
01496ecb | 55 | |
18cadd88 TO |
56 | int rrd_parse_legend( |
57 | const char *const, | |
58 | unsigned int *const, | |
c4e8c1ea | 59 | graph_desc_t *const); |
01496ecb | 60 | |
18cadd88 TO |
61 | int rrd_parse_color( |
62 | const char *const, | |
c4e8c1ea | 63 | graph_desc_t *const); |
01496ecb | 64 | |
b9a0121c | 65 | int rrd_parse_textalign( |
01496ecb TO |
66 | const char *const, |
67 | unsigned int *const, | |
68 | graph_desc_t *const); | |
69 | ||
70 | ||
18cadd88 TO |
71 | int rrd_parse_CF( |
72 | const char *const, | |
73 | unsigned int *const, | |
c4e8c1ea | 74 | graph_desc_t *const, |
18cadd88 | 75 | enum cf_en *const); |
01496ecb | 76 | |
18cadd88 TO |
77 | int rrd_parse_print( |
78 | const char *const, | |
79 | unsigned int *const, | |
c4e8c1ea TO |
80 | graph_desc_t *const, |
81 | image_desc_t *const); | |
01496ecb | 82 | |
18cadd88 TO |
83 | int rrd_parse_shift( |
84 | const char *const, | |
85 | unsigned int *const, | |
c4e8c1ea TO |
86 | graph_desc_t *const, |
87 | image_desc_t *const); | |
01496ecb | 88 | |
18cadd88 TO |
89 | int rrd_parse_xport( |
90 | const char *const, | |
91 | unsigned int *const, | |
c4e8c1ea TO |
92 | graph_desc_t *const, |
93 | image_desc_t *const); | |
01496ecb | 94 | |
18cadd88 TO |
95 | int rrd_parse_PVHLAST( |
96 | const char *const, | |
97 | unsigned int *const, | |
c4e8c1ea TO |
98 | graph_desc_t *const, |
99 | image_desc_t *const); | |
01496ecb | 100 | |
18cadd88 TO |
101 | int rrd_parse_make_vname( |
102 | const char *const, | |
103 | unsigned int *const, | |
c4e8c1ea TO |
104 | graph_desc_t *const, |
105 | image_desc_t *const); | |
01496ecb | 106 | |
18cadd88 TO |
107 | int rrd_parse_find_vname( |
108 | const char *const, | |
109 | unsigned int *const, | |
c4e8c1ea TO |
110 | graph_desc_t *const, |
111 | image_desc_t *const); | |
01496ecb | 112 | |
18cadd88 TO |
113 | int rrd_parse_def( |
114 | const char *const, | |
115 | unsigned int *const, | |
c4e8c1ea TO |
116 | graph_desc_t *const, |
117 | image_desc_t *const); | |
01496ecb | 118 | |
18cadd88 TO |
119 | int rrd_parse_vdef( |
120 | const char *const, | |
121 | unsigned int *const, | |
c4e8c1ea TO |
122 | graph_desc_t *const, |
123 | image_desc_t *const); | |
01496ecb | 124 | |
18cadd88 TO |
125 | int rrd_parse_cdef( |
126 | const char *const, | |
127 | unsigned int *const, | |
c4e8c1ea TO |
128 | graph_desc_t *const, |
129 | image_desc_t *const); | |
18cadd88 | 130 | |
18cadd88 TO |
131 | int rrd_parse_find_gf( |
132 | const char *const line, | |
133 | unsigned int *const eaten, | |
c4e8c1ea | 134 | graph_desc_t *const gdp) |
18cadd88 TO |
135 | { |
136 | char funcname[11], c1 = 0; | |
137 | int i = 0; | |
6465207c | 138 | |
3da125e9 | 139 | /* start an argument with DEBUG to be able to see how it is parsed */ |
6465207c AB |
140 | sscanf(&line[*eaten], "DEBUG%n", &i); |
141 | if (i) { | |
18cadd88 TO |
142 | gdp->debug = 1; |
143 | (*eaten) += i; | |
144 | i = 0; | |
145 | dprintf("Scanning line '%s'\n", &line[*eaten]); | |
6465207c | 146 | } |
18cadd88 TO |
147 | i = 0; |
148 | c1 = '\0'; | |
829df33a | 149 | sscanf(&line[*eaten], "%10[A-Z]%n%c", funcname, &i, &c1); |
6465207c | 150 | if (!i) { |
18cadd88 TO |
151 | rrd_set_error("Could not make sense out of '%s'", line); |
152 | return 1; | |
6465207c | 153 | } |
18cadd88 TO |
154 | (*eaten) += i; |
155 | if ((int) (gdp->gf = gf_conv(funcname)) == -1) { | |
156 | rrd_set_error("'%s' is not a valid function name", funcname); | |
157 | return 1; | |
3da125e9 | 158 | } else { |
18cadd88 | 159 | dprintf("- found function name '%s'\n", funcname); |
adb27eb6 | 160 | } |
3da125e9 | 161 | |
7d0bd260 | 162 | if (c1 == '\0') { |
18cadd88 TO |
163 | rrd_set_error("Function %s needs parameters. Line: %s\n", funcname, |
164 | line); | |
165 | return 1; | |
7d0bd260 | 166 | } |
18cadd88 TO |
167 | if (c1 == ':') |
168 | (*eaten)++; | |
7d0bd260 TO |
169 | |
170 | /* Some commands have a parameter before the colon | |
171 | * (currently only LINE) | |
172 | */ | |
173 | switch (gdp->gf) { | |
18cadd88 TO |
174 | case GF_LINE: |
175 | if (c1 == ':') { | |
176 | gdp->linewidth = 1; | |
c79bd073 | 177 | dprintf("- using default width of 1\n"); |
18cadd88 TO |
178 | } else { |
179 | i = 0; | |
180 | sscanf(&line[*eaten], "%lf:%n", &gdp->linewidth, &i); | |
181 | if (!i) { | |
182 | rrd_set_error("Cannot parse line width '%s' in line '%s'\n", | |
183 | &line[*eaten], line); | |
184 | return 1; | |
185 | } else { | |
c79bd073 | 186 | dprintf("- scanned width %f\n", gdp->linewidth); |
18cadd88 TO |
187 | if (isnan(gdp->linewidth)) { |
188 | rrd_set_error | |
189 | ("LINE width '%s' is not a number in line '%s'\n", | |
190 | &line[*eaten], line); | |
191 | return 1; | |
192 | } | |
193 | if (isinf(gdp->linewidth)) { | |
194 | rrd_set_error | |
195 | ("LINE width '%s' is out of range in line '%s'\n", | |
196 | &line[*eaten], line); | |
197 | return 1; | |
198 | } | |
199 | if (gdp->linewidth < 0) { | |
200 | rrd_set_error | |
201 | ("LINE width '%s' is less than 0 in line '%s'\n", | |
202 | &line[*eaten], line); | |
203 | return 1; | |
204 | } | |
205 | } | |
206 | (*eaten) += i; | |
207 | } | |
208 | break; | |
209 | default: | |
210 | if (c1 == ':') | |
211 | break; | |
212 | rrd_set_error("Malformed '%s' command in line '%s'\n", &line[*eaten], | |
213 | line); | |
214 | return 1; | |
6465207c | 215 | } |
7e9d426d | 216 | if (line[*eaten] == '\0') { |
18cadd88 TO |
217 | rrd_set_error("Expected some arguments after '%s'\n", line); |
218 | return 1; | |
7e9d426d | 219 | } |
6465207c AB |
220 | return 0; |
221 | } | |
adb27eb6 | 222 | |
18cadd88 TO |
223 | int rrd_parse_legend( |
224 | const char *const line, | |
225 | unsigned int *const eaten, | |
c4e8c1ea | 226 | graph_desc_t *const gdp) |
18cadd88 TO |
227 | { |
228 | int i; | |
6465207c | 229 | |
18cadd88 TO |
230 | if (line[*eaten] == '\0' || line[*eaten] == ':') { |
231 | dprintf("- no (or: empty) legend found\n"); | |
232 | return 0; | |
3da125e9 | 233 | } |
6465207c | 234 | |
18cadd88 | 235 | i = scan_for_col(&line[*eaten], FMT_LEG_LEN, gdp->legend); |
6465207c | 236 | |
18cadd88 | 237 | (*eaten) += i; |
3da125e9 | 238 | |
18cadd88 TO |
239 | if (line[*eaten] != '\0' && line[*eaten] != ':') { |
240 | rrd_set_error("Legend too long"); | |
241 | return 1; | |
6465207c | 242 | } else { |
18cadd88 | 243 | return 0; |
adb27eb6 | 244 | } |
6465207c AB |
245 | } |
246 | ||
18cadd88 TO |
247 | int rrd_parse_color( |
248 | const char *const string, | |
c4e8c1ea | 249 | graph_desc_t *const gdp) |
18cadd88 TO |
250 | { |
251 | unsigned int r = 0, g = 0, b = 0, a = 0, i; | |
6465207c | 252 | |
3da125e9 | 253 | /* matches the following formats: |
18cadd88 TO |
254 | ** RGB |
255 | ** RGBA | |
256 | ** RRGGBB | |
257 | ** RRGGBBAA | |
258 | */ | |
259 | ||
260 | i = 0; | |
261 | while (string[i] && isxdigit((unsigned int) string[i])) | |
262 | i++; | |
263 | if (string[i] != '\0') | |
264 | return 1; /* garbage follows hexdigits */ | |
3da125e9 | 265 | switch (i) { |
18cadd88 TO |
266 | case 3: |
267 | case 4: | |
268 | sscanf(string, "%1x%1x%1x%1x", &r, &g, &b, &a); | |
269 | r *= 0x11; | |
270 | g *= 0x11; | |
271 | b *= 0x11; | |
272 | a *= 0x11; | |
273 | if (i == 3) | |
274 | a = 0xFF; | |
275 | break; | |
276 | case 6: | |
277 | case 8: | |
278 | sscanf(string, "%02x%02x%02x%02x", &r, &g, &b, &a); | |
279 | if (i == 6) | |
280 | a = 0xFF; | |
281 | break; | |
282 | default: | |
283 | return 1; /* wrong number of digits */ | |
284 | } | |
9c4e67d9 | 285 | gdp->col = gfx_hex_to_col(r << 24 | g << 16 | b << 8 | a); |
6465207c AB |
286 | return 0; |
287 | } | |
288 | ||
18cadd88 TO |
289 | int rrd_parse_CF( |
290 | const char *const line, | |
291 | unsigned int *const eaten, | |
c4e8c1ea | 292 | graph_desc_t *const gdp, |
18cadd88 TO |
293 | enum cf_en *cf) |
294 | { | |
295 | char symname[CF_NAM_SIZE]; | |
296 | int i = 0; | |
297 | ||
298 | sscanf(&line[*eaten], CF_NAM_FMT "%n", symname, &i); | |
299 | if ((!i) || ((line[(*eaten) + i] != '\0') && (line[(*eaten) + i] != ':'))) { | |
300 | rrd_set_error("Cannot parse CF in '%s'", line); | |
301 | return 1; | |
6465207c | 302 | } |
18cadd88 TO |
303 | (*eaten) += i; |
304 | dprintf("- using CF '%s'\n", symname); | |
adb27eb6 | 305 | |
18cadd88 TO |
306 | if ((int) (*cf = cf_conv(symname)) == -1) { |
307 | rrd_set_error("Unknown CF '%s' in '%s'", symname, line); | |
308 | return 1; | |
6465207c AB |
309 | } |
310 | ||
18cadd88 TO |
311 | if (line[*eaten] != '\0') |
312 | (*eaten)++; | |
6465207c AB |
313 | return 0; |
314 | } | |
315 | ||
7d0bd260 TO |
316 | /* Try to match next token as a vname. |
317 | * | |
318 | * Returns: | |
319 | * -1 an error occured and the error string is set | |
320 | * other the vname index number | |
321 | * | |
322 | * *eaten is incremented only when a vname is found. | |
323 | */ | |
18cadd88 TO |
324 | int rrd_parse_find_vname( |
325 | const char *const line, | |
326 | unsigned int *const eaten, | |
c4e8c1ea TO |
327 | graph_desc_t *const gdp, |
328 | image_desc_t *const im) | |
18cadd88 TO |
329 | { |
330 | char tmpstr[MAX_VNAME_LEN + 1]; | |
331 | int i; | |
332 | long vidx; | |
333 | ||
334 | i = 0; | |
335 | sscanf(&line[*eaten], DEF_NAM_FMT "%n", tmpstr, &i); | |
6465207c | 336 | if (!i) { |
18cadd88 TO |
337 | rrd_set_error("Could not parse line '%s'", line); |
338 | return -1; | |
6465207c | 339 | } |
18cadd88 TO |
340 | if (line[*eaten + i] != ':' && line[*eaten + i] != '\0') { |
341 | rrd_set_error("Could not parse line '%s'", line); | |
342 | return -1; | |
7d0bd260 | 343 | } |
18cadd88 | 344 | dprintf("- Considering '%s'\n", tmpstr); |
6465207c | 345 | |
18cadd88 TO |
346 | if ((vidx = find_var(im, tmpstr)) < 0) { |
347 | dprintf("- Not a vname\n"); | |
348 | rrd_set_error("Not a valid vname: %s in line %s", tmpstr, line); | |
349 | return -1; | |
6465207c | 350 | } |
18cadd88 TO |
351 | dprintf("- Found vname '%s' vidx '%li'\n", tmpstr, gdp->vidx); |
352 | if (line[*eaten + i] == ':') | |
353 | i++; | |
354 | (*eaten) += i; | |
7d0bd260 TO |
355 | return vidx; |
356 | } | |
357 | ||
358 | /* Parsing old-style xPRINT and new-style xPRINT */ | |
18cadd88 TO |
359 | int rrd_parse_print( |
360 | const char *const line, | |
361 | unsigned int *const eaten, | |
c4e8c1ea TO |
362 | graph_desc_t *const gdp, |
363 | image_desc_t *const im) | |
18cadd88 | 364 | { |
7d0bd260 | 365 | /* vname:CF:format in case of DEF-based vname |
18cadd88 TO |
366 | ** vname:CF:format in case of CDEF-based vname |
367 | ** vname:format[:strftime] in case of VDEF-based vname | |
368 | */ | |
369 | if ((gdp->vidx = rrd_parse_find_vname(line, eaten, gdp, im)) < 0) | |
370 | return 1; | |
371 | ||
6465207c | 372 | switch (im->gdes[gdp->vidx].gf) { |
18cadd88 TO |
373 | case GF_DEF: |
374 | case GF_CDEF: | |
375 | dprintf("- vname is of type DEF or CDEF, looking for CF\n"); | |
376 | if (rrd_parse_CF(line, eaten, gdp, &gdp->cf)) | |
377 | return 1; | |
378 | break; | |
379 | case GF_VDEF: | |
380 | dprintf("- vname is of type VDEF\n"); | |
381 | break; | |
382 | default: | |
383 | rrd_set_error("Encountered unknown type variable '%s'", | |
384 | im->gdes[gdp->vidx].vname); | |
385 | return 1; | |
386 | } | |
387 | ||
388 | if (rrd_parse_legend(line, eaten, gdp)) | |
389 | return 1; | |
054f4ff3 | 390 | /* for *PRINT the legend itself gets rendered later. We only |
6d54723b | 391 | get the format at this juncture */ |
18cadd88 TO |
392 | strcpy(gdp->format, gdp->legend); |
393 | gdp->legend[0] = '\0'; | |
5e01c4f7 | 394 | /* this is a very crud test, parsing :style flags should be in a function */ |
18cadd88 TO |
395 | if (im->gdes[gdp->vidx].gf == GF_VDEF |
396 | && strcmp(line + (*eaten), ":strftime") == 0) { | |
397 | gdp->strftm = 1; | |
398 | (*eaten) += strlen(":strftime"); | |
5e01c4f7 | 399 | } |
6465207c AB |
400 | return 0; |
401 | } | |
402 | ||
7d0bd260 TO |
403 | /* SHIFT:_def_or_cdef:_vdef_or_number_ |
404 | */ | |
18cadd88 TO |
405 | int rrd_parse_shift( |
406 | const char *const line, | |
407 | unsigned int *const eaten, | |
c4e8c1ea TO |
408 | graph_desc_t *const gdp, |
409 | image_desc_t *const im) | |
18cadd88 TO |
410 | { |
411 | int i; | |
7d0bd260 | 412 | |
18cadd88 TO |
413 | if ((gdp->vidx = rrd_parse_find_vname(line, eaten, gdp, im)) < 0) |
414 | return 1; | |
7d0bd260 TO |
415 | |
416 | switch (im->gdes[gdp->vidx].gf) { | |
18cadd88 TO |
417 | case GF_DEF: |
418 | case GF_CDEF: | |
419 | dprintf("- vname is of type DEF or CDEF, OK\n"); | |
420 | break; | |
421 | case GF_VDEF: | |
422 | rrd_set_error("Cannot shift a VDEF: '%s' in line '%s'\n", | |
423 | im->gdes[gdp->vidx].vname, line); | |
424 | return 1; | |
425 | default: | |
426 | rrd_set_error("Encountered unknown type variable '%s' in line '%s'", | |
427 | im->gdes[gdp->vidx].vname, line); | |
428 | return 1; | |
429 | } | |
430 | ||
431 | if ((gdp->shidx = rrd_parse_find_vname(line, eaten, gdp, im)) >= 0) { | |
432 | switch (im->gdes[gdp->shidx].gf) { | |
433 | case GF_DEF: | |
434 | case GF_CDEF: | |
435 | rrd_set_error("Offset cannot be a (C)DEF: '%s' in line '%s'\n", | |
436 | im->gdes[gdp->shidx].vname, line); | |
437 | return 1; | |
438 | case GF_VDEF: | |
439 | dprintf("- vname is of type VDEF, OK\n"); | |
440 | break; | |
441 | default: | |
442 | rrd_set_error | |
443 | ("Encountered unknown type variable '%s' in line '%s'", | |
444 | im->gdes[gdp->vidx].vname, line); | |
445 | return 1; | |
446 | } | |
7d0bd260 | 447 | } else { |
71de28d5 TO |
448 | long time_tmp = 0; |
449 | ||
18cadd88 TO |
450 | rrd_clear_error(); |
451 | i = 0; | |
10dda66c TO |
452 | sscanf(&line[*eaten], "%li%n", &time_tmp, &i); |
453 | gdp->shval = time_tmp; | |
18cadd88 TO |
454 | if (i != (int) strlen(&line[*eaten])) { |
455 | rrd_set_error("Not a valid offset: %s in line %s", &line[*eaten], | |
456 | line); | |
457 | return 1; | |
458 | } | |
459 | (*eaten) += i; | |
460 | dprintf("- offset is number %li\n", gdp->shval); | |
461 | gdp->shidx = -1; | |
7d0bd260 TO |
462 | } |
463 | return 0; | |
c4e7b680 TO |
464 | } |
465 | ||
7d0bd260 TO |
466 | /* XPORT:_def_or_cdef[:legend] |
467 | */ | |
18cadd88 TO |
468 | int rrd_parse_xport( |
469 | const char *const line, | |
470 | unsigned int *const eaten, | |
c4e8c1ea TO |
471 | graph_desc_t *const gdp, |
472 | image_desc_t *const im) | |
18cadd88 TO |
473 | { |
474 | if ((gdp->vidx = rrd_parse_find_vname(line, eaten, gdp, im)) < 0) | |
475 | return 1; | |
7d0bd260 TO |
476 | |
477 | switch (im->gdes[gdp->vidx].gf) { | |
18cadd88 TO |
478 | case GF_DEF: |
479 | case GF_CDEF: | |
480 | dprintf("- vname is of type DEF or CDEF, OK\n"); | |
481 | break; | |
482 | case GF_VDEF: | |
483 | rrd_set_error("Cannot xport a VDEF: '%s' in line '%s'\n", | |
484 | im->gdes[gdp->vidx].vname, line); | |
485 | return 1; | |
486 | default: | |
487 | rrd_set_error("Encountered unknown type variable '%s' in line '%s'", | |
488 | im->gdes[gdp->vidx].vname, line); | |
489 | return 1; | |
490 | } | |
491 | dprintf("- looking for legend in '%s'\n", &line[*eaten]); | |
492 | if (rrd_parse_legend(line, eaten, gdp)) | |
493 | return 1; | |
7d0bd260 | 494 | return 0; |
c4e7b680 TO |
495 | } |
496 | ||
01496ecb TO |
497 | int rrd_parse_textalign( |
498 | const char *const line, | |
499 | unsigned int *const eaten, | |
500 | graph_desc_t *const gdp) | |
501 | { | |
b9a0121c TO |
502 | if (strcmp(&line[*eaten], "left") == 0) { |
503 | gdp->txtalign = TXA_LEFT; | |
504 | } else if (strcmp(&line[*eaten], "right") == 0) { | |
505 | gdp->txtalign = TXA_RIGHT; | |
506 | } else if (strcmp(&line[*eaten], "justified") == 0) { | |
507 | gdp->txtalign = TXA_JUSTIFIED; | |
508 | } else if (strcmp(&line[*eaten], "center") == 0) { | |
509 | gdp->txtalign = TXA_CENTER; | |
01496ecb TO |
510 | } else { |
511 | rrd_set_error("Unknown alignement type '%s'", &line[*eaten]); | |
512 | return 1; | |
513 | } | |
514 | *eaten += strlen(&line[*eaten]); | |
515 | return 0; | |
516 | } | |
517 | ||
518 | ||
83b5eb89 | 519 | /* Parsing of VRULE, HRULE, LINE, AREA, STACK and TICK |
3da125e9 TO |
520 | ** is done in one function. |
521 | ** | |
83b5eb89 | 522 | ** Stacking VRULE, HRULE or TICK is not allowed. |
6465207c AB |
523 | ** |
524 | ** If a number (which is valid to enter) is more than a | |
525 | ** certain amount of characters, it is caught as an error. | |
526 | ** While this is arguable, so is entering fixed numbers | |
527 | ** with more than MAX_VNAME_LEN significant digits. | |
528 | */ | |
18cadd88 TO |
529 | int rrd_parse_PVHLAST( |
530 | const char *const line, | |
531 | unsigned int *const eaten, | |
c4e8c1ea TO |
532 | graph_desc_t *const gdp, |
533 | image_desc_t *const im) | |
18cadd88 | 534 | { |
58e13ed8 | 535 | int i, j, k, j2; |
18cadd88 TO |
536 | int colorfound = 0; |
537 | char tmpstr[MAX_VNAME_LEN + 10]; /* vname#RRGGBBAA\0 */ | |
15dbcb6e TO |
538 | static int spacecnt = 0; |
539 | ||
18cadd88 | 540 | if (spacecnt == 0) { |
a33bbffb | 541 | float one_space = gfx_get_text_width(im, 0, |
18cadd88 TO |
542 | im-> |
543 | text_prop[TEXT_PROP_LEGEND]. | |
83b5eb89 | 544 | font_desc, |
9c4e67d9 | 545 | im->tabwidth, " ") / 4.0; |
a33bbffb | 546 | float target_space = gfx_get_text_width(im, 0, |
18cadd88 TO |
547 | im-> |
548 | text_prop | |
83b5eb89 | 549 | [TEXT_PROP_LEGEND].font_desc, |
9c4e67d9 | 550 | im->tabwidth, "oo"); |
18cadd88 TO |
551 | |
552 | spacecnt = target_space / one_space; | |
553 | dprintf("- spacecnt: %i onespace: %f targspace: %f\n", spacecnt, | |
554 | one_space, target_space); | |
15dbcb6e TO |
555 | } |
556 | ||
6465207c | 557 | |
18cadd88 | 558 | dprintf("- parsing '%s'\n", &line[*eaten]); |
6465207c | 559 | |
2cbe4e85 | 560 | /* have simpler code in the drawing section */ |
18cadd88 TO |
561 | if (gdp->gf == GF_STACK) { |
562 | gdp->stack = 1; | |
2cbe4e85 TO |
563 | } |
564 | ||
18cadd88 TO |
565 | i = scan_for_col(&line[*eaten], MAX_VNAME_LEN + 9, tmpstr); |
566 | if (line[*eaten + i] != '\0' && line[*eaten + i] != ':') { | |
567 | rrd_set_error("Cannot parse line '%s'", line); | |
568 | return 1; | |
6465207c | 569 | } |
58e13ed8 TO |
570 | |
571 | j = i; | |
18cadd88 TO |
572 | while (j > 0 && tmpstr[j] != '#') |
573 | j--; | |
58e13ed8 TO |
574 | //see if there is a second color |
575 | j2 = j-1; | |
576 | while (j2 > 0 && tmpstr[j2] != '#') | |
577 | j2--; | |
578 | if (j && j2) { //yes, swap j and j2, so that j is first color, j2 is second | |
579 | int tmp = j; | |
580 | j = j2; | |
581 | j2 = tmp; | |
582 | tmpstr[j2] = '\0'; | |
583 | } else { | |
584 | j2 = 0; | |
585 | } | |
6465207c | 586 | |
3da125e9 | 587 | if (j) { |
18cadd88 | 588 | tmpstr[j] = '\0'; |
6465207c | 589 | } |
7d0bd260 TO |
590 | /* We now have: |
591 | * tmpstr[0] containing vname | |
592 | * tmpstr[j] if j!=0 then containing color | |
58e13ed8 TO |
593 | * tmpstr[j2] if j2!=0 then containing second color |
594 | * i size of vname | |
7d0bd260 | 595 | * j if j!=0 then size of vname |
58e13ed8 | 596 | * j2 if j2!=0 then size of vname + first color |
7d0bd260 | 597 | */ |
6465207c | 598 | |
45e333f4 | 599 | /* Number or vname ? |
7d0bd260 TO |
600 | * If it is an existing vname, that's OK, provided that it is a |
601 | * valid type (need time for VRULE, not a float) | |
602 | * Else see if it parses as a number. | |
45e333f4 | 603 | */ |
18cadd88 TO |
604 | dprintf("- examining string '%s'\n", tmpstr); |
605 | if ((gdp->vidx = find_var(im, tmpstr)) >= 0) { | |
606 | dprintf("- found vname: '%s' vidx %li\n", tmpstr, gdp->vidx); | |
607 | switch (gdp->gf) { | |
18cadd88 TO |
608 | case GF_VRULE: |
609 | case GF_HRULE: | |
610 | if (im->gdes[gdp->vidx].gf != GF_VDEF) { | |
611 | rrd_set_error("Using vname %s of wrong type in line %s\n", | |
612 | im->gdes[gdp->gf].vname, line); | |
613 | return 1; | |
614 | } | |
615 | break; | |
616 | default:; | |
617 | } | |
6465207c | 618 | } else { |
71de28d5 TO |
619 | long time_tmp = 0; |
620 | ||
18cadd88 TO |
621 | dprintf("- it is not an existing vname\n"); |
622 | switch (gdp->gf) { | |
623 | case GF_VRULE: | |
624 | k = 0; | |
71de28d5 | 625 | sscanf(tmpstr, "%li%n", &time_tmp, &k); |
10dda66c | 626 | gdp->xrule = time_tmp; |
18cadd88 TO |
627 | if (((j != 0) && (k == j)) || ((j == 0) && (k == i))) { |
628 | dprintf("- found time: %li\n", gdp->xrule); | |
629 | } else { | |
630 | dprintf("- is is not a valid number: %li\n", gdp->xrule); | |
631 | rrd_set_error | |
632 | ("parameter '%s' does not represent time in line %s\n", | |
633 | tmpstr, line); | |
634 | return 1; | |
635 | } | |
636 | default: | |
637 | k = 0; | |
638 | sscanf(tmpstr, "%lf%n", &gdp->yrule, &k); | |
639 | if (((j != 0) && (k == j)) || ((j == 0) && (k == i))) { | |
10dda66c | 640 | dprintf("- found number: %lf\n", gdp->yrule); |
18cadd88 | 641 | } else { |
10dda66c | 642 | dprintf("- is is not a valid number: %lf\n", gdp->yrule); |
18cadd88 TO |
643 | rrd_set_error |
644 | ("parameter '%s' does not represent a number in line %s\n", | |
645 | tmpstr, line); | |
646 | return 1; | |
647 | } | |
648 | } | |
6465207c | 649 | } |
3da125e9 TO |
650 | |
651 | if (j) { | |
18cadd88 TO |
652 | j++; |
653 | dprintf("- examining color '%s'\n", &tmpstr[j]); | |
654 | if (rrd_parse_color(&tmpstr[j], gdp)) { | |
655 | rrd_set_error("Could not parse color in '%s'", &tmpstr[j]); | |
656 | return 1; | |
657 | } | |
9c4e67d9 TO |
658 | dprintf("- parsed color %0.0f,%0.0f,%0.0f,%0.0f\n", gdp->col.red, |
659 | gdp->col.green, gdp->col.blue, gdp->col.alpha); | |
18cadd88 | 660 | colorfound = 1; |
58e13ed8 TO |
661 | if (j2) { //second color? |
662 | j2++; | |
663 | dprintf("- examining second color '%s'\n", &tmpstr[j2]); | |
664 | //TODO: maybe rrd_parse_color should take a pointer to gdp->col instead of gdp | |
665 | struct gfx_color_t firstcol = gdp->col; | |
666 | if (rrd_parse_color(&tmpstr[j2], gdp)) { | |
667 | rrd_set_error("Could not parse color in '%s'", &tmpstr[j2]); | |
668 | return 1; | |
669 | } | |
670 | dprintf("- parsed color %0.0f,%0.0f,%0.0f,%0.0f\n", gdp->col.red, | |
671 | gdp->col.green, gdp->col.blue, gdp->col.alpha); | |
672 | gdp->col2 = gdp->col; | |
673 | gdp->col = firstcol; | |
674 | //we now have a mandatory grid height | |
675 | (*eaten) += i; | |
676 | if (line[*eaten] != '\0') { | |
677 | (*eaten)++; | |
678 | } | |
679 | dprintf("- examining gradient height\n"); | |
680 | i = scan_for_col(&line[*eaten], MAX_VNAME_LEN + 9, tmpstr); | |
681 | sscanf(tmpstr, "%lf%n", &gdp->gradheight, &j); | |
682 | if (i != j) { | |
683 | rrd_set_error("Could not parse gradient height in '%s'", tmpstr); | |
684 | return 1; | |
685 | } | |
686 | dprintf("- parsed gradientheight %0.0f\n", gdp->gradheight); | |
687 | } | |
3da125e9 | 688 | } else { |
18cadd88 | 689 | dprintf("- no color present in '%s'\n", tmpstr); |
6465207c | 690 | } |
6465207c | 691 | |
18cadd88 TO |
692 | (*eaten) += i; /* after vname#color */ |
693 | if (line[*eaten] != '\0') { | |
694 | (*eaten)++; /* after colon */ | |
3da125e9 TO |
695 | } |
696 | ||
697 | if (gdp->gf == GF_TICK) { | |
18cadd88 TO |
698 | dprintf("- parsing '%s'\n", &line[*eaten]); |
699 | dprintf("- looking for optional TICK number\n"); | |
700 | j = 0; | |
701 | sscanf(&line[*eaten], "%lf%n", &gdp->yrule, &j); | |
702 | if (j) { | |
703 | if (line[*eaten + j] != '\0' && line[*eaten + j] != ':') { | |
704 | rrd_set_error("Cannot parse TICK fraction '%s'", line); | |
705 | return 1; | |
706 | } | |
707 | dprintf("- found number %f\n", gdp->yrule); | |
708 | if (gdp->yrule > 1.0 || gdp->yrule < -1.0) { | |
709 | rrd_set_error("Tick factor should be <= 1.0"); | |
710 | return 1; | |
711 | } | |
712 | (*eaten) += j; | |
713 | } else { | |
3da125e9 | 714 | dprintf("- not found, defaulting to 0.1\n"); |
18cadd88 TO |
715 | gdp->yrule = 0.1; |
716 | } | |
717 | if (line[*eaten] == '\0') { | |
718 | dprintf("- done parsing line\n"); | |
719 | return 0; | |
720 | } else { | |
721 | if (line[*eaten] == ':') { | |
722 | (*eaten)++; | |
723 | } else { | |
724 | rrd_set_error("Can't make sense of that TICK line"); | |
725 | return 1; | |
726 | } | |
3da125e9 TO |
727 | } |
728 | } | |
729 | ||
18cadd88 | 730 | dprintf("- parsing '%s'\n", &line[*eaten]); |
3da125e9 TO |
731 | |
732 | /* Legend is next. A legend without a color is an error. | |
18cadd88 TO |
733 | ** Stacking an item without having a legend is OK however |
734 | ** then an empty legend should be specified. | |
735 | ** LINE:val#color:STACK means legend is string "STACK" | |
736 | ** LINE:val#color::STACK means no legend, and do STACK | |
737 | ** LINE:val:STACK is an error (legend but no color) | |
738 | ** LINE:val::STACK means no legend, and do STACK | |
739 | */ | |
3da125e9 | 740 | if (colorfound) { |
18cadd88 TO |
741 | int err = 0; |
742 | char *linecp = strdup(line); | |
743 | ||
744 | dprintf("- looking for optional legend\n"); | |
745 | ||
746 | dprintf("- examining '%s'\n", &line[*eaten]); | |
747 | if (linecp[*eaten] != '\0' && linecp[*eaten] != ':') { | |
748 | int spi; | |
749 | ||
750 | /* If the legend is not empty, it has to be prefixed with spacecnt ' ' characters. This then gets | |
751 | * replaced by the color box later on. */ | |
752 | for (spi = 0; spi < spacecnt && (*eaten) > 1; spi++) { | |
753 | linecp[--(*eaten)] = ' '; | |
754 | } | |
755 | } | |
756 | ||
757 | if (rrd_parse_legend(linecp, eaten, gdp)) | |
758 | err = 1; | |
759 | free(linecp); | |
760 | if (err) | |
761 | return 1; | |
762 | ||
763 | dprintf("- found legend '%s'\n", &gdp->legend[2]); | |
3da125e9 | 764 | } else { |
18cadd88 TO |
765 | dprintf("- skipping empty legend\n"); |
766 | if (line[*eaten] != '\0' && line[*eaten] != ':') { | |
767 | rrd_set_error("Legend set but no color: %s", &line[*eaten]); | |
768 | return 1; | |
769 | } | |
6465207c | 770 | } |
18cadd88 TO |
771 | if (line[*eaten] == '\0') { |
772 | dprintf("- done parsing line\n"); | |
773 | return 0; | |
3da125e9 | 774 | } |
18cadd88 | 775 | (*eaten)++; /* after colon */ |
6465207c | 776 | |
83b5eb89 | 777 | /* HRULE, VRULE and TICK cannot be stacked. */ |
c79bd073 TO |
778 | if ((gdp->gf != GF_HRULE) |
779 | && (gdp->gf != GF_VRULE) | |
780 | && (gdp->gf != GF_TICK)) { | |
18cadd88 | 781 | |
c79bd073 | 782 | dprintf("- parsing '%s', looking for STACK\n", &line[*eaten]); |
18cadd88 | 783 | j = scan_for_col(&line[*eaten], 5, tmpstr); |
18cadd88 TO |
784 | if (!strcmp("STACK", tmpstr)) { |
785 | dprintf("- found STACK\n"); | |
786 | gdp->stack = 1; | |
787 | (*eaten) += j; | |
c79bd073 TO |
788 | if (line[*eaten] == ':') { |
789 | (*eaten) += 1; | |
790 | } else if (line[*eaten] == '\0') { | |
791 | dprintf("- done parsing line\n"); | |
792 | return 0; | |
793 | } else { | |
794 | dprintf("- found %s instead of just STACK\n", &line[*eaten]); | |
795 | rrd_set_error("STACK expected but %s found", &line[*eaten]); | |
796 | return 1; | |
797 | } | |
798 | } else | |
799 | dprintf("- not STACKing\n"); | |
800 | } | |
801 | ||
8530b16e | 802 | dprintf("- still more, should be dashes[=...]\n"); |
c79bd073 TO |
803 | dprintf("- parsing '%s'\n", &line[*eaten]); |
804 | if (line[*eaten] != '\0') { | |
8530b16e TO |
805 | /* parse dash arguments here. Possible options: |
806 | - dashes | |
807 | - dashes=n_on[,n_off[,n_on,n_off]] | |
808 | - dashes[=n_on[,n_off[,n_on,n_off]]]:dash-offset=offset | |
809 | allowing 64 characters for definition of dash style */ | |
810 | j = scan_for_col(&line[*eaten], 64, tmpstr); | |
811 | /* start with dashes */ | |
812 | if (strcmp(tmpstr, "dashes") == 0) { | |
813 | /* if line was "dashes" or "dashes:dash-offset=xdashes=" | |
814 | tmpstr will be "dashes" */ | |
c79bd073 | 815 | dprintf("- found %s\n", tmpstr); |
8530b16e TO |
816 | /* initialise all required variables we need for dashed lines |
817 | using default dash length of 5 pixels */ | |
c79bd073 TO |
818 | gdp->dash = 1; |
819 | gdp->p_dashes = (double *) malloc(sizeof(double)); | |
820 | gdp->p_dashes[0] = 5; | |
821 | gdp->ndash = 1; | |
822 | gdp->offset = 0; | |
823 | (*eaten) += j; | |
8530b16e TO |
824 | } else if (sscanf(tmpstr, "dashes=%s", tmpstr)) { |
825 | /* dashes=n_on[,n_off[,n_on,n_off]] */ | |
c79bd073 TO |
826 | char csv[64]; |
827 | char *pch; | |
828 | float dsh; | |
c79bd073 | 829 | int count = 0; |
2276b1de | 830 | char *saveptr; |
c79bd073 | 831 | |
2276b1de | 832 | strcpy(csv, tmpstr); |
e8b4313e TO |
833 | |
834 | pch = strtok_r(tmpstr, ",", &saveptr); | |
c79bd073 | 835 | while (pch != NULL) { |
e8b4313e | 836 | pch = strtok_r(NULL, ",", &saveptr); |
c79bd073 TO |
837 | count++; |
838 | } | |
8530b16e TO |
839 | dprintf("- %d dash value(s) found: ", count); |
840 | if (count > 0) { | |
841 | gdp->dash = 1; | |
842 | gdp->ndash = count; | |
843 | gdp->p_dashes = (double *) malloc(sizeof(double) * count); | |
e8b4313e | 844 | pch = strtok_r(csv, ",", &saveptr); |
8530b16e TO |
845 | count = 0; |
846 | while (pch != NULL) { | |
847 | if (sscanf(pch, "%f", &dsh)) { | |
848 | gdp->p_dashes[count] = (double) dsh; | |
849 | dprintf("%.1f ", gdp->p_dashes[count]); | |
850 | count++; | |
851 | } | |
e8b4313e | 852 | pch = strtok_r(NULL, ",", &saveptr); |
c79bd073 | 853 | } |
8530b16e TO |
854 | dprintf("\n"); |
855 | } else | |
856 | dprintf("- syntax error. No dash lengths found!\n"); | |
c79bd073 | 857 | (*eaten) += j; |
8530b16e TO |
858 | } else |
859 | dprintf("- error: expected dashes[=...], found %s\n", tmpstr); | |
860 | if (line[*eaten] == ':') { | |
861 | (*eaten) += 1; | |
862 | } else if (line[*eaten] == '\0') { | |
c79bd073 TO |
863 | dprintf("- done parsing line\n"); |
864 | return 0; | |
865 | } | |
8530b16e TO |
866 | /* dashes[=n_on[,n_off[,n_on,n_off]]]:dash-offset=offset |
867 | allowing 16 characters for dash-offset=.... | |
868 | => 4 characters for the offset value */ | |
c79bd073 TO |
869 | j = scan_for_col(&line[*eaten], 16, tmpstr); |
870 | if (sscanf(tmpstr, "dash-offset=%lf", &gdp->offset)) { | |
8530b16e | 871 | dprintf("- found dash-offset=%.1f\n", gdp->offset); |
c79bd073 TO |
872 | gdp->dash = 1; |
873 | (*eaten) += j; | |
874 | if (line[*eaten] == ':') | |
875 | (*eaten) += 1; | |
876 | } | |
877 | if (line[*eaten] == '\0') { | |
878 | dprintf("- done parsing line\n"); | |
879 | return 0; | |
18cadd88 TO |
880 | } |
881 | } | |
882 | if (line[*eaten] == '\0') { | |
883 | dprintf("- done parsing line\n"); | |
884 | return 0; | |
3da125e9 TO |
885 | } |
886 | (*eaten)++; | |
18cadd88 | 887 | dprintf("- parsing '%s'\n", &line[*eaten]); |
3da125e9 | 888 | |
6465207c AB |
889 | return 0; |
890 | } | |
891 | ||
18cadd88 TO |
892 | int rrd_parse_make_vname( |
893 | const char *const line, | |
894 | unsigned int *const eaten, | |
c4e8c1ea TO |
895 | graph_desc_t *const gdp, |
896 | image_desc_t *const im) | |
18cadd88 TO |
897 | { |
898 | char tmpstr[MAX_VNAME_LEN + 10]; | |
899 | int i = 0; | |
adb27eb6 | 900 | |
18cadd88 | 901 | sscanf(&line[*eaten], DEF_NAM_FMT "=%n", tmpstr, &i); |
6465207c | 902 | if (!i) { |
18cadd88 TO |
903 | rrd_set_error("Cannot parse vname from '%s'", line); |
904 | return 1; | |
6465207c | 905 | } |
d2dadad0 TO |
906 | if (line[*eaten+i] == '\0') { |
907 | rrd_set_error("String ends after the = sign on '%s'", line); | |
908 | return 1; | |
909 | } | |
18cadd88 | 910 | dprintf("- found candidate '%s'\n", tmpstr); |
adb27eb6 | 911 | |
18cadd88 TO |
912 | if ((gdp->vidx = find_var(im, tmpstr)) >= 0) { |
913 | rrd_set_error("Attempting to reuse '%s'", im->gdes[gdp->vidx].vname); | |
914 | return 1; | |
6465207c | 915 | } |
18cadd88 TO |
916 | strcpy(gdp->vname, tmpstr); |
917 | dprintf("- created vname '%s' vidx %lu\n", gdp->vname, im->gdes_c - 1); | |
918 | (*eaten) += i; | |
6465207c | 919 | return 0; |
adb27eb6 AB |
920 | } |
921 | ||
18cadd88 TO |
922 | int rrd_parse_def( |
923 | const char *const line, | |
924 | unsigned int *const eaten, | |
c4e8c1ea TO |
925 | graph_desc_t *const gdp, |
926 | image_desc_t *const im) | |
18cadd88 TO |
927 | { |
928 | int i = 0; | |
929 | char command[7]; /* step, start, end, reduce */ | |
930 | char tmpstr[256]; | |
b8c8cf9f | 931 | rrd_time_value_t start_tv, end_tv; |
18cadd88 TO |
932 | time_t start_tmp = 0, end_tmp = 0; |
933 | char *parsetime_error = NULL; | |
934 | ||
935 | start_tv.type = end_tv.type = ABSOLUTE_TIME; | |
936 | start_tv.offset = end_tv.offset = 0; | |
7ee93d7b TO |
937 | localtime_r(&gdp->start, &start_tv.tm); |
938 | localtime_r(&gdp->end, &end_tv.tm); | |
6465207c | 939 | |
18cadd88 TO |
940 | dprintf("- parsing '%s'\n", &line[*eaten]); |
941 | dprintf("- from line '%s'\n", line); | |
942 | ||
943 | if (rrd_parse_make_vname(line, eaten, gdp, im)) | |
944 | return 1; | |
945 | i = scan_for_col(&line[*eaten], sizeof(gdp->rrd) - 1, gdp->rrd); | |
946 | if (line[*eaten + i] != ':') { | |
947 | rrd_set_error("Problems reading database name"); | |
948 | return 1; | |
6465207c | 949 | } |
18cadd88 TO |
950 | (*eaten) += ++i; |
951 | dprintf("- using file '%s'\n", gdp->rrd); | |
6465207c | 952 | |
18cadd88 TO |
953 | i = 0; |
954 | sscanf(&line[*eaten], DS_NAM_FMT ":%n", gdp->ds_nam, &i); | |
6465207c | 955 | if (!i) { |
18cadd88 TO |
956 | rrd_set_error("Cannot parse DS in '%s'", line); |
957 | return 1; | |
6465207c | 958 | } |
18cadd88 TO |
959 | (*eaten) += i; |
960 | dprintf("- using DS '%s'\n", gdp->ds_nam); | |
6465207c | 961 | |
18cadd88 TO |
962 | if (rrd_parse_CF(line, eaten, gdp, &gdp->cf)) |
963 | return 1; | |
8db0db54 | 964 | gdp->cf_reduce = gdp->cf; |
18cadd88 TO |
965 | |
966 | if (line[*eaten] == '\0') | |
967 | return 0; | |
6465207c AB |
968 | |
969 | while (1) { | |
18cadd88 TO |
970 | dprintf("- optional parameter follows: %s\n", &line[*eaten]); |
971 | i = 0; | |
972 | sscanf(&line[*eaten], "%6[a-z]=%n", command, &i); | |
973 | if (!i) { | |
974 | rrd_set_error("Parse error in '%s'", line); | |
975 | return 1; | |
976 | } | |
977 | (*eaten) += i; | |
978 | dprintf("- processing '%s'\n", command); | |
979 | if (!strcmp("reduce", command)) { | |
980 | if (rrd_parse_CF(line, eaten, gdp, &gdp->cf_reduce)) | |
981 | return 1; | |
982 | if (line[*eaten] != '\0') | |
983 | (*eaten)--; | |
984 | } else if (!strcmp("step", command)) { | |
985 | i = 0; | |
986 | sscanf(&line[*eaten], "%lu%n", &gdp->step, &i); | |
987 | gdp->step_orig = gdp->step; | |
988 | (*eaten) += i; | |
989 | dprintf("- using step %lu\n", gdp->step); | |
990 | } else if (!strcmp("start", command)) { | |
991 | i = scan_for_col(&line[*eaten], 255, tmpstr); | |
992 | (*eaten) += i; | |
b8c8cf9f | 993 | if ((parsetime_error = rrd_parsetime(tmpstr, &start_tv))) { |
18cadd88 TO |
994 | rrd_set_error("start time: %s", parsetime_error); |
995 | return 1; | |
996 | } | |
997 | dprintf("- done parsing: '%s'\n", &line[*eaten]); | |
998 | } else if (!strcmp("end", command)) { | |
999 | i = scan_for_col(&line[*eaten], 255, tmpstr); | |
1000 | (*eaten) += i; | |
b8c8cf9f | 1001 | if ((parsetime_error = rrd_parsetime(tmpstr, &end_tv))) { |
18cadd88 TO |
1002 | rrd_set_error("end time: %s", parsetime_error); |
1003 | return 1; | |
1004 | } | |
1005 | dprintf("- done parsing: '%s'\n", &line[*eaten]); | |
b09c79e8 TO |
1006 | } else if (!strcmp("daemon", command)) { |
1007 | i = scan_for_col(&line[*eaten], | |
1008 | sizeof (gdp->daemon), gdp->daemon); | |
1009 | (*eaten) += i; | |
1010 | dprintf("- using daemon '%s'\n", gdp->daemon); | |
18cadd88 TO |
1011 | } else { |
1012 | rrd_set_error("Parse error in '%s'", line); | |
1013 | return 1; | |
1014 | } | |
1015 | if (line[*eaten] == '\0') | |
1016 | break; | |
1017 | if (line[*eaten] != ':') { | |
1018 | dprintf("- Expected to see end of string but got '%s'\n", | |
1019 | &line[*eaten]); | |
1020 | rrd_set_error("Parse error in '%s'", line); | |
1021 | return 1; | |
1022 | } | |
1023 | (*eaten)++; | |
1024 | } | |
b8c8cf9f TO |
1025 | if (rrd_proc_start_end(&start_tv, &end_tv, &start_tmp, &end_tmp) == -1) { |
1026 | /* error string is set in rrd_parsetime.c */ | |
18cadd88 TO |
1027 | return 1; |
1028 | } | |
1029 | if (start_tmp < 3600 * 24 * 365 * 10) { | |
1030 | rrd_set_error("the first entry to fetch should be " | |
1031 | "after 1980 (%ld)", start_tmp); | |
1032 | return 1; | |
6465207c AB |
1033 | } |
1034 | ||
1035 | if (end_tmp < start_tmp) { | |
18cadd88 TO |
1036 | rrd_set_error("start (%ld) should be less than end (%ld)", |
1037 | start_tmp, end_tmp); | |
1038 | return 1; | |
6465207c AB |
1039 | } |
1040 | ||
1041 | gdp->start = start_tmp; | |
1042 | gdp->end = end_tmp; | |
564ca7e9 TO |
1043 | gdp->start_orig = start_tmp; |
1044 | gdp->end_orig = end_tmp; | |
6465207c | 1045 | |
18cadd88 TO |
1046 | dprintf("- start time %lu\n", gdp->start); |
1047 | dprintf("- end time %lu\n", gdp->end); | |
6465207c AB |
1048 | |
1049 | return 0; | |
1050 | } | |
adb27eb6 | 1051 | |
18cadd88 TO |
1052 | int rrd_parse_vdef( |
1053 | const char *const line, | |
1054 | unsigned int *const eaten, | |
c4e8c1ea TO |
1055 | graph_desc_t *const gdp, |
1056 | image_desc_t *const im) | |
18cadd88 TO |
1057 | { |
1058 | char tmpstr[MAX_VNAME_LEN + 1]; /* vname\0 */ | |
1059 | int i = 0; | |
6465207c | 1060 | |
18cadd88 TO |
1061 | dprintf("- parsing '%s'\n", &line[*eaten]); |
1062 | if (rrd_parse_make_vname(line, eaten, gdp, im)) | |
1063 | return 1; | |
6465207c | 1064 | |
18cadd88 | 1065 | sscanf(&line[*eaten], DEF_NAM_FMT ",%n", tmpstr, &i); |
6465207c | 1066 | if (!i) { |
18cadd88 TO |
1067 | rrd_set_error("Cannot parse line '%s'", line); |
1068 | return 1; | |
6465207c | 1069 | } |
18cadd88 TO |
1070 | if ((gdp->vidx = find_var(im, tmpstr)) < 0) { |
1071 | rrd_set_error("Not a valid vname: %s in line %s", tmpstr, line); | |
1072 | return 1; | |
6465207c | 1073 | } |
18cadd88 TO |
1074 | if (im->gdes[gdp->vidx].gf != GF_DEF && im->gdes[gdp->vidx].gf != GF_CDEF) { |
1075 | rrd_set_error("variable '%s' not DEF nor " | |
1076 | "CDEF in VDEF '%s'", tmpstr, gdp->vname); | |
1077 | return 1; | |
6465207c | 1078 | } |
18cadd88 TO |
1079 | dprintf("- found vname: '%s' vidx %li\n", tmpstr, gdp->vidx); |
1080 | (*eaten) += i; | |
6465207c | 1081 | |
18cadd88 TO |
1082 | dprintf("- calling vdef_parse with param '%s'\n", &line[*eaten]); |
1083 | vdef_parse(gdp, &line[*eaten]); | |
1084 | while (line[*eaten] != '\0' && line[*eaten] != ':') | |
1085 | (*eaten)++; | |
6465207c AB |
1086 | |
1087 | return 0; | |
1088 | } | |
1089 | ||
18cadd88 TO |
1090 | int rrd_parse_cdef( |
1091 | const char *const line, | |
1092 | unsigned int *const eaten, | |
c4e8c1ea TO |
1093 | graph_desc_t *const gdp, |
1094 | image_desc_t *const im) | |
18cadd88 TO |
1095 | { |
1096 | dprintf("- parsing '%s'\n", &line[*eaten]); | |
1097 | if (rrd_parse_make_vname(line, eaten, gdp, im)) | |
1098 | return 1; | |
1099 | if ((gdp->rpnp = rpn_parse((void *) im, &line[*eaten], &find_var_wrapper) | |
1100 | ) == NULL) { | |
1101 | rrd_set_error("invalid rpn expression in: %s", &line[*eaten]); | |
1102 | return 1; | |
6465207c | 1103 | }; |
18cadd88 TO |
1104 | while (line[*eaten] != '\0' && line[*eaten] != ':') |
1105 | (*eaten)++; | |
6465207c AB |
1106 | return 0; |
1107 | } | |
1108 | ||
18cadd88 TO |
1109 | void rrd_graph_script( |
1110 | int argc, | |
1111 | char *argv[], | |
c4e8c1ea | 1112 | image_desc_t *const im, |
18cadd88 TO |
1113 | int optno) |
1114 | { | |
1115 | int i; | |
1116 | ||
e2cc7239 | 1117 | /* save state for STACK backward compat function */ |
18cadd88 TO |
1118 | enum gf_en last_gf = GF_PRINT; |
1119 | float last_linewidth = 0.0; | |
6465207c | 1120 | |
18cadd88 TO |
1121 | for (i = optind + optno; i < argc; i++) { |
1122 | graph_desc_t *gdp; | |
1123 | unsigned int eaten = 0; | |
6465207c | 1124 | |
18cadd88 TO |
1125 | if (gdes_alloc(im)) |
1126 | return; /* the error string is already set */ | |
1127 | gdp = &im->gdes[im->gdes_c - 1]; | |
6465207c | 1128 | #ifdef DEBUG |
18cadd88 | 1129 | gdp->debug = 1; |
6465207c AB |
1130 | #endif |
1131 | ||
18cadd88 TO |
1132 | if (rrd_parse_find_gf(argv[i], &eaten, gdp)) |
1133 | return; | |
1134 | ||
1135 | switch (gdp->gf) { | |
1136 | case GF_SHIFT: /* vname:value */ | |
1137 | if (rrd_parse_shift(argv[i], &eaten, gdp, im)) | |
1138 | return; | |
1139 | break; | |
01496ecb TO |
1140 | case GF_TEXTALIGN: /* left|right|center|justified */ |
1141 | if (rrd_parse_textalign(argv[i], &eaten, gdp)) | |
1142 | return; | |
1143 | break; | |
18cadd88 TO |
1144 | case GF_XPORT: |
1145 | if (rrd_parse_xport(argv[i], &eaten, gdp, im)) | |
1146 | return; | |
1147 | break; | |
1148 | case GF_PRINT: /* vname:CF:format -or- vname:format */ | |
1149 | im->prt_c++; | |
1150 | case GF_GPRINT: /* vname:CF:format -or- vname:format */ | |
1151 | if (rrd_parse_print(argv[i], &eaten, gdp, im)) | |
1152 | return; | |
1153 | break; | |
1154 | case GF_COMMENT: /* text */ | |
1155 | if (rrd_parse_legend(argv[i], &eaten, gdp)) | |
1156 | return; | |
1157 | break; | |
18cadd88 TO |
1158 | case GF_VRULE: /* value#color[:legend] */ |
1159 | case GF_HRULE: /* value#color[:legend] */ | |
1160 | case GF_LINE: /* vname-or-value[#color[:legend]][:STACK] */ | |
1161 | case GF_AREA: /* vname-or-value[#color[:legend]][:STACK] */ | |
58e13ed8 | 1162 | case GF_GRAD: /* vname-or-value[#color[:legend][#color[:gradientheight]]][:STACK] */ |
18cadd88 TO |
1163 | case GF_TICK: /* vname#color[:num[:legend]] */ |
1164 | if (rrd_parse_PVHLAST(argv[i], &eaten, gdp, im)) | |
1165 | return; | |
1166 | last_gf = gdp->gf; | |
1167 | last_linewidth = gdp->linewidth; | |
1168 | break; | |
1169 | case GF_STACK: /* vname-or-value[#color[:legend]] */ | |
1170 | if (rrd_parse_PVHLAST(argv[i], &eaten, gdp, im)) | |
1171 | return; | |
58e13ed8 | 1172 | if (last_gf == GF_LINE || last_gf == GF_AREA || last_gf == GF_GRAD) { |
18cadd88 TO |
1173 | gdp->gf = last_gf; |
1174 | gdp->linewidth = last_linewidth; | |
1175 | } else { | |
1176 | rrd_set_error("STACK must follow LINE or AREA! command:\n%s", | |
1177 | &argv[i][eaten], argv[i]); | |
1178 | return; | |
1179 | } | |
1180 | break; | |
1181 | /* data acquisition */ | |
1182 | case GF_DEF: /* vname=x:DS:CF:[:step=#][:start=#][:end=#] */ | |
1183 | if (rrd_parse_def(argv[i], &eaten, gdp, im)) | |
1184 | return; | |
1185 | break; | |
1186 | case GF_CDEF: /* vname=rpn-expression */ | |
1187 | if (rrd_parse_cdef(argv[i], &eaten, gdp, im)) | |
1188 | return; | |
1189 | break; | |
1190 | case GF_VDEF: /* vname=rpn-expression */ | |
1191 | if (rrd_parse_vdef(argv[i], &eaten, gdp, im)) | |
1192 | return; | |
1193 | break; | |
1194 | } | |
1195 | if (gdp->debug) { | |
0a6a55e2 | 1196 | dprintf("used %i out of %zi chars\n", eaten, strlen(argv[i])); |
18cadd88 TO |
1197 | dprintf("parsed line: '%s'\n", argv[i]); |
1198 | dprintf("remaining: '%s'\n", &argv[i][eaten]); | |
1199 | if (eaten >= strlen(argv[i])) | |
1200 | dprintf("Command finished successfully\n"); | |
1201 | } | |
1202 | if (eaten < strlen(argv[i])) { | |
01496ecb | 1203 | rrd_set_error("I don't understand '%s' in command: '%s'.", |
18cadd88 TO |
1204 | &argv[i][eaten], argv[i]); |
1205 | return; | |
1206 | } | |
6465207c AB |
1207 | } |
1208 | } |