+ }
+ *eaten+=++i;
+
+ /* If a color is specified and the only remaining part is
+ ** ":STACK" then it is assumed to be the legend. An empty
+ ** legend can be specified as expected. This means the
+ ** following can be done: LINE1:x#FF0000FF::STACK
+ */
+ if (colorfound) { /* no legend if no color */
+ if (gdp->gf == GF_TICK) {
+ dprintf("- looking for optional number\n");
+ sscanf(&line[*eaten],"%lf%n",&gdp->yrule,&j);
+ if (j) {
+ dprintf("- found number %f\n",gdp->yrule);
+ (*eaten)+=j;
+ if (gdp->yrule > 1.0 || gdp->yrule < -1.0) {
+ rrd_set_error("Tick factor should be <= 1.0");
+ return 1;
+ }
+ if (line[*eaten] == ':')
+ (*eaten)++;
+ } else {
+ dprintf("- not found, defaulting to 0.1\n");
+ gdp->yrule=0.1;
+ return 0;
+ }
+ }
+ dprintf("- looking for optional legend\n");
+ dprintf("- in '%s'\n",&line[*eaten]);
+ /* the legend for a graph item must start with "m " the first
+ m will then be over drawn with a color box. Since there
+ is ample space I overwrite the first few characters of the line
+ with the material that I want to see in the legend */
+ if (line[*eaten] != '\0' && line[*eaten] != ':'){
+ *eaten = *eaten - 2;
+ line[*eaten] = 'm';
+ line[*eaten+1] = ' ';
+ }
+ if (rrd_parse_legend(line, eaten, gdp)) return 1;
+ }
+
+ /* PART, HRULE, VRULE and TICK cannot be stacked. We're finished */
+ if ( (gdp->gf == GF_HRULE)
+ || (gdp->gf == GF_VRULE)
+#ifdef WITH_PIECHART
+ || (gdp->gf == GF_PART)
+#endif
+ || (gdp->gf == GF_TICK)
+ ) return 0;
+
+ if (line[*eaten]!='\0') {
+ dprintf("- still more, should be STACK\n");
+ (*eaten)++;
+ j=scan_for_col(&line[*eaten],5,tmpstr);
+ if (line[*eaten+j]!='\0') {
+ rrd_set_error("Garbage found where STACK expected");
+ return 1;
+ }
+ if (!strcmp("STACK",tmpstr)) {
+ dprintf("- found STACK\n");
+ gdp->stack=1;
+ (*eaten)+=5;
+ } else {
+ rrd_set_error("Garbage found where STACK expected");
+ return 1;
+ }
+ }
+ /* have simpler code in the drawing section */
+ if ( gdp->gf == GF_STACK ){
+ gdp->stack=1;
+ }
+ return 0;
+}
+
+int
+rrd_parse_vname(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
+ char tmpstr[MAX_VNAME_LEN + 10];
+ int i=0;
+
+ sscanf(&line[*eaten], DEF_NAM_FMT "=%n", tmpstr,&i);
+ if (!i) {
+ rrd_set_error("Cannot parse vname from '%s'",line);
+ return 1;
+ }
+ dprintf("- found candidate '%s'\n",tmpstr);
+
+ if ((gdp->vidx=find_var(im,tmpstr))>=0) {
+ rrd_set_error("Attempting to reuse '%s'",im->gdes[gdp->vidx].vname);
+ return 1;
+ }
+ strcpy(gdp->vname,tmpstr);
+ dprintf("- created vname '%s' vidx %lu\n", gdp->vname,im->gdes_c-1);
+ (*eaten)+=i;
+ return 0;
+}
+
+int
+rrd_parse_def(char *line, unsigned int *eaten, graph_desc_t *gdp, image_desc_t *im) {
+ int i=0;
+ char command[7]; /* step, start, end, reduce */
+ char tmpstr[256];
+ struct rrd_time_value start_tv,end_tv;
+ time_t start_tmp=0,end_tmp=0;
+ char *parsetime_error=NULL;
+
+ start_tv.type = end_tv.type=ABSOLUTE_TIME;
+ start_tv.offset = end_tv.offset=0;
+ localtime_r(&gdp->start, &start_tv.tm);
+ localtime_r(&gdp->end, &end_tv.tm);
+
+ dprintf("- parsing '%s'\n",&line[*eaten]);
+ dprintf("- from line '%s'\n",line);
+
+ if (rrd_parse_vname(line,eaten,gdp,im)) return 1;
+ i=scan_for_col(&line[*eaten],254,gdp->rrd);
+ if (line[*eaten+i]!=':') {
+ rrd_set_error("Problems reading database name");
+ return 1;
+ }
+ (*eaten)+=++i;
+ dprintf("- using file '%s'\n",gdp->rrd);
+
+ i=0;
+ sscanf(&line[*eaten], DS_NAM_FMT ":%n", gdp->ds_nam,&i);
+ if (!i) {
+ rrd_set_error("Cannot parse DS in '%s'",line);
+ return 1;
+ }
+ (*eaten)+=i;
+ dprintf("- using DS '%s'\n",gdp->ds_nam);
+
+ if (rrd_parse_CF(line,eaten,gdp,&gdp->cf)) return 1;
+ gdp->cf_reduce = gdp->cf;
+
+ if (line[*eaten]=='\0') return 0;
+
+ while (1) {
+ dprintf("- optional parameter follows: %s\n", &line[*eaten]);
+ i=0;
+ sscanf(&line[*eaten], "%6[a-z]=%n", command, &i);
+ if (!i) {
+ rrd_set_error("Parse error in '%s'",line);
+ return 1;
+ }
+ (*eaten)+=i;
+ dprintf("- processing '%s'\n",command);
+ if (!strcmp("reduce",command)) {
+ if (rrd_parse_CF(line,eaten,gdp,&gdp->cf_reduce)) return 1;
+ if (line[*eaten] != '\0')
+ (*eaten)--;
+ } else if (!strcmp("step",command)) {
+ i=0;
+ sscanf(&line[*eaten],"%lu%n",&gdp->step,&i);
+ (*eaten)+=i;
+ dprintf("- using step %lu\n",gdp->step);
+ } else if (!strcmp("start",command)) {
+ i=scan_for_col(&line[*eaten],255,tmpstr);
+ (*eaten)+=i;
+ if ((parsetime_error = parsetime(tmpstr, &start_tv))) {
+ rrd_set_error( "start time: %s", parsetime_error );
+ return 1;
+ }
+ dprintf("- done parsing: '%s'\n",&line[*eaten]);
+ } else if (!strcmp("end",command)) {
+ i=scan_for_col(&line[*eaten],255,tmpstr);
+ (*eaten)+=i;
+ if ((parsetime_error = parsetime(tmpstr, &end_tv))) {
+ rrd_set_error( "end time: %s", parsetime_error );
+ return 1;
+ }
+ dprintf("- done parsing: '%s'\n",&line[*eaten]);
+ } else {
+ rrd_set_error("Parse error in '%s'",line);
+ return 1;
+ }
+ if (line[*eaten]=='\0') break;
+ if (line[*eaten]!=':') {
+ dprintf("- Expected to see end of string but got '%s'\n",\
+ &line[*eaten]);
+ rrd_set_error("Parse error in '%s'",line);
+ return 1;
+ }
+ (*eaten)++;
+ }
+ if (proc_start_end(&start_tv,&end_tv,&start_tmp,&end_tmp) == -1){
+ /* error string is set in parsetime.c */
+ return 1;
+ }
+ if (start_tmp < 3600*24*365*10) {
+ rrd_set_error("the first entry to fetch should be "
+ "after 1980 (%ld)",start_tmp);
+ return 1;
+ }