/*
**      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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <msql.h>

#ifdef OS2
#  include <common/config.h>
#  include <common/portable.h>
#else
#  include "portable.h"
#endif

#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;


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;
}


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;
}



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

        cur = varHead;
        while(cur)
        {
                if (strcmp(cur->name,var) == 0)
                {
                        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];


        /*
        ** Look for an internal variable
        */
        cur = varHead;
        while(cur)
        {
                if (strcmp(cur->name,var) == 0)
                {
                        return(cur->value);
                }
                cur = cur->next;
        }

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


void convertVariable(var)
        char    *var;
{
        char    *psz,
                *val;
        int     cIdx0,
                cIdx1;

        val = getVariable( var );

        if( NULL != val && NULL != (psz=malloc(1+2*strlen(val))) )
        {
                cIdx0 = cIdx1 = 0;
                while( '\0' != val[cIdx0] )
                {
                        switch( val[cIdx0] )
                        {
                                case '\'':
                                        psz[cIdx1+0] = '\\';
                                        psz[cIdx1+1] = '\'';
                                        cIdx1 += 2;
                                        break;
                                default:
                                        psz[cIdx1] = val[cIdx0];
                                        cIdx1++;
                        } /* switch */

                        cIdx0++;

                } /* while */

                psz[cIdx1] = '\0';
                setVariable( var, psz );
                free( psz );

        } /* if */

        setVariable( var, val );
}



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 '\\':
                                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);
}
