The cgihtml library is a collection of routines written in C for parsing Common Gateway Interface input and for outputting HyperText Markup Language. These tasks, which normally require several lines of C, can be reduced to just a few lines. Using cgihtml enables you to focus on the main algorithms of your code rather than on laborious parsing and output routines.
The cgihtml routines were written for UNIX machines. The library has been successfully ported to Windows NT and Windows 3.1, and probably could be ported to other operating systems fairly easily.
The cgihtml library includes the following files:
README | A file you should read first |
CHANGES | Version revision information |
TODO | Things or changes I want to implement eventually |
docs/ | Documentation directory |
debug-cgi.sh | Shell script to help debug CGI code |
Makefile | A makefile to compile and install cgihtml |
cgi-lib.c | Source code |
html-lib.c | Source code |
llist.c | Source code |
string-lib.c | Source code |
cgi-lib.h | Header file for routines |
html-lib.h | Header file for routines |
llist.h | Header file for routines |
string-lib.h | Header file for routines |
query-results.c | Example program |
mail.cgi.c | Example program |
ignore.cgi.c | Example program |
index-sample.cgi.c | Example program |
test.cgi.c | Example program |
The latest version of cgihtml is always available at
<URL:ftp://hcs.harvard.edu/pub/web/tools/cgihtml.tar.gz>
The cgihtml home page, which contains links to documentation and other cgihtml resources, is available at
<URL:http://hcs.harvard.edu/~eekim/web/cgihtml/>
You can subscribe to the cgihtml mailing list for the latest cgihtml information and announcements. To subscribe, send e-mail to majordomo@hcs.harvard.edu with the following body:
subscribe cgihtml
The cgihtml archive comes in one of three different compressed formats: gzip (.gz), compress (.Z), and pkzip (.zip). To unpack the gzipped or UNIX-compressed archive, try the following commands:
% gzip -c cgihtml.tar.gz | tar xvof -
or
% zcat cgihtml.tar.Z | tar xvof -
To unpack the pkzipped archive, use the following command:
C:\> pkunzip -a cgihtml.zip
After you unpack the distribution, you need to compile it. First, look over the makefile, which by default looks like this:
# Makefile for cgihtml.a
# $Id: Makefile,v 1.4 1996/02/21 13:42:21 eekim Exp eekim $
CC= gcc
RANLIB = ranlib
CFLAGS= -g -Wall -DUNIX
CGI-BIN= /home/eekim/Web/cgi-bin
all: cgihtml.a query-results mail.cgi index-sample.cgi ignore.cgi test.cgi
cgihtml.a: cgi-lib.o llist.o html-lib.o string-lib.o
ar cr cgihtml.a cgi-lib.o llist.o html-lib.o string-lib.o
$(RANLIB) cgihtml.a
query-results: query-results.o cgihtml.a
$(CC) query-results.o cgihtml.a -o query-results
mail.cgi: mail.cgi.o cgihtml.a
$(CC) mail.cgi.o cgihtml.a -o mail.cgi
index-sample.cgi: index-sample.cgi.o cgihtml.a
$(CC) index-sample.cgi.o cgihtml.a -o index-sample.cgi
ignore.cgi: ignore.cgi.o cgihtml.a
$(CC) ignore.cgi.o cgihtml.a -o ignore.cgi
test.cgi: test.cgi.o cgihtml.a
$(CC) test.cgi.o cgihtml.a -o test.cgi
install: all
chmod a+x query-results mail.cgi index-sample.cgi ignore.cgi test.cgi
strip query-results mail.cgi index-sample.cgi gnore.cgi test.cgi
mv -f query-results mail.cgi index-sample.cgi ignore.cgi test.cgi $(CGI-BIN)
clean:
rm -f *.o cgihtml.a
rm -f query-results mail.cgi index-sample.cgi ignore.cgi test.cgi
You might want to change a few options. If you are compiling this package on any non-UNIX platform, especially Windows NT, comment out the -DUNIX reference, as follows:
CFLAGS= -g -Wall #-DUNIX
You can also change -g to -O2 if you don't want debugging information compiled into the library. If you do not have the Gnu C Compiler, change the CC variable to the name of your C compiler. It must be ANSI-compliant. Finally, change the value of CGI-BIN to the value of your cgi-bin directory.
To compile the library, type the following:
% make cgihtml.a
This command builds the library cgihtml.a. To compile the library as well as all the example programs, type the following:
% make all
While you compile the libraries on various UNIX machines, you might have trouble with the ranlib command. If your system doesn't seem to have this command, you most likely don't need it. Set the RANLIB variable in the makefile to True.
After you successfully build cgihtml.a, copy it and all the header files to your CGI source code directory.
When you use cgihtml, consider what header files you must include and what variables you need to initialize. The possible header files are
cgi-lib.h
html-lib.h
llist.h
string-lib.h
You do not have to include llist.h if you include cgi-lib.h because cgi-lib.h implicitly includes llist.h.
If you are parsing CGI input, you must take the following steps:
The best way to understand how to use cgihtml properly is by example. The following is a basic template for all CGI applications:
/* template using cgihtml.a library */
#include <stdio.h> /* standard io functions */
#include "cgi-lib.h" /* CGI-related routines */
#include "html-lib.h" /* HTML-related routines */
int main()
{
llist entries; /* define a linked list; this is where the entries */
/* are stored. */
read_cgi_input(&entries); /* parse the form data and add it to the list */
/* The data is now in a very usable form. To search the list entries
by name, call the function:
cgi_val(entries, "nameofentry")
which returns a pointer to the value associated with "nameofentry". */
html_header(); /* print HTML MIME header */
html_begin("Output"); /* send appropriate HTML headers with title */
/* Output */
/* display whatever data you wish, probably with printf() */
html_end(); /* send appropriate HTML end footers ( ) */
list_clear(&entries); /* free up the pointers in the linked list */
return 0; send exit code of 0 -- successful */
}
Most of the C code throughout this book uses cgihtml, so look through the other chapters for more examples.
To compile your program with the library, include the file cgihtml.a when you link your object files. For example, if your main object file is program.cgi.o, the following should work successfully:
% gcc -o program.cgi program.cgi.o cgihtml.a
This section contains listings and explanations for the routines contained in the cgihtml library.
cgi-lib.h defines constants for the standard CGI environment variables. The value of the environment variable QUERY_STRING, for example, is stored in the constant QUERY_STRING in cgi-lib.h. Here is a list of the constants:
SERVER_SOFTWARE
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
The following is a listing of the functions. The following sections are the global definitions needed by the functions.
void die();
short accept_image()
void unescape_url()
int read_cgi_input(llist *entries);
char* cgi_val(llist l, char *name);
char **cgi_val_multi(llist l, char *name);
void print_cgi_env();
void print_entries(llist l);
char* escape_input(char *str);
short is_form_empty(llist l);
You should use die() in conjunction with UNIX's signal handling libraries. To prevent runaway processes, you should send an alarm signal after a certain amount of time and call die() upon receiving this signal.
At this stage, die() is somewhat primitive. It displays a simple error message and kills the program gracefully.
If you are not using UNIX, then die() is unavailable.
The function accept_image() determines whether the browser accepts pictures. It does so by checking the HTTP_ACCEPT environment variable for an image MIME type. It returns a 1 if the browser accepts graphics, a 0 otherwise.
The function unescape_url() converts escaped URI values into their character form. read_cgi_input() calls this function. You rarely, if ever, need to access this function directly, but it is made available in case you do.
This routine parses the raw CGI data passed from the browser to the server and adds each associated name and value to the linked list entries. It parses information transmitted using both the GET and POST method. If it receives no information, it returns a 0; otherwise, it returns a 1.
Remember that receiving no information is not the same as receiving an empty form. An empty form means that the values are empty, but read_cgi_input() still reads the names of each field.
The routine cgi_val() searches the linked list for the value of the entry named name and returns the value if it finds it. If it cannot find an entry with name name, it returns a null string.
This routine is the same as cgi_val() except that it returns multiple values with the same name to an array of strings. It returns a null string if it cannot find an entry with name name.
This routine prints the environment variables defined in cgi-lib.h. It prints (null) if the variables are empty.
This generic routine iterates through the linked list and prints each name and associated value in HTML form. It uses the <dl> list format to display the list.
The routine escape_input() "escapes" shell metacharacters in the string. Because I could not find any authoritative documentation on what characters are considered metacharacters, escape_input() escapes all nonalphanumeric characters.
C routines including system() and popen() open up a Bourne shell process before running. If you do not escape shell metacharacters in the input (prefix metacharacters with a backslash), then malicious users might be able to take advantage of your system.
This routine returns a 1 if an empty form is submitted; it returns 0 otherwise.
The following explains the contents of the html-lib.h header file.
The following are listings the functions. The following sections are the global definitions needed by the functions.
void html_header();
void mime_header(char *mime);
void nph_header(char *status);
void show_html_page(char *loc)
void status(char *status);
void pragma(char *msg);
void html_begin(char *title);
void html_end();
void h1(char *str); ... void h6(char *str);
void hidden(char *name, char *value);
The routine html_header() prints a MIME-compliant header that should precede the output of any HTML document from a CGI script. It simply prints the following line and a blank line to stdout:
Content-Type: text/html
This routine enables you to print any MIME header. If you are about to send a GIF image to the standard output from your C CGI program, for example, precede your program with the following:
mime_header("image/gif");
/* now you can send your GIF file to stdout */
The mime_header() routine simply prints Content-Type: followed by your specified MIME header and a blank line.
This routine sends a standard HTTP header for direct communication with the client using no parse header. status is the status code followed by the status message. To send a No Content header, for example, you can use the following:
nph_header("204 No Content");
html_header();
These lines send the following:
HTTP/1.0 204 No Content
Server: CGI using cgihtml
Content-Type: text/html
The nph_header() function does not send a blank line after printing the headers, so you must follow it with either another header or a blank line. Also, scripts using this function must have nph- preceding their filenames.
This routine sends a Location: header. loc is the location of the HTML file you want sent to the browser. If you want to send the root index file from the CGI program, for example, use the following line:
show_html_page("/index.html");
This routine sends an HTTP Status header. status is a status code followed by a status message. To send a status code of 302 (temporary redirection) followed by a location header, for example, use the following:
status("302 Temporarily Moved");
show_html_page("http://hcs.harvard.edu/");
The status() function does not print a blank line following the header, so you must follow it with either another function that does output a blank line or an explicit printf("\r\n");.
This routine sends an HTTP pragma header. It is most commonly used to tell the browser not to cache the document. Here's an example:
pragma("No-cache");
html_header();
As with status(), pragma() does not print a blank line following the header.
The html_begin() function sends somewhat standard HTML tags that should generally be at the top of every HTML file. It sends the following:
<html> <head>
<title>title</title>
</head>
<body>
The html_end() function is the complement to html_begin(), sending the following HTML:
</body> </html>
Note that neither html_begin() nor html_end() are necessary for your CGI scripts to output HTML, but they are good style, and I encourage use of these routines.
This routine surrounds str with the headline 1 tags: <h1>. Routines h2(), h3(), h4(), h5(), and h6() also do the same.
This routine prints an <input type=hidden> tag with name *name and value *value. It is useful for maintaining state.
For most scripts, you will most likely never have to use any of the link list routines available, with the exception of list_clear(), because cgi-lib.h handles most common linked list manipulation almost transparently. You might sometimes want to manipulate the information directly, however, or perform special functions on each entry, in which case these routines can be useful.
The following are listings of the functions. The following sections are the global definitions needed by the functions.
typedef struct {
char *name;
char *value;
} entrytype;
typedef struct _node {
entrytype entry;
struct _node* next;
} node;
typedef struct {
node* head;
} llist;
The following are listings of the functions. The following sections are the global definitions needed by the functions.
void list_create(llist *l);
node* list_next(node* w);
short on_list(llist *l, node* w);
short on_list_debug(llist *l, node* w);
void list_traverse(llist *l, void (*visit)(entrytype item));
node* list_insafter(llist* l, node* w, entrytype item);
void list_clear(llist* l);
The routine list_create() creates and initializes the list, and it should be called at the beginning of every CGI script using this library to parse input.
The routine list_next() returns the next node on the list.
The routine on_list() returns a 1 if the node w is on the linked list l; otherwise, it returns a 0.
The previous routine makes the assumption that your linked list routines are bug-free, a possibly bad assumption. If you are using linked list routines and on_list() doesn't return the correct value, try using on_list_debug(), which makes no assumptions, is almost definitely reliable, but is a little slower than the other routine.
The routine list_traverse() lets you pass a pointer to a function that manipulates each entry on the list.
To use this routine, you must create a function that takes as its argument a variable of type entrytype. If you want to write your own print_entries() function, for example, you could do the following:
void print_element(entrytype item);
{
printf("%s = %s\n",item.name,item.value);
}
void print_entries(llist entries);
{
list_traverse(&stuff, print_element);
}
The routine list_insafter() adds the entry item after the node w and returns the pointer to the newly created node. I didn't write a function to insert before a node because my CGI functions don't need one.
This routine frees up the memory used by the linked list after you are finished with it. It is imperative that you call this function at the end of every program that calls read_cgi_input().
This section lists and describes the contents of string-lib.h.
The following are listings of the functions. The following sections are the global definitions needed by the functions.
char* newstr(char *str);
char *substr(char *str, int offset, int len);
char *replace_ltgt(char *str);
The function newstr() allocates memory and returns a copy of str. Use this function to allocate memory correctly and copy strings.
This routine is equivalent to the Perl function with the same name. It returns a substring of str of length len starting from offset away from either the beginning or end of the string (if it's positive or negative, respectively).
This routine replaces less-than (<) and greater-than (>) signs with their HTML-escaped equivalents (< and >, respectively).
Listings E.1 through E.8 provide the complete source code for cgihtml.
Listing E.1. llist.h.
/* llist.h - Header file for llist.c
Eugene Kim, eekim@fas.harvard.edu
$Id: llist.h,v 1.2 1995/08/13 21:30:53 eekim Exp $
Copyright (C) 1995 Eugene Eric Kim
All Rights Reserved
*/
typedef struct {
char *name;
char *value;
} entrytype;
typedef struct _node {
entrytype entry;
struct _node* next;
} node;
typedef struct {
node* head;
} llist;
void list_create(llist *l);
node* list_next(node* w);
short on_list(llist *l, node* w);
short on_list_debug(llist *l, node* w);
void list_traverse(llist *l, void (*visit)(entrytype item));
node* list_insafter(llist* l, node* w, entrytype item);
void list_clear(llist* l);
Listing E.2. llist.c.
/* llist.c - Minimal linked list library for revised CGI C library
Eugene Kim, eekim@fas.harvard.edu
$Id: llist.c,v 1.2 1995/08/13 21:30:53 eekim Exp $
Copyright (C) 1995 Eugene Eric Kim
All Rights Reserved
*/
#include <stdlib.h>
#include <string.h>
#include "llist.h"
#include "string-lib.h"
void list_create(llist *l)
{
(*l).head = 0;
}
node* list_next(node* w)
{
return (*w).next;
}
short on_list(llist *l, node* w)
{
return (w != 0);
}
short on_list_debug(llist *l, node* w)
{
node* current;
if (w == 0)
return 0;
else {
current = (*l).head;
while ( (current != w) && (current != 0) )
current = (*current).next;
if (current == w)
return 1;
else
return 0;
}
}
void list_traverse(llist *l, void (*visit)(entrytype item))
{
node* current;
current = (*l).head;
while (current != 0) {
(*visit)((*current).entry);
current = (*current).next;
}
}
node* list_insafter(llist* l, node* w, entrytype item)
{
node* newnode = malloc(sizeof(node));
(*newnode).entry.name = newstr(item.name);
(*newnode).entry.value = newstr(item.value);
if ( (*l).head == 0) {
(*newnode).next = 0;
(*l).head = newnode;
}
else if (!on_list(l,w))
/* ERROR: can't insert item after w since w is not on l */
exit(1);
else {
/* insert node after */
if (newnode == 0) /* can assume that w != NULL */
/* ERROR: nothing to insert after */
exit(1);
else {
(*newnode).next = (*w).next;
(*w).next = newnode;
}
}
return newnode;
}
void list_clear(llist* l)
{
node* lastnode;
node* nexttolast;
node* current;
while ((*l).head != 0) {
current = (*l).head;
if ((*current).next == 0) {
free(current);
current = 0;
(*l).head = current;
}
else {
while ( (*current).next != 0 ) {
nexttolast = current;
lastnode = (*current).next;
current = lastnode;
}
free(lastnode);
(*nexttolast).next = 0;
}
}
}
Listing E.3. string-lib.h.
/* string-lib.h - headers for string-lib.c
$Id: string-lib.h,v 1.1 1995/08/13 21:30:53 eekim Exp $
*/
char *newstr(char *str);
char *substr(char *str, int offset, int len);
char *replace_ltgt(char *str);
Listing E.4. string-lib.c.
/* string-lib.c - generic string processing routines
$Id: string-lib.c,v 1.2 1996/02/18 22:33:27 eekim Exp eekim $
Copyright © 1996 Eugene Eric Kim
All Rights Reserved.
*/
#include <malloc.h>
#include <stdio.h>
#include <string.h>
#include "string-lib.h"
char *newstr(char *str)
{
return strcpy((char *)malloc(sizeof(char) * strlen(str)+1),str);
}
char *substr(char *str, int offset, int len)
{
int slen, start, i;
char *nstr;
if (str == NULL)
return NULL;
else
slen = strlen(str);
nstr = malloc(sizeof(char) * slen + 1);
if (offset >= 0)
start = offset;
else
start = slen + offset - 1;
if ( (start < 0) || (start > slen) ) /* invalid offset */
return NULL;
for (i = start; i < slen; i++)
nstr[i - start] = str[i];
nstr[slen] = '\0';
return nstr;
}
char *replace_ltgt(char *str)
{
int i,j = 0;
char *new = malloc(sizeof(char) * (strlen(str) * 4 + 1));
for (i = 0; i < strlen(str); i++) {
if (str[i] == '<') {
new[j] = '&';
new[j+1] = 'l';
new[j+2] = 't';
new[j+3] = ';';
j += 3;
}
else if (str[i] == '>') {
new[j] = '&';
new[j+1] = 'g';
new[j+2] = 't';
new[j+3] = ';';
j += 3;
}
else
new[j] = str[i];
j++;
}
new[j] = '\0';
return new;
}
Listing E.5. cgi-lib.h.
/* cgi-lib.h - header file for cgi-lib.c
Eugene Kim, eekim@fas.harvard.edu
$Id: cgi-lib.h,v 1.4 1996/02/21 13:40:41 eekim Exp eekim $
Copyright (C) 1996 Eugene Eric Kim
All Rights Reserved
*/
#include <stdlib.h>
#include "llist.h"
/* CGI Environment Variables */
#define SERVER_SOFTWARE getenv("SERVER_SOFTWARE")
#define SERVER_NAME getenv("SERVER_NAME")
#define GATEWAY_INTERFACE getenv("GATEWAY_INTERFACE")
#define SERVER_PROTOCOL getenv("SERVER_PROTOCOL")
#define SERVER_PORT getenv("SERVER_PORT")
#define REQUEST_METHOD getenv("REQUEST_METHOD")
#define PATH_INFO getenv("PATH_INFO")
#define PATH_TRANSLATED getenv("PATH_TRANSLATED")
#define SCRIPT_NAME getenv("SCRIPT_NAME")
#define QUERY_STRING getenv("QUERY_STRING")
#define REMOTE_HOST getenv("REMOTE_HOST")
#define REMOTE_ADDR getenv("REMOTE_ADDR")
#define AUTH_TYPE getenv("AUTH_TYPE")
#define REMOTE_USER getenv("REMOTE_USER")
#define REMOTE_IDENT getenv("REMOTE_IDENT")
#define CONTENT_TYPE getenv("CONTENT_TYPE")
#define CONTENT_LENGTH getenv("CONTENT_LENGTH")
#ifdef UNIX
void die();
#endif
short accept_image();
/* form processing routines */
void unescape_url(char *url);
int read_cgi_input(llist* entries);
char *cgi_val(llist l,char *name);
char **cgi_val_multi(llist l, char *name);
/* miscellaneous CGI routines */
void print_cgi_env();
void print_entries(llist l);
char *escape_input(char *str);
short is_form_empty(llist l);
Listing E.6. cgi-lib.c.
/* cgi-lib.c - C routines that make writing CGI scripts in C a breeze
Eugene Kim, <eekim@fas.harvard.edu>
$Id: cgi-lib.c,v 1.7 1996/02/21 13:40:27 eekim Exp eekim $
Motivation: Perl is a much more convenient language to use when
writing CGI scripts. Unfortunately, it is also a larger drain on
the system. Hopefully, these routines will make writing CGI
scripts just as easy in C.
Copyright (C) 1996 Eugene Eric Kim
All Rights Reserved
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "cgi-lib.h"
#include "html-lib.h"
#include "string-lib.h"
#ifdef UNIX
void die()
{
/* this routine needs some beefing up. I hope to eventually add:
o more detailed information
o error logging
o perhaps sending a header which signifies an internal error
*/
html_header();
html_begin("CGI Error");
printf("<h1>CGI Error</h1>\r\n");
printf("An internal error has occurred. Please contact your web\r\n");
printf("administrator. Thanks.\r\n");
html_end();
exit(1);
}
#endif
short accept_image()
{
char *httpaccept = getenv("HTTP_ACCEPT");
if (strstr(httpaccept,"image") == NULL)
return 0;
else
return 1;
}
/* x2c() and unescape_url() stolen from NCSA code */
char x2c(char *what)
{
register char digit;
digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
digit *= 16;
digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
return(digit);
}
void unescape_url(char *url)
{
register int x,y;
for (x=0,y=0; url[y]; ++x,++y) {
if((url[x] = url[y]) == '%') {
url[x] = x2c(&url[y+1]);
y+=2;
}
}
url[x] = '\0';
}
int read_cgi_input(llist* entries)
{
int i,j,content_length;
short NM = 1;
char *input;
entrytype entry;
node* window;
list_create(entries);
window = (*entries).head;
/* get the input */
if (REQUEST_METHOD == NULL) {
/* perhaps add an HTML error message here for robustness sake;
don't know whether CGI is running from command line or from
web server. In fact, maybe a general CGI error routine might
be nice, sort of a generalization of die(). */
fprintf(stderr,"caught by cgihtml: REQUEST_METHOD is null\n");
exit(1);
}
if (!strcmp(REQUEST_METHOD,"POST")) {
if (CONTENT_LENGTH != NULL) {
content_length = atoi(CONTENT_LENGTH);
input = malloc(sizeof(char) * content_length + 1);
if (fread(input,sizeof(char),content_length,stdin) != content_length) {
/* consistency error. */
fprintf(stderr,"caught by cgihtml: input length < CONTENT_LENGTH\n");
exit(1);
}
}
else { /* null content length */
/* again, perhaps more detailed, robust error message here */
fprintf(stderr,"caught by cgihtml: CONTENT_LENGTH is null\n");
exit(1);
}
}
else if (!strcmp(REQUEST_METHOD,"GET")) {
if (QUERY_STRING == NULL) {
fprintf(stderr,"caught by cgihtml: QUERY_STRING is null\n");
exit(1);
}
input = newstr(QUERY_STRING);
content_length = strlen(input);
}
else { /* error: invalid request method */
fprintf(stderr,"caught by cgihtml: REQUEST_METHOD invalid\n");
exit(1);
}
/* parsing starts here */
if (content_length == 0)
return 0;
else {
j = 0;
entry.name = malloc(sizeof(char) * content_length + 1);
entry.value = malloc(sizeof(char) * content_length + 1);
for (i = 0; i < content_length; i++) {
if (input[i] == '=') {
entry.name[j] = '\0';
unescape_url(entry.name);
if (i == content_length - 1) {
strcpy(entry.value,"");
window = list_insafter(entries,window,entry);
}
j = 0;
NM = 0;
}
else if ( (input[i] == '&') || (i == content_length - 1) ) {
if (i == content_length - 1) {
entry.value[j] = input[i];
j++;
}
entry.value[j] = '\0';
unescape_url(entry.value);
window = list_insafter(entries,window,entry);
j = 0;
NM = 1;
}
else if (NM) {
if (input[i] == '+')
entry.name[j] = ' ';
else
entry.name[j] = input[i];
j++;
}
else if (!NM) {
if (input[i] == '+')
entry.value[j] = ' ';
else
entry.value[j] = input[i];
j++;
}
}
return 1;
}
}
char *cgi_val(llist l, char *name)
{
short FOUND = 0;
node* window;
window = l.head;
while ( (window != 0) && (!FOUND) )
if (!strcmp((*window).entry.name,name))
FOUND = 1;
else
window = (*window).next;
if (FOUND)
return (*window).entry.value;
else
return NULL;
}
/* cgi_val_multi - contributed by Mitch Garnaat <garnaat@wrc.xerox.com>;
modified by me */
char **cgi_val_multi(llist l, char *name)
{
short FOUND = 0;
node* window;
char **ret_val = 0;
int num_vals = 0, i;
window = l.head;
while (window != 0) {
if (!strcmp((*window).entry.name,name)) {
FOUND = 1;
num_vals++;
}
window = (*window).next;
}
if (FOUND) {
/* copy the value pointers into the returned array */
ret_val = (char**) malloc(sizeof(char*) * (num_vals + 1));
window = l.head;
i = 0;
while (window != NULL) {
if (!strcmp((*window).entry.name,name)) {
ret_val[i] = (*window).entry.value;
i++;
}
window = (*window).next;
}
/* NULL terminate the array */
ret_val[i] = 0;
return ret_val;
}
else
return NULL;
}
/* miscellaneous useful CGI routines */
void print_cgi_env()
{
printf("<p>SERVER_SOFTWARE = %s<br>\n",SERVER_SOFTWARE);
printf("SERVER_NAME = %s<br>\n",SERVER_NAME);
printf("GATEWAY_INTERFACE = %s<br>\n",GATEWAY_INTERFACE);
printf("SERVER_PROTOCOL = %s<br>\n",SERVER_PROTOCOL);
printf("SERVER_PORT = %s<br>\n",SERVER_PORT);
printf("REQUEST_METHOD = %s<br>\n",REQUEST_METHOD);
printf("PATH_INFO = %s<br>\n",PATH_INFO);
printf("PATH_TRANSLATED = %s<br>\n",PATH_TRANSLATED);
printf("SCRIPT_NAME = %s<br>\n",SCRIPT_NAME);
printf("QUERY_STRING = %s<br>\n",QUERY_STRING);
printf("REMOTE_HOST = %s<br>\n",REMOTE_HOST);
printf("REMOTE_ADDR = %s<br>\n",REMOTE_ADDR);
printf("AUTH_TYPE = %s<br>\n",AUTH_TYPE);
printf("REMOTE_USER = %s<br>\n",REMOTE_USER);
printf("REMOTE_IDENT = %s<br>\n",REMOTE_IDENT);
printf("CONTENT_TYPE = %s<br>\n",CONTENT_TYPE);
printf("CONTENT_LENGTH = %s<br></p>\n",CONTENT_LENGTH);
}
void print_entries(llist l)
{
node* window;
window = l.head;
printf("<dl>\r\n");
while (window != NULL) {
printf(" <dt> <b>%s</b>\r\n",(*window).entry.name);
printf(" <dd> %s\r\n",replace_ltgt((*window).entry.value));
window = (*window).next;
}
printf("</dl>\r\n");
}
char *escape_input(char *str)
/* takes string and escapes all metacharacters. should be used before
including string in system() or similar call. */
{
int i,j = 0;
char *new = malloc(sizeof(char) * (strlen(str) * 2 + 1));
for (i = 0; i < strlen(str); i++) {
if (!( ((str[i] >= 'A') && (str[i] <= 'Z')) ||
((str[i] >= 'a') && (str[i] <= 'z')) ||
((str[i] >= '0') && (str[i] <= '9')) )) {
new[j] = '\\';
j++;
}
new[j] = str[i];
j++;
}
new[j] = '\0';
return new;
}
short is_form_empty(llist l)
{
node* window;
short EMPTY = 1;
window = l.head;
while ( (window != NULL) && (EMPTY == 1) ) {
if (strcmp((*window).entry.value,""))
EMPTY = 0;
window = (*window).next;
}
return EMPTY;
}
Listing E.7. html-lib.h.
/* html-lib.h - header file for html-lib.c
Eugene Kim, eekim@fas.harvard.edu
$Id: html-lib.h,v 1.3 1996/02/18 22:33:27 eekim Exp eekim $
Copyright (C) 1996 Eugene Eric Kim
All Rights Reserved
*/
void html_header();
void mime_header(char *mime);
void nph_header(char *status);
void show_html_page(char *loc);
void status(char *status);
void pragma(char *msg);
void html_begin(char *title);
void html_end();
/* better to do printf inside of function, or return string? */
void h1(char *str);
void h2(char *str);
void h3(char *str);
void h4(char *str);
void h5(char *str);
void h6(char *str);
void hidden(char *name, char *value);
Listing E.8. html-lib.c.
/* html-lib.c - C routines that output various HTML constructs
Eugene Kim, eekim@fas.harvard.edu
$Id: html-lib.c,v 1.3 1996/02/18 22:33:27 eekim Exp eekim $
Copyright (C) 1996 Eugene Eric Kim
All Rights Reserved
*/
#include <stdio.h>
#include "html-lib.h"
/* HTTP headers */
void html_header()
{
printf("Content-type: text/html\r\n\r\n");
}
void mime_header(char *mime)
/* char *mime = valid mime type */
{
printf("Content-type: %s\r\n\r\n",mime);
}
void nph_header(char *status)
{
printf("HTTP/1.0 %s\r\n",status);
printf("Server: CGI using cgihtml\r\n");
}
void show_html_page(char *loc)
{
printf("Location: %s\r\n\r\n",loc);
}
void status(char *status)
{
printf("Status: %s\r\n",status);
}
void pragma(char *msg)
{
printf("Pragma: %s\r\n",msg);
}
/* HTML shortcuts */
void html_begin(char *title)
{
printf("<html> <head>\n");
printf("<title>%s</title>\n",title);
printf("</head>\n\n");
printf("<body>\n");
}
void html_end()
{
printf("</body> </html>\n");
}
void h1(char *str)
{
printf("<h1>%s</h1>\n",str);
}
void h2(char *str)
{
printf("<h2>%s</h2>\n",str);
}
void h3(char *str)
{
printf("<h3>%s</h3>\n",str);
}
void h4(char *str)
{
printf("<h4>%s</h4>\n",str);
}
void h5(char *str)
{
printf("<h5>%s</h5>\n",str);
}
void h6(char *str)
{
printf("<h6>%s</h6>\n",str);
}
void hidden(char *name, char *value)
{
printf("<input type=hidden name=\"%s\" value=\"%s\">\n",name,value);
}