#include <stdio.h>
#include <stdlib.h>
#include <stdarg.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(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(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(char c)
{
  if (c >= 'A' && c <= 'F')
    return(10+(c-'A')) ;
  else return(c-'0') ;
}

static void decode_pair_string(char *old, char **new1, char **new2)
{
  char *new3 ;
  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 ;
  new3 = *new1 ;
  j = 0 ;
  while (old[i] != '\0') {
    switch(old[i]) {
    case '+':
      new3[j++] = ' ' ;
      i++ ; 
      break ;
    case '%':
      if (!strncmp(old+i, "%0D%0A", 6)) { /* CR-LF - want to skip CR */
	i += 3 ;
      } 
      else {
	new3[j++] = (char)(hexdigit(old[i+1])*16 + hexdigit(old[i+2])) ;
	i += 3 ;
      }
      break ;
    case '=':
      new3[j] = '\0' ;
      new3 = *new2 ;
      j = 0 ;
      i++ ;
      break ;
    default:
      new3[j++] = old[i] ;
      i++ ;
      break ;
    }
  }
  if (new3 == *new2) new3[j] = '\0' ;
}

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

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

  va_start(args, count) ;

	for(i=0; i < count; i++)
	{
		str = va_arg(args, char *);
		var = va_arg(args, char **);
		if(str != NULL)
		{
			real_count++;
    	*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 ;
		}
		else
		{
			break;
		}
	}

  va_end(args) ;
  items = real_count;

  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((char*) (*(list[k].var)) + strlen(new2) + 2)) ;
	strcat(*(list[k].var), ",") ;
	strcat(*(list[k].var), new2) ;
	free(new2) ;
      }
    }
  }
}

