#include <stdio.h>
#include <stdlib.h>
#include <varargs.h>

#define nonempty(X) ((X) != NULL && (int)strlen(X) > 0)

void capitalize(char *s)
{
  if (nonempty(s)) {
    int i;
    s[0] = toupper(s[0]) ;
    for (i=1 ; s[i] != '\0' ; i++) s[i] = tolower(s[i]) ;
  }
}

void uncapitalize(char *s)
{
  if (nonempty(s)) {
    int i ;
    for (i=0 ; s[i] != '\0' ; i++) s[i] = tolower(s[i]) ;
  }
}

void strip_trailing_spaces(char *s)
{
  int i ;
  if (s != NULL) {
    i = (int)strlen(s)-1  ;
    while (i >= 0 && isspace(s[i])) {
      s[i] = '\0' ; 
      i-- ;
    }
  }
}

void no_cache()
{
  printf("Pragma: no-cache\n") ;
}

void redirect(s)
char *s ;
{
  printf("Status: 302 Redirected\n") ;
  printf("Location: %s\n\n", s) ;
  printf("\n") ;
  printf("Your browser is not capable of handling redirection requests.\n") ;
  printf("<a href=\"%s\">This link</a> will take you to the ", s) ;
  printf("redirection destination.") ;
}

void return_header(s)
char *s ;
{
  printf("Content-type: %s\n\n", s) ;
}

void return_nothing()
{
  printf("Status: 204 No return\n") ;
  printf("Content-type: text/html\n\n") ;
}

static int hexdigit(c)
char c ;
{
  if (c >= 'A' && c <= 'F')
    return(10+(c-'A')) ;
  else return(c-'0') ;
}

static void decode_pair_string(old, new1, new2)
char *old, **new1, **new2 ;
{
  char *new ;
  int i, j ;

  *new1 = (char *)malloc(sizeof(char) * (strlen(old)+1)) ;
  *new2 = (char *)malloc(sizeof(char) * (strlen(old)+1)) ;
  *new1[0] = *new2[0] = '\0' ;
  i = 0 ;
  new = *new1 ;
  j = 0 ;
  while (old[i] != '\0') {
    switch(old[i]) {
    case '+':
      new[j++] = ' ' ;
      i++ ; 
      break ;
    case '%':
      if (!strncmp(old+i, "%0D%0A", 6)) { /* CR-LF - want to skip CR */
	i += 3 ;
      } 
      else {
	new[j++] = (char)(hexdigit(old[i+1])*16 + hexdigit(old[i+2])) ;
	i += 3 ;
      }
      break ;
    case '=':
      new[j] = '\0' ;
      new = *new2 ;
      j = 0 ;
      i++ ;
      break ;
    default:
      new[j++] = old[i] ;
      i++ ;
      break ;
    }
  }
  if (new == *new2) new[j] = '\0' ;
}

struct str_var_pair {
  char *str ;
  char **var ;
} ;

void decode_query_string(...)
{
  va_list args ;
  struct str_var_pair *list ;
  char *str, *old, *new1, *new2 ;
  char **var ;
  int i, items, j, k, len ;

  list = NULL ; 

  va_start(args) ;
  i = 0 ;

  while ((str = va_arg(args, char *)) != NULL) {
    var = va_arg(args, char **) ;
    *var = NULL ;
    if (list == NULL) 
      list = (struct str_var_pair *)malloc(sizeof(struct str_var_pair)) ;
    else 
      list = (struct str_var_pair *)
	realloc(list, (i+1)*sizeof(struct str_var_pair)) ;
    list[i].str = str ;
    list[i].var = var ;
    i++ ;
  }
  va_end(args) ;
  items = i ;

  if (!strcmp(getenv("REQUEST_METHOD"), "GET")) {
    old = getenv("QUERY_STRING") ;
    len = strlen(old) ;
  }
  else { /* post */
    len = atoi(getenv("CONTENT_LENGTH")) ;
    old = (char *)malloc(sizeof(char) * (len+1)) ;
    fread(old, sizeof(char), len, stdin) ;
    old[len] = '\0' ;
  }

  i = 0 ; j = 0 ;
  while (i < len) {
    while (old[i] != '\0' && old[i] != '&') i++ ;
    old[i++] = '\0' ;
    decode_pair_string(old+j, &new1, &new2) ;
    j = i ;
    k = 0 ;
    while (k < items && strcmp(list[k].str, new1)) k++ ;
    if (k < items) {
      if (*(list[k].var) == NULL)
	*(list[k].var) = new2 ;
      else {
	*(list[k].var) = 
	  realloc(*(list[k].var), 
		  strlen(*(list[k].var)) + strlen(new2) + 2) ;
	strcat(*(list[k].var), ",") ;
	strcat(*(list[k].var), new2) ;
	free(new2) ;
      }
    }
  }
}

