/*
**      variable.c      -
**
**
** Copyright (c) 1995  Hughes Technologies Pty Ltd
**
** Permission to use, copy, and distribute for non-commercial purposes,
** is hereby granted without fee, providing that the above copyright
** notice appear in all copies and that both the copyright notice and this
** permission notice appear in supporting documentation.
**
** This software is provided "as is" without any expressed or implied warranty.
**
**
*/


#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <msql.h>
#include <string.h>

#include "portability.h"
#include "w3-msql.h"



typedef struct _var {
	char	*name,
		*value;
	struct _var *next;
} var_t;



#define iswhite(c)	(c==' '||c=='\t'||c=='\n')


static	var_t	*varHead = NULL;
char chcase='a' - 'A';

void clearAllVariables()
{
	var_t	*cur,
		*prev;

	cur = varHead;
	while(cur)
	{
		prev = cur;
		cur = cur->next;
		if (prev->name)
			free(prev->name);
		if (prev->value)
			free(prev->value);
		free(prev);
	}
	varHead = NULL;
}


char upper(char ret_char)
{
	if (ret_char>'Z')
	{
		ret_char-=chcase;
	}

return(ret_char);
}

char lower(char ret_char)
{
	if (ret_char<'a')
	{
		ret_char+=chcase;
	}

return(ret_char);
}


void clearVariable(var)
	char	*var;
{
	var_t	*cur,
		*prev;

	cur = varHead;
	while(cur)
	{
		if (strcmp(cur->name,var) == 0)
		{
			if (cur = varHead)
			{
				varHead = cur->next;
			}
			else
			{
				prev->next = cur->next;
			}
			if (cur->name)
				free(cur->name);
			if (cur->value)
				free(cur->value);
			free(cur);
			return;
		}
		prev = cur;
		cur = cur->next;
	}
}


void setVariable(var,val)
	char	*var,
		*val;
{
	var_t	*cur,
		*new;

	cur = varHead;
	while(cur)
	{
		if (strcmp(cur->name,var) == 0)
		{
			if (cur->value)
				free(cur->value);
			cur->value = (char *)strdup(val);
			return;
		}
		cur = cur->next;
	}

	new = (var_t *)malloc(sizeof(var_t));
	bzero(new,sizeof(var_t));
	new->name = (char *)strdup(var);
	if (val)
		new->value = (char *)strdup(val);
	else
		new->value = NULL;
	new->next = varHead;
	varHead = new;
}

char *getVariable(var)
	char	*var;
{
	var_t	*cur;
	char	*envVal,
		errBuf[160];
	char	tmpVal[255];
	char	tmpVal2[255];
	int	Counter;
	int	stage=0;
	strcpy(tmpVal2,"");

	/*
	** Look for an internal variable
	*/
	if (var[0]=='^')
	{
		stage=1;
		var[0]='$';
	}
	cur = varHead;
	while(cur)
	{
		if (strcmp(cur->name,var) == 0)
		{
			if (stage==0)
				return(cur->value);
			if (stage==1)
			{
				stage=2;
				strcpy(tmpVal,cur->value);
			}
		}
		cur = cur->next;
	}

	if (stage>0)
		var[0]='^';

	/*
	** How about an environment variable
	*/
	envVal = (char *)getenv(var+1);
	if ((!envVal) && (stage != 2))
	{
		sprintf(errBuf,"Unknown variable '%s'",var);
		error(errBuf);
		exit(1);
	}


	if (var[0]=='^') 
	{
		if(stage == 1)
			strcpy(tmpVal,envVal);
		envVal=(char *)tmpVal2;
		for(Counter=0; Counter<strlen(tmpVal); Counter++)
		{
			strcat(envVal,"[");
			strncat(envVal,tmpVal+Counter,1);
			envVal[strlen(envVal)-1]=upper(envVal[strlen(envVal)-1]);
			strncat(envVal,tmpVal+Counter,1);
			envVal[strlen(envVal)-1]=lower(envVal[strlen(envVal)-1]);
			strcat(envVal,"]");
		}
	}
	return(envVal);
}


char *substVariables(str)
	char	*str;
{
	static	char buf[2048];
	char	*cp1,*cp2,
		*val,
		*var1,*var2,varBuf[80],
		*h1,*h2,handle[80];
	qHandle	*qh;
	int	offset;
	
	cp1 = str;
	cp2 = buf;
	bzero(buf,sizeof(buf));
	while (*cp1)
	{
		switch(*cp1)
		{
			case '$':
				var1 = cp1;
				var2 = cp1+1;
				while(isalnum(*var2) || *var2 == '_')
				{
					var2++;
				}
				bzero(varBuf,sizeof(varBuf));
				strncpy(varBuf,var1,var2-var1);
				val = getVariable(varBuf);
				if (val)
				{
					strcpy(cp2,val);
					cp2 += strlen(val);
				}
				cp1 = var2;
				break;

			case '^':
				var1 = cp1;
				var2 = cp1+1;
				while(isalnum(*var2) || *var2 == '_')
				{
					var2++;
				}
				bzero(varBuf,sizeof(varBuf));
				strncpy(varBuf,var1,var2-var1);
				val = getVariable(varBuf);
				if (val)
				{
					strcpy(cp2,val);
					cp2 += strlen(val);
				}
				cp1 = var2;
				break;
	
			case '\\':
				cp1++;
				if (*cp1)
				{
					switch(*cp1)
					{
						case 'n':
							*cp2++ = '\n';
							break;
						case 't':
							*cp2++ = '\t';
							break;
						case 'r':
							*cp2++ = '\r';
							break;
						default:
							*cp2++ = *cp1;
							break;
					}
					cp1++;
				}
				else
				{
					*cp2 = '\\';
				}
				break;

			case '@':

				/*
				** Get the row handle id
				*/
				h1 = cp1+1;
				h2 = cp1+2;
				while(isalnum(*h2) || *h2 == '_')
				{
					h2++;
				}
				bzero(handle,sizeof(handle));
				strncpy(handle,h1,h2-h1);

				/*
				** Check for the dot
				*/
				cp1 = h2;
				while(iswhite(*cp1))
					cp1++;

				if (*cp1 != '.')
				{
					error("Bad row variable");
					exit(1);
				}

				cp1++;
				while(iswhite(*cp1))
					cp1++;

				/*
				** Get the field offset
				*/
				var1 = cp1;
				var2 = cp1+1;
				if (!isdigit(*var1))
				{
					error("Bad row value offset");
					exit(1);
				}
				while(isdigit(*var2))
				{
					var2++;
				}
				bzero(varBuf,sizeof(varBuf));
				strncpy(varBuf,var1,var2-var1);

				/*
				** Get the actual value
				*/
				qh = getHandle(handle);
				offset = atoi(varBuf);
				if (offset > msqlNumFields(qh->res))
				{
					error("Row value offset too large for query data");
					exit(1);
				}
				val = (char *)qh->row[offset];
				if (val)
				{
					strcpy(cp2,val);
					cp2 += strlen(val);
				}
				cp1 = var2;
				break;
				

			default:
				*cp2++ = *cp1++;
				break;
		}
	}
	return(buf);
}
