#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "struct.h"
#include "ctype.h"

/**/
extern char **Messages;

void C_Done()
{
	;
}

void C_Ok()
{
	UPrintf("Ok\n");
}

void C_Msg()
{
	PMsg(Arg());
}

int Q_Get()
{
	tag i=Arg();
	if(CanPut(i,Me())==0)
	{
		UPrintf("You can't carry that.\n");
		return(0);
	}
	MoveItem(i,Me());
	DoesT(Me(),"takes",17,i);
	return(1);
}

void C_Drop()
{
	tag i=Arg();
	MoveItem(i,LOC(Me()));
	DoesT(Me(),"drops",17,i);
}

void C_Place()
{
	tag i=Arg();
	tag j=Arg();
	MoveItem(i,j);
}

void C_Call()
{
	ExecTable(NUM(Arg()));
}

void C_Ld()
{
	int a=Arg();
	SysFlags[FLAG(a)]=Arg();
}

int Q_NumOf()
{
	int v;
	int a=MSG(Arg());
	int r;
	r=sscanf(Messages[a],"%d",&v);
	if(r==0)
	{
		Arg();
		return(r);
	}
	SysFlags[FLAG(Arg())]=v;
	return(1);
}

void C_LdF()
{
	int a=Arg();
	SysFlags[FLAG(a)]=SysFlags[FLAG(Arg())];
}

void C_Print()
{
	UPrintf("%d",NUM(Arg()));
}


/*
 *	FixMe: enforce 0-127 ranging
 */
 
void C_LdO()
{
	tag a=Arg();
	tag b=Arg();
	SysFlags[FLAG(a)]=OBJECT(b)->ob_Data[NUM(Arg())];
}

void C_LdR()
{
	tag a=Arg();
	tag b=Arg();
	SysFlags[FLAG(a)]=ROOM(b)->rm_Data[NUM(Arg())];
}

void C_LdP()
{
	tag a=Arg();
	tag b=Arg();
	SysFlags[FLAG(a)]=PLAYER(b)->pl_Data[NUM(Arg())];
}

void C_SetO()
{
	tag a=Arg();
	tag b=Arg();
	OBJECT(a)->ob_Data[NUM(b)]=Arg();
}

void C_SetP()
{
	tag a=Arg();
	tag b=Arg();
	PLAYER(a)->pl_Data[NUM(b)]=Arg();
}

void C_SetR()
{
	tag a=Arg();
	tag b=Arg();
	ROOM(a)->rm_Data[NUM(b)]=Arg();
}

void C_Mul()
{
	tag a=Arg();
	tag t=SysFlags[FLAG(a)]*NUM(Arg());
/*	if(!IFNUM(t))
	{
		log_error("[DATABASE ERROR]: MUL overflow.\n",NULL);
		panic();
	}*/
	SysFlags[FLAG(a)]=ISNUM(t);
}

void C_Div()
{
	tag a=FLAG(Arg());
	tag b=NUM(Arg());
	if(b==0)
	{
		log_error("[DATABASE ERROR]: Division by Zero\n",NULL);
		panic();
	}
	SysFlags[a]=ISNUM(SysFlags[a]/b);
}

void C_Add()
{
	tag a=FLAG(Arg());
	tag t;
/*	NUM(SysFlags[a]); */
	t=SysFlags[a]+NUM(Arg());
/*	if(!IFNUM(t))
	{
		log_error("[DATABASE ERROR]: Add - range error\n",NULL);
		panic();
	}*/
	SysFlags[a]=ISNUM(t);
}

void C_Sub()
{
	tag a=FLAG(Arg());
	tag t=SysFlags[a]-NUM(Arg());
/*	if(!IFNUM(t))
	{
		log_error("[DATABASE ERROR]: Sub - range error\n",NULL);
		panic();
	}*/
	SysFlags[a]=ISNUM(t);
}

void C_Set()
{
	tag a=FLAG(Arg());
	tag b=NUM(Arg());
	if((b<0||b>28)&&(b!=31))
	{
		log_error("[DATABASE ERROR]: Set - bad bit\n",NULL);
		panic();
	}
	SysFlags[a]|=(1<<b);
}

void C_Res()
{
	tag a=FLAG(Arg());
	tag b=NUM(Arg());
	if((b<0||b>28)&&(b!=31))
	{
		log_error("[DATABASE ERROR]: Set - bad bit\n",NULL);
		panic();
	}
	SysFlags[a]&=~(1<<b);
}

void C_Inc()
{
	tag a=Arg();
	if(STATE(a)<MAXSTATE(a))
		SetState(a,STATE(a)+1);
}

void C_Dec()
{
	tag a=Arg();
	if(STATE(a))
		SetState(a,STATE(a)-1);
}

void C_SetState()
{
	tag a=Arg();
	tag b=NUM(Arg());
	SetState(a,b);
}

void C_DoAct()
{
	tag a=Arg();
	tag b=Arg();
	tag c=Arg();
	Does(a,b,c,ISOBJ(-1));
}

void C_DoTo()
{
	tag a=Arg();
	tag b=Arg();
	tag c=Arg();
	tag d=Arg();
	Does(a,b,c,d);
}

