#include	<stdio.h>
//#include	<stdlib.h>
//#include	<string.h>
//#include	<unistd.h>
//#include	<stdarg.h>
//#include	<fcntl.h>
//#include	<time.h>
//#include	<sys/mman.h>
#include	"org.h"

//**************************************************
// CGIパラメータの取得
// dt には取り込んだ値が入っているから、この関数を呼んだプログラム側で保存すること
//**************************************************
orgget(
	unsigned char	dt[],		// 引数を入れるところ
	int		n,			// その長さ
	char	*pt[],		// トークンを入れる
	int		kn			// トークンの個数
){
	FILE	*fp;
	char	*sp,*org,dd[100],*env;
	int		ln,nn,i,t,e;

	// データをコピー
	env=(char*)getenv("REQUEST_METHOD");
	if(env!=NULL && strncmp(env,"GET",3)==0){
		sp=(char*)getenv("QUERY_STRING");
		strncpy(dt,sp,n);
	}else
	if(env!=NULL && strncmp(env,"POST",4)==0){
		ln=atoi(getenv("CONTENT_LENGTH"));
		if(ln>n){
			dt[0]=0;
			err("ln>n");
		}
		nn=fread(dt,ln,1,stdin);
		if(nn==ln)		err("nn==ln");
		dt[ln]=0;
	}else{
		dt[0]=0;
	}
	// トークンに分解
	pt[0]=dt;
	for(i=0,t=1;t<kn;i++){
		if(dt[i]==0)	break;
		if(dt[i]=='+')	dt[i]=' ';
		if(dt[i]=='\\')	dt[i]=0;
		if(dt[i]=='&' || dt[i]==','){
			dt[i]=0;
			pt[t++]=dt+i+1;
			if(t>=kn)	err("t>=kn");
		}
	}
	return(t);			// 個数を返す
}
//**************************************//
//  CGIパラメータ取り出し               //
//  項目名を指定して取り出す            //
//  引数: *pt[], p, nm[]                //
//  戻り値:ss                           //
//**************************************//
char* orgmach(
	char	*pt[],		// 項目ごとのポインター
	int		ep,			// 項目の件数
	char	nm[]		// 取り出したい項目名
){
	int		i,k;
	static char		ss[2];

	for(i=0;i<ep;i++){
		for(k=0;k<50;k++){
			if(pt[i][k] != nm[k])	break;
			if(pt[i][k] == '='){
				if(pt[i][k+1]==0)	break;
				return(pt[i]+k+1);
			}
		}
	}
	ss[0]=0;
	return(ss);
}

