static char sccsid[]="%Z% %M% %I% %E% %U%";
/*****************************************************/
/*                                                   */
/*           coded by A.Kobayashi  2010.5.29         */
/*                                                   */
/*****************************************************/
#include "akxcommon.h"

#define OPTION			7
#define _MAX_DA			400
#define ERROR_MALLOC		-4
#define ERROR_SYNTAX		-17
#define ERROR_NOT_COLNAME	-19
#define ERROR_MAX_OBJ		-24
#define ERROR_MAX_DA		-25
#define ERROR_NO_ITEM		-29
#define ERROR_REMAIN_STACK	-30
#define ERROR_NOT_OPECODE	-31

static int _compile();
static int _ex_obj();
static char *hk[]={"<>","><",">=","=>","<=","=<","==","==","!=","^=",
"&&","||","<<",">>",NULL};

static short act[9][9]={
	{99,-1,-1, 3, 3, 3, 3, 3,-1},	/*       */
	{ 2, 2,-1, 2, 2,-1, 2, 2,-1},	/*  (    */
	{-1, 4,-1, 3, 3, 3, 3, 3,-1},	/*  )    */
	{ 2, 2,-1, 3, 2, 2, 2, 2,-1},	/*  *,/  */
	{ 2, 2,-1, 3, 3, 2, 2, 2,-1},	/*  +-   */
	{ 2, 2,-1, 3, 3,-1, 2, 2,-1},	/*  =<> like */
	{ 2, 2,-1, 3, 3, 3, 3, 2,-1},	/*  and  */
	{ 2, 2,-1, 3, 3, 3, 3, 3,-1},	/*  or   */
	{ 1, 1,-1, 1, 1, 1, 1, 1,-1}	/*       */
};

static short jdg[7][3]={
	{1,0,1},	/*  !=  */
	{0,1,1},	/*  >=  */
	{1,1,0},	/*  <=  */
	{0,1,0},	/*  =   */
	{0,0,1},	/*  >   */
	{1,0,0}, 	/*  <   */
	{0,1,0}		/* like */
};

static int ida,init_da=0;
static char **da;
static int ids, *dstk;

static int   cmp_gtwd();
static int   cmp_mkix();
static int   cmp_name();
static int   cmp_vchg();
static char *cmp_schg();
static int   _comp_judge();

static int _compile(pNS,sql,len)
tdtStplSql *pNS;
char *sql;
int  len;
{
	int maxcolm,nobj,*obj,*stack;
	SSP_S ssp;
	int i,sp,attr,attr0,i1,i2,ac,iob;
	char w[256];
	int date_flg,data_cnt,ret,ncolm;

	maxcolm = pNS->ns_maxcolm;
	nobj    = pNS->ns_maxobj;
	obj     = pNS->ns_obj;
	da      = pNS->ns_da;
	stack   = pNS->ns_stack;
	stack[0] = 0;
	sp = 1;
	attr = 0;
	iob = 0;
	ida = 0;
	data_cnt = date_flg = 0;
	ssp.sp = 0;
	ssp.wd = w;
	for(;;) {
		attr0 = attr;
		for(;;) {
			attr = cmp_gtwd(sql,len,&ssp);
			if (attr == 99) {
				attr = 0;
			}
			else if (attr == 98) return ERROR_SYNTAX;
			else if (attr == 500) {
				if (ida >= pNS->ns_maxda) return ERROR_MAX_DA;
				if (da[ida]) {
					if (!(da[ida]=Realloc(da[ida],strlen(ssp.wd)+1)))
						return ERROR_MALLOC;
				}
				else {
					if (!(da[ida]=Malloc(strlen(ssp.wd)+1)))
						return ERROR_MALLOC;
				}
				strcpy(da[ida],ssp.wd);
				attr += ++ida;
			}
			else if (attr == 100) {
				attr = cmp_name(ssp.wd,maxcolm);
				if (attr < 0) return attr;
				attr += 100;
			}
			else if (attr==3 || attr==7 || attr==8 || attr==9) {
				if (attr0<=1 || (attr0>=11 && attr0<=22)) {
					if (attr == 7) continue;
					else attr = -attr;
				}
			}
			break;
		}
		i2 = cmp_mkix(attr);
		for(;;) {
			if (sp < 1) return ERROR_SYNTAX;
			i1 = cmp_mkix(stack[sp-1]);
			ac = act[i2][i1];
			if (ac < 0) return ERROR_SYNTAX;
			else if (ac == 99) {
				if (iob >= nobj) return ERROR_MAX_OBJ;
				obj[iob++] = ac;
				pNS->ns_nobj = iob;
				return iob;
			}
			else if (ac == 1) {
				if (iob+1 >= nobj) return ERROR_MAX_OBJ;
				obj[iob++] = 31;
				obj[iob++] = attr;
				data_cnt++;
			}
			else if (ac == 2) {
				stack[sp++] = attr;
			}
			else if (ac == 3) {
				if (iob >= nobj) return ERROR_MAX_OBJ;
				if (sp < 1) return ERROR_SYNTAX;
				obj[iob++] = stack[--sp];
				date_flg = 0;
				data_cnt = 0;
				continue;
			}
			else if (ac == 4) {
					sp--;
			}
			else {
				return ERROR_SYNTAX;
			}
			break;
		}
	}
}