void C_Score()
{
	UPrintf("Your score is %d\n",SCORE(Me()));
}

void C_Look()
{
	int ct;
	if(FLAGS(Me())&PFL_BLIND)
		return;
	MarkClean(Me());
	if((Me()<ISOBJ(MAXU))&&(Me()>ISOBJ(0)))
		WriteToHandle(UserArray[OBJ(Me())].us_Handle,PK_IDSC,"");
	if(LOC(Me())==ISOBJ(-1))
	{
		UPrintf("You are no more.\n");
		goto l2;
	}
	if(TYPE(LOC(Me()))!=FL_ROOM)
	{
		UPrintf("You are in %s.\n",NAME(LOC(Me())));
		goto l1;
	}
	if(Q_Dark())
	{
		UPrintf("It is dark.\n");
		if((Me()<ISOBJ(MAXU))&&(Me()>ISOBJ(0)))
			WriteToHandle(UserArray[OBJ(Me())].us_Handle,PK_EDSC,"");
		return;
	}
ndchk:	UPrintf("%s\n",ROOM(LOC(Me()))->rm_Name);
	if(FLAGS(Me())&PFL_BRIEF)
		goto brief;
	UPrintf("%s\n",ROOM(LOC(Me()))->rm_Long);
	ExecTable(2);
	ct=OBJECT(LOC(Me()))->ob_Child;	/* DO HERE - Tab 2 might move things !! */
	while(ct != -1)
	{
		if(ISITEM(ct)&&TYPE(ct)==FL_OBJECT&&
		   (FLAGS(ct)&OFL_FLANNEL))
		{
			if(strlen(ODESC(ct,STATE(ct))))
				UPrintf("%s\n",ODESC(ct,STATE(ct)));
		}
		ct=OBJECT(ct)->ob_Next;
	}
l1:;
brief:	ct=OBJECT(LOC(Me()))->ob_Child;
	while(ct != -1)
	{
		if(ISITEM(ct)&&(TYPE(ct)==FL_PLAYER)&&(CANSEE(Me(),ct))&&
			(ct!=Me()))
		{
			UPrintf("%s %s",MakeCName(ct),PLAYER(ct)->pl_IOH[0]);
			ChkCarried(ct);
		}
		ct=OBJECT(ct)->ob_Next;
	}
	DoLobjl(LOC(Me()));
	ExecTable(3);
l2:	if((Me()<ISOBJ(MAXU))&&(Me()>ISOBJ(-1)))
		WriteToHandle(UserArray[Me()].us_Handle,PK_EDSC,"");
}

void ChkCarried(x)
tag x;
{
	int ct=OBJECT(x)->ob_Child;
	while(ct != -1)
	{
		if(ISITEM(ct))
		{
			UPrintf(" carrying ");
			Lobs(x);
			UPrintf("\n");
			return;
		}
		ct=OBJECT(ct)->ob_Next;
	}
	UPrintf(".\n");
}

void C_DoLobj()
{
	DoLobjl(Arg());
}

void DoLobjl(x)
tag x;
{
	tag ct=OBJECT(x)->ob_Child;
	while(ct != -1)
	{
		if(ISITEM(ct)&&(TYPE(ct)==FL_OBJECT)&&
			((FLAGS(ct)&OFL_FLANNEL)==0))
		{
			UPrintf("%s\n",ODESC(ct,STATE(ct)));
		}
		ct=OBJECT(ct)->ob_Next;
	}
}

void C_Lobjs()
{
	tag a=Arg();
	Lobs(a);
}

void Lobs(a)
tag a;
{
	tag ct=OBJECT(a)->ob_Child;
	tag hfn1= ISOBJ(-1);
	int h1=0;
	while(ct != -1)
	{
		if(ISITEM(ct))
		{
			if(hfn1!=-1)
			{
				h1=1;
				UPrintf("%s, ",NAME(hfn1));
			}
			hfn1=ct;
		}
		ct=OBJECT(ct)->ob_Next;
	}
	if(hfn1!=ISOBJ(-1))
	{
		if(h1)
			UPrintf("and %s.",NAME(hfn1));
		else
			UPrintf("%s.",NAME(hfn1));
	}
	else
		UPrintf("nothing.");
}

void C_PName()
{
	tag a=Arg();
	UPrintf("%s",NAME(a));
}

void C_PDesc()
{
	tag a=Arg();
	tag b=NUM(Arg());
	if(TYPE(a)!=FL_OBJECT)
	{
		log_error("[DATABASE ERROR]: PDesc - needs object.\n",NULL);
		panic();
	}
	UPrintf("%s",ODESC(a,b));
}

void C_PLong()
{
	tag a=Arg();
	if(TYPE(a)!=FL_ROOM)
	{
		log_error("[DATABASE ERROR]: PLong - needs room.\n",NULL);
		panic();
	}
	UPrintf("%s\n",ROOM(a)->rm_Long);
}

void C_JP()
{
	NextLineMove(NUM(Arg()));
}

void C_CR()
{
	UPrintf("\n");
}

void C_MsgCR()
{
	C_Msg();
	C_CR();
}

Q_Z()
{
	return(SysFlags[FLAG(Arg())]==0);
}

