+/* rrd_name_or_num()
+**
+** Scans for a VDEF-variable or a number
+**
+** Returns an integer describing what was found:
+**
+** 0: error
+** 1: found an integer; it is returned in both l and d
+** 2: found a float; it is returned in d
+** 3: found a vname; its index is returned in l
+**
+** l and d are undefined unless described above
+*/
+static int
+rrd_name_or_num(image_desc_t *im, char *param, long *l, double *d)
+{
+ int i1=0,i2=0,i3=0,i4=0,i5=0,i6=0;
+ char vname[MAX_VNAME_LEN+1];
+
+ sscanf(param, "%li%n%*s%n", l,&i1,&i2);
+ sscanf(param, "%lf%n%*s%n", d,&i3,&i4);
+ sscanf(param, DEF_NAM_FMT "%n%*s%n", vname, &i5,&i6);
+
+ if ( (i1) && (!i2) ) return 1;
+ if ( (i3) && (!i4) ) return 2;
+ if ( (i5) && (!i6) ) {
+ if ((*l = find_var(im,vname))!=-1) return 3;
+ }
+ return 0;
+}
+
+/* rrd_vname_color()
+**
+** Parses "[<vname|number>][#color]" where at least one
+** of the optional strings must exist.
+**
+** Returns an integer describing what was found.
+** If the result is 0, the rrd_error string may be set.
+**
+** ...CVVVV
+** ---------:-----------------------------------
+** 00000000 : error
+** ....0000 : a value/variable was not found
+** ....0001 : an integer number was found, returned in both l and d
+** ....0010 : a floating point number was found, returned in d
+** ....0011 : reserved for future values
+** ....01xx : reserved for future values
+** ....1000 : an existing DEF vname was found, idx returned in l
+** ....1001 : an existing CDEF vname was found, idx returned in l
+** ....1010 : an existing VDEF vname was found, idx returned in l
+** ....1011 : reserved for future variables
+** ....11xx : reserved for future variables
+** ...0.... : a color was not found, returned in color
+** ...1.... : a color was found, returned in color
+*/
+static int
+rrd_vname_color(image_desc_t *im, char * param,
+ long *l,
+ double *d,
+ gfx_color_t *color)
+{
+ int result=0,i=0;
+
+ if (param[0]!='#') { /* vname or num present or empty string */
+ char *s,*c=param;
+ while ((*c!='\0')&&(*c!='#')) c++,i++;
+ if (*c!='\0') {
+ s=malloc(i+1);
+ if (s==NULL) {
+ rrd_set_error("Out of memory in function rrd_vname_color");
+ return 0;
+ }
+ strncpy(s,param,i);
+ s[i]='\0';
+ result=rrd_name_or_num(im, s, l, d);
+ if (!result) {
+ rrd_set_error("Use of uninitialized vname %s",s);
+ free(s);
+ }
+ } else {
+ result=rrd_name_or_num(im, param, l, d);
+ if (!result) {
+ rrd_set_error("Use of uninitialized vname %s",param);
+ }
+ }
+ switch (result) {
+ case 0: return 0; /* error set above */
+ case 1:
+ case 2: break;
+ case 3:
+ switch (im->gdes[*l].gf) {
+ case GF_DEF: result=0x08;break;
+ case GF_CDEF: result=0x09;break;
+ case GF_VDEF: result=0x0A;break;
+ default:
+ rrd_set_error("Unexpected GF result from function "
+ "rrd_name_or_num() called from rrd_vname_color");
+ return 0;
+ }
+ break;
+ default:
+ rrd_set_error("Unexpected result from function "
+ "rrd_name_or_num() called from rrd_vname_color");
+ return 0;
+ }
+ }
+ /* Parse color, if any. */
+ if (param[i] == '\0') return result;
+ else {
+ unsigned int r=0,g=0,b=0,a=0xFF;
+ int i1=0,i2=0;
+ sscanf(¶m[i], "#%02x%02x%02x%n%02x%n",
+ &r,&g,&b,&i1,&a,&i2);
+ if (!i1) {
+ rrd_set_error("Unparsable color %s",¶m[i]);
+ return 0;
+ }
+ if (i2) i1=i2;
+ i2=0;
+ sscanf(¶m[i+i1],"%*s%n",&i2);
+ if (i2) {
+ rrd_set_error("Garbage after color %s",param[i]);
+ return 0;
+ }
+ *color=r<<24|g<<16|b<<8|a;
+ return result|0x10;
+ }
+}
+
+/* rrd_find_function()
+**
+** Checks if the parameter is a valid function and
+** if so, returns it in the graph description pointer.
+**
+** The return value is a boolean; true if found
+*/
+static int
+rrd_find_function(char *param, graph_desc_t *gdp)
+{
+ size_t i1=0,i2=0;
+ char funcname[11];
+
+ sscanf(param,"%10[A-Z]%n%*1[1-3]%n",funcname,(int *)&i1,(int *)&i2);
+ gdp->gf=gf_conv(funcname);
+ if ((int)gdp->gf == -1) {
+ rrd_set_error("'%s' is not a valid function name",funcname);
+ return 0;
+ }
+ if (gdp->gf==GF_LINE) {
+ if (i2) {
+ gdp->linewidth=param[i1]-'0';
+ } else {
+ rrd_set_error("LINE should have a width");
+ return 0;
+ }
+ } else {
+ if (i2) {
+ rrd_set_error("Only LINE should have a width: %s",param);
+ return 0;
+ } else {
+ i2=i1;
+ }
+ }
+ if (strlen(param) != i2) {
+ rrd_set_error("Garbage after function name: %s",param);
+ return 0;
+ }
+ return 1;
+}
+/* rrd_split_line()
+**
+** Takes a string as input; splits this line into multiple
+** parameters on each ":" boundary.
+**
+** If this function returns successful, the caller will have
+** to free() the allocated memory for param.
+**
+** The input string is destroyed, its memory is used by the
+** output array.
+*/
+static int
+rrd_split_line(char *line,char ***param)
+{
+ int i=0,n=0;
+ char *c=line;
+
+ /* scan the amount of colons in the line. We need
+ ** at most this amount+1 pointers for the array. If
+ ** any colons are escaped we waste some space.
+ */
+ if (*c!='\0') n=1;
+ while (*c != '\0')
+ if (*c++ == ':') n++;
+
+ if (n==0) {
+ rrd_set_error("No line to split. rrd_split_line was given the empty string.");
+ return -1;
+ }
+
+ /* Allocate memory for an array of n char pointers */
+ *param=calloc(n,sizeof(char *));
+ if (*param==NULL) {
+ rrd_set_error("Memory allocation failed inside rrd_split_line");
+ return -1;
+ }
+
+ /* split the line and fill the array */
+ c = line;
+ i=0;
+ (*param)[i] = c;
+ while (*c != '\0') {
+ switch (*c) {
+ case '\\':
+ c++;
+ if (*c=='\0') {
+ free(*param);
+ rrd_set_error("Lone backslash found inside rrd_split_line");
+ return -1;
+ }
+ c++;
+ break;
+ case ':':
+ *c = '\0';
+ c++;
+ i++;
+ (*param)[i] = c;
+ break;
+ default:
+ c++;
+ }
+ }
+ i++; /* i separators means i+1 parameters */
+
+ return i;
+}