static int cmp_gtwd(sql,sqllen,ssp)
char *sql;
SSP_S *ssp;
int  sqllen;
{
	static char sep[]={" \t'~+-*%/&|=^!<>(),;"};
	int len,atr,i;
	char wk[3],c,*p,*wd;

	atr = 0;
	len = akxtgwns(sql,sqllen,ssp,sep,OPTION);
	wd = ssp->wd;
	if (len>0 || ssp->attr[0]>0) {
		if ((atr=ssp->attr[0]) < 10) {
			if (atr == 1) {
				atr = 100;
				if ((c=wd[0])>='0' && (c<='9')) atr = 500;
				else if (!stricmp(wd,"null")) {
					wd[0] = '\0';
					atr = 500;
				}
				else if (!stricmp(wd,"like")) atr = 17;
				else if (!stricmp(wd,"and")) atr = 21;
				else if (!stricmp(wd,"not")) atr = 9;
				else if (!stricmp(wd,"or")) atr = 22;
				else if (!stricmp(wd,"is")) atr = 14;
				else if (!stricmp(wd,"order") ||
				         !stricmp(wd,"group") ||
				         !stricmp(wd,"having")) atr = 99;
			}
			else atr = 500;
		}
		else if ((c=wd[0]) == ';') atr = 99;
		else if (c == ',') atr = 98;
		else if (c == '(') atr = 1;
		else if (c == ')') atr = 2;
		else if (c == '~') atr = 3;
		else if (c == '*') atr = 4;
		else if (c == '/') atr = 5;
		else if (c == '%') atr = 6;
		else if (c == '+') atr = 7;
		else if (c == '-') atr = 8;
		else {
			wk[0] = c;
			wk[1] = sql[ssp->sp];
			wk[2] = '\0';
			for(i=0,p=hk[i];p=hk[i];i++) {
				if (!strcmp(wk,p)) {
					if (i < 10) {
						atr = (i/2) + 11;
						if (atr == 15) atr = 11;
					}
					else if (i < 12) atr = i + 11;
					else atr = i + 17;
					ssp->sp++;
					strcpy(wd,wk);
					return atr;
				}
			}
			if (c == '=') atr = 14;
			else if (c == '>') atr = 15;
			else if (c == '<') atr = 16;
			else if (c == '&') atr = 19;
			else if (c == '|') atr = 20;
			else if (c == '!') atr = 9;
			else if (c == '^') atr = 18;
			else atr = 500;
		}
	}
	return atr;
}

static int cmp_mkix(attr)
int attr;
{
	int atx,ix;

	if (attr == -8 || attr == -9) return 3;
	if ((atx=attr) < 0) atx = -atx;

	if (atx <= 3) ix = atx;
	else if (atx <= 6) ix = 3;
	else if (atx <= 8) ix = 4;
	else if (atx <= 10) ix = 3;
	else if (atx <= 20) ix = 5;
	else if (atx <= 22) ix = atx - 15;
	else if (atx <= 30) ix = 3;
	else ix = 8;

	return ix;
}

static int cmp_name(name,maxcolm)
char *name;
int  maxcolm;
{
	int i;

	if (*name == '#') {
		if ((i = atoi(name+1)) <= maxcolm) return i;
	}
	return ERROR_NOT_COLNAME;
}

