formecho.c


/*

  FORMECHO.C
  ==========
  (c) Paul Griffiths 1999
  Email: mail@paulgriffiths.net

  Simple CGI program to echo the keys and values
  returned from an HTML form.

*/


#include <stdlib.h>
#include <stdio.h>
#include "cgihelp.h"


/*  Forward function declaratios  */

void DisplayErrorHTML();


/*  main() function  */

int main() {
    int   n = 1;
    char *key;
    char *value;

    /*  Get key/value pairs from input  */

    if ( !InitInput(1000) )
	DisplayErrorHTML();

    
    /*  Output HTML header  */

    printf("Content-Type: text/html\n\n");

    printf("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 4.0//EN\">\n\n");
    printf("<HTML>\n\n<HEAD>\n");
    printf("    <TITLE>Formecho Output</TITLE>\n");
    printf("</HEAD>\n\n");
    printf("<BODY>\n\n");


    /*  Output table of key/value pairs  */

    printf("<TABLE BORDER=1 CELLPADDING=10px>\n\n");
    printf("    <TR>\n");
    printf("        <TH>Key</TH>\n\n");
    printf("        <TH>Value</HT>\n\n");
    printf("    </TR>\n\n");

    while ( (key = GetIndexedKey(n)) && (value = GetIndexedValue(n)) ) {
	printf("    <TR>\n");
	printf("        <TD>%s</TD>\n", key);
	printf("        <TD>%s</TD>\n", value);
	printf("    </TR>\n\n");
	++n;
    }

    printf("</TABLE>\n\n");


    /*  Output HTML footer  */

    printf("</BODY>\n\n</HTML>\n\n");


    /*  Clean up and exit  */

    FreeCGI();
    return 0;
}


/*  Outputs HTML indicating error if CGI functions fail  */

void DisplayErrorHTML() {
    printf("Content-Type: text/html\n\n");
    
    printf("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 4.0//EN\">\n\n");
    printf("<HTML>\n\n<HEAD>\n");
    printf("    <TITLE>Formecho Output</TITLE>\n");
    printf("</HEAD>\n\n");
    printf("<BODY>\n\n");
    printf("<H2>Error!</H2>\n\n");
    printf("<P>An error has occurred. Please contact the ");
    printf("site administrator.\n\n<BR><HR><BR>\n\n");
    printf("</BODY>\n\n</HTML>\n");

    exit(EXIT_FAILURE);
}



cgihelp.h


/*

  CGIHELP.H
  =========
  (c) Paul Griffiths 1999
  Email: mail@paulgriffiths.net

  Interface to CGI helper functions

*/


#ifndef PG_CGIHELP
#define PG_CGIHELP


/*  Global macros  */

#define ERR_BADREQUEST          (1)
#define ERR_BADMALLOC           (2)


/*  Function declarations  */

int    InitInput      (int   maxbuffer);
char * GetValue       (char *key);
char * GetIndexedValue(int   index);
char * GetIndexedKey  (int   index);
void   FreeCGI        ();


#endif    /*  PG_CGIHELP  */



cgihelp.c


/*

  CGIHELP.C
  =========
  (c) Paul Griffiths 1999
  Email: mail@paulgriffiths.net

  CGI helper functions

*/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "cgihelp.h"


/*  Forward function declarations  */

void cleanurl(char *str);


/*  Linked list node to hold key/value pairs  */

typedef struct varlist {
    char *key;
    char *value;
    struct varlist *next;
} varlist;

varlist* varstart;


/*  Get all key/value pairs from input  */

int InitInput(int maxbuffer) {
    varlist *var;
    char    *input;


    /*  Allocate memory for input buffer  */

    if ( !(input = malloc(sizeof(char) * maxbuffer)) )
	return ERR_BADMALLOC;
    memset(input, '\0', sizeof(char) * maxbuffer);


    /*  Determine request method and fill input buffer  */
    
    if ( !strcmp(getenv("REQUEST_METHOD"), "GET") )
	strncpy(input, getenv("QUERY_STRING"), maxbuffer - 1);
    else if ( !strcmp(getenv("REQUEST_METHOD"), "POST") )
	fgets(input, maxbuffer, stdin);
    else
	return ERR_BADREQUEST;


    /*  Allocate memory for first key/value pair  */

    if ( ! (varstart = malloc(sizeof(varlist)) ) )
	return ERR_BADMALLOC;
    var = varstart;

    
    /*  Populate key/value pairs  */

    if ( (input = strtok(input, "=")) ) {
	while ( var ) {
	    if ( !(var->key = malloc(sizeof(char) * strlen(input))) )
		return ERR_BADMALLOC;
	    strcpy(var->key, input);
	    cleanurl(var->key);

	    input = strtok(NULL, "&");
	    if ( !(var->value = malloc(sizeof(char) * strlen(input))) )
		return ERR_BADMALLOC;
	    strcpy(var->value, input);
	    cleanurl(var->value);

	    if ( (input = strtok(NULL, "=")) ) {
		if ( !(var->next = malloc(sizeof(varlist))) )
		    return ERR_BADMALLOC;
	    }
	    else {
		var->next = NULL;
	    }
	    var = var->next;
	}
    }	 
    else {

	/*  No key/value pairs in input if we get here  */

	free(varstart);
	varstart = NULL;
    }

    free(input);
    return 0;
}


/*  Retrieves a value from a key  */

char * GetValue(char *key) {
    varlist *var = varstart;
    while ( var ) {
	if ( !strcmp(key, var->key) )
	    return var->value;
	var = var->next;
    }
    return NULL;
}


/*  Retrieves a key using a 1-based index  */

char * GetIndexedKey(int index) {
    int n;
    varlist *var = varstart;
    for ( n = 1; n < index; ++n )
	if ( var->next == NULL )
	    return NULL;
	else
	    var = var->next;
    return var->key;
}


/*  Retrieves a value using a 1-based index  */

char * GetIndexedValue(int index) {
    int n;
    varlist *var = varstart;
    for ( n = 1; n < index; ++n )
	if ( var->next == NULL )
	    return NULL;
	else
	    var = var->next;
    return var->value;
}


/*  Frees memory used by key/value pairs  */

void FreeCGI() {
    varlist *var = varstart;
    while ( var ) {
	free(var->key);
	free(var->value);
	var = var->next;
	free(varstart);
	varstart = var;
    }
}


/*  Cleans up url-encoded string  */
	
void cleanurl(char *str) {
    char asciinum[3] = {0};
    int i = 0, c;
    
    while ( str[i] ) {
	if ( str[i] == '+' )
	    str[i] = ' ';
	else if ( str[i] == '%' ) {
	    asciinum[0] = str[i+1];
	    asciinum[1] = str[i+2];
	    str[i] = strtol(asciinum, NULL, 16);
	    c = i+1;
	    do {
		str[c] = str[c+2];
	    } while ( str[2+(c++)] );
	}
	++i;
    }
}



Please send all comments, suggestions, bug reports etc to mail@paulgriffiths.net