//*********************************************************************
// ORG システム関係の関数
//*********************************************************************
//*********************************************************************
// orgファイルの様式に従って 画面を出力する
//*********************************************************************
orgpage(
	ORG		*org,
	char	*fnam
){
	FILE			*fp;
	PW_TAG			tag;
	unsigned char	dt[1000],dd[100];
	char			fg,ifg;
	long			sp;
	int				i,e;

	if((fp=fopen(fnam,"r"))==NULL)		return(0);
	tag.ec=0;
	ifg=' ';
	for(;;){
		sp=ftell(fp);
		if(fgets(dt,1000,fp)==NULL){
			if(orgreclude(org,&fp)==0)		break;		// includeファイルからの脱出
		}
		if(dt[0]=='#' && dt[1]=='/')	continue;
		if(dt[0]=='#' && dt[1]=='#' && dt[2]!='$'){
			// orgファイルの変数の取り込み
			orgkget(org,dt+2);
			continue;
		}
		for(i=0;i<1000;){
			if(dt[i]==0)	break;
			// #があれば
			if(dt[i]=='#'){
				if(dt[i+1]=='$'){					// include 処理
					i=addinclude(dd,"",dt,i+2,&ifg);
				}else
				if(dt[i+1]=='#' && dt[i+2]=='$'){	// include 処理 廃止予定
					i=addinclude(dd,"",dt,i+3,&ifg);
				}else
				if(dt[i+1]=='{'){					// loop 処理
					i=loophed(org,fp,dt,i,&sp);
				}else
				if(dt[i+1]=='}' && dt[i+2]=='#'){	// loopの終了処理
					i=loopend(org,fp,dt,i,&sp);
				}else
				if(dt[i+1]=='['){					// 表示制御 あれば
					i=chktag(&tag,dt,i,2,&fg);
					if(fg=='A'){
						e=machtag(org,&tag);
						if(e<0)		i=pageskip(fp,dt,i,&sp);
					}
				}else
				if(dt[i+1]==']' && dt[i+2]=='[' && dt[i+3]=='#'){
					i=pageskip(fp,dt,i+4,&sp);
				}else
				if(dt[i+1]==']' && dt[i+2]=='#'){	// 表示制御の終了処理
					i+=3;
				}else{
					i=chktag(&tag,dt,i,1,&fg);
					if(fg=='A'){
						e=machtag(org,&tag);
						if(e>=0){
							if(ifg=='A')	i=addinclude(dd,org->arry[e].str,dt,i,&ifg);
							else			printf("%s",org->arry[e].str);
						}
					}else{
						putchar(dt[i++]);
					}
				}
				continue;
			}
			putchar(dt[i++]);
		}
		// dd[] はinclude処理用 値が入っていればinclude処理を実行
		if(ifg=='B')	orginclude(org,&fp,dd);
		ifg=' ';
	}
	fclose(fp);
	// debugに EXEC ORG名を表示する
	printf("<!-- exec=%s org=%s -->\n",getenv("TEST_EXEC"),fnam);
}
//*********************************************************************
//		ORGの準備
//		ln は利用できる変数の件数
//		dn はデータ類を保存するエリアのサイズ
//*********************************************************************
ORG *orgset(
	int		ln,
	int		dn
){
	ORG		*org;

	if((org = (ORG*)malloc(sizeof(ORG)) )==NULL)    err("arry malloc");
	// 変数の保存エリア
	if((org->arry = (PW_ARRY*)malloc(ln*sizeof(PW_ARRY)) )==NULL)    err("arry malloc");
	org->pa=0;
	org->ea=ln;
	// 変数値の保存エリア
	if((org->dt = (char*)malloc(dn) )==NULL)    err("dt malloc");
	org->pd=0;
	org->ed=dn;
	// ループ処理の保存エリア
	if((org->loop = (PW_LOOP*)malloc(30*sizeof(PW_LOOP)) )==NULL)    err("loop malloc");
	org->pl=0;
	org->el=30;
	// includeのネスト
	org->nst=0;

	return(org);
}
//*********************************************************************
// includeタグで ddに値を取り込んでいく
//*********************************************************************
addinclude(
	char	dd[],		// include のファイル名
	char	str[],		// タグの値
	char	dt[],		// 取り込み中の１行
	int		pt,			// その位置
	char	*ifg
){
	int		i,t;

	if(*ifg==' ')	dd[0]=0;
	for(i=0;i<100;i++){
		if(dd[i]==0)	break;
	}
	for(t=0;i<100;t++,i++){
		dd[i]=str[t];
		if(dd[i]==0)	break;
	}
	for(;i<100;pt++,i++){
		dd[i]=dt[pt];
		if(dd[i]<=' '){
			*ifg='B';
			break;
		}
		if(dd[i]=='#'){
			*ifg='A';
			break;
		}
	}
	dd[i]=0;
//printf("AAAA dd=%s,str=%s,dt=%s BBB<br>\n",dd,str,dt);
	return(pt);
}
//*********************************************************************
//	エリアをどのくらい使ったか
// デバックの時に使う
//*********************************************************************
orginfo(org)
	ORG		*org;
{
	printf("ln=%d-%d dn=%d-%d <br>\n",org->pa,org->ea,org->pd,org->ed);
}
//*********************************************************************
// ORGを開放する
//*********************************************************************
orgend(
	ORG		*org
){
	free(org->arry);
	free(org->dt);
	free(org->loop);
	free(org);
}
//*********************************************************************
// 変数に値を保存する
// 文字列変数対応
//*********************************************************************
orgput(
	ORG		*org,
	char	*str,
	char	*nam,
	int		n0,
	int		n1,
	int		n2,
	int		n3,
	int		n4
){
	int		i,t,e,n;

	// 変数名を保存する
	e=org->pa;
	if((org->pd+30) > org->ed)		err("(org->pd+30) > org->ed");
	org->arry[e].nam = org->dt+org->pd;
	for(i=0;i<29;i++){
		org->arry[e].nam[i]=nam[i];
		if(nam[i]==0)		break;
	}
	org->arry[e].nam[i]=0;
	org->pd += i+1;
		org->arry[e].ec=0;
	if(n0<0)	goto next;
		org->arry[e].ec=1;
		org->arry[e].cnt[0]=n0;
	if(n1<0)	goto next;
		org->arry[e].ec=2;
		org->arry[e].cnt[1]=n1;
	if(n2<0)	goto next;
		org->arry[e].ec=3;
		org->arry[e].cnt[2]=n2;
	if(n3<0)	goto next;
		org->arry[e].ec=4;
		org->arry[e].cnt[3]=n3;
	if(n4<0)	goto next;
		org->arry[e].ec=5;
		org->arry[e].cnt[4]=n4;

next:;
	// 変数値を保存する
	n = org->ed - org->pd-1;
	org->arry[e].str = org->dt+org->pd;
	for(t=0;t<n;t++){
		org->arry[e].str[t] = str[t];
		if(str[t]==0)	break;
	}
	org->arry[e].str[t] = 0;
	org->pd += t+1;
	// 繰り返し回数
	org->arry[e].pr  = atoi(org->arry[e].str);		// 2004.5.6
	org->arry[e].kbn=' ';

	if(org->pa < org->ea)	org->pa++;
}
//*********************************************************************
// 変数に値を保存する
// 数値変数に対応
//*********************************************************************
orgiput(
	ORG		*org,
	int		pr,
	char	*nam,
	int		n0,
	int		n1,
	int		n2,
	int		n3,
	int		n4
){
	int		i,t,e,n;

	e=org->pa;
	org->arry[e].nam = org->dt+org->pd;
	for(i=0;i<29;i++){
		org->arry[e].nam[i]=nam[i];
		if(nam[i]==0)		break;
	}
	org->arry[e].nam[i]=0;
	org->pd += i+1;
		org->arry[e].ec=0;
	if(n0<0)	goto next;
		org->arry[e].ec=1;
		org->arry[e].cnt[0]=n0;
	if(n1<0)	goto next;
		org->arry[e].ec=2;
		org->arry[e].cnt[1]=n1;
	if(n2<0)	goto next;
		org->arry[e].ec=3;
		org->arry[e].cnt[2]=n2;
	if(n3<0)	goto next;
		org->arry[e].ec=4;
		org->arry[e].cnt[3]=n3;
	if(n4<0)	goto next;
		org->arry[e].ec=5;
		org->arry[e].cnt[4]=n4;

next:;
	// 変数値を保存する
	n = org->ed - org->pd -1;
	org->arry[e].str = org->dt+org->pd;
	strncpy(org->arry[e].str,mjc(pr,10),n);
	n=strlen(org->arry[e].str);
	org->pd += n+1;
	// 繰り返し回数
	org->arry[e].pr  = pr;
	org->arry[e].kbn=' ';

	if(org->pa < org->ea)	org->pa++;
}
//*********************************************************************
// 変数に値を保存する
// char に対応
//*********************************************************************
orgcput(
	ORG		*org,
	char	pr,
	char	*nam,
	int		n0,
	int		n1,
	int		n2,
	int		n3,
	int		n4
){
	int		i,t,e,n;

	e=org->pa;
	org->arry[e].nam = org->dt+org->pd;
	for(i=0;i<29;i++){
		org->arry[e].nam[i]=nam[i];
		if(nam[i]==0)		break;
	}
	org->pd += i+1;
		org->arry[e].ec=0;
	if(n0<0)	goto next;
		org->arry[e].ec=1;
		org->arry[e].cnt[0]=n0;
	if(n1<0)	goto next;
		org->arry[e].ec=2;
		org->arry[e].cnt[1]=n1;
	if(n2<0)	goto next;
		org->arry[e].ec=3;
		org->arry[e].cnt[2]=n2;
	if(n3<0)	goto next;
		org->arry[e].ec=4;
		org->arry[e].cnt[3]=n3;
	if(n4<0)	goto next;
		org->arry[e].ec=5;
		org->arry[e].cnt[4]=n4;

next:;
	// 変数値を保存する
	if((org->ed - org->pd)<2)	err("org->pd<2");
	org->arry[e].str = org->dt+org->pd;
	*(org->arry[e].str) = pr;
	*(org->arry[e].str+1) = 0;
	org->pd += 2;
	org->arry[e].pr  = 0;
	org->arry[e].kbn=' ';
	if(org->pa < org->ea)	org->pa++;
}
//*********************************************************************
// 変数に値を保存する
// orgファイル中の##タグで指定された変数値を使う
//*********************************************************************
orgkput(
	ORG		*org,
	char	*str,
	char	*nam,
	int		n0,
	int		n1,
	int		n2,
	int		n3,
	int		n4
){
	int		i,t,e,n;

	// 変数名を保存する
	e=org->pa;
	if((org->pd+30) > org->ed)		err("(org->pd+30) > org->ed");
	org->arry[e].nam = org->dt+org->pd;
	for(i=0;i<29;i++){
		org->arry[e].nam[i]=nam[i];
		if(nam[i]==0)		break;
	}
	org->arry[e].nam[i]=0;
	org->pd += i+1;
		org->arry[e].ec=0;
	if(n0<0)	goto next;
		org->arry[e].ec=1;
		org->arry[e].cnt[0]=n0;
	if(n1<0)	goto next;
		org->arry[e].ec=2;
		org->arry[e].cnt[1]=n1;
	if(n2<0)	goto next;
		org->arry[e].ec=3;
		org->arry[e].cnt[2]=n2;
	if(n3<0)	goto next;
		org->arry[e].ec=4;
		org->arry[e].cnt[3]=n3;
	if(n4<0)	goto next;
		org->arry[e].ec=5;
		org->arry[e].cnt[4]=n4;

next:;
	// 変数値を保存する
	n = org->ed - org->pd-1;
	org->arry[e].str = org->dt+org->pd;
	for(t=0;t<n;t++){
		org->arry[e].str[t] = str[t];
		if(str[t]==0)	break;
	}
	org->arry[e].str[t] = 0;
	org->pd += t+1;
	org->arry[e].kbn='K';			// orgkput 用

	if(org->pa < org->ea)	org->pa++;
}
//*********************************************************************
// orgファイル中の##タグで指定された変数と変数値を取り込む
//*********************************************************************
orgkget(
	ORG		*org,
	unsigned char	*dd
){
	int		i,t,e,n;

	// 変数名を保存する
	e=org->pa;
	if((org->pd+30) > org->ed)		err("(org->pd+30) > org->ed");
	org->arry[e].nam = org->dt+org->pd;
	for(i=0;i<29;i++){
		org->arry[e].nam[i]=dd[i];
		if(dd[i]=='=')		break;
		if(dd[i]==':')		return(0);
	}
	org->arry[e].nam[i]=0;
	org->pd += i+1;
	// 変数値を保存する
	n = org->ed - org->pd-1;
	org->arry[e].str = org->dt+org->pd;
	i++;
	for(t=0;t<n;t++,i++){
		org->arry[e].str[t] = dd[i];
		if(dd[i]==0x0D)	break;
		if(dd[i]==0x0A)	break;
		if(dd[i]==0)	break;
	}
	org->arry[e].str[t] = 0;
	org->pd += t+1;
	org->arry[e].kbn='k';			// orgkputのorg 用

	if(org->pa < org->ea)	org->pa++;
}
//*********************************************************************
// includeファイルの取り込み
// ファイルポインターを保存し新しくファイルを開く
//*********************************************************************
orginclude(
	ORG		*org,
	FILE	**fp,
	char	fnam[]
){
	int		i,t,e,n;

	if(org->nst>=10)		err("org->nst>=9");
	org->fp[org->nst]=*fp;
	chop(fnam,100);
	if((*fp=fopen(fnam,"r"))==NULL)		err(fnam);
	org->nst++;
}
//*********************************************************************
// includeファイルからの脱出
// ファイルが終了したら そのファイルをクローズし元のファイルポインターに戻す
//*********************************************************************
orgreclude(
	ORG		*org,
	FILE	**fp
){
	if(org->nst<=0)		return(0);
	org->nst--;
	fclose(*fp);
	*fp=org->fp[org->nst];
	return(1);
}
//*********************************************************************
// 文字列比較
//*********************************************************************
memcmppw(dt,dd,n)
	char	dt[],dd[];
	int		n;
{
	int		i;

	for(i=0;i<n;i++){
		if(dt[i]=='*')		continue;		// 2004.4.23
		if(dt[i]!=dd[i])	return(-1);
		if(dt[i]==0)		return(0);
	}
	return(0);
}
//*********************************************************************
//	表示制御で未表示部分をスキップする
//*********************************************************************
pageskip(
	FILE			*fp,
	unsigned char	*dt,
	int				pt,
	long			*sp
){
	int		i,nst;
	char	fg;

	nst=1;
	for(i=pt,fg=' ';i<1000;i++){
		if(dt[i]==0){
			*sp=ftell(fp);
			if(fgets(dt,1000,fp)==NULL)		break;
			i=0;
			fg=' ';
		}
		if(dt[i]<=' ')		fg=' ';
		if(dt[i]=='#'){
			if(fg==' '){				// １個目の#
				if(dt[i+2]=='#'){
					if(dt[i+1]=='}')	nst--;			// #}#
					if(dt[i+1]==']')	nst--;			// #]#
					if(nst==0)		return(i+3);
				}else
				if(dt[i+3]=='#'){						// #][#
					if(dt[i+1]==']')	nst--;
					if(nst==0)		return(i+4);
					if(dt[i+2]=='[')	nst++;
				}
				if(dt[i+1]=='{')	fg='A';				// #{xxxxx#
				if(dt[i+1]=='[')	fg='A';				// #[xxxxx#
			}else{						// ２個目の#
				nst++;
				fg=' ';
			}
		}
	}
}
//*********************************************************************
// ループ開始時の処理
//*********************************************************************
loophed(
	ORG				*org,
	FILE			*fp,
	unsigned char	*dt,
	int				pt,
	long			*sp
){
	PW_TAG	tag;
	int		e,pl;
	char	fg;

	tag.ec=0;
	pt=chktag(&tag,dt,pt,2,&fg);
	if(fg==' ')		return(pt);
	e=machtag(org,&tag);
	if(e<0)						return(pageskip(fp,dt,pt,sp));
	if(org->arry[e].pr==0)		return(pageskip(fp,dt,pt,sp));
	pl=org->pl;
	memcpy(org->loop[pl].nam, tag.nam[0], sizeof(org->loop[pl].nam));
	org->loop[pl].sp=*sp;
	org->loop[pl].pt=pt;
	org->loop[pl].cnt=org->arry[e].pr;
	org->loop[pl].n = 0;
	// loop のエリアを１つ進める
	if(pl<org->el)		org->pl++;
	return(pt);
}
//*********************************************************************
// loop終了時の処理
//*********************************************************************
loopend(
	ORG				*org,
	FILE			*fp,
	unsigned char	*dt,
	int				pt,
	long			*sp
){
	int		pl;

	pl=org->pl-1;
	// カウントがまだ残っていたら ｛まで戻す
	org->loop[pl].n++;
	if(org->loop[pl].cnt > org->loop[pl].n){
		fseek(fp,org->loop[pl].sp,0);
		*sp=org->loop[pl].sp;
		fgets(dt,1000,fp);
		return(org->loop[pl].pt);
	}else{
		// loop エリアを１つ戻す
		org->pl--;
		return(pt+3);
	}
}
//*********************************************************************
//	org のタグかを調べる
//	orgのタグなら内容をtagに取り込む
//*********************************************************************
chktag(
	PW_TAG			*tag,
	unsigned char	*dt,
	int				pt,
	int				n,						// 戻る時のづれの調整
	char			*fg
){
	int		t,r,k;

	*fg=' ';
	r=0;
	for(t=pt+n,k=0;t<1000;t++){
		if(dt[t]<=' ')		return(pt);
		if(dt[t]=='>')		return(pt);
		if(dt[t]=='.'){				// . があると設定されている名称を tag.nam に取り込む
			tag->nam[r][k]=0;
			tag->ec=r;
			r++;
			if(r>=10)	return(pt);
			k=0;
		}else
		if(dt[t]=='#'){				// org タグだった
			tag->nam[r][k]=0;
			tag->ec=r;
			r++;
			*fg='A';
			return(t+1);
		}else{
			tag->nam[r][k]=dt[t];
			k++;
			if(k>30)	return(pt);
		}
	}
}
//*********************************************************************
// 表示制御開始処理
// 変数に対応する文字を探す
//*********************************************************************
machtag(
	ORG		*org,
	PW_TAG	*tag
){
	int		i,t,ec,pl,pa;
	char	*str;

	// tag のパラメータ部の名前に対応した loop の現在の数値を取り込む
	ec=tag->ec;
	pl=org->pl;
	for(i=0;i<ec;i++){
		// パラメータ部が数字ならそのまま使う
		if(suji(tag->nam[i+1],30)==1){
			tag->cnt[i]=atoi(tag->nam[i+1]);
			continue;
		}
		for(t=0;t<pl;t++){
			if(memcmppw(org->loop[t].nam,tag->nam[i+1],30)<0)	continue;
			tag->cnt[i]=org->loop[t].n;
			break;
		}
	}
	// tag の先頭の名前と各パラメータに対応した arry を探す
	pa=org->pa;
	for(i=0;i<pa;i++){
		if(tag->ec != org->arry[i].ec)		continue;
		if(memcmppw(org->arry[i].nam,tag->nam[0],30)<0)	continue;
		for(t=0;t<ec;t++){
			if(org->arry[i].cnt[t]!=tag->cnt[t])		goto next;
		}
		if(org->arry[i].kbn==' ')		return(i);
		// orgkput タイプ
		str=org->arry[i].str;
		for(i=0;i<pa;i++){
			if(org->arry[i].kbn!='k')	continue;
			if(memcmppw(org->arry[i].nam,str,30)==0)	return(i);
		}
next:;
	}
	return(-1);
}
suji(dt,n)
	char	dt[];
	int		n;
{
	int		i;

	for(i=0;i<n;i++){
		if(dt[i]==0)	return(1);
		if(dt[i]<'0')	return(-1);
		if(dt[i]>'9')	return(-1);
	}
	return(1);
}
//*********************************************************************
// ORG 関係関数終了
//*********************************************************************

/************************************
// 数字を文字に直す
// 終端の 0 を入れる
************************************/
char *mjc(a,n)
	int		a,n;
{
	static unsigned char	dd[100];
	static int		pt=0;
	int				i,u;

	if((pt+n)>90)		pt=0;
	u=a;
	if(a<0)		a = (a ^ 0xFFFFFFFF) + 1;
	dd[pt+n+1]=0;
	for(i=n;i>=1;i--){
		if(i<n && a==0)		break;
		dd[pt+i] = a%10+'0';
		a = a/10;
	}
//	for(i--;i>=1;i--)	dd[pt+i]='0';
	if(u<0){
		dd[pt+i]='-';
		i--;
	}
	u=pt+i+1;
	pt=pt+n+1;
	return(dd+u);
}
//*************************************
// 文字列の最後にある 0x0a 0x0d を取る
//*************************************
chop(
	unsigned char	dt[],
	int				n
){
	int		i;

	for(i=0;i<n;i++){
		if(dt[i]<' ')	break;
	}
	dt[i]=0;
}
//**************************************
// エラー表示の簡易関数
// エラー終了のメッセージを出して終了する
//**************************************
orgerr(msg)
	char	msg[];
{
	printf("error %s\n",msg);
	exit(-1);
}


