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. *
****************************************************************************/
/* OS-specific */
#ifndef __unix__
#include <io.h>
#include <share.h>
#endif
/* ANSI */
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include "cmdshell.h"
#include "ars_defs.h"
#include "crc32.h"
#include "genwrap.h" /* portability wrappers */
#include "dirwrap.h" /* MAX_PATH */
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;
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;
BOOL pause_on_error=FALSE;
void bail(int retval)
if(out)
fclose(out);
if(retval!=0) {
if(bin_file[0]!=0)
remove(bin_file);
if(pause_on_error) {
printf("\nHit enter to contiue...");
getchar();
}
}
exit(retval);
}
/****************************************************************************/
/****************************************************************************/
while((l=(*str++)|0x20)!=0x20)
val=(l&0xf)+(l>>6&1)*9+val*16;
return(val);
}
/* C Escape char */
uchar cesc(char ch)
{
case 'e':
return(ESC);
case 'r':
return(CR);
case 'n':
return(LF);
case 't':
return(TAB);
case 'b':
return(BS);
case 'a':
return(BEL);
case 'f':
return(FF);
case 'v':
return(11);
default:
return(ch);
}
if(isdigit((uchar)*p) || *p=='-') /* Dec, Hex, or Oct */
l=strtol(p,&p,0);
else if(*p=='\'') { /* Char */
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");
bail(1);
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
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;
case '#':
inside=0;
return(l); }
inside=0;
return(l);
void writecstr(char *p)
{
char str[1024];
int j=0,inquotes=0;
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)))
p++;
j++;
continue; }
switch(*(p++)) {
case 'x':
tmp[0]=*(p++);
tmp[1]=0;
if(isxdigit((uchar)*p)) { /* if another hex digit, skip too */
tmp[1]=*(p++);
tmp[2]=0; }
str[j]=(char)ahtoul(tmp);
break;
case 'e':
str[j]=ESC;
break;
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':
str[j]=BEL;
break;
case 'f':
str[j]=FF;
break;
case 'v':
str[j]=11; /* VT */
break;
default:
str[j]=*(p-1);
break; }
str[j++]=*(p++); }
str[j]=0;
fwrite(str,1,j+1,out);
void writestr(char *p)
{
char str[1024];
int j=0;
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);
}
void cvttab(char *str)
{
int i;
void newvar(char* src, char *in)
if(isdigit((uchar)*in)) {
printf("!SYNTAX ERROR (illegal variable name):\n");
printf(linestr,src,line,(char*)in);
bail(1);
}
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;
}
if((var_name=(uint32_t *)realloc(var_name,sizeof(int32_t)*(vars+1)))==NULL) {
bail(1); }
void writecrc(char *src, char *in)
char name[128];
char* p;
/* Automatically terminate variable name Oct-09-2000 rswindell */
sprintf(name,"%.80s",in);
else if(strncmp(name,"var_",4)==0) /* decompiled source? */
l=strtoul(name+4,NULL,16);
if(!case_sens)
strupr(name);
for(i=0;i<vars;i++)
if(var_name[i]==l)
break;
if(i==vars) {
printf("!SYNTAX ERROR (expecting variable name):\n");
printf(linestr,src,line,*in ? (char*)in : "<end of line>");
bail(1);
int32_t isvar(char *arg)
char name[128],*p;
if(!arg || !(*arg) || isdigit((uchar)*arg))
if((p=strchr(name,' '))!=NULL) /* Truncate at first space */
if(strncmp(name,"var_",4)==0) /* decompiled source? */
return(strtoul(name+4,NULL,16));
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)
{
if(case_sens)
return(strcmp(s1,s2));
return(stricmp(s1,s2));
void expdefs(char *line)
char str[512],*p,*sp,sav[2]={0};
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!='_')
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 */
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;
char path[MAX_PATH+1];
printf("error %d opening %s for read\n",errno,src);
bail(1); }
if((str=malloc(1024))==NULL) {
printf("malloc error\n");
bail(1);
if((save=malloc(1024))==NULL) {
printf("malloc error\n");
bail(1);
while(!feof(in) && !ferror(in)) {
if(!fgets(str,1000,in))
truncsp(str);
cvttab(str);
line++;
strcpy(save,str);
p=str;
SKIPCTRLSP(p); /* look for beginning of command */
if((*p)==0)
continue;
if(*p=='#') /* remarks start with # */
continue;
expdefs(p); /* expand defines */
if(display)
printf("%s\n",p);
arg=arg2=arg3=arg4="";
SKIPCTRLSP(arg);
SKIPCTRLSP(arg2);
SKIPCTRLSP(arg3);
if(sp) {
arg4=sp+1;
SKIPCTRLSP(arg4);
}
}
}
}
sprintf(path,"%s%s",include_dir,arg);
compile(path);
continue;
}
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)))
bail(1); }
if((define_str[defines]=(char *)malloc(strlen(arg)+1))==NULL) {
bail(1); }
if((define_val=(char **)realloc(define_val,sizeof(char *)*(defines+1)))
bail(1); }
if((define_val[defines]=(char *)malloc(strlen(arg2)+1))==NULL) {
bail(1); }
strcpy(define_str[defines],arg);
strcpy(define_val[defines],arg2);
defines++;
continue; }
if(!stricmp(p,"!GLOBAL")) { /* declare global variables */
if(!(*arg)) break;
for(p=arg;*p && *p!='#';) {
newvar(src,p);
SKIPCTRLSP(p);
}
if(!stricmp(p,"PATCH")) {
if(!(*arg)) break;
p=arg;
while(*p) {
tmp[0]=*p++;
tmp[1]=*p++;
tmp[2]=0;
if(!tmp[0])
break;
ch=ahtoul(tmp);
fputc(ch,out); }
continue; }
if(!stricmp(p,"SHOW_VARS")) {
fputc(CS_VAR_INSTRUCTION,out);
fputc(SHOW_VARS,out);
continue; }
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; }
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
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; }
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; }
if(!stricmp(p,"USER_EVENT")) {
if(!(*arg))
break;
if((l=isvar(arg))!=0) {
fwrite(&l,4,1,out); /* variable */
fputc(2,out); /* int offset */
fputc(1,out); /* int length */
ch=0; } /* place holder */
ch=val(src,arg);
fprintf(out,"%c%c",CS_TWO_MORE_BYTES,CS_USER_EVENT);
fwrite(&ch,1,1,out);
continue; }
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);
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
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++;
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");
bail(1); }
if((label_name=(char **)realloc(label_name,sizeof(char *)*(labels+1)))
bail(1); }
if((label_indx=(uint *)realloc(label_indx,sizeof(int)*(labels+1)))
bail(1); }
if((label_name[labels]=(char *)malloc(strlen(p)+1))==NULL) {
bail(1); }
strcpy(label_name[labels],p);
label_indx[labels]=ftell(out);
labels++;
continue; }
if(!stricmp(p,"GOTO")) { /* goto */
if(!(*arg)) break;
if((goto_label=(char **)realloc(goto_label,sizeof(char *)*(gotos+1)))
bail(1); }
if((goto_file=(char **)realloc(goto_file,sizeof(char *)*(gotos+1)))
bail(1); }
if((goto_indx=(uint *)realloc(goto_indx,sizeof(int)*(gotos+1)))
bail(1); }
if((goto_line=(uint *)realloc(goto_line,sizeof(int)*(gotos+1)))
bail(1); }
if((goto_label[gotos]=(char *)malloc(strlen(arg)+1))==NULL) {
bail(1); }
if((goto_file[gotos]=(char *)malloc(strlen(str)+1))==NULL) {
bail(1); }
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;
if((call_label=(char **)realloc(call_label,sizeof(char *)*(calls+1)))
bail(1); }
if((call_file=(char **)realloc(call_file,sizeof(char *)*(calls+1)))
bail(1); }
if((call_indx=(uint *)realloc(call_indx,sizeof(int)*(calls+1)))
bail(1); }
if((call_line=(uint *)realloc(call_line,sizeof(int)*(calls+1)))
bail(1); }
if((call_label[calls]=(char *)malloc(strlen(arg)+1))==NULL) {
bail(1); }
if((call_file[calls]=(char *)malloc(strlen(src)+1))==NULL) {
bail(1); }
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; }
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;
ch=toupper(*arg);
if(ch=='/')
ch=*(arg+1)|0x80; /* high bit indicates slash required */
else if(ch=='^' && (*(arg+1)>=0x40))
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; }
if(!stricmp(p,"DEFINE_STR_VAR") || !stricmp(p,"STR")) {
if(!(*arg)) break;
for(p=arg;*p && *p!='#';) {
if(sp) *sp=0;
fputc(CS_VAR_INSTRUCTION,out);
fputc(DEFINE_STR_VAR,out);
newvar(src,p);
writecrc(src,p);
if(!sp)
break;
p=sp+1;
SKIPCTRLSP(p);
}
continue; }
if(!stricmp(p,"DEFINE_INT_VAR") || !stricmp(p,"INT")) {
if(!(*arg)) break;
for(p=arg;*p && *p!='#';) {
if(sp) *sp=0;
fputc(CS_VAR_INSTRUCTION,out);
fputc(DEFINE_INT_VAR,out);
newvar(src,p);
writecrc(src,p);
if(!sp)
break;
p=sp+1;
SKIPCTRLSP(p);
}
continue; }
if(!stricmp(p,"DEFINE_GLOBAL_STR_VAR") || !stricmp(p,"GLOBAL_STR")) {
if(!(*arg)) break;
for(p=arg;*p && *p!='#';) {
if(sp) *sp=0;
fputc(CS_VAR_INSTRUCTION,out);
fputc(DEFINE_GLOBAL_STR_VAR,out);
newvar(src,p);
writecrc(src,p);
if(!sp)
break;
p=sp+1;
SKIPCTRLSP(p);
}
continue; }
if(!stricmp(p,"DEFINE_GLOBAL_INT_VAR") || !stricmp(p,"GLOBAL_INT")) {
if(!(*arg)) break;
for(p=arg;*p && *p!='#';) {
if(sp) *sp=0;
fputc(CS_VAR_INSTRUCTION,out);
fputc(DEFINE_GLOBAL_INT_VAR,out);
newvar(src,p);
writecrc(src,p);
if(!sp)
break;
p=sp+1;
SKIPCTRLSP(p);
}
if(!stricmp(p,"LOGIN")) {
if(!(*arg)) break;
fputc(CS_STR_FUNCTION,out);
fputc(CS_LOGIN,out);
writecstr(arg);
continue; }
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);
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);
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);
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);
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; }
if(!(*arg) || !(*arg2)) break;
fputc(CS_VAR_INSTRUCTION,out);
fputc(COPY_FIRST_CHAR,out);
writecrc(src,arg);
writecrc(src,arg2);
continue; }
if(!stricmp(p,"COMPARE_FIRST_CHAR")) {
if(!(*arg) || !(*arg2)) break;