Q_Eq()
{
	tag a=FLAG(Arg());
	return(SysFlags[a]==Arg());
}

Q_Gt()
{
	tag a=FLAG(Arg());
	return(SysFlags[a]>Arg());
}

Q_Lt()
{
	tag a=FLAG(Arg());
	return(SysFlags[a]<Arg());
}

Q_At()
{
	return(LOC(Me())==Arg());
}

Q_Is()
{
	tag a=Arg();
	return(TYPE(a)==NUM(Arg()));
}

Q_Bit()
{
	tag a=FLAG(Arg());
	return(SysFlags[a]&(1<<NUM(Arg())));
}

Q_IsAt()
{
	tag a=Arg();
	return(LOC(a)==Arg());
}

Q_Here()
{
	tag a=Arg();
	return(LOC(Me())==LOC(a));
}

Q_Pres()
{
	tag x=Arg();
	tag a=LOC(x);
	return((a==Me())||(a==LOC(Me())));
}

Q_Dark()
{
	if((FLAGS(LOC(Me()))&RFL_DARK)==0)
		return(0);
	return(IsDark(LOC(Me()),Me()));
}

Q_State()
{
	tag a=Arg();
	return(STATE(a)==NUM(Arg()));
}

Q_Chance()
{
	return((rand()%10000)<(NUM(Arg())));
}

Q_OBit()
{
	tag n=Arg();
	if(FLAGS(n)&(1<<NUM(Arg())))
		return(1);
	return(0);
}

Q_PBit()
{
	tag n=Arg();
	if(FLAGS(n)&(1<<NUM(Arg())))
		return(1);
	return(0);
}

Q_RBit()
{
	tag n=Arg();
	if(FLAGS(n)&(1<<NUM(Arg())))
		return(1);
	return(0);
}

Q_CanSee()
{
	tag a=Arg();
	tag b=Arg();
	if(TYPE(b)==FL_PLAYER)
	{
		if(!CANSEE(a,b))
			return(0);
	}
	if(LOC(a)==LOC(b)&&IsDark(LOC(a),a))
	{
		return(0);
	}
	return(1);
}

Q_Level()
{
	if(LEVEL(Me())>=NUM(Arg()))
		return(1);
	return(0);
}

Q_Arch()
{
	extern char *ArchName[];
	int ct=0;
	int a=Arg();
	while(ct<16)
	{
		if(ArchName[ct]==NULL)
			break;
		if(strcmp(NAME(a),ArchName[ct])==0)
			return(1);
		ct++;
	}
	return(0);
}

Q_Called()
{
	tag a=Arg();
	tag b=MSG(Arg());
	return(strcmp(NAME(a),Messages[b])==0);
}

Q_Weighs()
{
	return(Weight(Me())>=NUM(Arg()));
}

Q_CanPut()
{
	tag a=Arg();
	return(CanPut(a,Arg()));
}

Q_Got()
{
	tag a=Arg();
	return(LOC(a)==Me());
}


void C_Exit()
{
	extern USER UserArray[];
	OBJ(Me());
	if(Me()<ISOBJ(MAXU)&&Me()>=ISOBJ(0))
		WriteToHandle(UserArray[Me()].us_Handle,PK_DISC,"forum");
	Exit_Player(SysFlags[0]);
}

void C_Save()
{
	OBJ(Me());
	UPrintf("Saving %s.\n",NAME(Me()));
	SaveUser(Me(),NAME(Me()));
	UPrintf("Ok.\n");
}

Q_Neil()
{
	static tag pa,pb;
	tag a=Arg();
	tag b=OBJ(Arg());
	if(b==-1)
	{
		b=OBJECT(a)->ob_Child;
		if(b==-1)
		{
			Arg();
			return(0);
		}
		pa=a;
		pb=OBJECT(b)->ob_Next; /* Cache one */
		SysFlags[FLAG(Arg())]=b;
		return(1);
	}
	if(LOC(b)!=a)
	{
		if(pa==a)
		{
			b=pb;
			goto resync;
		}
		Arg();
		return(0);
	}
	b=OBJECT(b)->ob_Next;
resync:	if(b==-1)
	{
		Arg();
		return(0);
	}
	pa=a;
	pb=OBJECT(b)->ob_Next;	/* Cache one ahead */
	SysFlags[FLAG(Arg())]=b;
	return(1);
}

void C_GetWords()
{
	tag a=Arg();
	SysFlags[FLAG(Arg())]=ADJ(a);
	SysFlags[FLAG(Arg())]=NOUN(a);
}

void C_Parse()
{
	char a[256];
	strncpy(a,Messages[MSG(Arg())],255);
	a[255]=0;
	if(Parser(a))
	{
		WhatThings();
		ExecTable(0);
	}
}

void C_TabTo()
{
	/*OBJ(SysFlags[0]);*/
	Set_Tab(SysFlags[0],NUM(Arg()));
}

void C_Prompt()
{
	if(Me()>=ISOBJ(0)&&Me()<ISOBJ(MAXU))
		WriteToHandle(UserArray[Me()].us_Handle,PK_PRMP,Messages[Arg()]);
}

void C_AutoVerb()
{
	UPrintf("Not currently implemented!\n");
}

