///////////////////////////////////////////////////////////////////////////////
// CGISetup Class                                                            //
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// Author:  Hexar William Anderson                                           //
// Date:    10/25/2000                                                       //
// Desc:    This class does all of the work for you when it comes to         //
//          separating CGI input into name/value pairs.  Then, you can access//
//          these values by name or by number.                               //
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
// COPYRIGHT NOTICE                                                          //
// Copyright (c) 2000 Hexar W. Anderson                                      //
//                                                                           //
// CGISetup may be used and modified free of charge by anyone so long as this//
// copyright notice remains intact.  By using this code you agree to         //
// indemnify Hexar Anderson from any liability that might arise from its use.//
//                                                                           //
// Attempting to sell the source code for this program without prior written //
// consent is expressly forbidden.  Obtain permission before redistributing  //
// this software over the Internet or any other medium.                      //
///////////////////////////////////////////////////////////////////////////////
 
 
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <iostream.h>
 
#include "cgisetup.hxx"
 
// Constants ///////////////////////////////////////////////////////////////////
 
const int MAX_LEN = 1000;
const char CGI_METHOD[] = "REQUEST_METHOD";
const char CGI_QUERY[] = "QUERY_STRING";
const char CGI_LENGTH[] = "CONTENT_LENGTH";
 
// Public Functions ////////////////////////////////////////////////////////////
 
 
// CGISetup() Constructor ///////////////////////////////////////////////////////
// 
// Description:  This function automatically detects the type of CGI input and
// then proceeds to take the data and split it into name/value pairs.  This
// allows the user of the class to use the GetValue function to retrieve the
// values of different CGI variables.
///////////////////////////////////////////////////////////////////////////////
 
CGISetup::CGISetup()
{
   char *method;
   char string[MAX_LEN];
   
   
   // Find the method and then find the CGI data
   // accordingly.
   
   method = getenv(CGI_METHOD);
 
   if (strcmp(method, "GET") == 0)
      MethodGet(string);
   else if (strcmp(method, "POST") == 0)
      MethodPost(string);
   else
      throw "Error: No CGI input data detected!";    
 
   // Now that we have the encoded data in string, we must
   // create space for it.
   
   num = CountValues(string);
 
   DecodeURL(string);
   
   names  = new char*[num];
   values = new char*[num];
   
   // Now we need to copy the characters into the right places.
   
   ParseString(string);
   
   
   // We're done.
  }   
   
  
// ~CGISetup() ////////////////////////////////////////////////////////////////
//
// Description:  This function assumes that memory has been allocated for
// a variable number of variable-length strings.  This function cleans up after
// itself when the CGISetup object is deleted by freeing that memory.
///////////////////////////////////////////////////////////////////////////////
  
CGISetup::~CGISetup()
{
 
   for (int i = 0; i < num; i++)
     {
      delete[] names[i];
      delete[] values[i];
     }
     
   delete[] names;
   delete[] values;
   
}
 
// GetNum() ///////////////////////////////////////////////////////////////////
//
// Description:  This function returns the number of name/value pairs assigned
// to the class.
///////////////////////////////////////////////////////////////////////////////
 
int CGISetup::GetNum() const
{
   return num;
}
 
// GetName(int) //////////////////////////////////////////////////////////////
//
// Description:  This function takes a number N and subsequently returns a 
// character pointer to the Nth name.
///////////////////////////////////////////////////////////////////////////////
 
char* CGISetup::GetName(int n) const
{
   if (n < num && n >= 0)
      return names[n];
   else
     { 
      throw "Error: Index out of range.";
      return "";
     } 
}
 
// GetValue(int) //////////////////////////////////////////////////////////////
//
// Description:  This function takes a number N and subsequently returns a 
// character pointer to the Nth value.
///////////////////////////////////////////////////////////////////////////////
 
char* CGISetup::GetValue(int n) const
{
   if (n < num && n >= 0)
      return values[n];
   else
     {
      throw "Error: Index out of range.";
      return "";
     }
}   
 
