X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=blobdiff_plain;f=src%2Frrd_cgi.c;h=5fc5a6235ba740a7d896306723ea6cec45e51417;hp=7f248ab04f1feac44885bd971bce88bb7d89e889;hb=c112f7c06e534ce7a5a4e25b6f7f742aeb051850;hpb=55e9b0c9f6eaa8a35d7a2e0578cdebd6032fdd19 diff --git a/src/rrd_cgi.c b/src/rrd_cgi.c index 7f248ab..5fc5a62 100644 --- a/src/rrd_cgi.c +++ b/src/rrd_cgi.c @@ -1,5 +1,5 @@ /***************************************************************************** - * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2002 + * RRDtool 1.2rc3 Copyright by Tobi Oetiker, 1997-2005 ***************************************************************************** * rrd_cgi.c RRD Web Page Generator *****************************************************************************/ @@ -10,13 +10,15 @@ #define MEMBLK 1024 +/*#define DEBUG_PARSER +#define DEBUG_VARS*/ /* global variable for libcgi */ -s_cgi **cgiArg; +s_cgi *cgiArg; /* in arg[0] find tags beginning with arg[1] call arg[2] on them and replace by result of arg[2] call */ -int parse(char **, long, char *, char *(*)(long , char **)); +int parse(char **, long, char *, char *(*)(long , const char **)); /**************************************************/ /* tag replacers ... they are called from parse */ @@ -24,46 +26,206 @@ int parse(char **, long, char *, char *(*)(long , char **)); /**************************************************/ /* return cgi var named arg[0] */ -char* cgiget(long , char **); +char* cgiget(long , const char **); /* return a quoted cgi var named arg[0] */ -char* cgigetq(long , char **); +char* cgigetq(long , const char **); /* return a quoted and sanitized cgi variable */ -char* cgigetqp(long , char **); +char* cgigetqp(long , const char **); -/* call rrd_graph and insert apropriate image tag */ +/* call rrd_graph and insert appropriate image tag */ char* drawgraph(long, char **); /* return PRINT functions from last rrd_graph call */ -char* drawprint(long, char **); +char* drawprint(long, const char **); /* pretty-print the value for some.rrd via strftime() */ -char* printtimelast(long, char **); +char* printtimelast(long, const char **); /* pretty-print current time */ -char* printtimenow(long,char **); +char* printtimenow(long, const char **); -/* set an evironment variable */ -char* rrdsetenv(long, char **); +/* set an environment variable */ +char* rrdsetenv(long, const char **); -/* get an evironment variable */ -char* rrdgetenv(long, char **); +/* get an environment variable */ +char* rrdgetenv(long, const char **); /* include the named file at this point */ -char* includefile(long, char **); +char* includefile(long, const char **); /* for how long is the output of the cgi valid ? */ -char* rrdgoodfor(long, char **); +char* rrdgoodfor(long, const char **); + +char* rrdstrip(char *buf); +char* scanargs(char *line, int *argc, char ***args); /* format at-time specified times using strftime */ -char* printstrftime(long, char**); +char* printstrftime(long, const char**); -/** http protocol needs special format, and GMT time **/ +/** HTTP protocol needs special format, and GMT time **/ char *http_time(time_t *); -/* return a pointer to newly alocated copy of this string */ -char *stralloc(char *); +/* return a pointer to newly allocated copy of this string */ +char *stralloc(const char *); + + +/* rrd interface to the variable functions {put,get}var() */ +char* rrdgetvar(long argc, const char **args); +char* rrdsetvar(long argc, const char **args); +char* rrdsetvarconst(long argc, const char **args); + + +/* variable store: put/get key-value pairs */ +static int initvar(); +static void donevar(); +static const char* getvar(const char* varname); +static const char* putvar(const char* name, const char* value, int is_const); + +/* key value pair that makes up an entry in the variable store */ +typedef struct +{ + int is_const; /* const variable or not */ + const char* name; /* variable name */ + const char* value; /* variable value */ +} vardata; + +/* the variable heap: + start with a heapsize of 10 variables */ +#define INIT_VARSTORE_SIZE 10 +static vardata* varheap = NULL; +static size_t varheap_size = 0; + +/* allocate and initialize variable heap */ +static int +initvar() +{ + varheap = (vardata*)malloc(sizeof(vardata) * INIT_VARSTORE_SIZE); + if (varheap == NULL) { + fprintf(stderr, "ERROR: unable to initialize variable store\n"); + return -1; + } + memset(varheap, 0, sizeof(vardata) * INIT_VARSTORE_SIZE); + varheap_size = INIT_VARSTORE_SIZE; + return 0; +} + +/* cleanup: free allocated memory */ +static void +donevar() +{ + int i; + if (varheap) { + for (i=0; i<(int)varheap_size; i++) { + if (varheap[i].name) { + free((char*)varheap[i].name); + } + if (varheap[i].value) { + free((char*)varheap[i].value); + } + } + free(varheap); + } +} + +/* Get a variable from the variable store. + Return NULL in case the requested variable was not found. */ +static const char* +getvar(const char* name) +{ + int i; + for (i=0; i<(int)varheap_size && varheap[i].name; i++) { + if (0 == strcmp(name, varheap[i].name)) { +#ifdef DEBUG_VARS + printf("\n", name, varheap[i].value); +#endif + return varheap[i].value; + } + } +#ifdef DEBUG_VARS + printf("\n", name); +#endif + return NULL; +} + +/* Put a variable into the variable store. If a variable by that + name exists, it's value is overwritten with the new value unless it was + marked as 'const' (initialized by RRD::SETCONSTVAR). + Returns a copy the newly allocated value on success, NULL on error. */ +static const char* +putvar(const char* name, const char* value, int is_const) +{ + int i; + for (i=0; i < (int)varheap_size && varheap[i].name; i++) { + if (0 == strcmp(name, varheap[i].name)) { + /* overwrite existing entry */ + if (varheap[i].is_const) { +#ifdef DEBUG_VARS + printf("\n", name, value); +# endif + return varheap[i].value; + } +#ifdef DEBUG_VARS + printf("\n", + name, value, varheap[i].value); +#endif + /* make it possible to promote a variable to readonly */ + varheap[i].is_const = is_const; + free((char*)varheap[i].value); + varheap[i].value = stralloc(value); + return varheap[i].value; + } + } + + /* no existing variable found by that name, add it */ + if (i == (int)varheap_size) { + /* ran out of heap: resize heap to double size */ + size_t new_size = varheap_size * 2; + varheap = (vardata*)(realloc(varheap, sizeof(vardata) * new_size)); + if (!varheap) { + fprintf(stderr, "ERROR: Unable to realloc variable heap\n"); + return NULL; + } + /* initialize newly allocated memory */; + memset(&varheap[varheap_size], 0, sizeof(vardata) * varheap_size); + varheap_size = new_size; + } + varheap[i].is_const = is_const; + varheap[i].name = stralloc(name); + varheap[i].value = stralloc(value); + +#ifdef DEBUG_VARS + printf("\n", name, value); +#endif + return varheap[i].value; +} + +/* expand those RRD:* directives that can be used recursivly */ +static char* +rrd_expand_vars(char* buffer) +{ + int i; + +#ifdef DEBUG_PARSER + printf("expanding variables in '%s'\n", buffer); +#endif + + for (i=0; buffer[i]; i++) { + if (buffer[i] != '<') + continue; + parse(&buffer, i, "= argc ) { + fprintf(stderr, "ERROR: expected a filename\n"); + exit(1); + } else { + length = readfile(argv[optind], &buffer, 1); + } - /* pass 2 */ - for (i=0;buffer[i] != '\0'; i++){ - i += parse(&buffer,i," 0){ - time_t now; - now = time(NULL); - printf ("Last-Modified: %s\n",http_time(&now)); - now += labs(goodfor); - printf ("Expires: %s\n",http_time(&now)); - if (goodfor < 0) { - printf("Refresh: %ld\n", labs(goodfor)); - } - } - printf ("\n"); - } - printf ("%s", buffer); - calfree(); - if (buffer){ - free(buffer); - } - exit(0); +#ifdef DEBUG_PARSER + /* some fake header for testing */ + printf ("Content-Type: text/html\nContent-Length: 10000000\n\n\n"); +#endif + + + /* expand rrd directives in buffer recursivly */ + for (i=0; buffer[i]; i++) { + if (buffer[i] != '<') + continue; + if (!filter) { + parse(&buffer, i, " 0) { + time_t now; + now = time(NULL); + printf("Last-Modified: %s\n", http_time(&now)); + now += labs(goodfor); + printf("Expires: %s\n", http_time(&now)); + if (goodfor < 0) { + printf("Refresh: %ld\n", labs(goodfor)); + } + } + printf("\n"); + } + + /* output result */ + printf("%s", buffer); + + /* cleanup */ + calfree(); + if (buffer){ + free(buffer); + } + donevar(); + exit(0); } -/* remove occurences of .. this is a general measure to make +/* remove occurrences of .. this is a general measure to make paths which came in via cgi do not go UP ... */ -char* rrdsetenv(long argc, char **args){ - if (argc >= 2) { - char *xyz=malloc((strlen(args[0])+strlen(args[1])+3)*sizeof(char)); - if (xyz == NULL){ - return stralloc("[ERROR: allocating setenv buffer]"); - }; - sprintf(xyz,"%s=%s",args[0],args[1]); - if( putenv(xyz) == -1) { - return stralloc("[ERROR: faild to do putenv]"); - }; - } else { - return stralloc("[ERROR: setenv faild because not enough arguments were defined]"); - } - return stralloc(""); +char* rrdsetenv(long argc, const char **args) { + if (argc >= 2) { + char *xyz = malloc((strlen(args[0]) + strlen(args[1]) + 2)); + if (xyz == NULL) { + return stralloc("[ERROR: allocating setenv buffer]"); + }; + sprintf(xyz, "%s=%s", args[0], args[1]); + if(putenv(xyz) == -1) { + free(xyz); + return stralloc("[ERROR: failed to do putenv]"); + }; + return stralloc(""); + } + return stralloc("[ERROR: setenv failed because not enough " + "arguments were defined]"); } -char* rrdgetenv(long argc, char **args){ - if (argc != 1) { - return stralloc("[ERROR: getenv faild because it did not get 1 argument only]"); - } - else if (getenv(args[0]) == NULL) { - return stralloc(""); - } - else { - return stralloc(getenv(args[0])); - } +/* rrd interface to the variable function putvar() */ +char* +rrdsetvar(long argc, const char **args) +{ + if (argc >= 2) + { + const char* result = putvar(args[0], args[1], 0 /* not const */); + if (result) { + /* setvar does not return the value set */ + return stralloc(""); + } + return stralloc("[ERROR: putvar failed]"); + } + return stralloc("[ERROR: putvar failed because not enough arguments " + "were defined]"); } -char* rrdgoodfor(long argc, char **args){ +/* rrd interface to the variable function putvar() */ +char* +rrdsetvarconst(long argc, const char **args) +{ + if (argc >= 2) + { + const char* result = putvar(args[0], args[1], 1 /* const */); + if (result) { + /* setvar does not return the value set */ + return stralloc(""); + } + return stralloc("[ERROR: putvar failed]"); + } + return stralloc("[ERROR: putvar failed because not enough arguments " + "were defined]"); +} + +char* rrdgetenv(long argc, const char **args) { + char buf[128]; + const char* envvar; + if (argc != 1) { + return stralloc("[ERROR: getenv failed because it did not " + "get 1 argument only]"); + }; + envvar = getenv(args[0]); + if (envvar) { + return stralloc(envvar); + } else { +#ifdef WIN32 + _snprintf(buf, sizeof(buf), "[ERROR:_getenv_'%s'_failed", args[0]); +#else + snprintf(buf, sizeof(buf), "[ERROR:_getenv_'%s'_failed", args[0]); +#endif + return stralloc(buf); + } +} + +char* rrdgetvar(long argc, const char **args) { + char buf[128]; + const char* value; + if (argc != 1) { + return stralloc("[ERROR: getvar failed because it did not " + "get 1 argument only]"); + }; + value = getvar(args[0]); + if (value) { + return stralloc(value); + } else { +#ifdef WIN32 + _snprintf(buf, sizeof(buf), "[ERROR:_getvar_'%s'_failed", args[0]); +#else + snprintf(buf, sizeof(buf), "[ERROR:_getvar_'%s'_failed", args[0]); +#endif + return stralloc(buf); + } +} + +char* rrdgoodfor(long argc, const char **args){ if (argc == 1) { goodfor = atol(args[0]); } else { @@ -246,7 +490,7 @@ char* rrdgoodfor(long argc, char **args){ * start and end times, because, either might be relative to the other. * */ #define MAX_STRFTIME_SIZE 256 -char* printstrftime(long argc, char **args){ +char* printstrftime(long argc, const char **args){ struct rrd_time_value start_tv, end_tv; char *parsetime_error = NULL; char formatted[MAX_STRFTIME_SIZE]; @@ -298,12 +542,13 @@ char* printstrftime(long argc, char **args){ } } -char* includefile(long argc, char **args){ +char* includefile(long argc, const char **args){ char *buffer; if (argc >= 1) { - readfile(args[0], &buffer, 0); + char* filename = args[0]; + readfile(filename, &buffer, 0); if (rrd_test_error()) { - char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE)*sizeof(char)); + char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE)); sprintf(err, "[ERROR: %s]",rrd_get_error()); rrd_clear_error(); return err; @@ -317,22 +562,29 @@ char* includefile(long argc, char **args){ } } -static -char* rrdstrip(char *buf){ - char *start; - if (buf == NULL) return NULL; - buf = stralloc(buf); /* make a copy of the buffer */ - if (buf == NULL) return NULL; - while ((start = strstr(buf,"<"))){ - *start = '_'; +/* make a copy of buf and replace open/close brackets with '_' */ +char* rrdstrip(char *buf) { + char* p; + if (buf == NULL) { + return NULL; } - while ((start = strstr(buf,">"))){ - *start = '_'; + /* make a copy of the buffer */ + buf = stralloc(buf); + if (buf == NULL) { + return NULL; + } + + p = buf; + while (*p) { + if (*p == '<' || *p == '>') { + *p = '_'; + } + p++; } return buf; } -char* cgigetq(long argc, char **args){ +char* cgigetq(long argc, const char **args){ if (argc>= 1){ char *buf = rrdstrip(cgiGetValue(cgiArg,args[0])); char *buf2; @@ -342,7 +594,7 @@ char* cgigetq(long argc, char **args){ for(c=buf;*c != '\0';c++) if (*c == '"') qc++; - if((buf2=malloc((strlen(buf) + qc*4 +4) * sizeof(char)))==NULL){ + if ((buf2 = malloc((strlen(buf) + 4 * qc + 4))) == NULL) { perror("Malloc Buffer"); exit(1); }; @@ -367,57 +619,66 @@ char* cgigetq(long argc, char **args){ return stralloc("[ERROR: not enough argument for RRD::CV::QUOTE]"); } -/* remove occurences of .. this is a general measure to make +/* remove occurrences of .. this is a general measure to make paths which came in via cgi do not go UP ... */ -char* cgigetqp(long argc, char **args){ - if (argc>= 1){ - char *buf = rrdstrip(cgiGetValue(cgiArg,args[0])); - char *buf2; - char *c,*d; - int qc=0; - if (buf==NULL) return NULL; - - for(c=buf;*c != '\0';c++) - if (*c == '"') qc++; - if((buf2=malloc((strlen(buf) + qc*4 +4) * sizeof(char)))==NULL){ - perror("Malloc Buffer"); - exit(1); +char* cgigetqp(long argc, const char **args){ + char* buf; + char* buf2; + char* p; + char* d; + + if (argc < 1) + { + return stralloc("[ERROR: not enough arguments for RRD::CV::PATH]"); + } + + buf = rrdstrip(cgiGetValue(cgiArg, args[0])); + if (!buf) + { + return NULL; + } + + buf2 = malloc(strlen(buf)+1); + if (!buf2) + { + perror("cgigetqp(): Malloc Path Buffer"); + exit(1); }; - c=buf; - d=buf2; - *(d++) = '"'; - while(*c != '\0'){ - if (*c == '"') { - *(d++) = '"'; - *(d++) = '\''; - *(d++) = '"'; - *(d++) = '\''; - } - if(*c == '/') { - *(d++) = '_';c++; - } else { - if (*c=='.' && *(c+1) == '.'){ - c += 2; - *(d++) = '_'; *(d++) ='_'; - } else { - - *(d++) = *(c++); - } - } + + p = buf; + d = buf2; + + while (*p) + { + /* prevent mallicious paths from entering the system */ + if (p[0] == '.' && p[1] == '.') + { + p += 2; + *d++ = '_'; + *d++ = '_'; + } + else + { + *d++ = *p++; + } } - *(d++) = '"'; - *(d) = '\0'; + + *d = 0; free(buf); - return buf2; - } - return stralloc("[ERROR: not enough arguments for RRD::CV::PATH]"); + /* Make sure the path is relative, e.g. does not start with '/' */ + p = buf2; + while ('/' == *p) + { + *p++ = '_'; + } + return buf2; } -char* cgiget(long argc, char **args){ +char* cgiget(long argc, const char **args){ if (argc>= 1) return rrdstrip(cgiGetValue(cgiArg,args[0])); else @@ -428,6 +689,7 @@ char* cgiget(long argc, char **args){ char* drawgraph(long argc, char **args){ int i,xsize, ysize; + double ymin,ymax; for(i=0;i' arives */ -static -char* scanargs(char *aLine, long *argc, char ***args) +/* Scan buffer until an unescaped '>' arives. + * Update argument array with arguments found. + * Return end cursor where parsing stopped, or NULL in case of failure. + * + * FIXME: + * To allow nested constructs, we call rrd_expand_vars() for arguments + * that contain RRD::x directives. These introduce a small memory leak + * since we have to stralloc the arguments the way parse() works. + */ +char* +scanargs(char *line, int *argument_count, char ***arguments) { - char *getP, *putP; - char Quote = 0; - int argal = MEMBLK; - int braket = 0; - int inArg = 0; - if (((*args) = (char **) malloc(MEMBLK*sizeof(char *))) == NULL) { - return NULL; - } - /* sikp leading blanks */ - while (*aLine && *aLine <= ' ') aLine++; - - *argc = 0; - getP = aLine; - putP = aLine; - while (*getP && !( !Quote && (braket == 0) && ((*getP) == '>'))){ - if ((unsigned)*getP < ' ') *getP = ' '; /*remove all special chars*/ - switch (*getP) { - case ' ': - if (Quote){ - *(putP++)=*getP; - } else - if(inArg) { - *(putP++) = 0; - inArg = 0; - } - break; - case '"': - case '\'': - if (Quote != 0) { - if (Quote == *getP) - Quote = 0; - else { - *(putP++)=*getP; + char *getP; /* read cursor */ + char *putP; /* write cursor */ + char Quote; /* type of quote if in quoted string, 0 otherwise */ + int tagcount; /* open tag count */ + int in_arg; /* if we currently are parsing an argument or not */ + int argsz; /* argument array size */ + int curarg_contains_rrd_directives; + + /* local array of arguments while parsing */ + int argc = 0; + char** argv; + +#ifdef DEBUG_PARSER + printf("<-- scanargs(%s) -->\n", line); +#endif + + *arguments = NULL; + *argument_count = 0; + + /* create initial argument array of char pointers */ + argsz = 32; + argv = (char **)malloc(argsz * sizeof(char *)); + if (!argv) { + return NULL; } - } else { - if(!inArg){ - (*args)[++(*argc)] = putP; - inArg=1; - } - Quote = *getP; - } - break; - default: - if (Quote == 0 && (*getP) == '<') { - braket++; - } - if (Quote == 0 && (*getP) == '>') { - braket--; - } - if(!inArg){ - (*args)[++(*argc)] = putP; - inArg=1; - } - *(putP++)=*getP; - break; - } - if ((*argc) >= argal-10 ) { - argal += MEMBLK; - if (((*args)=rrd_realloc((*args),(argal)*sizeof(char *))) == NULL) { - return NULL; - } - } - getP++; - } - - *putP = '\0'; - (*argc)++; - if (Quote) - return NULL; - else - return getP+1; /* pointer to next char after parameter */ + /* skip leading blanks */ + while (isspace((int)*line)) { + line++; + } + + getP = line; + putP = line; + + Quote = 0; + in_arg = 0; + tagcount = 0; + + curarg_contains_rrd_directives = 0; + + /* start parsing 'line' for arguments */ + while (*getP) + { + unsigned char c = *getP++; + + if (c == '>' && !Quote && !tagcount) { + /* this is our closing tag, quit scanning */ + break; + } + + /* remove all special chars */ + if (c < ' ') { + c = ' '; + } + + switch (c) + { + case ' ': + if (Quote || tagcount) { + /* copy quoted/tagged (=RRD expanded) string */ + *putP++ = c; + } + else if (in_arg) + { + /* end argument string */ + *putP++ = 0; + in_arg = 0; + if (curarg_contains_rrd_directives) { + argv[argc-1] = rrd_expand_vars(stralloc(argv[argc-1])); + curarg_contains_rrd_directives = 0; + } + } + break; + + case '"': /* Fall through */ + case '\'': + if (Quote != 0) { + if (Quote == c) { + Quote = 0; + } else { + /* copy quoted string */ + *putP++ = c; + } + } else { + if (!in_arg) { + /* reference start of argument string in argument array */ + argv[argc++] = putP; + in_arg=1; + } + Quote = c; + } + break; + + default: + if (!in_arg) { + /* start new argument */ + argv[argc++] = putP; + in_arg = 1; + } + if (c == '>') { + if (tagcount) { + tagcount--; + } + } + if (c == '<') { + tagcount++; + if (0 == strncmp(getP, "RRD::", strlen("RRD::"))) { + curarg_contains_rrd_directives = 1; + } + } + *putP++ = c; + break; + } + + /* check if our argument array is still large enough */ + if (argc == argsz) { + /* resize argument array */ + argsz *= 2; + argv = rrd_realloc(argv, argsz * sizeof(char *)); + if (*argv == NULL) { + return NULL; + } + } + } + + /* terminate last argument found */ + *putP = '\0'; + if (curarg_contains_rrd_directives) { + argv[argc-1] = rrd_expand_vars(stralloc(argv[argc-1])); + } + +#ifdef DEBUG_PARSER + if (argc > 0) { + int n; + printf("<-- arguments found [%d]\n", argc); + for (n=0; n\n"); + } else { + printf("\n"); + } +#endif + + /* update caller's notion of the argument array and it's size */ + *arguments = argv; + *argument_count = argc; + + if (Quote) { + return NULL; + } + + /* Return new scanning cursor: + pointer to char after closing bracket */ + return getP; } +/* + * Parse(): scan current portion of buffer for given tag. + * If found, parse tag arguments and call 'func' for it. + * The result of func is inserted at the current position + * in the buffer. + */ +int +parse( + char **buf, /* buffer */ + long i, /* offset in buffer */ + char *tag, /* tag to handle */ + char *(*func)(long , const char **) /* function to call for 'tag' */ + ) +{ + /* the name of the vairable ... */ + char *val; + long valln; + char **args; + char *end; + long end_offset; + int argc; + size_t taglen = strlen(tag); + + /* Current position in buffer should start with 'tag' */ + if (strncmp((*buf)+i, tag, taglen) != 0) { + return 0; + } + /* .. and match exactly (a whitespace following 'tag') */ + if (! isspace(*((*buf) + i + taglen)) ) { + return 0; + } -int parse(char **buf, long i, char *tag, - char *(*func)(long argc, char **args)){ - - /* the name of the vairable ... */ - char *val; - long valln; - char **args; - char *end; - long end_offset; - long argc; - /* do we like it ? */ - if (strncmp((*buf)+i, tag, strlen(tag))!=0) return 0; - if (! isspace(*( (*buf) + i + strlen(tag) )) ) return 0; - /* scanargs puts \0 into *buf ... so after scanargs it is probably - not a good time to use strlen on buf */ - end = scanargs((*buf)+i+strlen(tag),&argc,&args); - if (! end) { - for (;argc>2;argc--){ - *((args[argc-1])-1)=' '; - } - val = stralloc("[ERROR: Parsing Problem with the following text\n" - " Check original file. This may have been altered by parsing.]\n\n"); - end = (*buf)+i+1; - } else { - val = func(argc-1,args+1); - free (args); - } - /* for (ii=0;ii 0 ? valln-1: valln; +#ifdef DEBUG_PARSER + printf("parse(): handling tag '%s'\n", tag); +#endif + + /* Scan for arguments following the tag; + scanargs() puts \0 into *buf ... so after scanargs it is probably + not a good time to use strlen on buf */ + end = scanargs((*buf) + i + taglen, &argc, &args); + if (end) + { + /* got arguments, call function for 'tag' with arguments */ + val = func(argc, args); + free(args); + } + else + { + /* unable to parse arguments, undo 0-termination by scanargs */ + for (; argc > 0; argc--) { + *((args[argc-1])-1) = ' '; + } + + /* next call, try parsing at current offset +1 */ + end = (*buf) + i + 1; + + val = stralloc("[ERROR: Parsing Problem with the following text\n" + " Check original file. This may have been altered " + "by parsing.]\n\n"); + } + + /* remember offset where we have to continue parsing */ + end_offset = end - (*buf); + + valln = 0; + if (val) { + valln = strlen(val); + } + + /* Optionally resize buffer to hold the replacement value: + Calculating the new length of the buffer is simple. add current + buffer pos (i) to length of string after replaced tag to length + of replacement string and add 1 for the final zero ... */ + if (end - (*buf) < (i + valln)) { + /* make sure we do not shrink the mallocd block */ + size_t newbufsize = i + strlen(end) + valln + 1; + *buf = rrd_realloc(*buf, newbufsize); + + if (*buf == NULL) { + perror("Realoc buf:"); + exit(1); + }; + } + + /* Update new end pointer: + make sure the 'end' pointer gets moved along with the + buf pointer when realloc moves memory ... */ + end = (*buf) + end_offset; + + /* splice the variable: + step 1. Shift pending data to make room for 'val' */ + memmove((*buf) + i + valln, end, strlen(end) + 1); + + /* step 2. Insert val */ + if (val) { + memmove((*buf)+i, val, valln); + free(val); + } + return (valln > 0 ? valln-1: valln); } char * http_time(time_t *now) { - struct tm tmptime; + struct tm *tmptime; static char buf[60]; - gmtime_r(now, &tmptime); - strftime(buf,sizeof(buf),"%a, %d %b %Y %H:%M:%S GMT", &tmptime); + tmptime=gmtime(now); + strftime(buf,sizeof(buf),"%a, %d %b %Y %H:%M:%S GMT",tmptime); return(buf); }