void C_Append()
{
	tag fv=MSG(Arg());
	tag m=MSG(Arg());
	FILE *f=fopen(Messages[fv],"a");
	if(f)
	{
		fprintf(f,"%s\n",Messages[m]);
		fclose(f);
	}
	else
	{
		UPrintf("Can't access file!\n");
	}
}

Q_Type()
{
#ifndef UNIX
	/* Kludge to translate filenames to a TOS-like form */
	extern char *f_tos();
	FILE *f=fopen(f_tos(Messages[MSG(Arg())]),"r");
#else
	FILE *f=fopen(Messages[MSG(Arg())],"r");
#endif
	char buf[128];
	if(f)
	{
		while(fgets(buf,127,f))
			UPrintf("%s",buf);
		fclose(f);
		return(1);
	}
	return(0);
}

Q_NextMatch()
{
	tag a=Arg();
	tag b=Arg();
	tag c=Arg();
	tag d=Arg();
	tag e=FLAG(Arg());
	SysFlags[e]=NextIn(a,b,c,d);
	if(SysFlags[e]==-1)
		return(0);
	return(1);
}
	

Q_NextGMatch()
{
	tag a=Arg();
	int b=NUM(Arg());
	int c=NUM(Arg());
	int e=FLAG(Arg());
	SysFlags[e]=NextAny(a,b,c);
	if(SysFlags[e]==-1)
		return(0);
	return(1);
}
	

void C_Random()
{
	long t;
	int a=FLAG(Arg());
	time(&t);
	SysFlags[a]=(rand()^t)%10000;
}

void C_PwChange()
{
	int a=VAL(Me());
	int h;
	OBJ(Me());	/* do type check anyway */
	if(a<0||a>=MAXU)
	{
		log_error("[DATABASE ERROR]: PWChange not valid for non user.\n",NULL);
		panic();
	}
	h=UserArray[a].us_Handle;
	WriteToHandle(h,PK_PRMP,"Current Password: ");
	WriteToHandle(h,PK_NECH,NULL);
	UserArray[a].us_State=US_CPWC;
}

void C_PwForce()
{
	char *u=Messages[MSG(Arg())];
	char *pw=Messages[MSG(Arg())];
	ForcePassword(u);
}

void C_MkPlayer()
{
	int m=MSG(Arg());
	int a=FLAG(Arg());
	tag b;
	SysFlags[a]=(b=AddPlayer());
	OBJECT(b)->ob_Child= -1;
	OBJECT(b)->ob_Next= -1;
	AddName(Messages[m],b,1);
}

void C_MkRoom()
{
	int m=MSG(Arg());
	int a=FLAG(Arg());
	tag b;
	SysFlags[a]=(b=AddRoom());
	OBJECT(b)->ob_Child= -1;
	OBJECT(b)->ob_Next= -1;
	AddName(Messages[m],b,1);
}

void C_MkObject()
{
	int m=MSG(Arg());
	int a=FLAG(Arg());
	tag b;
	SysFlags[a]=(b=AddObject());
	OBJECT(b)->ob_Child= -1;
	OBJECT(b)->ob_Next= -1;
	AddName(Messages[m],b,1);
}

void C_PCName()
{
	char *c;
	char x;
	int a=Arg();
/*	OBJ(a); */
	c=NAME(a);
	x= *c;
	if(islower(x))
		*c=toupper(x);
	UPrintf("%s",NAME(a));
	*c=x;
}

