/* Time-stamp: <96/12/12 11:37:08 john> */

/*
# Purpose: Parse CGI arguments, caching them as they are asked for.
 */

#include <stdio.h>
#include "attr.h"
#include "readbuffers.h"
#include "style.h"		/* required by misc.h */
#include "misc.h"
#include "cgi.h"

/* #define debugging 1 */

typedef struct cgi_field {
  struct cgi_field *next;
  char *name;
  char *value;
} CGI_FIELD;

static struct cgi_field *parsed = NULL;

void cgi_parse_reset()
{
  while (parsed != NULL)
    {
      struct cgi_field *next = parsed->next;
      Free(parsed->name);
      Free(parsed->value);
      Free(parsed);
      parsed = next;
    }
}

static char *return_field(char *name, char *data)
{
  char *p, *q;
  char c;
  struct cgi_field *new = (struct cgi_field*)malloc(sizeof(struct cgi_field));
  char *new_name = (char*)malloc(strlen(name)+1);
  char *new_value;
  for (p = data, c = *p; (c = *p) != '\0'; p++)
    if (c == '&') break;
  new_value = (char*)malloc(p - data);

  strcpy(new_name, name);
  
  for (p = data, q = new_value, c = *p;
       (c = *p) != '\0';
       p++, q++)
    {
      if (c == '&') break;
      if (c == '+')
	{
	  *q = ' ';
	} else if (c == '%')
	  {
	    int c1, c2;
	    c1 = *++p;
	    c2 = *++p;

	    c = (hd2i(c1) << 4) + hd2i(c2);
	    *q = c;
#ifdef debugging
	    printf("[%c%c==>%x]", c1, c2, c);
#endif
	  } else {
	    *q = c;
	  }
    }
 
  *q = '\0';

  new->name = new_name;
  new->value = new_value;
  new->next = parsed;
  parsed = new;

  return new_value;
}

char *get_field(char *qs, char *name)
{
#ifdef debug
  printf("get_field(\"%s\", \"%s\")\n", qs, name);
#endif
  do {
    char *a;
    char qc;

    for (a = name;
	 *a != '\0';
	 a++)
      {
	qc = *qs++;
	if ((qc == '&') ||  (qc == '\0')) return "on";
	if ((qc != *a) || (qc == '=')) break;
      }

    if (*a == '\0') return return_field(name, qs+1);

    do {
      qc = *qs++;
      if (qc == '\0') return NULL;
    } while (qc != '&');
  } while (*qs != '\0');
  

  return NULL;
}

#define IN_NAME_MATCHED 1
#define IN_VALUE 2
#define SKIPPING 3

char *remove_field(char *old_string, char *field_name)
{
  /* do it in one pass, guaranteeing enough room saves time counting it: */
  char *new_string = (char*)malloc(strlen(old_string)+1);
  char *a;
  char *b = field_name;
  char *z;
  char *completed;
  char c;
  int state = IN_NAME_MATCHED;

  if (new_string == NULL) return NULL;

  if (old_string[0] == '\0')
    {
      new_string[0] = '\0';
      return new_string;
    }

  for (a = old_string,
       z = new_string,
       completed = z;
       (c = *a) != '\0';
       a++)
    {
      switch (state)
	{
	case IN_NAME_MATCHED:
	  if (c == '=')
	    {
	      *z++ = c;
	      state = SKIPPING;
	    } else {
	      if (c != *b++)
		{
		  state = IN_VALUE;
		  z = completed;
		}
	      *z++ = c;
	    }
	  break;
	case SKIPPING:
	  if (c == '&')
	    {
	      state = IN_NAME_MATCHED;
	      b = field_name;
	      *z++ = c;
	    }
	  break;
	case IN_VALUE:
	  if (c == '&')
	    {
	      state = IN_NAME_MATCHED;
	      b = field_name;
	      completed = z+1;
	    }
	  *z++ = c;
	    
	  break;
	}
    }

  if (state == SKIPPING)
    {
      z = completed - 1;
    }

  *z = c;

  return new_string;
}

static int process_kvp(char *keybuf, char *valbuf, struct attribute **attrs)
{
  struct attribute *new_attr = (struct attribute*)malloc(sizeof(struct attribute));
#ifdef debugging
  printf("<p>Processing(\"%s\",\"%s\")</p>\n", keybuf, valbuf);
#endif
  if (new_attr == NULL) return 0;

  new_attr->next = *attrs;
  new_attr->key = (char*)malloc(strlen(keybuf)+1);
  if (new_attr->key == NULL)
    {
      Free(new_attr);
      return 0;
    }
  new_attr->value = (char*)malloc(strlen(valbuf)+1);
  if (new_attr->value == NULL)
    {
      Free(new_attr->key);
      Free(new_attr);
      return 0;
    }
     
  strcpy(new_attr->key, keybuf);
  strcpy(new_attr->value, valbuf);

  *attrs = new_attr;

  return 1;
}

int parse_post_input(struct attribute **attrs,
		     FILE *raw_edit_file,
		     int debug)
{

  int c;
  int keyi = 0;
  int vali = 0;
  int reading_key = 1;

  if (debug)
    {
      printf("<h2>Parsing input</h2><pre>\n");
    }

  while ((c=getchar()) != EOF)
    {
      if (c == '&')
	{
	  if (debug)
	    {
#ifdef debugging
	      printf("<h3>Next entry</h3>\n");
#endif
	    }
	  c = '\n';
	  valbuf[vali] = '\0';
	  reading_key = 1;
	  keyi = 0;
	  vali = 0;
	  if (!process_kvp(keybuf, valbuf, attrs))
	    {
	      printf("Out of memory!\n");
	      exit(0);
	    }
		
	} else {
	  if (c == '+') c = ' ';
	  if (c == '%')
	    {
	      int c1, c2;
	      c1 = getchar();
	      c2 = getchar();

	      c = (hd2i(c1) << 4) + hd2i(c2);
#ifdef debugging
	      printf("[%c%c==>%x]", c1, c2, c);
#endif
	    }
	  if (reading_key)
	    {
	      if (c == '=')
		{
		  keybuf[keyi] = '\0';
		  reading_key = 0;
		} else {
		  keybuf[keyi++] = c;
		  Check_Keyindex(keyi);
		}
	    } else {
	      valbuf[vali++] = c;
	      Check_Valindex(vali);
	    }
		  
	}
#ifdef debugging
      putchar(c);
#endif
      putc(c, raw_edit_file);
    }
  valbuf[vali] = '\0';

  if (!process_kvp(keybuf, valbuf, attrs))
    {
      printf("Out of memory!\n");
      exit(0);
    }
}

/* end of cgi.c */