// GetValue(char*) ////////////////////////////////////////////////////////////
// 
// Description:  This function takes a variable string as input and then
// searches the name/value pairs for the matching name.  Then it returns
// a pointer to the correct value.
//
// Note:  This is potentially dangerous because the function returns the actual
// address of the value.  This value could be manipulated outside of the class.
///////////////////////////////////////////////////////////////////////////////
 
char* CGISetup::GetValue(const char *name) const
{
 
   for (int i = 0; i < num; i++)
      if (strcmp(name, names[i]) == 0)
         return values[i];
   
   throw "Error: Name/value pair not found.";
   return NULL;
}
 
 
// Public Static Functions /////////////////////////////////////////////////////
 
// CopyFile ///////////////////////////////////////////////////////////////////
//
// Description:  Takes source and destination strings for filenames of a file
// to copy into into another file.
///////////////////////////////////////////////////////////////////////////////
 
void CGISetup::CopyFile(const char *from, const char *to)
{
 
   FILE *f1;
   FILE *f2;
   char ch;
   
   f1 = fopen(from, "r");
   f2 = fopen(to, "w");
   
   ch = getc(f1);
   
   while (!feof(f1))
     {
      fputc(ch, f2);
      ch = getc(f1);
     }
   
   fclose(f1);
   fclose(f2);
   
   return;
}
 
 
// DecodeURL ///////////////////////////////////////////////////////////////////
//
// Description:  Takes a URL-encoded string as input and modifies the string so
// that the encoded sequences are translated into the intended string.  This
// is done by changing '+' into spaces and by changing hexadecimal %dd
// sequences into non-printable characters.
////////////////////////////////////////////////////////////////////////////////
 
void CGISetup::DecodeURL(char *s)
{
 
   char *temp;
   int i, j = 0;
   
   // Translate + into Space
   
   ReplaceChar(s, '+', ' ');
   
   temp = new char[strlen(s)];
   
   // i is the index for S
   // j in the index for temp
   
   
   for (i = 0; i < strlen(s); i++, j++)
     {
      if (s[i] == '%')
        {
         // Translate hex-encoded values to their decimal equivs.
         
         temp[j] = ConvHex(s[i+1]) * 16 + ConvHex(s[i+2]);
         i += 2;
        }
      else
         temp[j] = s[i];
      
     }
   
   // Terminate new string and copy to original.
    
   temp[j] = 0;
   
   strcpy(s, temp);
   
   delete[] temp;
 
 
   return;
}
 
// MoveFile ///////////////////////////////////////////////////////////////////
//
// Description:  Copies first file into second file and then removes the
// first file.
///////////////////////////////////////////////////////////////////////////////
 
void CGISetup::MoveFile(const char *from, const char *to)
{
 
   CopyFile(from, to);
   
   unlink(from);
   
   return;
}
 
 
// StrLwr /////////////////////////////////////////////////////////////////////
//
// Description:  Converts an input string's alphabetic characters into
// lowercase characters.
///////////////////////////////////////////////////////////////////////////////
 
void CGISetup::StrLwr(char *s)
{
    
   for (int i = 0; i < strlen(s); i++)
      s[i] = tolower(s[i]);
      
 
   return;
}
 
// ViewFile ///////////////////////////////////////////////////////////////////
//
// Description:  Takes a string as an input argument and proceeds to open
// this file and to print its contents to STDOUT.
///////////////////////////////////////////////////////////////////////////////
 
void CGISetup::ViewFile(const char *filename)
{
   FILE *f1;
   char ch;
   
   f1 = fopen(filename, "r");
   
   ch = getc(f1);
   
   while (!feof(f1))
     {
      putchar(ch);
      ch = getc(f1);
     }
   
   fclose(f1);
 
   return;
}
  
 
// Private Utility Functions ///////////////////////////////////////////////////
 
// CountChars //////////////////////////////////////////////////////////////////
//
// Description:  Returns the number of occurrences of the character in the
// string.
////////////////////////////////////////////////////////////////////////////////
 
int CGISetup::CountChars(char ch, const char *s)
{
 
   int count = 0;
       
   for (int i = 0; i < strlen(s); i++)
      if (s[i] == ch)
         count++;
   
   return count;
 
}
   
// CountStrings ///////////////////////////////////////////////////////////////
// 
// Description:  Counts the number of occurrences of the first string inside
// of the second string.  The order is important.  You are finding a "needle"
// in a "haystack".
//////////////////////////////////////////////////////////////////////////////   
 
