Skip to content
Snippets Groups Projects
baja.c 84.2 KiB
Newer Older
/* baja.c */

/* Synchronet command shell/module compiler */

/* $Id$ */

/****************************************************************************
 * @format.tab-size 4		(Plain Text/Source Code File Header)			*
 * @format.use-tabs true	(see http://www.synchro.net/ptsc_hdr.html)		*
 *																			*
 * Copyright 2005 Rob Swindell - http://www.synchro.net/copyright.html		*
 *																			*
 * This program is free software; you can redistribute it and/or			*
 * modify it under the terms of the GNU General Public License				*
 * as published by the Free Software Foundation; either version 2			*
 * of the License, or (at your option) any later version.					*
 * See the GNU General Public License for more details: gpl.txt or			*
 * http://www.fsf.org/copyleft/gpl.html										*
 *																			*
 * Anonymous FTP access to the most recent released source is available at	*
 * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net	*
 *																			*
 * Anonymous CVS access to the development source and modification history	*
 * is available at cvs.synchro.net:/cvsroot/sbbs, example:					*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs login			*
 *     (just hit return, no password is necessary)							*
 * cvs -d :pserver:anonymous@cvs.synchro.net:/cvsroot/sbbs checkout src		*
 *																			*
 * For Synchronet coding style and modification guidelines, see				*
 * http://www.synchro.net/source.html										*
 *																			*
 * You are encouraged to submit any modifications (preferably in Unix diff	*
 * format) via e-mail to mods@synchro.net									*
 *																			*
 * Note: If this box doesn't appear square, then you need to fix your tabs.	*
 ****************************************************************************/

rswindell's avatar
rswindell committed
/* OS-specific */
#ifndef __unix__
	#include <io.h>
	#include <share.h>
#endif

/* ANSI */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
rswindell's avatar
rswindell committed
#include <errno.h>
rswindell's avatar
rswindell committed

/* Synchronet-specific */
#include "cmdshell.h"
#include "ars_defs.h"
#include "crc32.h"
#include "genwrap.h"	/* portability wrappers */
#include "dirwrap.h"	/* MAX_PATH */

#ifdef __BORLANDC__
unsigned _stklen=20000;	/* Set stack size in code, not header */
#endif

char **label_name=NULL
	,**goto_file=NULL
	,**goto_label=NULL
	,**call_file=NULL
	,**call_label=NULL;

deuce's avatar
deuce committed
uint32_t *var_name=NULL,vars=0;

char **define_str=NULL
	,**define_val=NULL;

char *linestr="%s %d: %s\n";
char tmp[256];

uint *label_indx=NULL
	,*goto_indx=NULL
	,*goto_line=NULL
	,*call_indx=NULL
	,*call_line=NULL;

char bin_file[MAX_PATH+1];
char output_dir[MAX_PATH+1];
char include_dir[MAX_PATH+1];
uint display=0,line=0,labels=0,gotos=0,calls=0,defines=0,case_sens=0;
	if(retval!=0) {
		if(bin_file[0]!=0)
			remove(bin_file);
			printf("\nHit enter to contiue...");
			getchar();
		}
	}
}

/****************************************************************************/
rswindell's avatar
rswindell committed
/* Converts an ASCII Hex string into an ulong								*/
/****************************************************************************/
deuce's avatar
deuce committed
uint32_t ahtoul(char *str)
deuce's avatar
deuce committed
	uint32_t l,val=0;
rswindell's avatar
rswindell committed
	while((l=(*str++)|0x20)!=0x20)
		val=(l&0xf)+(l>>6&1)*9+val*16;
	return(val);
}

/* C Escape char */