void C_MFormat()
{
/*
 *	Be careful with this routine.. make sure panics occur before
 *	result is malloc'd or you will get a memory leak..
 */
	int s=MSG(Arg());
	int t=Arg();
	int sm[2];
	char *result;
	tag si[3];
	int l=0;
	char *sp=Messages[s];
/*	MSG(t); */
	sm[0]=Arg();
	sm[1]=Arg();
	si[0]=Arg();
	si[1]=Arg();
	si[2]=Arg();
/*	MSG(sm[0]);
	MSG(sm[1]);
	OBJ(si[0]);
	OBJ(si[1]);
	OBJ(si[2]);*/
	while(*sp)
	{
		if(*sp=='%')
		{
			sp++;
			switch(*sp)
			{
				case '%':l++;break;
				case 'N':switch(*++sp)
				{
					case '0':l+=strlen(NAME(si[0]));break;
					case '1':l+=strlen(NAME(si[1]));break;
					case '2':l+=strlen(NAME(si[2]));break;
					default:FormErr(t);return;
				}
				break;
				case 'n':switch(*++sp)
				{
					case '0':l+=strlen(NAME(si[0]));break;
					case '1':l+=strlen(NAME(si[1]));break;
					case '2':l+=strlen(NAME(si[2]));break;
					default:FormErr(t);return;
				}
				break;
				case 'd':switch(*++sp)
				{
					case '0':l+=strlen(ODESC(si[0],STATE(si[0])));break;
					case '1':l+=strlen(ODESC(si[1],STATE(si[1])));break;
					case '2':l+=strlen(ODESC(si[2],STATE(si[2])));break;
					default:FormErr(t);return;
				}
				break;
				case 'h':switch(*++sp)
				{
					case '0':l+=strlen(PLAYER(si[0])->pl_IOH[0]);break;
					case '1':l+=strlen(PLAYER(si[1])->pl_IOH[0]);break;
					case '2':l+=strlen(PLAYER(si[2])->pl_IOH[0]);break;
					default:FormErr(t);return;
				}
				break;
				case 'l':switch(*++sp)
				{
					case '0':l+=strlen(PLAYER(si[0])->pl_IOH[1]);break;
					case '1':l+=strlen(PLAYER(si[1])->pl_IOH[1]);break;
					case '2':l+=strlen(PLAYER(si[2])->pl_IOH[1]);break;
					default:FormErr(t);return;
				}
				break;
				case 'a':switch(*++sp)
				{
					case '0':l+=strlen(PLAYER(si[0])->pl_IOH[2]);break;
					case '1':l+=strlen(PLAYER(si[1])->pl_IOH[2]);break;
					case '2':l+=strlen(PLAYER(si[2])->pl_IOH[2]);break;
					default:FormErr(t);return;
				}
				break;
				case 'm':switch(*++sp)
				{
					case '0':l+=strlen(Messages[sm[0]]);break;
					case '1':l+=strlen(Messages[sm[1]]);break;
					default:FormErr(t);return;
				}
				break;
				case 'r':switch(*++sp)
				{
					case '0':l+=strlen(RDESC(si[0]));break;
					case '1':l+=strlen(RDESC(si[1]));break;
					case '2':l+=strlen(RDESC(si[2]));break;
					default:FormErr(t);return;
				}
				break;
				case 'T':switch(*++sp)
				{
					case '0':l+=strlen(TrueName(si[0]));break;
					case '1':l+=strlen(TrueName(si[1]));break;
					case '2':l+=strlen(TrueName(si[2]));break;
					default:FormErr(t);return;
				}
			}
		}
		else
			l++;
		sp++;
	}
	result=(char *)emalloc(l+1);
	*result=0;
	sp=Messages[s];
	while(*sp)
	{
		if(*sp=='%')
		{
			sp++;
			switch(*sp)
			{
				case '%':strcat(result,"%");break;
				case 'N':switch(*++sp)
				{
					case '0':strcat(result,MakeCName(si[0]));break;
					case '1':strcat(result,MakeCName(si[1]));break;
					case '2':strcat(result,MakeCName(si[2]));break;
					default:FormErr(t);return;
				}
				break;
				case 'n':switch(*++sp)
				{
					case '0':strcat(result,NAME(si[0]));break;
					case '1':strcat(result,NAME(si[1]));break;
					case '2':strcat(result,NAME(si[2]));break;
					default:FormErr(t);return;
				}
				break;
				case 'd':switch(*++sp)
				{
					case '0':strcat(result,ODESC(si[0],STATE(si[0])));break;
					case '1':strcat(result,ODESC(si[1],STATE(si[1])));break;
					case '2':strcat(result,ODESC(si[2],STATE(si[2])));break;
					default:FormErr(t);return;
				}
				break;
				case 'h':switch(*++sp)
				{
					case '0':strcat(result,PLAYER(si[0])->pl_IOH[0]);break;
					case '1':strcat(result,PLAYER(si[1])->pl_IOH[0]);break;
					case '2':strcat(result,PLAYER(si[2])->pl_IOH[0]);break;
					default:FormErr(t);return;
				}
				break;
				case 'l':switch(*++sp)
				{
					case '0':strcat(result,PLAYER(si[0])->pl_IOH[1]);break;
					case '1':strcat(result,PLAYER(si[1])->pl_IOH[1]);break;
					case '2':strcat(result,PLAYER(si[2])->pl_IOH[1]);break;
					default:FormErr(t);return;
				}
				break;
				case 'a':switch(*++sp)
				{
					case '0':strcat(result,PLAYER(si[0])->pl_IOH[2]);break;
					case '1':strcat(result,PLAYER(si[1])->pl_IOH[2]);break;
					case '2':strcat(result,PLAYER(si[2])->pl_IOH[2]);break;
					default:FormErr(t);return;
				}
				break;
				case 'm':switch(*++sp)
				{
					case '0':strcat(result,Messages[sm[0]]);break;
					case '1':strcat(result,Messages[sm[1]]);break;
					default:FormErr(t);return;
				}
				break;
				case 'r':switch(*++sp)
				{
					case '0':strcat(result,RDESC(si[0]));break;
					case '1':strcat(result,RDESC(si[1]));break;
					case '2':strcat(result,RDESC(si[2]));break;
					default:FormErr(t);return;
				}
				break;
				case 'T':switch(*++sp)
				{
					case '0':strcat(result,TrueName(si[0]));break;
					case '1':strcat(result,TrueName(si[1]));break;
					case '2':strcat(result,TrueName(si[2]));break;
					default:FormErr(t);return;
				}
			}
		}
		else
		{
			char x[2];
			x[0]= *sp;
			x[1]=0;
			strcat(result,x);
		}
		sp++;
	}
	free(Messages[MSG(t)]);
	Messages[MSG(t)]=result;
}