int CGISetup::CountStrings(const char *needle, const char *haystack)
{
 
   int count = 0;
   
   for (int i = 0; i < strlen(haystack) - strlen(needle); i++)
     {
      if (strncmp(&haystack[i], needle, strlen(needle)) == 0)
         count++;
     }
     
   return count;
 
}
 
// CountValues ////////////////////////////////////////////////////////////////
//
// Description:  This simple function counts the number of &'s and &='s in a 
// CGI data string in order to calculate how many name/value pairs it will
// contain.
///////////////////////////////////////////////////////////////////////////////
 
int CGISetup::CountValues(const char *s)
{
   return CountChars('&', s) + 1 - CountStrings("=&", s);
}
 
// ConvHex ////////////////////////////////////////////////////////////////////
//
// Description:  This function converts a alphanumeric character ch into its
// decimal equivalent.  This could probably be done with a more general-purpose
// built-in C/C++ function but this version is going to be faster.
///////////////////////////////////////////////////////////////////////////////
 
int CGISetup::ConvHex(char ch)
{
 
   ch = toupper(ch);
   
   if (isalpha(ch))
      return ch - 'A' + 10;
   else
      return ch - '0';
   
}    
 
// MethodGet //////////////////////////////////////////////////////////////////
//
// Description:  Assumes that the CGI input method is GET and copies the CGI
// data into string 's' accordingly.
///////////////////////////////////////////////////////////////////////////////
 
void CGISetup::MethodGet(char *s) const
{
 
   strcpy(s, getenv(CGI_QUERY));
   
}
 
// MethodPost /////////////////////////////////////////////////////////////////
//
// Description: Assumes that the CGI input method is POST and copies the CGI
// data into string 's' accordingly.
///////////////////////////////////////////////////////////////////////////////
 
void CGISetup::MethodPost(char *s) const
{
   int i;
   int len;
   
   // Determine the length of the POST content
   
   len = atoi(getenv(CGI_LENGTH));
      
   // Now read that many characters from STDIN
   
   for (i = 0; i < len; i++)
      s[i] = getchar();
   
   s[i] = 0;
   
   return;
}
 
// ParseString ////////////////////////////////////////////////////////////////
//
// Description:  Takes a CGI-data string that has already been URL-decoded
// and then proceeds to allocate memory for individual name/value strings
// and copies the correct values accordingly.
///////////////////////////////////////////////////////////////////////////////
 
void CGISetup::ParseString(const char *s)
{
 
   char *temp;
   int currNum, i = 0, j = 0;
   
   temp = new char[strlen(s)];
   
   
   for (currNum = 0; currNum < num; currNum++)
     {
      for (j = 0; s[i] != '='; i++, j++)
         temp[j] = s[i];
      temp[j] = 0;
      
      i++;
      
      if (s[i] == '&')
        {
         // Empty values must not go into our class here.
         
         num--;
         i++;
         continue;
        }
      
      // Otherwise allocate memory for the name.
      
      names[currNum] = new char[strlen(temp)];
      strcpy(names[currNum], temp);
      
      
      // Now parse the Value
 
      for (j = 0; s[i] != '&' && i < strlen(s); i++, j++)
         temp[j] = s[i];
      temp[j] = 0;
      
      values[currNum] = new char[strlen(temp)];
      strcpy(values[currNum], temp);
      i++;
     }
 
   delete [] temp;
 
   return;
 
}
 
// ReplaceChar ////////////////////////////////////////////////////////////////
//
// Description:  Searches a string and replaces all occurrences of the first
// character with the second one.
///////////////////////////////////////////////////////////////////////////////
 
void CGISetup::ReplaceChar(char *s, char from, char to)
{
    
   for (int i = 0; i < strlen(s); i++)
     if (s[i] == from)
        s[i] = to;
  
   return;
   
}
 
    
 
// End of File ////////////////////////////////////////////////////////////////

All material Copyright (c) 2001-2010 Hexar
Please direct all inquiries, love letters, and hate mail to .

Home •  Blog •  Photos •  Code •  Features •  Resume •  WinTetris