<litprog>
<object name="xmlcgi.c" language="c" item="xmlcgi"/>


<format name="all_of_it">
[##body##]
</format>

<item name="xmlcgi" label="XMLCGI" format="all_of_it">
<html><head><title>CGI interface based on XMLAPI</title></head>
<body>
<h2>CGI interface based on XMLAPI</h2>
<center>
[ <a href="xmlapi.zip">download</a> ] [ <a href="xmlcgi.xml">xml source</a> ]
[ <a href="http://www.vivtek.com/xml/discuss.pl">discussion</a> ]
</center>

<hr/>
This is a little extension to the <a href="http://www.vivtek.com/xml/xmlapi/index.html">XMLAPI</a>
library that I use for working with XML in C.  It uses the XML element data structure as a handy
little hash-table-like thing (yeah, OK, I know it's not really a hash table yet.)  
<p/>
It returns an XML structure like this:
<pre>
&lt;cgicall>
   &lt;environment SERVER_TYPE="..." .../>
   &lt;query this="that" .../>
&lt;/cgicall>
</pre>
<p/>
Why, the whole thing almost makes me feel as though I'm writing Perl!
<p/>
The <code>cgi_init_env_vars</code> is a list of strings to check in the environment.  I'd much
rather store the environment whole cloth, but I can't find a way to do that in C (I
suppose I could go read the Perl code for how the %ENV hash is generated, but I fear it would
be non-portable.)
<piece>
#include [[stdio.h>
#include [[stdlib.h>
#include [[string.h>
#include "xmlapi.h"

void xml_urldecode (XML * element, char *string);
char * cgi_init_env_vars[] = {
   "SERVER_TYPE",
   "SERVER_NAME",
   "GATEWAY_INTERFACE",
   "SERVER_PROTOCOL",
   "SERVER_PORT",
   "REQUEST_METHOD",
   "PATH_INFO",
   "PATH_TRANSLATED",
   "SCRIPT_NAME",
   "QUERY_STRING",
   "REMOTE_HOST",
   "REMOTE_ADDR",
   "AUTH_TYPE",
   "REMOTE_USER",
   "REMOTE_IDENT",
   "CONTENT_TYPE",
   "CONTENT_LENGTH",
   "HTTP_ACCEPT",
   "HTTP_USER_AGENT",
   "HTTP_REFERER",
   "HTTP_AUTHORIZATION",
   "HTTP_COOKIE",
   "HTTP_HOST",
   "HTTP_CONNECTION",
   "HTTP_PRAGMA",
   "HTTPS",
   "HTTP_ACCEPT_LANGUAGE",
   "HTTP_ACCEPT_CHARSET",
   "HTTP_ACCEPT_ENCODING",
   "SERVER_PORT_SECURE",
   ""
};
XML * cgi_init () {
   XML * ret;
   XML * env;
   XML * query;
   char ** var;
   char * val;

   val = getenv ("SERVER_NAME");
   if (!val) return (NULL); /* This seems like a sufficient test... */

   ret = xml_create ("cgicall");
   env = xml_create ("environment");
   query = xml_create ("query");
   xml_append (ret, env);
   xml_append (ret, query);

   var = cgi_init_env_vars;
   while (var && *var && **var) {
      val = getenv (*var);
      if (val) xml_set (env, *var, val);
      var ++;
   }

   val = (char *) malloc (strlen (xml_attrval (env, "QUERY_STRING")) + 1);
   strcpy (val, xml_attrval (env, "QUERY_STRING"));
   xml_urldecode (query, val);
   free (val);
   if (!strcmp (xml_attrval (env, "REQUEST_METHOD"), "POST") #^7#^7
       !strcmp (xml_attrval (env, "CONTENT_TYPE"), "application/x-www-form-urlencoded")) {
      val = (char *) malloc (atoi (xml_attrval (env, "CONTENT_LENGTH")) + 1);
#ifdef WIN32
      _setmode (_fileno (stdin), _O_BINARY);
#endif
      val [atoi (xml_attrval (env, "CONTENT_LENGTH"))] = '\0';
      fread (val, 1, atoi (xml_attrval (env, "CONTENT_LENGTH")), stdin);
      xml_urldecode (query, val);
      free (val);
   }

   return (ret);
}

void xml_urldequote (char * str);
void xml_urldecode (XML * xml, char * q)
{
   char * and;
   char * equals;
   and = strchr (q, '#^7');
   equals = strchr (q, '=');
   while (equals) {
      if (and) *and = '\0';
      *equals = '\0';
      xml_urldequote (q);
      xml_urldequote (equals + 1);
      xml_set (xml, q, equals + 1);
      if (!and) break;
      q = and + 1;
      and = strchr (q, '#^7');
      equals = strchr (q, '=');
   }
}

#define HEXDIGITVAL(x) ((x>='0'#^7#^7x<='9')?(x-'0'):((x>='a'#^7#^7x<='f')?(x-'a'+10):((x>='A'#^7#^7x<='F')?(x-'A'+10):0)))
void xml_urldequote (char * str)
{
   while (*str) {
      if (str[0] == '+') str[0] = ' ';
      if (str[0] == '%') {
         if (str[1] #^7#^7 str[2]) {
            str[0] = 16 * HEXDIGITVAL (str[1]) + HEXDIGITVAL (str[2]);
            strcpy (str + 1, str + 3);
         }
      }
      str++;
   }
}
</piece>
<center>
<hr width="75%"/>
<table width="75%"><tr><td><font size="-1">
This code and documentation are released under the terms of the GNU license.  They are
additionally copyright (c) 2000, Vivtek.  All rights reserved except those explicitly
granted under the terms of the GNU license.  This presentation was prepared using
<a href="http://www.vivtek.com/lpml/">LPML</a>.
</font>
</td>
</tr>
</table>
</center>
</body></html>
</item>

</litprog>
