"Fossies" - the Fresh Open Source Software Archive

Member "libgcgi.a-0.9.5/src/gcgi.c" (22 Jun 2002, 32735 Bytes) of package /linux/www/old/gcgi-0.9.5.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gcgi.c" see the Fossies "Dox" file reference documentation.

    1 /* -*-mode:c; c-style:k&r; c-basic-offset:4; -*- */
    2 /*
    3  * GCGI Library, implementing NCSA'a Common Gateway Interface and RFC2338.
    4  * Copyright (C) 2001-2002 Julian Catchen, julian@catchen.org
    5  *
    6  * This library is free software; you can redistribute it and/or
    7  * modify it under the terms of the GNU Lesser General Public
    8  * License as published by the Free Software Foundation; either
    9  * version 2.1 of the License, or (at your option) any later version.
   10  *
   11  * This library is distributed in the hope that it will be useful,
   12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14  * Lesser General Public License for more details.
   15  *
   16  * You should have received a copy of the GNU Lesser General Public
   17  * License along with this library; if not, write to the Free Software
   18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   19  */
   20 
   21 #include "gcgi_private.h"
   22 
   23 static const char* const envVars[] = 
   24     {
   25     "HTTP_COOKIE",
   26     "HTTP_REFERER",
   27     "AUTH_TYPE", 
   28     "CONTENT_LENGTH",
   29     "CONTENT_TYPE",
   30     "GATEWAY_INTERFACE",
   31     "PATH_INFO",
   32     "PATH_TRANSLATED",
   33     "QUERY_STRING",
   34     "REMOTE_ADDR",
   35     "REMOTE_HOST",
   36     "REMOTE_IDENT",
   37     "REMOTE_USER",
   38     "REQUEST_METHOD",
   39     "SCRIPT_NAME",
   40     "SERVER_NAME",
   41     "SERVER_PORT",
   42     "SERVER_PROTOCOL",
   43     "SERVER_SOFTWARE"
   44     };
   45 
   46 #define ENVCOUNT 19
   47 
   48 /*------ Global Variables ------*/
   49 static CgiQuery *cgiQuery         = NULL;
   50 static int       debug            = 0;
   51 static char     *envVariablesFile = NULL;
   52 static char     *cgiQueryFile     = NULL;
   53 static size_t    fieldLimit       = 0;
   54 static size_t    queryLimit       = 0;
   55 
   56 static const char gcgi_ident[] =
   57     "$GCGI: GCGI " VERSION " Copyright (C) 2001-2002 Julian Catchen $\n"
   58     "$Authors:  Julian Catchen, topeka@catchen.org $";
   59 
   60 gcgiReturnType 
   61 initCgi( ) 
   62 {
   63     int numBytes, gcgifd;
   64 
   65     if (debug)
   66     gcgiLoadEnvVariables(envVariablesFile);
   67 
   68     /* Dup stdout to gcgiOut */
   69     gcgifd = dup(fileno(stdout));
   70     gcgiOut = fdopen(gcgifd, "w");
   71 
   72     /* Create the cgiQuery object. */
   73     createCgiQuery();
   74 
   75     if (cgiQuery->env[gcgiRequestMethod] == NULL ) 
   76     return GCGIFATALERROR;
   77     
   78     if (! strncasecmp(cgiQuery->env[gcgiRequestMethod],"GET", 3) ) {
   79     parseGetQueryString(&numBytes);
   80     if (numBytes < 0)
   81         return GCGIFATALERROR;
   82     }
   83     else if (! strncasecmp(cgiQuery->env[gcgiRequestMethod],"POST", 4) ) {
   84     parsePostQueryString(&numBytes);
   85     if (numBytes < 0)
   86         return GCGIFATALERROR;
   87     }
   88     else
   89     return GCGIFATALERROR;
   90   
   91     return GCGISUCCESS;
   92 }
   93 
   94 
   95 void 
   96 freeCgi( )
   97 {
   98     freeCgiQuery();
   99 
  100     if (envVariablesFile != NULL) XFREE(envVariablesFile);
  101     if (cgiQueryFile != NULL) XFREE(cgiQueryFile);
  102     
  103 }
  104 
  105 
  106 /* Limits specified in number of bytes. */
  107 gcgiReturnType
  108 gcgiSetLimits(size_t flimit, size_t qlimit)
  109 {
  110     fieldLimit = flimit;
  111     queryLimit = qlimit;
  112 
  113     return GCGISUCCESS;
  114 }
  115 
  116 
  117 gcgiReturnType 
  118 parsePostQueryString(int *numBytes)
  119 {
  120     FILE   *input;
  121     char   *querystring;
  122     size_t  clen;
  123     int     result;
  124 
  125     querystring = NULL;
  126     result      = 0;
  127 
  128     /* Return if we don't have the content length env variable. */
  129     if (cgiQuery->env[gcgiContentLength] == NULL || cgiQuery->env[gcgiContentType] == NULL)
  130     return GCGIFATALERROR;
  131     
  132     clen = strtol(cgiQuery->env[gcgiContentLength], NULL, 10);
  133     /* Content Length was out of range */
  134     if (errno == ERANGE)
  135     return GCGIFATALERROR;
  136 
  137     if (debug) {
  138     if ((input = fopen(cgiQueryFile, "r")) == NULL)
  139         return GCGIFATALERROR;
  140     }
  141     else {
  142     input = stdin;
  143     }
  144 
  145     /* Standard URL Encoded POST string. */
  146     if (strncasecmp(cgiQuery->env[gcgiContentType], "application/x-www-form-urlencoded", 33) == 0) {
  147     querystring = readQueryFromStream(input, clen);
  148     parseUrlEncoded(querystring, clen);
  149 
  150     *numBytes = clen;
  151     }
  152     
  153     /* RFC2388 Encoding */
  154     else if (strncasecmp(cgiQuery->env[gcgiContentType], "multipart/form-data", 19) == 0) {
  155     /* Pass the file to the MIME library to parse. */
  156     if ((result = parseFormData(input)) == GCGIFATALERROR)
  157         return GCGIFATALERROR;
  158     
  159     *numBytes = clen;    
  160     }
  161    
  162     /* Unknown Encoding. */
  163     else {
  164     fprintf(stderr,"Unknown Encoding.\n");
  165     return GCGIFATALERROR;
  166     }
  167 
  168     if (debug) fclose(input);
  169     
  170     XFREE(querystring);
  171     
  172     if (result == GCGITRUNCATED)
  173     return GCGITRUNCATED;
  174     else
  175     return GCGISUCCESS;
  176 }
  177 
  178 
  179 gcgiReturnType 
  180 parseGetQueryString(int *numBytes)
  181 {
  182     size_t clen;
  183     
  184     if (cgiQuery->env[gcgiQueryString] == NULL)
  185     return GCGIFATALERROR;
  186 
  187     clen = strlen(cgiQuery->env[gcgiQueryString]);
  188  
  189     if (clen <= 0)
  190     return GCGIFATALERROR;
  191 
  192     *numBytes = parseUrlEncoded(cgiQuery->env[gcgiQueryString], clen);
  193 
  194     return GCGISUCCESS;
  195 }
  196 
  197 
  198 gcgiReturnType 
  199 parseUrlEncoded(char *querystring, int clen) 
  200 {
  201     QueryStringNode *qstring; 
  202     char            *beg, *end, *qlen;
  203     char            *offset, *p; 
  204     int              i;
  205 
  206     beg = end = qlen = NULL;
  207 
  208     offset = querystring + strlen(querystring);
  209     /* Count the number of fileds in the Query String. */
  210     for (p = querystring, i = 0; p < offset; p++)
  211     if (*p == '&')
  212         i++;
  213     /* There is one more field than '&' characters. */
  214     i++;
  215     /* Create the QueryStringColl Array */
  216     createQueryStringCollArray(i);
  217 
  218     qlen = querystring + clen;
  219     for (beg = querystring; beg < qlen && end < qlen; beg = end+1) {
  220     /* Malloc the queryString object and initialize it. */
  221     createQueryStringNode(&qstring);
  222 
  223     /* Get Field Name */
  224     for (end = beg; *end != '=' && end < qlen; end++);
  225     qstring->field = XMALLOC(char, end - beg + 1);
  226     strncpy(qstring->field, beg, end-beg);
  227     qstring->field[end-beg] = '\0';                      /* Zero out the string */
  228 
  229     /* Get Data */
  230     for (beg = end+1; *end != '&' && end < qlen; end++);
  231     qstring->data = XMALLOC(char, end - beg + 1);
  232     strncpy(qstring->data, beg, end-beg);
  233     qstring->data[end-beg] = '\0';                       /* Zero out the string */
  234     qstring->size = end - beg + 1;
  235     
  236     decodeUrl(qstring);
  237 
  238     /* Add struct to linked list. */
  239     insertQueryStringNode(qstring);
  240 
  241     } /* for (beg = querystring; *beg < qlen && *end < qlen; beg++) */
  242     
  243     return GCGISUCCESS;
  244 }
  245 
  246 
  247 gcgiReturnType 
  248 parseFormData(FILE *data)
  249 {
  250     MimePart *mime, *n;
  251     QueryStringNode *node;
  252     int len, i, trunc;
  253 
  254     if ((mime = mimeParseMimeMessage(data, queryLimit, fieldLimit)) == NULL)
  255     return GCGIFATALERROR;
  256     
  257     /* Check if the MIME message was truncated. */
  258     trunc = mime->truncated;
  259 
  260     /* Count the number of fileds in the Query String. */
  261     for (n = mime->next, i = 0; n != NULL; n = n->next) i++;
  262     createQueryStringCollArray(i);
  263 
  264     for (n = mime->next; n != NULL; n = n->next) {
  265     createQueryStringNode(&node);
  266     len = strlen(n->name);
  267     node->field = XMALLOC(char, len + 1);
  268     strncpy(node->field, n->name, len);
  269     node->field[len] = '\0';
  270 
  271     node->type     = n->type;
  272     node->encoding = n->encoding;
  273 
  274     len = strlen(n->subtype);
  275     node->subtype = XMALLOC(char, len + 1);
  276     strncpy(node->subtype, n->subtype, len);
  277     node->subtype[len] = '\0';
  278 
  279     if (n->filename != NULL) {
  280         len = strlen(n->filename);
  281         node->filename = XMALLOC(char, len + 1);
  282         strncpy(node->filename, n->filename, len);
  283         node->filename[len] = '\0';
  284     }
  285 
  286     len = n->bodylen;
  287     node->data = XMALLOC(char, len + 1);
  288     /* Remove final "\r\n" that separated the boundary from the body. */
  289     if (n->body[len-1] == '\n' && n->body[len-2] == '\r') 
  290         len -= 2;
  291     
  292     memcpy(node->data, n->body, len);
  293     node->data[len] = '\0';
  294     node->size = len;
  295     node->truncated = n->truncated;
  296     
  297     if (debug)
  298         fprintf(stderr,"N: Field: %s, Type: %d, Subtype: %s\n",n->name, n->type, n->subtype);
  299     insertQueryStringNode(node);
  300     node = NULL;
  301     }
  302 
  303     /* Free the MIME structures. */
  304     mimeFreeMimeMessage(mime);
  305 
  306     if (trunc)
  307     return GCGITRUNCATED;
  308     else
  309     return GCGISUCCESS;
  310 }
  311 
  312 
  313 void 
  314 decodeUrl(QueryStringNode *qstring)
  315 {
  316     char *f, *d;
  317     int  flen, dlen;
  318 
  319     gcgiDecodeUrlEncodedString(qstring->field, &f, &flen);
  320     strncpy(qstring->field, f, flen);
  321     qstring->field[flen-1] = '\0';
  322 
  323     gcgiDecodeUrlEncodedString(qstring->data, &d, &dlen);
  324     strncpy(qstring->data, d, dlen);
  325     qstring->data[dlen-1] = '\0';
  326 
  327     XFREE(d);
  328     XFREE(f);
  329 }
  330 
  331 
  332 gcgiReturnType  
  333 gcgiSendContentType(char *mimeType, char *name, char *charset, HTTPHeader header)
  334 {
  335     fprintf(gcgiOut, "Content-Type: %s", mimeType);
  336 
  337     if ( (charset!= NULL) && (strlen(charset) > 0) )
  338     fprintf(gcgiOut, "; charset=\"%s\"", charset);
  339 
  340     if ( (name!= NULL) && (strlen(name) > 0) )
  341     fprintf(gcgiOut, "; name=\"%s\"", name);
  342 
  343     if (header == LAST)
  344     fprintf(gcgiOut, "\r\n");
  345 
  346     fprintf(gcgiOut, "\r\n");
  347 
  348     return GCGISUCCESS;
  349 }
  350 
  351 
  352 gcgiReturnType  
  353 gcgiSendContentDisp(MimeDisposition disp, char *filename, HTTPHeader header)
  354 {
  355     char *strDisp[] = { "inlined",
  356             "attachment",
  357             "formdata"    };
  358 
  359     fprintf(gcgiOut, "Content-Disposition: %s", strDisp[disp]);
  360 
  361     if ( (filename!= NULL) && (strlen(filename) > 0) )
  362     fprintf(gcgiOut, "; filename=\"%s\"", filename);
  363 
  364     if (header == LAST)
  365     fprintf(gcgiOut, "\r\n");
  366 
  367     fprintf(gcgiOut, "\r\n");
  368 
  369     return GCGISUCCESS;
  370 }
  371 
  372 
  373 gcgiReturnType  
  374 gcgiSendContentLength(int length, HTTPHeader header)
  375 {
  376     fprintf(gcgiOut, "Content-Length: %d", length);
  377 
  378     if (header == LAST)
  379     fprintf(gcgiOut, "\r\n");
  380 
  381     fprintf(gcgiOut, "\r\n");
  382 
  383     return GCGISUCCESS;
  384 }
  385 
  386 
  387 gcgiReturnType  
  388 gcgiSendLocation(char *redirectURL)
  389 {
  390     fprintf(gcgiOut, "Location: %s\r\n\r\n", redirectURL);
  391 
  392     return GCGISUCCESS;
  393 }
  394 
  395 
  396 gcgiReturnType  
  397 gcgiSendStatus(int status, char *message)
  398 {
  399     fprintf(gcgiOut, "HTTP/1.1 %d %s\r\n\r\n", status, message);
  400 
  401     return GCGISUCCESS;
  402 }
  403 
  404 
  405 gcgiReturnType  
  406 gcgiSendCacheControl(char *cache, HTTPHeader header)
  407 {
  408     fprintf(gcgiOut, "Cache-Control: %s", cache);
  409 
  410     if (header == LAST)
  411     fprintf(gcgiOut, "\r\n");
  412 
  413     fprintf(gcgiOut, "\r\n");
  414 
  415     return GCGISUCCESS;
  416 }
  417 
  418 
  419 gcgiReturnType  
  420 gcgiSendCookie(char *name, char *value, char *path, char *domain, char *expires, int secure, HTTPHeader header)
  421 {
  422     char *cookieEncoded;
  423 
  424     gcgiEncodeBaseSixtyFourString(value, strlen(value), &cookieEncoded);
  425     
  426     fprintf(gcgiOut,
  427         "Set-Cookie: %s=%s; path=%s; domain=%s;", 
  428         name, cookieEncoded, path, domain);
  429 
  430     if (expires && strlen(expires) > 0)
  431     fprintf(gcgiOut, " expires=%s;", expires);
  432 
  433     if (secure)
  434     fprintf(gcgiOut, " secure");
  435 
  436     if (header == LAST)
  437     fprintf(gcgiOut, "\r\n");
  438 
  439     fprintf(gcgiOut, "\r\n");
  440 
  441     XFREE(cookieEncoded);
  442 
  443     return GCGISUCCESS;
  444 }
  445 
  446 
  447 gcgiReturnType  
  448 gcgiFetchCookies(char ***cookies)
  449 {
  450     tokenizeString(cgiQuery->env[gcgiHttpCookie], strlen(cgiQuery->env[gcgiHttpCookie]), cookies);
  451 
  452     return GCGISUCCESS;
  453 }
  454 
  455 
  456 gcgiReturnType  
  457 gcgiParseCookie(char *cookie, char **name, char **value)
  458 {
  459     char *encoded, *decoded;
  460     int   size;
  461 
  462     parseToken(cookie, name, &encoded);
  463 
  464     gcgiDecodeBaseSixtyFourString(encoded, &decoded, &size);
  465 
  466     size++;
  467     decoded = XREALLOC(char, decoded, size);
  468     decoded[size-1] = '\0';
  469 
  470     *value = decoded;
  471     XFREE(encoded);
  472 
  473     return GCGISUCCESS;
  474 }
  475 
  476 
  477 gcgiReturnType  
  478 gcgiFreeCookies(char **cookies)
  479 {
  480     freeStringArray(cookies);
  481 
  482     return GCGISUCCESS;
  483 }
  484 
  485 
  486 #ifdef USE_SSL
  487 gcgiReturnType  
  488 gcgiSendEncryptedCookie(char *name, char *value, char *path, char *domain, char *expires, 
  489             int secure, unsigned char *key, HTTPHeader header)
  490 {
  491     char          *cookieEncoded;
  492     char          *ciphertext, *digestEncoded;
  493     unsigned char *digest;
  494     int            ctlen, dlen;
  495 
  496     ciphertext    = NULL;
  497     digest        = NULL;
  498     digestEncoded = NULL;
  499     ctlen         = 0;
  500     dlen          = 0;
  501 
  502     encryptString(value, strlen(value), key, &ciphertext, &ctlen);
  503     generateStringHMAC(ciphertext, ctlen, &digest, &dlen);
  504     gcgiEncodeBaseSixtyFourString(ciphertext, ctlen, &cookieEncoded);
  505     gcgiEncodeBaseSixtyFourString(digest, dlen, &digestEncoded);
  506     
  507     fprintf(gcgiOut,
  508         "Set-Cookie: %s=%s&%s; path=%s; domain=%s;", 
  509         name, cookieEncoded, digestEncoded, path, domain);
  510 
  511     if (expires && strlen(expires) > 0)
  512     fprintf(gcgiOut, " expires=%s;", expires);
  513 
  514     if (secure)
  515     fprintf(gcgiOut, " secure");
  516 
  517     if (header == LAST)
  518     fprintf(gcgiOut, "\r\n");
  519 
  520     fprintf(gcgiOut, "\r\n");
  521 
  522     XFREE(cookieEncoded);
  523     XFREE(ciphertext);
  524     XFREE(digest);
  525     XFREE(digestEncoded);
  526 
  527     return GCGISUCCESS;
  528 }
  529 
  530 
  531 gcgiReturnType  
  532 gcgiParseEncryptedCookie(char *cookie, unsigned char *key, char **name, char **value)
  533 {
  534     char          **tokens;
  535     int             size;
  536     char           *ciphertext, *cdigest, *encoded, *decoded;
  537     unsigned char  *digest;
  538     int             ctlen, dlen, cdlen;
  539 
  540     ciphertext = NULL;
  541     digest     = NULL;
  542     cdigest    = NULL;
  543     ctlen      = 0;
  544     dlen       = 0;
  545     cdlen      = 0;
  546 
  547     parseToken(cookie, name, &encoded);
  548 
  549     tokenizeURLString(encoded, strlen(encoded), &tokens);
  550     gcgiDecodeBaseSixtyFourString(tokens[0], &ciphertext, &ctlen);
  551     decryptString(ciphertext, ctlen, key, &decoded, &size);
  552     gcgiDecodeBaseSixtyFourString(tokens[1], &cdigest, &cdlen);
  553     generateStringHMAC(ciphertext, ctlen, &digest, &dlen);
  554 
  555     if (dlen != cdlen && strncmp(digest, cdigest, dlen) != 0)
  556     return GCGIBADDATA;
  557 
  558     size++;
  559     decoded = XREALLOC(char, decoded, size);
  560     decoded[size-1] = '\0';
  561 
  562     *value = decoded;
  563 
  564     freeStringArray(tokens);
  565     XFREE(encoded);
  566     XFREE(ciphertext);
  567     XFREE(digest);
  568     XFREE(cdigest);
  569 
  570     return GCGISUCCESS;
  571 }
  572 
  573 
  574 gcgiReturnType  
  575 gcgiGenerateKey(unsigned char **key)
  576 {
  577     *key = generateKey();
  578 
  579     return GCGISUCCESS;
  580 }
  581 
  582 
  583 gcgiReturnType  
  584 gcgiWriteKeyToFile(unsigned char *key, char *path)
  585 {
  586     if (writeKeyToFile(key, path) < 0)
  587     return GCGIFATALERROR;
  588 
  589     return GCGISUCCESS;
  590 }
  591 
  592 
  593 gcgiReturnType  
  594 gcgiReadKeyFromFile(char *path, unsigned char **key)
  595 {
  596     if (readKeyFromFile(path, key) < 0)
  597     return GCGIFATALERROR;
  598 
  599     return GCGISUCCESS;
  600 }
  601 #endif
  602 
  603 
  604 gcgiReturnType
  605 gcgiNumFormFields(int *ret)
  606 {
  607     *ret = cgiQuery->queryCount;
  608 
  609     return GCGISUCCESS;
  610 }
  611 
  612 
  613 gcgiReturnType
  614 gcgiNumFields(char *field, int *ret)
  615 {
  616     int i;
  617     
  618     if (findQueryStringColl(field, &i) == GCGIFIELDNOTFOUND) {
  619     *ret = 0;
  620     return GCGIFIELDNOTFOUND;
  621     }
  622 
  623     *ret = cgiQuery->query[i]->num;
  624     
  625     return GCGISUCCESS;
  626 }
  627 
  628 
  629 gcgiReturnType 
  630 gcgiFetchInteger(char *field, int *ret, int defaultRet)
  631 {
  632     int i;
  633     QueryStringNode *qs;
  634 
  635     if (findQueryStringNodeFirst(field, &qs) == GCGIFIELDNOTFOUND) {
  636     *ret = defaultRet;
  637     return GCGIFIELDNOTFOUND;
  638     }
  639 
  640     if (qs->size <= 1 && qs->data[0] == '\0') {
  641     *ret = defaultRet;
  642     return GCGIFIELDEMPTY;
  643     }
  644 
  645     i = strtol(qs->data,NULL,10);
  646 
  647     if (errno == ERANGE) {
  648     *ret = defaultRet;
  649     return GCGIBADDATA;
  650     }
  651     else
  652     *ret = i;
  653 
  654     return GCGISUCCESS;
  655 }
  656 
  657 
  658 gcgiReturnType 
  659 gcgiFetchIntegerNext(char *field, int *ret, int defaultRet)
  660 {
  661     int i;
  662     QueryStringNode *qs;
  663 
  664     if (findQueryStringNode(field, &qs) == GCGIFIELDNOTFOUND) {
  665     *ret = defaultRet;
  666     return GCGIFIELDNOTFOUND;
  667     }
  668 
  669     if (qs->size <= 1 && qs->data[0] == '\0') {
  670     *ret = defaultRet;
  671     return GCGIFIELDEMPTY;
  672     }
  673 
  674     i = strtol(qs->data,NULL,10);
  675 
  676     if (errno == ERANGE) {
  677     *ret = defaultRet;
  678     return GCGIBADDATA;
  679     }
  680     else
  681     *ret = i;
  682 
  683     return GCGISUCCESS;
  684 }
  685 
  686 
  687 gcgiReturnType 
  688 gcgiFetchDouble(char *field, double *ret, double defaultRet)
  689 {
  690     double i;
  691     QueryStringNode *qs;
  692 
  693     if (findQueryStringNodeFirst(field, &qs) == GCGIFIELDNOTFOUND) {
  694     *ret = defaultRet;
  695     return GCGIFIELDNOTFOUND;
  696     }
  697 
  698     if (qs->size <= 1 && qs->data[0] == '\0') {
  699     *ret = defaultRet;
  700     return GCGIFIELDEMPTY;
  701     }
  702 
  703     i = strtod(qs->data, NULL);
  704 
  705     if (errno == ERANGE) {
  706     *ret = defaultRet;
  707     return GCGIBADDATA;
  708     }
  709     else
  710     *ret = i;
  711 
  712     return GCGISUCCESS;
  713 }
  714 
  715 
  716 gcgiReturnType 
  717 gcgiFetchDoubleNext(char *field, double *ret, double defaultRet)
  718 {
  719     double i;
  720     QueryStringNode *qs;
  721 
  722     if (findQueryStringNode(field, &qs) == GCGIFIELDNOTFOUND) {
  723     *ret = defaultRet;
  724     return GCGIFIELDNOTFOUND;
  725     }
  726 
  727     if (qs->size <= 1 && qs->data[0] == '\0') {
  728     *ret = defaultRet;
  729     return GCGIFIELDEMPTY;
  730     }
  731 
  732     i = strtod(qs->data, NULL);
  733 
  734     if (errno == ERANGE) {
  735     *ret = defaultRet;
  736     return GCGIBADDATA;
  737     }
  738     else
  739     *ret = i;
  740 
  741     return GCGISUCCESS;
  742 }
  743 
  744 
  745 gcgiReturnType 
  746 gcgiFieldLength(char *field, int *ret)
  747 {
  748     QueryStringNode *qs;
  749     
  750     if (findQueryStringNodeFirst(field, &qs) == GCGIFIELDNOTFOUND) {
  751     *ret = 0;
  752     return GCGIFIELDNOTFOUND;
  753     }
  754 
  755     *ret = strlen(qs->data);
  756     
  757     if (*ret == 0)
  758     return GCGIFIELDEMPTY;
  759     else
  760     return GCGISUCCESS;
  761 }
  762 
  763 
  764 gcgiReturnType 
  765 gcgiFieldLengthCur(char *field, int *ret)
  766 {
  767     QueryStringNode *qs;
  768     
  769     if (findQueryStringNodeCur(field, &qs) == GCGIFIELDNOTFOUND) {
  770     *ret = 0;
  771     return GCGIFIELDNOTFOUND;
  772     }
  773 
  774     *ret = strlen(qs->data);
  775 
  776     if (*ret == 0)
  777     return GCGIFIELDEMPTY;
  778     else
  779     return GCGISUCCESS;
  780 }
  781 
  782 
  783 gcgiReturnType 
  784 gcgiFieldLengthNext(char *field, int *ret)
  785 {
  786     QueryStringNode *qs;
  787     
  788     if (findQueryStringNode(field, &qs) == GCGIFIELDNOTFOUND) {
  789     *ret = 0;
  790     return GCGIFIELDNOTFOUND;
  791     }
  792 
  793     *ret = strlen(qs->data);
  794 
  795     if (*ret == 0)
  796     return GCGIFIELDEMPTY;
  797     else
  798     return GCGISUCCESS;
  799 }
  800 
  801 
  802 gcgiReturnType 
  803 gcgiFieldSize(char *field, int *ret)
  804 {
  805     QueryStringNode *qs;
  806     
  807     if (findQueryStringNodeFirst(field, &qs) == GCGIFIELDNOTFOUND) {
  808     *ret = 0;
  809     return GCGIFIELDNOTFOUND;
  810     }
  811 
  812     *ret = qs->size;
  813     
  814     return GCGISUCCESS;
  815 }
  816 
  817 
  818 gcgiReturnType 
  819 gcgiFieldSizeCur(char *field, int *ret)
  820 {
  821     QueryStringNode *qs;
  822     
  823     if (findQueryStringNodeCur(field, &qs) == GCGIFIELDNOTFOUND) {
  824     *ret = 0;
  825     return GCGIFIELDNOTFOUND;
  826     }
  827 
  828     *ret = qs->size;
  829     
  830     return GCGISUCCESS;
  831 }
  832 
  833 
  834 gcgiReturnType 
  835 gcgiFieldSizeNext(char *field, int *ret)
  836 {
  837     QueryStringNode *qs;
  838     
  839     if (findQueryStringNode(field, &qs) == GCGIFIELDNOTFOUND) {
  840     *ret = 0;
  841     return GCGIFIELDNOTFOUND;
  842     }
  843 
  844     *ret = qs->size;
  845     
  846     return GCGISUCCESS;
  847 }
  848 
  849 
  850 char *
  851 gcgiFetchEnvVar(int env)
  852 {
  853     return cgiQuery->env[env];
  854 }
  855 
  856 
  857 gcgiReturnType 
  858 gcgiFetchString(char *field, char *ret, int max)
  859 {
  860     int i;
  861     QueryStringNode *qs;
  862 
  863     if (findQueryStringNodeFirst(field, &qs) == GCGIFIELDNOTFOUND) {
  864     ret[0] = '\0';
  865     return GCGIFIELDNOTFOUND;
  866     }
  867     
  868     i = strlen(qs->data);
  869 
  870     if (i >= max) 
  871     i = max-1;
  872     
  873     strncpy(ret, qs->data, i);
  874     ret[i] = '\0';
  875 
  876     if (i == 0)
  877     return GCGIFIELDEMPTY;
  878     else
  879     return GCGISUCCESS;
  880 }
  881 
  882 
  883 gcgiReturnType 
  884 gcgiFetchStringNext(char *field, char *ret, int max)
  885 {
  886     int i;
  887     QueryStringNode *qs;
  888 
  889     if (findQueryStringNode(field, &qs) == GCGIFIELDNOTFOUND) {
  890     ret[0] = '\0';
  891     return GCGIFIELDNOTFOUND;
  892     }
  893   
  894     i = strlen(qs->data);
  895     if (i >= max) 
  896     i = max-1;
  897     
  898     strncpy(ret, qs->data, i);
  899     ret[i] = '\0';
  900 
  901     if (i == 0)
  902     return GCGIFIELDEMPTY;
  903     else
  904     return GCGISUCCESS;
  905 }
  906 
  907 
  908 gcgiReturnType  
  909 gcgiFetchStringNoNewLines(char *field, char *ret, int max)
  910 {
  911     int len,i,j;
  912     QueryStringNode *qs;
  913 
  914     if (findQueryStringNodeFirst(field, &qs) == GCGIFIELDNOTFOUND) {
  915     ret[0] = '\0';
  916     return GCGIFIELDNOTFOUND;
  917     }
  918   
  919     len = strlen(qs->data);
  920     if (len >= max) 
  921     len = max-1;
  922 
  923     for (j = 0, i = 0; i <= len && qs->data[j] != '\0'; j++, i++) 
  924     if (qs->data[j] == '\r' && qs->data[j+1] == '\n') {
  925         ret[i] = ' ';
  926         j++;
  927     }
  928     else if (qs->data[j] == '\n') {
  929         ret[i] = ' ';
  930     }
  931     else
  932         ret[i] = qs->data[j];
  933     
  934     if (i <= len)
  935     ret[i] = '\0';
  936     else
  937     ret[len] = '\0';
  938     
  939     if (len == 0)
  940     return GCGIFIELDEMPTY;
  941     else
  942     return GCGISUCCESS;
  943 }
  944 
  945 
  946 gcgiReturnType  
  947 gcgiFetchStringNoNewLinesNext(char *field, char *ret, int max)
  948 {
  949     int len,i,j;
  950     QueryStringNode *qs;
  951 
  952     if (findQueryStringNode(field, &qs) == GCGIFIELDNOTFOUND) {
  953     ret[0] = '\0';
  954     return GCGIFIELDNOTFOUND;
  955     }
  956   
  957     len = strlen(qs->data);
  958     if (len >= max) 
  959     len = max-1;
  960 
  961     for (j = 0, i = 0; i <= len && qs->data[j] != '\0'; j++, i++) 
  962     if (qs->data[j] == '\r' && qs->data[j+1] == '\n') {
  963         ret[i] = ' ';
  964         i++;
  965         j += 2;
  966     }
  967     else if (qs->data[j] == '\n') {
  968         ret[i] = ' ';
  969         j++;
  970     }
  971     else
  972         ret[i] = qs->data[j];
  973     
  974     if (i <= len)
  975     ret[i] = '\0';
  976     else
  977     ret[len] = '\0';
  978     
  979     if (i == 0)
  980     return GCGIFIELDEMPTY;
  981     else
  982     return GCGISUCCESS;
  983 }
  984 
  985 
  986 gcgiReturnType
  987 gcgiFetchData(char *field, char *ret, int max, MimeType *type, 
  988           char **subtype, MimeEncoding *encoding, char **filename, int *truncated)
  989 {
  990     size_t i;
  991     QueryStringNode *qs;
  992 
  993     if (findQueryStringNodeFirst(field, &qs) == GCGIFIELDNOTFOUND) 
  994     return GCGIFIELDNOTFOUND;
  995   
  996     if (qs->truncated)
  997     *truncated = 1;
  998     else
  999     *truncated = 0;
 1000 
 1001     i = qs->size;
 1002     if (i >= max) 
 1003     i = max;
 1004     
 1005     if (i == 0)
 1006     return GCGIFIELDNOTFOUND;
 1007 
 1008     memcpy(ret, qs->data, i);
 1009 
 1010     *type     = qs->type;
 1011     *encoding = qs->encoding;
 1012 
 1013     if (subtype != NULL) {
 1014     *subtype = XMALLOC(char, strlen(qs->subtype)+1);
 1015     strcpy(*subtype, qs->subtype);
 1016     }
 1017 
 1018     if (filename != NULL) {
 1019     *filename = XMALLOC(char, strlen(qs->filename)+1);
 1020     strcpy(*filename, qs->filename);
 1021     }
 1022 
 1023     return GCGISUCCESS;
 1024 }
 1025 
 1026 
 1027 gcgiReturnType
 1028 gcgiFetchDataNext(char *field, char *ret, int max, MimeType *type, 
 1029           char **subtype, MimeEncoding *encoding, char **filename, int *truncated)
 1030 {
 1031     size_t i;
 1032     QueryStringNode *qs;
 1033 
 1034     if (findQueryStringNode(field, &qs) == GCGIFIELDNOTFOUND)
 1035     return GCGIFIELDNOTFOUND;
 1036   
 1037     i = qs->size;
 1038     if (i >= max) 
 1039     i = max;
 1040     
 1041     if (i == 0)
 1042     return GCGIFIELDNOTFOUND;
 1043 
 1044     memcpy(ret, qs->data, i);
 1045 
 1046     *type     = qs->type;
 1047     *encoding = qs->encoding;
 1048 
 1049     return GCGISUCCESS;
 1050 }
 1051 
 1052 
 1053 gcgiReturnType 
 1054 gcgiFetchMultipleString(char *field, char ***data)
 1055 {
 1056     int i, j;
 1057     QueryStringNode *qs;
 1058     QueryStringColl *qsc;
 1059 
 1060     if (findQueryStringColl(field, &i) == GCGIFIELDNOTFOUND) {
 1061     *data = NULL;
 1062     return GCGIFIELDNOTFOUND;
 1063     }
 1064     
 1065     qsc = cgiQuery->query[i];
 1066 
 1067     /* Malloc the array of char pointers. */
 1068     *data = XMALLOC(char *, qsc->num + 1);
 1069 
 1070     (*data)[qsc->num] = '\0';
 1071 
 1072     for (qs = qsc->beg, j = 0; qs != NULL; qs = qs->next, j++) {
 1073     (*data)[j] = XMALLOC(char, qs->size);
 1074     strncpy((*data)[j], qs->data, qs->size - 1);
 1075     (*data)[j][qs->size - 1] = '\0';
 1076     }
 1077 
 1078     return GCGISUCCESS;
 1079 }
 1080 
 1081 
 1082 gcgiReturnType
 1083 gcgiFreeMultipleString(char **data)
 1084 {
 1085     int i; 
 1086 
 1087     if (data == NULL)
 1088     return GCGISUCCESS;
 1089 
 1090     for (i = 0; data[i] != NULL; i++)
 1091     XFREE(data[i]);
 1092 
 1093     XFREE(data);
 1094     return GCGISUCCESS;
 1095 }
 1096 
 1097 
 1098 gcgiReturnType  
 1099 gcgiResetMultipleField(char *field)
 1100 {
 1101     int i;
 1102 
 1103     if (findQueryStringColl(field, &i) == GCGIFIELDNOTFOUND) 
 1104     return GCGIFIELDNOTFOUND;
 1105     
 1106     cgiQuery->query[i]->cur = cgiQuery->query[i]->beg;
 1107     
 1108     return GCGISUCCESS;
 1109 }
 1110 
 1111 
 1112 gcgiReturnType
 1113 gcgiFetchSelectIndex(char *field, char **data, int size, int *ret, int defaultVal)
 1114 {
 1115     QueryStringNode *qs;
 1116     int i;
 1117 
 1118     *ret = -1;
 1119 
 1120     if (findQueryStringNode(field, &qs) == GCGIFIELDNOTFOUND)
 1121     return GCGIFIELDNOTFOUND;
 1122 
 1123     for (i = 0; data[i] != NULL && i < size; i++) 
 1124     if (strncmp(data[i],qs->data,qs->size) == 0)
 1125         *ret = i;
 1126     
 1127     if (*ret == -1) {
 1128     *ret = defaultVal;
 1129     return GCGIFIELDNOTFOUND;
 1130     }
 1131 
 1132     return GCGISUCCESS;
 1133 }
 1134 
 1135 
 1136 gcgiReturnType   
 1137 gcgiFetchCheckbox(char *field, int *ret)
 1138 {
 1139     QueryStringNode *qs;
 1140 
 1141     if (findQueryStringNodeFirst(field, &qs) == GCGIFIELDNOTFOUND) {
 1142     *ret = 0;
 1143     return GCGIFIELDNOTFOUND;
 1144     }
 1145     
 1146     *ret = 1;
 1147 
 1148     return GCGISUCCESS;
 1149 }
 1150 
 1151 
 1152 gcgiReturnType
 1153 gcgiFetchMultipleCheckbox(char *field, char **data, int size, int **ret)
 1154 {
 1155     QueryStringNode *qs;
 1156     int i;
 1157 
 1158     for (i = 0; data[i] != NULL && i < size; i++) {
 1159     if (findQueryStringNodeByData(field, data[i], &qs) == GCGIFIELDNOTFOUND)
 1160         (*ret)[i] = 0;
 1161     else
 1162         (*ret)[i] = 1;
 1163     }
 1164     
 1165     return GCGISUCCESS;
 1166 }
 1167 
 1168 
 1169 gcgiReturnType  
 1170 gcgiLoadEnvVariables(char *path)
 1171 {
 1172     FILE *envfile;
 1173     char  line[256], *p;
 1174     char *input;
 1175     int   ilen, len;
 1176     int   isize;
 1177 
 1178     input = NULL;
 1179 
 1180     if ((envfile = fopen(path,"r")) == NULL) 
 1181     return GCGIFATALERROR;
 1182  
 1183     while (!feof(envfile)) {
 1184     /* Allocate a new string */
 1185     ilen  = 0;
 1186     isize = 256;
 1187     input = XMALLOC(char, isize);
 1188     memset(input, 0, isize);
 1189 
 1190     do {
 1191         fgets(line, 256, envfile);
 1192         len = strlen(line);
 1193         if (ilen + len <= isize - 1) {
 1194         strcat(input, line);
 1195         ilen += len;
 1196         }
 1197         else {
 1198         isize = isize * 2;
 1199         ilen += len;
 1200         input = XREALLOC(char, input, isize);
 1201         strcat(input, line);
 1202         }               
 1203     } while (!feof(envfile) && input[ilen-1] != '\n');
 1204 
 1205     /* Remove the newline. */
 1206     for (p = input; *p != '\n' && p < (input+ilen); p++);
 1207     if (*(p-1) == '\r') *p = '\0';
 1208     if (*p     == '\n') *p = '\0';
 1209 
 1210     /* String becomes part of the environment */
 1211     if (putenv(input) < 0) {
 1212         fclose(envfile);
 1213         XFREE(input);
 1214         return GCGIFATALERROR;
 1215     }
 1216     }
 1217 
 1218     fclose(envfile);
 1219     XFREE(input);
 1220 
 1221     return GCGISUCCESS;
 1222 }
 1223 
 1224 
 1225 gcgiReturnType 
 1226 gcgiSaveEnvVariables(char *path)
 1227 {
 1228     FILE *envfile;
 1229     int i;
 1230 
 1231     if ((envfile = fopen(path,"w")) == NULL) {
 1232     fprintf(stderr, "Unable to open file to save environment variables to: %s\n", path);    
 1233     return GCGIFATALERROR;
 1234     }
 1235   
 1236     for (i = 0; i < ENVCOUNT; i++) {
 1237     if (cgiQuery->env[i] != NULL)
 1238         fprintf(envfile, "%s=%s\n", envVars[i], cgiQuery->env[i]);
 1239     }
 1240     
 1241     fclose(envfile);
 1242 
 1243     return GCGISUCCESS;
 1244 }
 1245 
 1246 
 1247 gcgiReturnType  
 1248 gcgiDebug(char *envVarsPath, char *cgiQueryPath)
 1249 {
 1250     int evlen, cqlen;
 1251     
 1252     evlen = strlen(envVarsPath);
 1253     cqlen = strlen(cgiQueryPath);
 1254 
 1255     debug++;
 1256     envVariablesFile  = XMALLOC(char, evlen + 1);
 1257     strncpy(envVariablesFile, envVarsPath, evlen);
 1258     envVariablesFile[evlen] = '\0';
 1259 
 1260     cgiQueryFile = XMALLOC(char, cqlen + 1);
 1261     strncpy(cgiQueryFile, cgiQueryPath, cqlen);
 1262     cgiQueryFile[cqlen] = '\0';
 1263 
 1264     return GCGISUCCESS;
 1265 }
 1266 
 1267 
 1268 gcgiReturnType 
 1269 createCgiQuery( )
 1270 {
 1271     int i;
 1272 
 1273     cgiQuery = XMALLOC(CgiQuery, 1);
 1274   
 1275     if ((cgiQuery->env = (char **) malloc(ENVCOUNT * sizeof(char *))) == NULL)
 1276     return GCGIFATALERROR;
 1277 
 1278     for (i = 0; i < ENVCOUNT; i++)
 1279     cgiQuery->env[i] = NULL;
 1280     cgiQuery->envCount   =  0;
 1281 
 1282     /* Populate the env array. */
 1283     getEnvVariables();
 1284     //gcgiSaveEnvVariables();
 1285   
 1286     /* Set the queryStringColl pointer to NULL for now. */
 1287     cgiQuery->query = NULL;
 1288     
 1289     return GCGISUCCESS;
 1290 }
 1291 
 1292 
 1293 gcgiReturnType 
 1294 freeCgiQuery( )
 1295 {
 1296     int i;
 1297 
 1298     if (cgiQuery == NULL)
 1299     return GCGISUCCESS;
 1300 
 1301     /* Free the env variables array */
 1302     for (i = 0; i < cgiQuery->envCount; i++) 
 1303     if (cgiQuery->env[i] != NULL) XFREE(cgiQuery->env[i]);
 1304   
 1305     /* Free the QueryNodeColl array */
 1306     for (i = 0; i < cgiQuery->queryCount; i++)
 1307     freeQueryStringColl(cgiQuery->query[i]);
 1308     
 1309     XFREE(cgiQuery->env);
 1310     XFREE(cgiQuery->query);
 1311     XFREE(cgiQuery);
 1312     
 1313     return GCGISUCCESS;
 1314 }
 1315 
 1316 
 1317 gcgiReturnType 
 1318 getEnvVariables( void )
 1319 {
 1320     int   i, len;
 1321     char *e;
 1322 
 1323     for (i = 0; i < ENVCOUNT; i++) {
 1324     if ((e = getenv(envVars[i])) != NULL) {
 1325         len = strlen(e);
 1326         cgiQuery->env[i] = XMALLOC(char, len + 1);
 1327         strncpy(cgiQuery->env[i], e, len);
 1328         cgiQuery->env[i][len] = '\0';
 1329         cgiQuery->envCount++;
 1330     }
 1331     else 
 1332         cgiQuery->env[i] = NULL;
 1333     }
 1334   
 1335     return GCGISUCCESS;
 1336 }
 1337 
 1338 
 1339 gcgiReturnType 
 1340 insertQueryStringNode(QueryStringNode *q)
 1341 {
 1342     int i, res;
 1343     QueryStringColl *qsc;
 1344 
 1345     res = findQueryStringColl(q->field, &i);
 1346 
 1347     /* A collection for this field doen not exist. */
 1348     if (res == GCGIFIELDNOTFOUND) { 
 1349     //qsc = cgiQuery->query[cgiQuery->queryCount];
 1350     createQueryStringColl(&qsc);
 1351     cgiQuery->query[cgiQuery->queryCount] = qsc;
 1352     i = cgiQuery->queryCount;
 1353     cgiQuery->queryCount++;
 1354     }
 1355     else {
 1356     qsc = cgiQuery->query[i];
 1357     }
 1358     
 1359     /* Insert the node at the end of the collection's node list. */
 1360     if (qsc->end == NULL) {
 1361     qsc->end = q;
 1362     qsc->beg = q;
 1363     qsc->cur = q;
 1364     }
 1365     else {
 1366     qsc->end->next = q;
 1367     qsc->end = q;
 1368     }
 1369     q->next = NULL;
 1370     qsc->num++;
 1371     
 1372     return GCGISUCCESS;
 1373 }
 1374 
 1375 
 1376 gcgiReturnType 
 1377 findQueryStringColl(char *field, int *index)
 1378 {
 1379     int flen, qlen, len;
 1380     QueryStringColl **qsc;
 1381 
 1382     flen = strlen(field);
 1383     if (cgiQuery == NULL) {
 1384     *index = -1;
 1385     return GCGIFIELDNOTFOUND;
 1386     }
 1387 
 1388     qsc = cgiQuery->query;
 1389 
 1390     for (*index = 0; *index < cgiQuery->queryCount; (*index)++) {
 1391     qlen = strlen(qsc[*index]->beg->field);          
 1392     (qlen >= flen) ? (len = qlen) : (len = flen);
 1393 
 1394     if (! strncmp(field, qsc[*index]->beg->field, len))
 1395         return GCGISUCCESS;
 1396     }
 1397 
 1398     return GCGIFIELDNOTFOUND;
 1399 }
 1400 
 1401 
 1402 gcgiReturnType
 1403 findQueryStringNodeFirst(char *field, QueryStringNode **q)
 1404 {
 1405     int flen, i, res;
 1406 
 1407     flen = strlen(field);
 1408     if (cgiQuery == NULL || cgiQuery->queryCount == 0) {
 1409     *q = NULL;
 1410     return GCGIFIELDNOTFOUND;
 1411     }
 1412   
 1413     res = findQueryStringColl(field, &i);
 1414     
 1415     if (res == GCGIFIELDNOTFOUND) {
 1416     *q = NULL;
 1417     return GCGIFIELDNOTFOUND;
 1418     }
 1419     
 1420     if (cgiQuery->query[i]->beg != NULL)
 1421     *q = cgiQuery->query[i]->beg;
 1422     else {
 1423     *q = NULL;
 1424     return GCGIFIELDNOTFOUND;
 1425     }
 1426   
 1427     return GCGISUCCESS;
 1428 }
 1429 
 1430 
 1431 gcgiReturnType 
 1432 findQueryStringNode(char *field, QueryStringNode **q) 
 1433 {
 1434     int flen, i, res;
 1435 
 1436     flen = strlen(field);
 1437     if (cgiQuery == NULL || cgiQuery->queryCount == 0) {
 1438     *q = NULL;
 1439     return GCGIFIELDNOTFOUND;
 1440     }
 1441   
 1442     res = findQueryStringColl(field, &i);
 1443     
 1444     if (res == GCGIFIELDNOTFOUND) {
 1445     *q = NULL;
 1446     return GCGIFIELDNOTFOUND;
 1447     }
 1448     
 1449     if (cgiQuery->query[i]->cur != NULL)
 1450     *q = cgiQuery->query[i]->cur;
 1451     else {
 1452     *q = NULL;
 1453     return GCGIFIELDNOTFOUND;
 1454     }
 1455   
 1456     /* Return the current item in the list and then increment it. */
 1457     if (cgiQuery->query[i]->cur->next != NULL)
 1458     cgiQuery->query[i]->cur = cgiQuery->query[i]->cur->next;
 1459     else
 1460     cgiQuery->query[i]->cur = NULL;
 1461     
 1462     return GCGISUCCESS;
 1463 }
 1464 
 1465 
 1466 gcgiReturnType 
 1467 findQueryStringNodeCur(char *field, QueryStringNode **q) 
 1468 {
 1469     int flen, i, res;
 1470 
 1471     flen = strlen(field);
 1472     if (cgiQuery == NULL || cgiQuery->queryCount == 0) {
 1473     *q = NULL;
 1474     return GCGIFIELDNOTFOUND;
 1475     }
 1476   
 1477     res = findQueryStringColl(field, &i);
 1478     
 1479     if (res == GCGIFIELDNOTFOUND) {
 1480     *q = NULL;
 1481     return GCGIFIELDNOTFOUND;
 1482     }
 1483     
 1484     /* Return the current item in the list but don't increment it. */
 1485     if (cgiQuery->query[i]->cur != NULL)
 1486     *q = cgiQuery->query[i]->cur;
 1487     else {
 1488     *q = NULL;
 1489     return GCGIFIELDNOTFOUND;
 1490     }
 1491     
 1492     return GCGISUCCESS;
 1493 }
 1494 
 1495 
 1496 gcgiReturnType
 1497 findQueryStringNodeByData(char *field, char *data, QueryStringNode **q)
 1498 {
 1499     QueryStringNode *qs;
 1500     int i;
 1501 
 1502     if (findQueryStringColl(field, &i) == GCGIFIELDNOTFOUND)
 1503     return GCGIFIELDNOTFOUND;
 1504 
 1505     for (qs = cgiQuery->query[i]->beg;
 1506      qs != NULL && strncmp(qs->data, data, qs->size) != 0;
 1507      qs = qs->next);
 1508 
 1509     if (qs != NULL) {
 1510     *q = qs;
 1511     return GCGISUCCESS;
 1512     }
 1513     else
 1514     return GCGIFIELDNOTFOUND;
 1515 }
 1516 
 1517 
 1518 gcgiReturnType 
 1519 createQueryStringNode(QueryStringNode **q)
 1520 {
 1521     *q = XMALLOC(QueryStringNode, 1);
 1522     (*q)->next      = NULL;
 1523     (*q)->field     = NULL;
 1524     (*q)->data      = NULL;
 1525     (*q)->subtype   = NULL;
 1526     (*q)->filename  = NULL;
 1527     (*q)->size      = 0;
 1528     (*q)->encoding  = sevenbit;
 1529     (*q)->type      = text;
 1530 
 1531     return GCGISUCCESS;
 1532 }
 1533 
 1534 
 1535 gcgiReturnType 
 1536 freeQueryStringNode(QueryStringNode *q)
 1537 {
 1538     if (q->data != NULL)    XFREE(q->data);
 1539     if (q->field != NULL)   XFREE(q->field);
 1540     if (q->subtype != NULL) XFREE(q->subtype);
 1541     if (q->subtype != NULL) XFREE(q->filename);
 1542     q->next = NULL;
 1543     
 1544     XFREE(q);
 1545   
 1546     return 0;
 1547 }
 1548 
 1549 
 1550 gcgiReturnType
 1551 createQueryStringColl(QueryStringColl **q)
 1552 {
 1553     *q = XMALLOC(QueryStringColl, 1);
 1554 
 1555     (*q)->num = 0;
 1556     (*q)->beg = NULL;
 1557     (*q)->end = NULL;
 1558     (*q)->cur = NULL;
 1559 
 1560     return GCGISUCCESS;
 1561 }
 1562 
 1563 
 1564 gcgiReturnType
 1565 createQueryStringCollArray(int numColls)
 1566 {
 1567     int i;
 1568 
 1569     /* Malloc the query[] array and clear it. */
 1570     if ((cgiQuery->query = (QueryStringColl **) malloc(numColls * sizeof(QueryStringColl *))) == NULL)
 1571     return GCGIFATALERROR;
 1572     
 1573     for (i = 0; i < numColls; i++) 
 1574     cgiQuery->query[i] = NULL;
 1575 
 1576     cgiQuery->queryCount = 0;
 1577 
 1578     return GCGISUCCESS;
 1579 }
 1580 
 1581 
 1582 gcgiReturnType
 1583 freeQueryStringColl(QueryStringColl *q)
 1584 {
 1585     QueryStringNode *m, *n;
 1586     
 1587     for (m = n = q->beg; n != NULL; m = n) {
 1588     n = n->next;
 1589     freeQueryStringNode(m);
 1590     }
 1591 
 1592     q->beg = NULL;
 1593     q->end = NULL;
 1594     q->cur = NULL;
 1595 
 1596     XFREE(q);
 1597     
 1598     return GCGISUCCESS;
 1599 }
 1600 
 1601 
 1602 gcgiReturnType 
 1603 printQueryStringColl(QueryStringColl *q, FILE *stream)
 1604 {
 1605     QueryStringNode *node;
 1606 
 1607     for (node = q->beg; node != NULL; node = node->next) {
 1608     printQueryStringNode(node, stream);
 1609     }
 1610 
 1611     return GCGISUCCESS;
 1612 }
 1613 
 1614 
 1615 gcgiReturnType 
 1616 printQuery(FILE *stream)
 1617 {
 1618     int i;
 1619   
 1620     for (i = 0; i < cgiQuery->queryCount; i++) {
 1621     fprintf(stream, "QueryString Collection #%d:\n", i);
 1622     printQueryStringColl(cgiQuery->query[i], stream);
 1623     }
 1624     
 1625     return GCGISUCCESS;
 1626 }
 1627 
 1628 
 1629 gcgiReturnType 
 1630 printQueryStringNode(QueryStringNode *q, FILE *stream)
 1631 {
 1632     fprintf(stream, "     %s: %s\n", q->field, q->data);
 1633   
 1634     return GCGISUCCESS;
 1635 }