/*************************************************************************/
/**                                                                     **/
/**     getcgivars.c -- rotina para ler variaveis de entrada CGI        **/
/**         e armazenar em um array de strings.                         **/
/**                                                                     **/
/**     As rotinas x2c() and unescape_url() foram extraidas diretamente **/
/**     do programa-exemplo util.c, incluido no pacote HTTPD da NCSA.   **/
/**                                                                     **/
/**     http://www.jmarshall.com/easy/cgi/portuguese/                   **/
/**                                                                     **/
/*************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/** Converter uma string de dois caracteres hexa no caractere correspondente **/
char x2c(char *what) {
   register char digit;

   digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
   digit *= 16;
   digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
   return(digit);
}

/** Converter qualquer "escape sequence" %xx nos caracteres correspondentes **/
void unescape_url(char *url) {
    register int i,j;

    for(i=0,j=0; url[j]; ++i,++j) {
        if((url[i] = url[j]) == '%') {
            url[i] = x2c(&url[j+1]) ;
            j+= 2 ;
        }
    }
    url[i] = '\0' ;
}


/** Ler a entrada CGI e colocar todos os pares nome/valor na lista. **/
/** Retorna lista contendo nome1, valor1, nome2, valor2, ... , NULL **/
char **getcgivars() {
    register int i ;
    char *request_method ;
    int content_length;
    char *cgiinput ;
    char **cgivars ;
    char **pairlist ;
    int paircount ;
    char *nvpair ;
    char *eqpos ;

    /** Dependendo do metodo de solicitacao, ler toda a entrada CGI e colocar em cgiinput **/
    /** (realmente deve produzir mensagens de erro HTML, em vez de sair com exit() ) **/
    request_method= getenv("REQUEST_METHOD") ;
    if (!strcmp(request_method, "GET") || !strcmp(request_method, "HEAD") ) {
        cgiinput= strdup(getenv("QUERY_STRING")) ;
    }
    else if (!strcmp(request_method, "POST")) {
        /* strcasecmp() nao e' suportada pelo Windows -- use strcmpi() */
        if ( strcasecmp(getenv("CONTENT_TYPE"), "application/x-www-form-urlencoded")) {
            printf("getcgivars(): Unsupported Content-Type.\n") ;
            exit(1) ;
        }
        if ( !(content_length = atoi(getenv("CONTENT_LENGTH"))) ) {
            printf("getcgivars(): No Content-Length was sent with the POST request.\n") ;
            exit(1) ;
        }
        if ( !(cgiinput= (char *) malloc(content_length+1)) ) {
            printf("getcgivars(): Could not malloc for cgiinput.\n") ;
            exit(1) ;
        }
        if (!fread(cgiinput, content_length, 1, stdin)) {
            printf("Couldn't read CGI input from STDIN.\n") ;
            exit(1) ;
        }
        cgiinput[content_length]='\0' ;
    }
    else {
        printf("getcgivars(): unsupported REQUEST_METHOD\n") ;
        exit(1) ;
    }

    /** Retornar todos os '+' para espacos **/
    for(i=0; cgiinput[i]; i++) if (cgiinput[i] == '+') cgiinput[i] = ' ' ;

    /** Primeiro, quebrar nos "&" para extrair os pares nome-valor para pairlist **/
    pairlist= (char **) malloc(256*sizeof(char **)) ;
    paircount= 0 ;
    nvpair= strtok(cgiinput, "&") ;
    while (nvpair) {
        pairlist[paircount++]= strdup(nvpair) ;
        if (!(paircount%256))
            pairlist= (char **) realloc(pairlist,(paircount+256)*sizeof(char **)) ;
        nvpair= strtok(NULL, "&") ;
    }
    pairlist[paircount]= 0 ;    /* terminar a lista com NULL */

    /** Agora, da lista de pares extrair os nomes e valores **/
    cgivars= (char **) malloc((paircount*2+1)*sizeof(char **)) ;
    for (i= 0; i<paircount; i++) {
        if (eqpos=strchr(pairlist[i], '=')) {
            *eqpos= '\0' ;
            unescape_url(cgivars[i*2+1]= strdup(eqpos+1)) ;
        } else {
            unescape_url(cgivars[i*2+1]= strdup("")) ;
        }
        unescape_url(cgivars[i*2]= strdup(pairlist[i])) ;
    }
    cgivars[paircount*2]= 0 ;   /* terminar a lista com NULL */
    
    /** Liberar tudo que deva ser liberado **/
    free(cgiinput) ;
    for (i=0; pairlist[i]; i++) free(pairlist[i]) ;
    free(pairlist) ;

    /** Retornar a lista de strings nome-valor **/
    return cgivars ;
    
}

/***************** fim do modulo getcgivars() ********************/
