#include	<stdio.h>

/*
 *	query parser
 *
 *	this reads the REQUEST_METHOD and QUERY_STRING things
 *	from the environment and outputs a sequence of strings
 *	of the form  NAME="Value"
 *	suitable for using with the . operator in /bin/sh
 *
 *	to handle un-=named fields (as in ISINDEX things) invoke
 *	with the -unnamed option
 *
 *	version: 17 Jan 2001 - made ~ and ? ok chars (for ewp.cgi)
 *	version: 11 Dec 2000 - added commandarg
 *	version: 10 Dec 2000 - fixed %## problem
 */

char	buffer[10240];

#define	TILDE_QMARK_OK

int	has_names   = 1;

main(ac,av)
char **av;
{
	char	*cp, *getenv();
	int	i;

	for( i = 1 ; i<ac ; i++ ){
		if ( strcmp( av[i], "-unnamed" ) == 0 )
			has_names = 0;
	}
	if ( ac > 1 )
		convert( av[1] );
	else
	{
		cp = getenv( "REQUEST_METHOD" );
		if ( cp == NULL )
			oops("No REQUEST_METHOD in environment!","");
		if ( strcmp( cp, "GET" ) == 0 )
			do_get();
		else if ( strcmp(cp, "POST") == 0 )
			do_post();
		else
			oops("unknown REQUEST_METHOD", cp);
	}
}

do_get()
{
	char	*cp, *getenv();

	cp = getenv( "QUERY_STRING" );
	if ( cp == NULL )
		oops("No QUERY_STRING in environment!","");
	convert( cp );
}


do_post()
{
	char	*buffer, *getenv(), *malloc();
	int	thelen ;
	char	*cp;
	int	c;
	
	cp = getenv( "CONTENT_LENGTH" );
	if ( cp == NULL )
		oops("No CONTENT_LENGTH in environment","");
	thelen = atoi( cp );
	if ( thelen <= 0 )
		oops("Content Length is not positive", "" );
	cp = buffer = malloc( thelen + 1 );
	if ( buffer == NULL )
		oops("Not enough memory for QUERY_STRING", "" );
	while( thelen-- ){
		c = getchar();
		if ( c == EOF )
			oops( "Insufficient data from stream", "" );
		*cp++ = c ;
	}
	*cp = '\0';
	convert( buffer );
}

oops(s1,s2)
char *s1, *s2;
{
	printf("PARSE_ERROR=YES\n");
	printf("PARSE_REASON=\"%s %s\"\n", s1, s2);
	exit(1);
}

/* this list ought to cover all the potential problems */


#ifdef	TILDE_QMARK_OK
char	badchars[] = "&;`'\"|*<>^()[]{}$\n\r";
#else
char	badchars[] = "&;`'\"|*?~<>^()[]{}$\n\r";
#endif

convert( char *s )
{
	char	c;
	int	in_name=1;

	while ( c = *s++ ){
		switch( c ){
			case '+':	putchar(' ');
					break;
			case '&':	printf("\"\n");
					in_name = 1;
					break;
			case '=':	if (in_name)
						printf("=\"");
					in_name=0;
					break;
			case '%':	c = x2c(s);
					s += 2;
					/* fall thru */
			default:	if ( strchr(badchars,c) )
						printf("\\%c",c);
					else
						putchar(c);
		}
	}
	printf("\"\n");
}

x2c(char *s)
{
	return (hexval(s[0])<<4) + hexval(s[1]);
}

hexval(c)
{
	if ( c >= '0' && c <= '9' )
		return c - '0';
	if ( c >= 'A' && c <= 'F' )
		return 10 + c - 'A' ;
	if ( c >= 'a' && c <= 'f' )
		return 10 + c - 'a' ;
	return 0;
}