static int _ex_obj(pNS,rec,nrec)
tdtStplSql *pNS;
char **rec;
int  nrec;
{
	int iob,*obj;
	int irs, *rstk;
	int ib,mc,rdt,v,a,b,t,j,ret;
	char *ap,*bp,w1[13],w2[13];

	iob  = pNS->ns_nobj;
	obj  = pNS->ns_obj;
	da   = pNS->ns_da;
	dstk = pNS->ns_dstk;
	rstk = pNS->ns_stack;
	ib = irs = ids = 0;
	if (iob < 1) return 1;
	while (ib <= iob) {
		mc = obj[ib++];
		if (mc == 99) {
			v = 1;
			if (irs > 1) return ERROR_REMAIN_STACK;
			else if (irs == 1) {
				v = cmp_vchg(rstk[--irs],rec,nrec,&ret);
				if (ret) return ret;
				dstk[0] = v;
				if (v) v = 1;
			}
			return v;
		}
		if (mc == 31) rstk[irs++] = obj[ib++];
		else if (mc == 32) continue;
		else if (mc==-3 || mc==-8 || mc==-9) {
			if (irs < 1) return ERROR_NO_ITEM;
			a = cmp_vchg(rstk[--irs],rec,nrec,&ret);
			if (ret) return ret;
			if (mc == -3) a = ~a;
			else if (mc == -8) a = -a;
			else a = !a;
			dstk[ids++] = a;
			rdt = 9001;
			rstk[irs++] = rdt;
		}
		else if (mc>=1 && mc<=30) {
			if (mc<11 || mc==19 || mc==20 || mc==29 || mc==30) {
				if (irs < 2) return ERROR_NO_ITEM;
				b = cmp_vchg(rstk[--irs],rec,nrec,&ret);
				if (ret) return ret;
				a = cmp_vchg(rstk[--irs],rec,nrec,&ret);
				if (ret) return ret;
				switch (mc) {
					case 4:	v = a*b; break;
					case 5:	if (b) v = a/b;
					        else   v = a;
							break;
					case 6:	if (b) v = a%b;
					        else   v = a;
							break;
					case 7:	v = a + b; break;
					case 8:	v = a - b; break;
					case 18:v = a ^ b; break;
					case 19:v = a & b; break;
					case 20:v = a | b; break;
					case 29:v = a << b; break;
					case 30:v = a >> b; break;
				}
			}
			else if (mc < 21) {
				if (irs < 2) return ERROR_NO_ITEM;
				if (rstk[irs-1]<=200 || rstk[irs-2]<=200) t=1;
				else t = 2;
				if (t == 1) {
					bp = cmp_schg(rstk[--irs],rec,nrec,w1,&ret);
					if (ret) return ret;
					ap = cmp_schg(rstk[--irs],rec,nrec,w2,&ret);
					if (ret) return ret;
					if(mc == 17) {
						if ((a=akxs_str_like(ap,bp)) < 0) return -1;
					}
					else a = strcmp(ap,bp);
					if(a > 0) j = 2;
					else if (a < 0) j = 0;
					else j = 1;
				}
				else {
					b = cmp_vchg(rstk[--irs],rec,nrec,&ret);
					if (ret) return ret;
					a = cmp_vchg(rstk[--irs],rec,nrec,&ret);
					if (ret) return ret;
					if (a > b) j = 2;
					else if (a < b) j = 0;
					else j = 1;
				}
				v = jdg[mc-11][j];
			}
			else if (mc < 31) {
				if (irs < 2) return ERROR_NO_ITEM;
				b = cmp_vchg(rstk[--irs],rec,nrec,&ret);
				if (ret) return ret;
				a = cmp_vchg(rstk[--irs],rec,nrec,&ret);
				if (ret) return ret;
				v = 0;
				if (mc == 21) {
					if (a && b) v = 1;
				}
				else {
					if (a || b) v = 1;
				}
			}
			else return ERROR_NOT_OPECODE;
			rdt = 9001;
			rstk[irs++] = rdt;
			dstk[ids++] = v;
		}
		else break;
	}
	return -99;
}

static int cmp_vchg(rst,rec,nrec,pret)
int rst,nrec,*pret;
char **rec;
{
	int v,ret,i;
	char *p;

	v = ret = 0;
	if (rst <= 100) ;
	else if (rst <= 9000) {
		if (rst <= 500) {
			if (rst <= 200) i = rst - 101;
			else i = rst - 201;
			if (!rec || i>=nrec) p = NULL;
			else p = rec[i];
		}
		else p = da[rst-501];
		if (p) {
			if ((ret=akxcgcvn(p,strlen(p),&v)) > 0) ret = -103;
		}
		else ret = -101;
	}
	else if (rst <= 10000) v = dstk[--ids];
	else v = rst - 10000;
	if (pret) *pret = ret;
	return v;
}