uchar cesc(char ch)
{
rswindell's avatar
rswindell committed
	switch(ch) {
rswindell's avatar
rswindell committed
		case 'r':
			return(CR);
		case 'n':
			return(LF);
		case 't':
			return(TAB);
		case 'b':
			return(BS);
		case 'a':
rswindell's avatar
rswindell committed
		case 'f':
			return(FF);
		case 'v':
			return(11);
		default:
			return(ch); 
	}
deuce's avatar
deuce committed
int32_t val(char *src, char *p)
{
	static int inside;
deuce's avatar
deuce committed
	int32_t l;
	if(isdigit((uchar)*p) || *p=='-')      /* Dec, Hex, or Oct */
rswindell's avatar
rswindell committed
		l=strtol(p,&p,0);
	else if(*p=='\'') {  /* Char */
rswindell's avatar
rswindell committed
		if(*p=='\\') {
			p++;
			l=cesc(*p); }
		else
			l=*p;
		p++; }
	else if(*p=='.')    /* Bit */
		l=1L<<strtol(p+1,&p,0);
	else {
		printf("!SYNTAX ERROR (expecting integer constant):\n");
rswindell's avatar
rswindell committed
		printf(linestr,src,line,*p ? p : "<end of line>");
rswindell's avatar
rswindell committed
		return(0); }
	if(inside) {
		return(l); }
	inside=1;
	while(*p)
		switch(*(p++)) {
			case '+':
				l+=val(src,p);
				break;
			case '-':
				l-=val(src,p);
				break;
			case '*':
				l*=val(src,p);
				break;
			case '/':
				l/=val(src,p);
				break;
			case '%':
				l%=val(src,p);
				break;
			case '&':
				l&=val(src,p);
				break;
			case '|':
				l|=val(src,p);
				break;
			case '~':
				l&=~val(src,p);
				break;
			case '^':
				l^=val(src,p);
				break;
			case '>':
				if(*p=='>') {
					p++;
					l>>=val(src,p); }
				break;
			case '<':
				if(*p=='<') {
					p++;
					l<<=val(src,p); }
				break;
rswindell's avatar
rswindell committed
			case '#':
				inside=0;
				return(l); }
	inside=0;
	return(l);
void writecstr(char *p)
{
	char str[1024];
	int j=0,inquotes=0;

rswindell's avatar
rswindell committed
	while(*p) {
		if(*p=='"') {   /* ignore quotes */
			if(inquotes)
				break;
			inquotes=1;
			p++;
			continue; }
		if(*p=='\\')    { /* escape */
			p++;
			if(isdigit((uchar)*p)) {
				sprintf(tmp,"%.3s",p);
				str[j]=atoi(tmp); 		/* decimal, NOT octal */
				if(isdigit((uchar)*(++p))) 	/* skip up to 3 digits */
					if(isdigit((uchar)*(++p)))
rswindell's avatar
rswindell committed
						p++;
				j++;
				continue; }
			switch(*(p++)) {
				case 'x':
					tmp[0]=*(p++);
					tmp[1]=0;
					if(isxdigit((uchar)*p)) {	/* if another hex digit, skip too */
rswindell's avatar
rswindell committed
						tmp[1]=*(p++);
						tmp[2]=0; }
					str[j]=(char)ahtoul(tmp);
					break;
rswindell's avatar
rswindell committed
				case 'r':
					str[j]=CR;
					break;
				case 'n':
					str[j]=LF;
					break;
				case 't':
					str[j]=TAB;
					break;
				case 'b':
					str[j]=BS;
					break;
				case 'a':
rswindell's avatar
rswindell committed
					break;
				case 'f':
					str[j]=FF;
					break;
				case 'v':
					str[j]=11;	/* VT */
					break;
				default:
					str[j]=*(p-1);
					break; }
rswindell's avatar
rswindell committed
		str[j++]=*(p++); }
	str[j]=0;
	fwrite(str,1,j+1,out);
rswindell's avatar
rswindell committed
	while(*p) {
		if(*p=='"') {   /* ignore quotes */
			p++;
			continue; }
		if(*p=='\\' && *(p+1)=='"' && *(p+2))
			p++;
		str[j++]=*(p++); }
	str[j]=0;
	fwrite(str,1,j+1,out);
rswindell's avatar
rswindell committed
	for(i=0;str[i];i++)
		if(str[i]==TAB)
void newvar(char* src, char *in)
deuce's avatar
deuce committed
	int32_t i,l;
	if(isdigit((uchar)*in)) {
		printf("!SYNTAX ERROR (illegal variable name):\n");
		printf(linestr,src,line,(char*)in);
		bail(1); 
	}

rswindell's avatar
rswindell committed
	sprintf(name,"%.80s",in);
	if(strncmp(name,"var_",4)==0)	/* decompiled source? */
		l=strtoul(name+4,NULL,16);
	else {
		if(!case_sens)
			strupr(name);
		l=crc32(name,0);
		for(i=0;i<vars;i++)
			if(var_name[i]==l)
				break;
		if(i<vars)
			return;
	}
deuce's avatar
deuce committed
	if((var_name=(uint32_t *)realloc(var_name,sizeof(int32_t)*(vars+1)))==NULL) {
deuce's avatar
deuce committed
		printf("Too many (%"PRIu32") variables!\n",vars);
rswindell's avatar
rswindell committed
	var_name[vars]=l;
	if(display)
deuce's avatar
deuce committed
		printf("newvar(%08"PRIX32")=%s\n",l,in);
rswindell's avatar
rswindell committed
	vars++;
void writecrc(char *src, char *in)
deuce's avatar
deuce committed
	int32_t	l;
	int		i;
rswindell's avatar
rswindell committed
	/* Automatically terminate variable name Oct-09-2000 rswindell */
	sprintf(name,"%.80s",in);
	p=strchr(name,' ');
rswindell's avatar
rswindell committed
	if(p) *p=0;
rswindell's avatar
rswindell committed
	if(!stricmp(name,"STR") || !name[0])
		l=0;
	else if(strncmp(name,"var_",4)==0)	/* decompiled source? */
		l=strtoul(name+4,NULL,16);
rswindell's avatar
rswindell committed
	else {
		l=crc32(name,0);
rswindell's avatar
rswindell committed
		for(i=0;i<vars;i++)
			if(var_name[i]==l)
				break;
		if(i==vars) {
			printf("!SYNTAX ERROR (expecting variable name):\n");
rswindell's avatar
rswindell committed
			printf(linestr,src,line,*in ? (char*)in : "<end of line>");
rswindell's avatar
rswindell committed
	}
	fwrite(&l,4,1,out);
int32_t isvar(char *arg)
deuce's avatar
deuce committed
	int32_t i,l;
	if(!arg || !(*arg) || isdigit((uchar)*arg))
rswindell's avatar
rswindell committed
		return(0);

	sprintf(name,"%.80s",arg);
	if((p=strchr(name,' '))!=NULL)	/* Truncate at first space */
rswindell's avatar
rswindell committed
		*p=0;
	if(strncmp(name,"var_",4)==0)	/* decompiled source? */
		return(strtoul(name+4,NULL,16));
rswindell's avatar
rswindell committed
	if(!case_sens)
		strupr(name);
	l=crc32(name,0);
rswindell's avatar
rswindell committed

	for(i=0;i<vars;i++)
		if(var_name[i]==l)
			break;
	if(i==vars)
		return(0);
	return(l);
}

int str_cmp(char *s1, char *s2)
{
rswindell's avatar
rswindell committed
	if(case_sens)
		return(strcmp(s1,s2));
	return(stricmp(s1,s2));
void expdefs(char *line)
	char str[512],*p,*sp,sav[2]={0};
rswindell's avatar
rswindell committed
	str[0]=0;
	for(p=line;*p;p++) {
rswindell's avatar
rswindell committed
			strcat(str," ");
			continue; }
rswindell's avatar
rswindell committed
		if(*p=='"') {               /* Skip quoted text */
			sp=strchr(p+1,'"');
			if(sp) *sp=0;
			strcat(str,p);
			if(!sp)
				break;
			strcat(str,"\"");
			p+=strlen(p);
			continue; }

		for(sp=p;*sp;sp++)
			if(!isalnum((uchar)*sp) && *sp!='_')
rswindell's avatar
rswindell committed
				break;
		sav[0]=*sp; 		/* Save delimiter */
		sav[1]=0;
		*sp=0;
		for(i=0;i<defines;i++)
			if(!str_cmp(define_str[i],p))
				break;
		if(i<defines)
			strcat(str,define_val[i]);
		else
			strcat(str,p);
		if(!sav[0]) 		/* Last argument */
rswindell's avatar
rswindell committed
		p+=strlen(p);
		strcat(str,sav);	/* Restore delimiter */
		}
	strcpy(line,str);
#define SKIPCTRLSP(p) while(*(p)<=' ' && *(p)>0) (p)++

void compile(char *src)
{
	char *str,*save,*p,*sp,*tp,*arg,*arg2,*arg3,*arg4,ch;
	uchar *ar;
deuce's avatar
deuce committed
	uint16_t i;
deuce's avatar
deuce committed
    uint16_t j;
deuce's avatar
deuce committed
	int32_t l;
	int savline;
rswindell's avatar
rswindell committed
	if((in=fopen(src,"rb"))==NULL) {
		printf("error %d opening %s for read\n",errno,src);
rswindell's avatar
rswindell committed
	line=0;
rswindell's avatar
rswindell committed
	if((str=malloc(1024))==NULL) {
		printf("malloc error\n");
rswindell's avatar
rswindell committed
	}
rswindell's avatar
rswindell committed
	if((save=malloc(1024))==NULL) {
		printf("malloc error\n");
rswindell's avatar
rswindell committed
	}
rswindell's avatar
rswindell committed
	while(!feof(in) && !ferror(in)) {
		if(!fgets(str,1000,in))
rswindell's avatar
rswindell committed
		truncsp(str);
		cvttab(str);
		line++;
		strcpy(save,str);
		p=str;
		SKIPCTRLSP(p);   /* look for beginning of command */
rswindell's avatar
rswindell committed
		if((*p)==0)
			continue;
		if(*p=='#')             /* remarks start with # */
			continue;
		expdefs(p); 			/* expand defines */
		if(display)
			printf("%s\n",p);
rswindell's avatar
rswindell committed
		if(sp) {
rswindell's avatar
rswindell committed
			arg=sp+1;
			sp=strchr(arg,' ');
rswindell's avatar
rswindell committed
			if(sp) {
				arg2=sp+1;
				sp=strchr(arg2,' ');
rswindell's avatar
rswindell committed
				if(sp) {
					arg3=sp+1;
					sp=strchr(arg3,' ');
rswindell's avatar
rswindell committed

		if(!stricmp(p,"!INCLUDE")) {
			savline=line;
			sp=strchr(arg,' ');
rswindell's avatar
rswindell committed
			if(sp) *sp=0;
			sprintf(path,"%s%s",include_dir,arg);
			compile(path);
rswindell's avatar
rswindell committed
			line=savline;
rswindell's avatar
rswindell committed
		if(!stricmp(p,"!DEFINE")) {                     /* define */
			sp=strchr(arg,' ');
rswindell's avatar
rswindell committed
			if(sp)
				*sp=0;
rswindell's avatar
rswindell committed
				break;
			tp=strrchr(arg2,'\"');
			if(!tp)
				tp=arg2;
			sp=strchr(tp,'#');
			if(sp)
				*sp=0;
			truncsp(arg2);
			if((define_str=(char **)realloc(define_str,sizeof(char *)*(defines+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many defines.\n");
			if((define_str[defines]=(char *)malloc(strlen(arg)+1))==NULL) {
				printf("Too many defines.\n");
			if((define_val=(char **)realloc(define_val,sizeof(char *)*(defines+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many defines.\n");
			if((define_val[defines]=(char *)malloc(strlen(arg2)+1))==NULL) {
				printf("Too many defines.\n");
rswindell's avatar
rswindell committed
			strcpy(define_str[defines],arg);
			strcpy(define_val[defines],arg2);
			defines++;
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"!GLOBAL")) {             /* declare global variables */
			if(!(*arg)) break;
			for(p=arg;*p && *p!='#';) {
rswindell's avatar
rswindell committed
				if(sp) *sp=0;
rswindell's avatar
rswindell committed
				if(!sp)
					break;
				p=sp+1;
rswindell's avatar
rswindell committed
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"PATCH")) {
			if(!(*arg)) break;
			p=arg;
			while(*p) {
rswindell's avatar
rswindell committed
				tmp[0]=*p++;
				tmp[1]=*p++;
				tmp[2]=0;
				if(!tmp[0])
					break;
				ch=ahtoul(tmp);
				fputc(ch,out); }
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"SHOW_VARS")) {
			fputc(CS_VAR_INSTRUCTION,out);
			fputc(SHOW_VARS,out);
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"COMPARE_ARS")) {
			if(!(*arg)) break;
			strupr(arg);
			ar=arstr(&i,arg,NULL);
			fprintf(out,"%c%c",CS_COMPARE_ARS,(uchar)i);
			fwrite(ar,i,1,out);
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"CHKSYSPASS")) {
			fprintf(out,"%c",CS_CHKSYSPASS);
			continue; }
		if(!stricmp(p,"INFO_SYSTEM")) {
			fprintf(out,"%c",CS_INFO_SYSTEM);
			continue; }
		if(!stricmp(p,"INFO_SUBBOARD")) {
			fprintf(out,"%c",CS_INFO_SUBBOARD);
			continue; }
		if(!stricmp(p,"INFO_DIRECTORY")) {
			fprintf(out,"%c",CS_INFO_DIRECTORY);
			continue; }
		if(!stricmp(p,"INFO_VERSION")) {
			fprintf(out,"%c",CS_INFO_VERSION);
			continue; }
		if(!stricmp(p,"INFO_USER")) {
			fprintf(out,"%c",CS_INFO_USER);
			continue; }
		if(!stricmp(p,"INFO_XFER_POLICY")) {
			fprintf(out,"%c",CS_INFO_XFER_POLICY);
			continue; }
		if(!stricmp(p,"LOGKEY")) {
			fprintf(out,"%c",CS_LOGKEY);
			continue; }
		if(!stricmp(p,"LOGKEY_COMMA")) {
			fprintf(out,"%c",CS_LOGKEY_COMMA);
			continue; }
		if(!stricmp(p,"LOGSTR")) {
			fprintf(out,"%c",CS_LOGSTR);
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"ONLINE")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_ONLINE);
			continue; }
		if(!stricmp(p,"OFFLINE")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_OFFLINE);
			continue; }
		if(!stricmp(p,"NEWUSER")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_NEWUSER);
			continue; }
		if(!stricmp(p,"LOGON")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_LOGON);
			continue; }
		if(!stricmp(p,"LOGOUT")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_LOGOUT);
			continue; }
		if(!stricmp(p,"EXIT")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_EXIT);
			continue; }
		if(!stricmp(p,"LOOP") || !stricmp(p,"LOOP_BEGIN")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_LOOP_BEGIN);
			continue; }
		if(!stricmp(p,"CONTINUE") || !stricmp(p,"CONTINUE_LOOP")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_CONTINUE_LOOP);
			continue; }
		if(!stricmp(p,"BREAK") || !stricmp(p,"BREAK_LOOP")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_BREAK_LOOP);
			continue; }
		if(!stricmp(p,"END_LOOP")) {
			fprintf(out,"%c%c",CS_ONE_MORE_BYTE,CS_END_LOOP);
			continue; }

rswindell's avatar
rswindell committed
		if(!stricmp(p,"USER_EVENT")) {
			if(!(*arg))
				break;
			if((l=isvar(arg))!=0) {
				fputc(CS_USE_INT_VAR,out);
				fwrite(&l,4,1,out); /* variable */
				fputc(2,out);		/* int offset */
				fputc(1,out);       /* int length */
				ch=0; }             /* place holder */
rswindell's avatar
rswindell committed
				ch=val(src,arg);
			fprintf(out,"%c%c",CS_TWO_MORE_BYTES,CS_USER_EVENT);
			fwrite(&ch,1,1,out);
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"PUT_NODE")) {
			fprintf(out,"%c",CS_PUT_NODE);
			continue; }
		if(!stricmp(p,"SYNC")) {
			fprintf(out,"%c",CS_SYNC);
			continue; }
		if(!stricmp(p,"ASYNC")) {
			fprintf(out,"%c",CS_ASYNC);
			continue; }
		if(!stricmp(p,"RIOSYNC")) {		/* deprecated */
			fprintf(out,"%c",CS_SYNC);
rswindell's avatar
rswindell committed
			continue; }
		if(!stricmp(p,"GETTIMELEFT")) {
			fprintf(out,"%c",CS_GETTIMELEFT);
			continue; }
		if(!stricmp(p,"SAVELINE")) {
			fprintf(out,"%c",CS_SAVELINE);
			continue; }
		if(!stricmp(p,"RESTORELINE")) {
			fprintf(out,"%c",CS_RESTORELINE);
			continue; }
		if(!stricmp(p,"IF_TRUE") || !stricmp(p,"IF_EQUAL")) {
			fprintf(out,"%c",CS_IF_TRUE);
			continue; }
		if(!stricmp(p,"IF_FALSE") || !stricmp(p,"IF_NOT_EQUAL")) {
			fprintf(out,"%c",CS_IF_FALSE);
			continue; }
		if(!stricmp(p,"IF_GREATER")) {
			fprintf(out,"%c",CS_IF_GREATER);
			continue; }
		if(!stricmp(p,"IF_GREATER_OR_EQUAL")
			|| !stricmp(p,"IF_EQUAL_OR_GREATER")) {
			fprintf(out,"%c",CS_IF_GREATER_OR_EQUAL);
			continue; }
		if(!stricmp(p,"IF_LESS")) {
			fprintf(out,"%c",CS_IF_LESS);
			continue; }
		if(!stricmp(p,"IF_LESS_OR_EQUAL")
			|| !stricmp(p,"IF_EQUAL_OR_LESS")) {
			fprintf(out,"%c",CS_IF_LESS_OR_EQUAL);
			continue; }
		if(!stricmp(p,"ENDIF") || !stricmp(p,"END_IF")) {
			fprintf(out,"%c",CS_ENDIF);
			continue; }
		if(!stricmp(p,"ELSE")) {
			fprintf(out,"%c",CS_ELSE);
			continue; }
		if(p[0]==':') {                     /* :label */
			p++;
rswindell's avatar
rswindell committed
			if(sp)
				*sp=0;
			for(i=0;i<labels;i++)
				if(!stricmp(label_name[i],p))
					break;
			if(i<labels) {
				printf("!SYNTAX ERROR (duplicate label name):\n");
rswindell's avatar
rswindell committed
				printf(linestr,src,line,p);
			if((label_name=(char **)realloc(label_name,sizeof(char *)*(labels+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many labels.\n");
			if((label_indx=(uint *)realloc(label_indx,sizeof(int)*(labels+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many labels.\n");
			if((label_name[labels]=(char *)malloc(strlen(p)+1))==NULL) {
				printf("Too many labels.\n");
rswindell's avatar
rswindell committed
			strcpy(label_name[labels],p);
			label_indx[labels]=ftell(out);
			labels++;
			continue; }
		if(!stricmp(p,"GOTO")) {           /* goto */
			if(!(*arg)) break;
			sp=strchr(arg,' ');
rswindell's avatar
rswindell committed
			if(sp)
				*sp=0;
			if((goto_label=(char **)realloc(goto_label,sizeof(char *)*(gotos+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many gotos.\n");
			if((goto_file=(char **)realloc(goto_file,sizeof(char *)*(gotos+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many gotos.\n");
			if((goto_indx=(uint *)realloc(goto_indx,sizeof(int)*(gotos+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many gotos.\n");
			if((goto_line=(uint *)realloc(goto_line,sizeof(int)*(gotos+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many gotos.\n");
			if((goto_label[gotos]=(char *)malloc(strlen(arg)+1))==NULL) {
				printf("Too many gotos.\n");
			if((goto_file[gotos]=(char *)malloc(strlen(str)+1))==NULL) {
				printf("Too many gotos.\n");
rswindell's avatar
rswindell committed
			strcpy(goto_label[gotos],arg);
			strcpy(goto_file[gotos],str);
			goto_indx[gotos]=ftell(out);
			goto_line[gotos]=line;
			gotos++;
			fprintf(out,"%c%c%c",CS_GOTO,0xff,0xff);
			continue; }
		if(!stricmp(p,"CALL")) {          /* call */
			if(!(*arg)) break;
			sp=strchr(arg,' ');
rswindell's avatar
rswindell committed
			if(sp)
				*sp=0;
			if((call_label=(char **)realloc(call_label,sizeof(char *)*(calls+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many calls.\n");
			if((call_file=(char **)realloc(call_file,sizeof(char *)*(calls+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many calls.\n");
			if((call_indx=(uint *)realloc(call_indx,sizeof(int)*(calls+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many calls.\n");
			if((call_line=(uint *)realloc(call_line,sizeof(int)*(calls+1)))
rswindell's avatar
rswindell committed
				==NULL) {
				printf("Too many calls.\n");
			if((call_label[calls]=(char *)malloc(strlen(arg)+1))==NULL) {
				printf("Too many calls.\n");
			if((call_file[calls]=(char *)malloc(strlen(src)+1))==NULL) {
				printf("Too many calls.\n");
rswindell's avatar
rswindell committed

			strcpy(call_label[calls],arg);
			strcpy(call_file[calls],src);
			call_indx[calls]=ftell(out);
			call_line[calls]=line;
			calls++;
			fprintf(out,"%c%c%c",CS_CALL,0xff,0xff);
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"RETURN")) {
			fprintf(out,"%c",CS_RETURN);
			continue; }
		if(!stricmp(p,"CMD_HOME")) {
			fprintf(out,"%c",CS_CMD_HOME);
			continue; }
		if(!stricmp(p,"CMDKEY")) {
			if(!(*arg)) break;
			if(!stricmp(arg,"DIGIT"))
				ch=CS_DIGIT;
			else if(!stricmp(arg,"EDIGIT"))
				ch=CS_EDIGIT;
rswindell's avatar
rswindell committed
				ch=toupper(*arg);
			if(ch=='/')
				ch=*(arg+1)|0x80;   /* high bit indicates slash required */
			else if(ch=='^' && (*(arg+1)>=0x40))
rswindell's avatar
rswindell committed
				ch=*(arg+1)-0x40;   /* ctrl char */
			else if(ch=='\\')
				ch=cesc(*(arg+1));
			else if(ch=='\'')
				ch=*(arg+1);
			fprintf(out,"%c%c",CS_CMDKEY,ch);
			continue; }
		if(!stricmp(p,"CMDCHAR")) {
			if(!(*arg)) break;
			fprintf(out,"%c%c",CS_CMDKEY,*arg);
			continue; }
		if(!stricmp(p,"SETLOGIC") || !stricmp(p,"SET_LOGIC")) {
			if(!(*arg)) break;
			if(!stricmp(arg,"TRUE") || !stricmp(arg,"EQUAL"))
				ch=LOGIC_TRUE;
			else if(!stricmp(arg,"GREATER"))
				ch=LOGIC_GREATER;
			else if(!stricmp(arg,"LESS"))
				ch=LOGIC_LESS;
			else
				ch=LOGIC_FALSE;
			fprintf(out,"%c%c",CS_SETLOGIC,ch);
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"DEFINE_STR_VAR") || !stricmp(p,"STR")) {
			if(!(*arg)) break;
			for(p=arg;*p && *p!='#';) {
rswindell's avatar
rswindell committed
				if(sp) *sp=0;
				fputc(CS_VAR_INSTRUCTION,out);
				fputc(DEFINE_STR_VAR,out);
rswindell's avatar
rswindell committed
				writecrc(src,p);
				if(!sp)
					break;
				p=sp+1;
rswindell's avatar
rswindell committed
			continue; }
		if(!stricmp(p,"DEFINE_INT_VAR") || !stricmp(p,"INT")) {
			if(!(*arg)) break;
			for(p=arg;*p && *p!='#';) {
rswindell's avatar
rswindell committed
				if(sp) *sp=0;
				fputc(CS_VAR_INSTRUCTION,out);
				fputc(DEFINE_INT_VAR,out);
rswindell's avatar
rswindell committed
				writecrc(src,p);
				if(!sp)
					break;
				p=sp+1;
rswindell's avatar
rswindell committed
			continue; }
		if(!stricmp(p,"DEFINE_GLOBAL_STR_VAR") || !stricmp(p,"GLOBAL_STR")) {
			if(!(*arg)) break;
			for(p=arg;*p && *p!='#';) {
rswindell's avatar
rswindell committed
				if(sp) *sp=0;
				fputc(CS_VAR_INSTRUCTION,out);
				fputc(DEFINE_GLOBAL_STR_VAR,out);
rswindell's avatar
rswindell committed
				writecrc(src,p);
				if(!sp)
					break;
				p=sp+1;
rswindell's avatar
rswindell committed
			continue; }
		if(!stricmp(p,"DEFINE_GLOBAL_INT_VAR") || !stricmp(p,"GLOBAL_INT")) {
			if(!(*arg)) break;
			for(p=arg;*p && *p!='#';) {
rswindell's avatar
rswindell committed
				if(sp) *sp=0;
				fputc(CS_VAR_INSTRUCTION,out);
				fputc(DEFINE_GLOBAL_INT_VAR,out);
rswindell's avatar
rswindell committed
				writecrc(src,p);
				if(!sp)
					break;
				p=sp+1;
rswindell's avatar
rswindell committed
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"LOGIN")) {
			if(!(*arg)) break;
			fputc(CS_STR_FUNCTION,out);
			fputc(CS_LOGIN,out);
			writecstr(arg);
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"LOAD_TEXT")) {
			if(!(*arg)) break;
			fputc(CS_STR_FUNCTION,out);
			fputc(CS_LOAD_TEXT,out);
			writestr(arg);
			continue; }

		if(!stricmp(p,"SET_STR_VAR")
			|| (!stricmp(p,"SET") && strchr(arg,'"'))) {
			if(!(*arg)) break;
			fputc(CS_VAR_INSTRUCTION,out);
			fputc(SET_STR_VAR,out);
			p=strchr(arg,' ');
rswindell's avatar
rswindell committed
			if(!p)
				break;
			*p=0;
			writecrc(src,arg);
			writecstr(arg2);
			continue; }
		if(!stricmp(p,"CAT_STR_VAR")
			|| (!stricmp(p,"STRCAT") && strchr(arg,'"'))) {
			fputc(CS_VAR_INSTRUCTION,out);
			fputc(CAT_STR_VAR,out);
			p=strchr(arg,' ');
rswindell's avatar
rswindell committed
			if(!p)
				break;
			*p=0;
			writecrc(src,arg);
			writecstr(arg2);
			continue; }
		if((!stricmp(p,"STRSTR") || !stricmp(p,"COMPARE_SUBSTR"))
			&& strchr(arg,'"')) {
			fputc(CS_VAR_INSTRUCTION,out);
			fputc(STRSTR_VAR,out);
			p=strchr(arg,' ');
rswindell's avatar
rswindell committed
			if(!p)
				break;
			*p=0;
			writecrc(src,arg);
			writecstr(arg2);
			continue; }
		if(!stricmp(p,"STRSTR") || !stricmp(p,"COMPARE_SUBSTR")) {
			if(!(*arg)) break;
			fputc(CS_VAR_INSTRUCTION,out);
			fputc(STRSTR_VARS,out);
			p=strchr(arg,' ');
rswindell's avatar
rswindell committed
			if(!p)
				break;
			*p=0;
			writecrc(src,arg);
			writecrc(src,arg2);
			continue; }
		if(!stricmp(p,"COPY_CHAR") || !stricmp(p,"COPY_KEY")) {
			if(!(*arg)) break;
			fprintf(out,"%c%c",CS_VAR_INSTRUCTION,COPY_CHAR);
			writecrc(src,arg);
			continue; }
rswindell's avatar
rswindell committed
		if(!stricmp(p,"COPY_FIRST_CHAR")) {
rswindell's avatar
rswindell committed
			fputc(CS_VAR_INSTRUCTION,out);
			fputc(COPY_FIRST_CHAR,out);
			writecrc(src,arg);
			writecrc(src,arg2);
			continue; }
		if(!stricmp(p,"COMPARE_FIRST_CHAR")) {
rswindell's avatar
rswindell committed
			fputc(CS_VAR_INSTRUCTION,out);
			fputc(COMPARE_FIRST_CHAR,out);
			writecrc(src,arg);
			fputc((uchar)val(src,arg2),out);
			continue; }