void FormErr(t)
tag t;
{
/*	MSG(t); */
	free(Messages[t]);
	Messages[t]=estralloc("Formatting Error");
	printf("[DATABASE WARNING]: Formatting Error\n");
}

Q_Next()
{
	tag a=Arg()+1;
	int b=Arg();
	tag c=FLAG(Arg());
	while(a<ISOBJ(NObs()))
	{
		if(ISITEM(a)&&(TYPE(a)==b))
		{
			SysFlags[c]=a;
			return(1);
		}
		a++;
	}
	return(0);
}

void C_Trash()
{
	extern struct Word *FindName();
	tag t=Arg();
	struct Word *w=FindName(OBJECT(t)->ob_Name,1);
	Tree_Unlink(t);
	TrashItem(t);
	if(w)
		DelName(w);
}	

void C_SetDesc()
{
	tag n=Arg();
	int v=Arg();
	int m=Arg();
	if(TYPE(n)!=FL_OBJECT)
	{
		log_error("[DATABASE ERROR]: SetDesc only valid on objects.\n",NULL);
		panic();
	}
	SetDesc(n,v,Messages[m]);
}

void C_SetMaxState()
{
	tag n=Arg();
	int m=NUM(Arg());
	if(TYPE(n)!=FL_OBJECT)
	{
		log_error("[DATABASE ERROR]: SetMaxState only valid on objects.\n",NULL);
		panic();
	}
	SetMaxState(n,m);
}

void C_SetLong()
{
	tag n=Arg();
	int m=MSG(Arg());
	if(TYPE(n)!=FL_ROOM)
	{
		log_error("[DATABASE ERROR]: SetLong only valid on rooms.\n",NULL);
		panic();
	}
	SetLong(n,Messages[m]);
}

void C_SetIOH()
{
	tag n=Arg();
	int o=NUM(Arg());
	int m=MSG(Arg());
	if(TYPE(n)!=FL_PLAYER)
	{
		log_error("[DATABASE ERROR]: SetIOH - not valid on non player.\n",NULL);
		panic();
	}
	if(o<0||o>2)
	{
		log_error("[DATABASE ERROR]: SetIOH - invalid option.\n",NULL);
		panic();
	}
	SetIOH(n,o,Messages[m]);
}

void C_SetName()
{
	tag n=Arg();
	int m=MSG(Arg());
	SetName(n,Messages[m]);
}

void C_SetVocab()
{
	tag i=Arg();
	int a=NUM(Arg());
	int n=NUM(Arg());
	ADJ(i)=a;
	NOUN(i)=n;
}

	
void C_Length()
{
	int a=MSG(Arg());
	SysFlags[FLAG(Arg())]=strlen(Messages[a]);
}

void C_AddWord()
{
	char *wn=Messages[MSG(Arg())];
	int wt=NUM(Arg());
	int wv=NUM(Arg());
	AddWord(wn,wv,wt);
}

void C_FindWord()
{
	char *wn=Messages[MSG(Arg())];
	int wt=NUM(Arg());
	SysFlags[FLAG(Arg())]=FindCWord(wn,wt);
}

void C_DelWord()
{
	extern struct Word *FindWord();
	struct Word *w;
	char *wn=Messages[MSG(Arg())];
	int wt=NUM(Arg());
	w=FindWord(wn,wt);
	if(w)
		DelWord(w);
}
	
void C_Tod()
{
	extern struct tm *localtime();
	struct tm *tl;
	long tv;
	time(&tv);
	tl=localtime(&tv);
	if(tl==NULL)
	{
		log_error("[INTERNAL]: Get local time failed.\n",NULL);
		panic();
	}
	SysFlags[FLAG(Arg())]=tl->tm_sec;
	SysFlags[FLAG(Arg())]=tl->tm_min;
	SysFlags[FLAG(Arg())]=tl->tm_hour;
	SysFlags[FLAG(Arg())]=tl->tm_mday;
	SysFlags[FLAG(Arg())]=tl->tm_mon;
	SysFlags[FLAG(Arg())]=tl->tm_year;
	SysFlags[FLAG(Arg())]=tl->tm_wday;
}
	
void C_Fload()
{
	tag ct,l;
	FILE *f=fopen(Messages[MSG(Arg())],"r");
	if(f==NULL)
	{
		log_error("[DATABASE ERROR]: Can't open for FLOAD.\n",NULL);
		panic();
	}
	ct=FLAG(Arg());
	l=FLAG(Arg());
	while(ct<l)
	{
		int v;
		fscanf(f,"%ld",&v);
		SysFlags[ct++]=v;
	}
	fclose(f);
}

void C_FSave()
{
	tag ct,l;
	FILE *f=fopen(Messages[MSG(Arg())],"w");
	if(f==NULL)
	{
		log_error("[DATABASE ERROR]: Can't open for FSVAE\n",NULL);
		panic();
	}
	ct=FLAG(Arg());
	l=FLAG(Arg());
	while(ct<l)
	{
		fscanf(f,"%ld",SysFlags[ct++]);
	}
	fclose(f);
}

int SeekFor=0;
int SeekIdent=0;
struct StackFrame *SysStack=NULL;