static char *cmp_schg(rst,rec,nrec,w,pret)
int rst,nrec,*pret;
char **rec;
char *w;
{
	char *s;
	int v,i,ret;

	ret = 0;
	s = w;
	*w = '\0';
	if (rst <= 100) ;
	else if (rst <= 500) {
		if (rst <= 200) i = rst - 101;
		else i = rst - 201;
		if (!rec || i>=nrec) ret = -102;
		else s = rec[i];
	}
	else if (rst <= 9000) s = da[rst-501];
	else {
		if (rst <= 10000) v = dstk[--ids];
		else v = rst - 10000;
		sprintf(w,"%d",v);
		s = w;
	}
	if (pret) *pret = ret;
	return s;
}

static int _comp_judge(iKind,j)
int iKind,j;
{
	if (iKind<1 || iKind>7) iKind = 4;
	return jdg[iKind-1][j];
}

tdtStplSql *akxs_stpl_sql_new(nparm,iParm)
int nparm,iParm[];
{
	tdtStplSql *pNS;
	int  len,mcolm;
	char *p;

	if (!(pNS=(tdtStplSql *)Malloc(sizeof(tdtStplSql)))) return NULL;
	memset(pNS,0,sizeof(tdtStplSql));

	mcolm = 0;
	if (iParm) {
		if (nparm >= 1) pNS->ns_maxcolm  = mcolm = iParm[0];
		if (nparm >= 2) pNS->ns_maxobj   = iParm[1];
		if (nparm >= 3) pNS->ns_maxda    = iParm[2];
		if (nparm >= 4) pNS->ns_maxstack = iParm[3];
	}
	if (mcolm <= 0) mcolm = 10;
	if (pNS->ns_maxobj   <= 0) pNS->ns_maxobj   = mcolm*8;
	if (pNS->ns_maxda    <= 0) pNS->ns_maxda    = mcolm*2;
	if (pNS->ns_maxstack <= 0) pNS->ns_maxstack = pNS->ns_maxobj/2;
	len = (pNS->ns_maxobj+pNS->ns_maxstack*2)*sizeof(int)+pNS->ns_maxda*sizeof(char *);
	if (!(p=Malloc(len))) {
		Free(pNS);
		return NULL;
	}

	pNS->ns_obj   = (int *)p;
	pNS->ns_dstk  = pNS->ns_obj  + pNS->ns_maxobj;
	pNS->ns_stack = pNS->ns_dstk + pNS->ns_maxstack;
	pNS->ns_da    = (char **)(pNS->ns_stack + pNS->ns_maxstack);
	memset(pNS->ns_da,0,pNS->ns_maxda*sizeof(char *));

	return pNS;
}

int akxs_stpl_sql_free(pNS)
tdtStplSql *pNS;
{
	int i;
	char **da,*p;

	if (!pNS) return -1;
	da = pNS->ns_da;
	for (i=0;i<pNS->ns_maxda;i++,da++)
		if (p = *da) Free(p);
	if (pNS->ns_obj) Free(pNS->ns_obj);
	Free(pNS);
	return 0;
}

int akxcecvn(ppNS,expbuf,len,pnum)
tdtStplSql **ppNS;
char *expbuf;
int  len;
int *pnum;
{
	static tdtStplSql *spNS=NULL;
	tdtStplSql *pNS;
	int ret;

	if ((ppNS && !(pNS = *ppNS)) || (!ppNS && !(pNS = spNS))) {
		pNS = akxs_stpl_sql_new(0,NULL);
		if (ppNS) *ppNS = pNS;
		else spNS = pNS;
	}

	if (!expbuf || len<=0) return -1;

	if (pNS) {
		if ((ret=_compile(pNS,expbuf,len)) >= 0) {
			if (ret) {
				if (ret==1 && pNS->ns_obj[0]==99) ret = -1;
				else if ((ret=_ex_obj(pNS,NULL,0)) >= 0) {
					if (pnum) *pnum = pNS->ns_dstk[0];
				}
			}
			else ret = -1;
		}
	}
	else ret = ERROR_MALLOC;
	return ret;
}
