/*****************************************************************************
- * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2004
+ * RRDtool 1.2.12 Copyright by Tobi Oetiker, 1997-2005
*****************************************************************************
* rrd_cgi.c RRD Web Page Generator
*****************************************************************************/
#include "rrd_tool.h"
-#include <cgi.h>
-#include <time.h>
#define MEMBLK 1024
/*#define DEBUG_PARSER
#define DEBUG_VARS*/
-/* global variable for libcgi */
-s_cgi **cgiArg;
+typedef struct var_s {
+ char *name, *value;
+} s_var;
+
+typedef struct cgi_s {
+ s_var **vars;
+} s_cgi;
/* 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 */
/**************************************************/
/* 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 appropriate image tag */
-char* drawgraph(long, char **);
+char* drawgraph(long, const char **);
/* return PRINT functions from last rrd_graph call */
-char* drawprint(long, char **);
+char* drawprint(long, const char **);
/* pretty-print the <last></last> 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 environment variable */
-char* rrdsetenv(long, char **);
+char* rrdsetenv(long, const char **);
/* get an environment variable */
-char* rrdgetenv(long, char **);
+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 **/
char *http_time(time_t *);
/* return a pointer to newly allocated copy of this string */
char *stralloc(const char *);
+/* global variable for rrdcgi */
+s_cgi *rrdcgiArg;
+
+/* rrdcgiHeader
+ *
+ * Prints a valid CGI Header (Content-type...) etc.
+ */
+void rrdcgiHeader(void);
+
+/* rrdcgiDecodeString
+ * decode html escapes
+ */
+
+char *rrdcgiDecodeString(char *text);
+
+/* rrdcgiDebug
+ *
+ * Set/unsets debugging
+ */
+void rrdcgiDebug(int level, int where);
+
+/* rrdcgiInit
+ *
+ * Reads in variables set via POST or stdin.
+ */
+s_cgi *rrdcgiInit (void);
+
+/* rrdcgiGetValue
+ *
+ * Returns the value of the specified variable or NULL if it's empty
+ * or doesn't exist.
+ */
+char *rrdcgiGetValue (s_cgi *parms, const char *name);
+
+/* rrdcgiFreeList
+ *
+ * Frees a list as returned by rrdcgiGetVariables()
+ */
+void rrdcgiFreeList (char **list);
+
+/* rrdcgiFree
+ *
+ * Frees the internal data structures
+ */
+void rrdcgiFree (s_cgi *parms);
+
+/* rrdcgiReadVariables()
+ *
+ * Read from stdin if no string is provided via CGI. Variables that
+ * doesn't have a value associated with it doesn't get stored.
+ */
+s_var **rrdcgiReadVariables(void);
+
+
+int rrdcgiDebugLevel = 0;
+int rrdcgiDebugStderr = 1;
+char *rrdcgiHeaderString = NULL;
+char *rrdcgiType = NULL;
/* rrd interface to the variable functions {put,get}var() */
-char* rrdgetvar(long argc, char **args);
-char* rrdsetvar(long argc, char **args);
-char* rrdsetvarconst(long argc, char **args);
+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 */
{
int i;
if (varheap) {
- for (i=0; i<varheap_size; i++) {
+ for (i=0; i<(int)varheap_size; i++) {
if (varheap[i].name) {
free((char*)varheap[i].name);
}
getvar(const char* name)
{
int i;
- for (i=0; i<varheap_size && varheap[i].name; i++) {
+ for (i=0; i<(int)varheap_size && varheap[i].name; i++) {
if (0 == strcmp(name, varheap[i].name)) {
#ifdef DEBUG_VARS
printf("<!-- getvar(%s) -> %s -->\n", name, varheap[i].value);
putvar(const char* name, const char* value, int is_const)
{
int i;
- for (i=0; i < varheap_size && varheap[i].name; 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) {
}
/* no existing variable found by that name, add it */
- if (i == varheap_size) {
+ 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));
parse(&buffer, i, "<RRD::CV::PATH", cgigetqp);
parse(&buffer, i, "<RRD::GETENV", rrdgetenv);
parse(&buffer, i, "<RRD::GETVAR", rrdgetvar);
+ parse(&buffer, i, "<RRD::TIME::LAST", printtimelast);
+ parse(&buffer, i, "<RRD::TIME::NOW", printtimenow);
+ parse(&buffer, i, "<RRD::TIME::STRFTIME", printstrftime);
}
return buffer;
}
#ifdef MUST_DISABLE_FPMASK
fpsetmask(0);
#endif
+ optind = 0; opterr = 0; /* initialize getopt */
+
/* what do we get for cmdline arguments?
for (i=0;i<argc;i++)
printf("%d-'%s'\n",i,argv[i]); */
}
if (!filter) {
- cgiDebug(0,0);
- cgiArg = cgiInit();
+ rrdcgiDebug(0,0);
+ rrdcgiArg = rrdcgiInit();
server_url = getenv("SERVER_URL");
}
/* initialize variable heap */
initvar();
+#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] != '<')
/* 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) {
+char* rrdsetenv(long argc, const char **args) {
if (argc >= 2) {
char *xyz = malloc((strlen(args[0]) + strlen(args[1]) + 2));
if (xyz == NULL) {
free(xyz);
return stralloc("[ERROR: failed to do putenv]");
};
+ return stralloc("");
}
return stralloc("[ERROR: setenv failed because not enough "
"arguments were defined]");
/* rrd interface to the variable function putvar() */
char*
-rrdsetvar(long argc, char **args)
+rrdsetvar(long argc, const char **args)
{
if (argc >= 2)
{
/* rrd interface to the variable function putvar() */
char*
-rrdsetvarconst(long argc, char **args)
+rrdsetvarconst(long argc, const char **args)
{
if (argc >= 2)
{
"were defined]");
}
-char* rrdgetenv(long argc, char **args) {
+char* rrdgetenv(long argc, const char **args) {
char buf[128];
const char* envvar;
if (argc != 1) {
if (envvar) {
return stralloc(envvar);
} else {
- snprintf(buf, sizeof(buf), "[ERROR:_getenv_'%s'_failed", args[0]);
- return stralloc(buf);
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+ _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, char **args) {
+char* rrdgetvar(long argc, const char **args) {
char buf[128];
const char* value;
if (argc != 1) {
if (value) {
return stralloc(value);
} else {
- snprintf(buf, sizeof(buf), "[ERROR:_getvar_'%s'_failed", args[0]);
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+ _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, char **args){
+char* rrdgoodfor(long argc, const char **args){
if (argc == 1) {
goodfor = atol(args[0]);
} else {
* 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];
}
}
-char* includefile(long argc, char **args){
+char* includefile(long argc, const char **args){
char *buffer;
if (argc >= 1) {
- char* filename = args[0];
+ const char* filename = args[0];
readfile(filename, &buffer, 0);
if (rrd_test_error()) {
char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE));
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 *buf = rrdstrip(rrdcgiGetValue(rrdcgiArg,args[0]));
char *buf2;
char *c,*d;
int qc=0;
/* 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) + 4 * qc + 4))) == 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(rrdcgiGetValue(rrdcgiArg, 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);
+
+ /* Make sure the path is relative, e.g. does not start with '/' */
+ p = buf2;
+ while ('/' == *p)
+ {
+ *p++ = '_';
+ }
+
return buf2;
- }
- return stralloc("[ERROR: not enough arguments for RRD::CV::PATH]");
}
-char* cgiget(long argc, char **args){
+char* cgiget(long argc, const char **args){
if (argc>= 1)
- return rrdstrip(cgiGetValue(cgiArg,args[0]));
+ return rrdstrip(rrdcgiGetValue(rrdcgiArg,args[0]));
else
return stralloc("[ERROR: not enough arguments for RRD::CV]");
}
-char* drawgraph(long argc, char **args){
+char* drawgraph(long argc, const char **args){
int i,xsize, ysize;
+ double ymin,ymax;
for(i=0;i<argc;i++)
if(strcmp(args[i],"--imginfo")==0 || strcmp(args[i],"-g")==0) break;
if(i==argc) {
args[argc++] = "--imginfo";
args[argc++] = "<IMG SRC=\"./%s\" WIDTH=\"%lu\" HEIGHT=\"%lu\">";
}
- optind=0; /* reset gnu getopt */
- opterr=0; /* reset gnu getopt */
calfree();
- if( rrd_graph(argc+1, args-1, &calcpr, &xsize, &ysize,NULL) != -1 ) {
+ if( rrd_graph(argc+1, (char **) args-1, &calcpr, &xsize, &ysize,NULL,&ymin,&ymax) != -1 ) {
return stralloc(calcpr[0]);
} else {
if (rrd_test_error()) {
return NULL;
}
-char* drawprint(long argc, char **args){
+char* drawprint(long argc, const char **args){
if (argc==1 && calcpr){
long i=0;
while (calcpr[i] != NULL) i++; /*determine number lines in calcpr*/
return stralloc("[ERROR: RRD::PRINT argument error]");
}
-char* printtimelast(long argc, char **args) {
+char* printtimelast(long argc, const char **args) {
time_t last;
struct tm tm_last;
char *buf;
if (buf == NULL){
return stralloc("[ERROR: allocating strftime buffer]");
};
- last = rrd_last(argc+1, args-1);
+ last = rrd_last(argc+1, (char **) args-1);
if (rrd_test_error()) {
char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE)*sizeof(char));
sprintf(err, "[ERROR: %s]",rrd_get_error());
return stralloc("[ERROR: not enough arguments for RRD::TIME::LAST]");
}
-char* printtimenow(long argc, char **args) {
+char* printtimenow(long argc, const char **args) {
time_t now = time(NULL);
struct tm tm_now;
char *buf;
{
case ' ':
if (Quote || tagcount) {
- /* copy quoted/tagged string */
+ /* copy quoted/tagged (=RRD expanded) string */
*putP++ = c;
}
else if (in_arg)
}
} else {
if (!in_arg) {
- /* reference argument string in argument array */
+ /* reference start of argument string in argument array */
argv[argc++] = putP;
in_arg=1;
}
break;
default:
- if (!Quote) {
if (!in_arg) {
/* start new argument */
argv[argc++] = putP;
curarg_contains_rrd_directives = 1;
}
}
- }
*putP++ = c;
break;
}
char **buf, /* buffer */
long i, /* offset in buffer */
char *tag, /* tag to handle */
- char *(*func)(long argc, char **args) /* function to call for 'tag' */
+ char *(*func)(long , const char **) /* function to call for 'tag' */
)
{
/* the name of the vairable ... */
if (end)
{
/* got arguments, call function for 'tag' with arguments */
- val = func(argc, args);
+ val = func(argc, (const char **) args);
free(args);
}
else
strftime(buf,sizeof(buf),"%a, %d %b %Y %H:%M:%S GMT",tmptime);
return(buf);
}
+
+void rrdcgiHeader(void)
+{
+ if (rrdcgiType)
+ printf ("Content-type: %s\n", rrdcgiType);
+ else
+ printf ("Content-type: text/html\n");
+ if (rrdcgiHeaderString)
+ printf ("%s", rrdcgiHeaderString);
+ printf ("\n");
+}
+
+void rrdcgiDebug(int level, int where)
+{
+ if (level > 0)
+ rrdcgiDebugLevel = level;
+ else
+ rrdcgiDebugLevel = 0;
+ if (where)
+ rrdcgiDebugStderr = 0;
+ else
+ rrdcgiDebugStderr = 1;
+}
+
+char *rrdcgiDecodeString(char *text)
+{
+ char *cp, *xp;
+
+ for (cp=text,xp=text; *cp; cp++) {
+ if (*cp == '%') {
+ if (strchr("0123456789ABCDEFabcdef", *(cp+1))
+ && strchr("0123456789ABCDEFabcdef", *(cp+2))) {
+ if (islower(*(cp+1)))
+ *(cp+1) = toupper(*(cp+1));
+ if (islower(*(cp+2)))
+ *(cp+2) = toupper(*(cp+2));
+ *(xp) = (*(cp+1) >= 'A' ? *(cp+1) - 'A' + 10 : *(cp+1) - '0' ) * 16
+ + (*(cp+2) >= 'A' ? *(cp+2) - 'A' + 10 : *(cp+2) - '0');
+ xp++;cp+=2;
+ }
+ } else {
+ *(xp++) = *cp;
+ }
+ }
+ memset(xp, 0, cp-xp);
+ return text;
+}
+
+/* rrdcgiReadVariables()
+ *
+ * Read from stdin if no string is provided via CGI. Variables that
+ * doesn't have a value associated with it doesn't get stored.
+ */
+s_var **rrdcgiReadVariables(void)
+{
+ int length;
+ char *line = NULL;
+ int numargs;
+ char *cp, *ip, *esp, *sptr;
+ s_var **result;
+ int i, k, len;
+ char tmp[101];
+
+ cp = getenv("REQUEST_METHOD");
+ ip = getenv("CONTENT_LENGTH");
+
+ if (cp && !strcmp(cp, "POST")) {
+ if (ip) {
+ length = atoi(ip);
+ if ((line = (char *)malloc (length+2)) == NULL)
+ return NULL;
+ fgets(line, length+1, stdin);
+ } else
+ return NULL;
+ } else if (cp && !strcmp(cp, "GET")) {
+ esp = getenv("QUERY_STRING");
+ if (esp && strlen(esp)) {
+ if ((line = (char *)malloc (strlen(esp)+2)) == NULL)
+ return NULL;
+ sprintf (line, "%s", esp);
+ } else
+ return NULL;
+ } else {
+ length = 0;
+ printf ("(offline mode: enter name=value pairs on standard input)\n");
+ memset (tmp, 0, sizeof(tmp));
+ while((cp = fgets (tmp, 100, stdin)) != NULL) {
+ if (strlen(tmp)) {
+ if (tmp[strlen(tmp)-1] == '\n')
+ tmp[strlen(tmp)-1] = '&';
+ if (length) {
+ length += strlen(tmp);
+ len = (length+1) * sizeof(char);
+ if ((line = (char *)realloc (line, len)) == NULL)
+ return NULL;
+ strcat (line, tmp);
+ } else {
+ length = strlen(tmp);
+ len = (length+1) * sizeof(char);
+ if ((line = (char *)malloc (len)) == NULL)
+ return NULL;
+ memset (line, 0, len);
+ strcpy (line, tmp);
+ }
+ }
+ memset (tmp, 0, sizeof(tmp));
+ }
+ if (!line)
+ return NULL;
+ if (line[strlen(line)-1] == '&')
+ line[strlen(line)-1] = '\0';
+ }
+
+ /*
+ * From now on all cgi variables are stored in the variable line
+ * and look like foo=bar&foobar=barfoo&foofoo=
+ */
+
+ if (rrdcgiDebugLevel > 0) {
+ if (rrdcgiDebugStderr)
+ fprintf (stderr, "Received cgi input: %s\n", line);
+ else
+ printf ("<b>Received cgi input</b><br>\n<pre>\n--\n%s\n--\n</pre>\n\n", line);
+ }
+
+ for (cp=line; *cp; cp++)
+ if (*cp == '+')
+ *cp = ' ';
+
+ if (strlen(line)) {
+ for (numargs=1,cp=line; *cp; cp++)
+ if (*cp == '&') numargs++;
+ } else
+ numargs = 0;
+ if (rrdcgiDebugLevel > 0) {
+ if (rrdcgiDebugStderr)
+ fprintf (stderr, "%d cgi variables found.\n", numargs);
+ else
+ printf ("%d cgi variables found.<br>\n", numargs);
+ }
+
+ len = (numargs+1) * sizeof(s_var *);
+ if ((result = (s_var **)malloc (len)) == NULL)
+ return NULL;
+ memset (result, 0, len);
+
+ cp = line;
+ i=0;
+ while (*cp) {
+ if ((ip = (char *)strchr(cp, '&')) != NULL) {
+ *ip = '\0';
+ }else
+ ip = cp + strlen(cp);
+
+ if ((esp=(char *)strchr(cp, '=')) == NULL) {
+ cp = ++ip;
+ continue;
+ }
+
+ if (!strlen(esp)) {
+ cp = ++ip;
+ continue;
+ }
+
+ if (i<numargs) {
+
+ /* try to find out if there's already such a variable */
+ for (k=0; k<i && (strncmp (result[k]->name,cp, esp-cp) || !(strlen (result[k]->name) == esp-cp)); k++);
+
+ if (k == i) { /* No such variable yet */
+ if ((result[i] = (s_var *)malloc(sizeof(s_var))) == NULL)
+ return NULL;
+ if ((result[i]->name = (char *)malloc((esp-cp+1) * sizeof(char))) == NULL)
+ return NULL;
+ memset (result[i]->name, 0, esp-cp+1);
+ strncpy(result[i]->name, cp, esp-cp);
+ cp = ++esp;
+ if ((result[i]->value = (char *)malloc((ip-esp+1) * sizeof(char))) == NULL)
+ return NULL;
+ memset (result[i]->value, 0, ip-esp+1);
+ strncpy(result[i]->value, cp, ip-esp);
+ result[i]->value = rrdcgiDecodeString(result[i]->value);
+ if (rrdcgiDebugLevel) {
+ if (rrdcgiDebugStderr)
+ fprintf (stderr, "%s: %s\n", result[i]->name, result[i]->value);
+ else
+ printf ("<h3>Variable %s</h3>\n<pre>\n%s\n</pre>\n\n", result[i]->name, result[i]->value);
+ }
+ i++;
+ } else { /* There is already such a name, suppose a mutiple field */
+ cp = ++esp;
+ len = (strlen(result[k]->value)+(ip-esp)+2) * sizeof (char);
+ if ((sptr = (char *)malloc(len)) == NULL)
+ return NULL;
+ memset (sptr, 0, len);
+ sprintf (sptr, "%s\n", result[k]->value);
+ strncat(sptr, cp, ip-esp);
+ free(result[k]->value);
+ result[k]->value = rrdcgiDecodeString (sptr);
+ }
+ }
+ cp = ++ip;
+ }
+ return result;
+}
+
+/* rrdcgiInit()
+ *
+ * Read from stdin if no string is provided via CGI. Variables that
+ * doesn't have a value associated with it doesn't get stored.
+ */
+s_cgi *rrdcgiInit(void)
+{
+ s_cgi *res;
+ s_var **vars;
+
+ vars = rrdcgiReadVariables();
+
+ if (!vars)
+ return NULL;
+
+ if ((res = (s_cgi *)malloc (sizeof (s_cgi))) == NULL)
+ return NULL;
+ res->vars = vars;
+
+ return res;
+}
+
+char *rrdcgiGetValue(s_cgi *parms, const char *name)
+{
+ int i;
+
+ if (!parms || !parms->vars)
+ return NULL;
+ for (i=0;parms->vars[i]; i++)
+ if (!strcmp(name,parms->vars[i]->name)) {
+ if (rrdcgiDebugLevel > 0) {
+ if (rrdcgiDebugStderr)
+ fprintf (stderr, "%s found as %s\n", name, parms->vars[i]->value);
+ else
+ printf ("%s found as %s<br>\n", name, parms->vars[i]->value);
+ }
+ return parms->vars[i]->value;
+ }
+ if (rrdcgiDebugLevel) {
+ if (rrdcgiDebugStderr)
+ fprintf (stderr, "%s not found\n", name);
+ else
+ printf ("%s not found<br>\n", name);
+ }
+ return NULL;
+}
+
+void rrdcgiFreeList (char **list)
+{
+ int i;
+
+ for (i=0; list[i] != NULL; i++)
+ free (list[i]);
+ free (list);
+}
+
+void rrdcgiFree (s_cgi *parms)
+{
+ int i;
+
+ if (!parms)
+ return;
+ if (parms->vars) {
+ for (i=0;parms->vars[i]; i++) {
+ if (parms->vars[i]->name)
+ free (parms->vars[i]->name);
+ if (parms->vars[i]->value)
+ free (parms->vars[i]->value);
+ free (parms->vars[i]);
+ }
+ free (parms->vars);
+ }
+ free (parms);
+
+ if (rrdcgiHeaderString) {
+ free (rrdcgiHeaderString);
+ rrdcgiHeaderString = NULL;
+ }
+ if (rrdcgiType) {
+ free (rrdcgiType);
+ rrdcgiType = NULL;
+ }
+}
+