void C_Do()
{
	int a=Arg();
	if(a<0||a>=MAXLOOP)
	{
		log_error("[DATABASE ERROR]: Do called with out of range loop number.\n",NULL);
		panic();
	}
	SysStack->LoopInfo[a]=GetCLine()+1;
}

extern int FindFor(tag,tag,int);

static int FindFor(st,l,t)
tag st,l;
int t;
{
	if(st==-1)
		st=OBJECT(l)->ob_Child;
	else
		st=OBJECT(st)->ob_Next;
	while(st!= -1)
	{
		if(ISITEM(st)&&LOC(st)==l)
		{
			if(!t||t==TYPE(st))
				return(st);
		}
		st++;
	}
	return(-1);
}

extern tag FindUser(tag);

static tag FindUser(x)
tag x;
{
	x++;
	while(x<ISOBJ(MAXU))
	{
		if(LOC(x)!=ISOBJ(-1)&&LOC(x)!=-1)
			return(x);
		x++;
	}
	return(ISOBJ(-1));
}

void C_For()
{
	int a=Arg();
	int f=FLAG(Arg());
	int l=Arg();
	int t=NUM(Arg());
	/*OBJ(l);*/
	if(a<0||a>=MAXLOOP)
	{
		printf("[DATABASE ERROR]: For called with out of range loop number.\n");
		panic();
	}
	SysStack->ForLoop[a]=GetCLine()+1;
	SysStack->ForLoc[a]=l;
	SysStack->ForVar[a]=f;
	SysStack->ForType[a]=t;
	SysFlags[SysStack->ForVar[a]]=FindFor(ISOBJ(0)-1,l,t);
	if(SysFlags[SysStack->ForVar[a]]==-1)
	{
		SeekFor=1;
		SeekIdent=a;
	}
}

void C_EndFor()
{
	int a=Arg();
	if(a<0||a>=MAXLOOP)
	{
		log_error("[DATABASE ERROR]: EndFor called with out of range loop number.\n",NULL);
		panic();
	}
	SysFlags[SysStack->ForVar[a]]=FindFor(
		SysFlags[SysStack->ForVar[a]],SysStack->ForLoc[a],
		SysStack->ForType[a]);
	if(SysFlags[SysStack->ForVar[a]]!=-1)
		SetCLine(SysStack->ForLoop[a]);
}

void C_ForUser()
{
	int a=NUM(Arg());
	int f=FLAG(Arg());
	if(a<0||a>=MAXLOOP)
	{
		log_error("[DATABASE ERROR]: ForUser called with out of range loop number.\n",NULL);
		panic();
	}
	SysStack->UserLoop[a]=GetCLine()+1;
	SysStack->UserVar[a]=f;
	SysFlags[SysStack->UserVar[a]]=FindUser(ISOBJ(0)-1);
	if(SysFlags[SysStack->UserVar[a]]==ISOBJ(-1))
	{
		SeekIdent=a;
		SeekFor=2;
	}
/*	printf("FORUSER: Loop %d, SeekFor=%d, UVar= %d(%d).\n",
		a,SeekFor,SysFlags[UserVar[a]],UserVar[a]);*/
}

void C_EndUser()
{
	int a=NUM(Arg());
	if(a<0||a>=MAXLOOP)
	{
		printf("[DATABASE ERROR]: EndUser called with out of range loop number.\n");
		panic();
	}
/*	printf("ENDUSER: Loop %d, SeekFor=%d, UVar= %d(%d).\n",
		a,SeekFor,SysFlags[UserVar[a]],UserVar[a]);*/

	if(SysFlags[SysStack->UserVar[a]]==ISOBJ(-1))
		return;
	SysFlags[SysStack->UserVar[a]]=FindUser(SysFlags[SysStack->UserVar[a]]);
	if(SysFlags[SysStack->UserVar[a]]!=ISOBJ(-1))
		SetCLine(SysStack->UserLoop[a]);
/*	printf("ENDUSER/2 Loop %d, SeekFor=%d, UVar= %d(%d).\n",
		a,SeekFor,SysFlags[UserVar[a]],UserVar[a]);*/
		
}

void C_Loop()
{
	int a=NUM(Arg());
	if(a<0||a>=MAXLOOP)
	{
		log_error("[DATABASE ERROR]: Do called with out of range loop number.\n",NULL);
		panic();
	}
	SetCLine(SysStack->LoopInfo[a]);
}

Q_DelFile()
{
	int n=MSG(Arg());
	if(unlink(Messages[n])==-1)
		return(0);
	return(1);
}

Q_FindStr()
{
	char *str=Messages[Arg()];
	char *srch=Messages[Arg()];
	int ct=Arg();
	int f=FLAG(Arg());
	int sl=strlen(str);
	while(ct<sl)
	{
		if(index(srch,str[ct]))
		{
			SysFlags[f]=ct;
			return(1);
		}
		ct++;
	}
	SysFlags[f]= -1;
	return(0);
}

Q_SkipStr()
{
	char *str=Messages[MSG(Arg())];
	char *srch=Messages[MSG(Arg())];
	int ct=Arg();
	int f=FLAG(Arg());
	int sl=strlen(str);
	while(ct<sl)
	{
		if(!index(srch,str[ct]))
		{
			SysFlags[f]=ct;
			return(1);
		}
		ct++;
	}
	SysFlags[f]= ISNUM(-1);
	return(0);
}

Q_LoadU()
{
	tag a=Arg();
	char *name=Messages[MSG(Arg())];
	if(TYPE(a)!=FL_PLAYER)
	{
		log_error("[DATABASE ERROR]: LoadU called with non player.\n",NULL);
		panic();
	}
	return(LoadUser(a,name));
}	

Q_SaveU()
{
	tag a=Arg();
	char *name=Messages[MSG(Arg())];
	if(TYPE(a)!=FL_PLAYER)
	{
		log_error("[DATABASE ERROR]: SaveU called with non player.\n",NULL);
		panic();
	}
	SaveUser(a,name);
	return(1);
}	

Q_SubStr()
{
	char *s1=Messages[MSG(Arg())];
	char *s2=Messages[MSG(Arg())];
	while(*s1)
	{
		if(strncmp(s1,s2,strlen(s2))==0)
			return(1);
		s1++;
	}
	return(0);
}

void C_Extract()
{
	char *from=Messages[MSG(Arg())];
	int to=MSG(Arg());
	int start=Arg();
	int end=Arg();
	free(Messages[to]);
	if((start>=strlen(from))||(start>end))
	{
		Messages[to]=estralloc("");
		return;
	}
	if(end>strlen(from))
		end=strlen(from);
	Messages[to]=(char *)emalloc(end-start+1);
	strncpy(Messages[to],from+start,end-start);
	Messages[to][end-start]=0;
}

void C_NumText()
{
	int a=Arg();
	char x[8];
	sprintf(x,"%d",a);
	a=MSG(Arg());
	free(Messages[a]);
	Messages[a]=estralloc(x);
}

void C_WText()
{
	int a=Arg();
	int b=Arg();
	tag c=MSG(Arg());
	struct Word *w;
	free(Messages[c]);
	w=(struct Word *)FindNumWord(a,b);
	if(w)
		Messages[c]=estralloc(w->wd_Text);
	else
		Messages[c]=estralloc("$ANY");
}

void C_FTrueName()
{
	extern struct Word *FindName();
	char *a=Messages[MSG(Arg())];
	int t=Arg();
	struct Word *w=FindName(a,t);
	SysFlags[FLAG(Arg())]=w?w->wd_Code:-1;
}

void C_NewMsg()
{
	char *a=Messages[MSG(Arg())];
	char *b=Messages[MSG(Arg())];
	tag f=Next_Msg();
	Messages[f]=estralloc(a);
	AddName(b,f,2);
	SysFlags[FLAG(Arg())]=ISMSG(f);
}

/*
 *	FIX THIS MSG NUMBERS NOT REUSED - WASTES 4 BYTES A TIME!!
 */
	
void C_DelMsg()
{
	int a=MSG(Arg());
/*	struct Word *w=MsgName(a);
	if(w)
		DelName(w);
	free(Messages[a]);
	Messages[a]=estralloc(""); */
}

FILE *Work_File=NULL;

Q_FOpen()
{
	char *x=Messages[MSG(Arg())];
	char *y=Messages[MSG(Arg())];	
	if(Work_File)
		fclose(Work_File);
	Work_File=fopen(x,y);
	if(Work_File==NULL)
		return(0);
	return(1);
}

void C_FClose()
{
	if(Work_File)
		fclose(Work_File);
}

Q_Fmove()
{
	char *f=Messages[MSG(Arg())];
	char *t=Messages[MSG(Arg())];
	if(rename(f,t)==0)
		return(1);
	return(0);
}

Q_FRead()
{
	char bf[256];
	int a=MSG(Arg());
	if(Work_File==NULL)
		return(0);
	if(fgets(bf,255,Work_File)==NULL)
		return(0);
	free(Messages[a]);
	Messages[a]=estralloc(bf);
	return(1);
}

Q_FWrite()
{
	char *a=Messages[MSG(Arg())];
	if(Work_File==NULL)
		return(0);
	if(fwrite(a,strlen(a),1,Work_File)!=1)
		return(0);
	return(1);
}


void C_Consult()
{
	tag i;
	int v,n1,n2;
	/* UNIMPLEMENTED
	DoConsult(i,v,n1,n2);*/
	log_error("CONSULT is unimplemented.\n",NULL);
}

void C_AttachTable()
{
	extern TABLE *Table;
	tag i=Arg();
	int t=Arg();
	OBJECT(i)->ob_Table=Table[t];
}

#ifndef UNIX
/* Translate filenames to TOS(and DOS). This translates spaces to underscores
 * and stuffs any extra characters after the period so that as many
 * characters as possible of the original name are used .
 */
char *f_tos(fname)
char *fname;
{
	static char tempname[512]; 	/* Hopefully enough ! */
	extern char *strrchr();
	register char *temptr=tempname,*temptr2=strrchr(fname,'/');
	if(temptr2)temptr2+=9;
	else temptr2=&fname[8];
	while(*temptr=*fname++)
	{
		if(*temptr==' ')*temptr='_'; temptr++;
		if(fname==temptr2)*temptr++='.';
	}
	return(tempname);
}
#endif