#include	"sysdef.h"



#include	"scerrd.h"
#include	"tempio.h"

#define	CMLIST		1
#define	CMVTEDIT	2
#define	CMLEN		3
#define	CMINSERT	4
#define	CMDELETE	5
#define	CMSTAT		6
#define	CMDUMP		7
#define	CMCHANGE	8
#define	CMMOVE		9
#define	CMREPLACE	10
#define	CMSEARCH	11
#define	CMASCII		12
#define	CMADD		13
#define	CMAPPEND	14
#define	CMDUP		15
#define	CMTRIM		16
#define	CMPLACE		17
#define	CMCHARDEL	18
#define	CMXCHANGE	19
#define	CMTAPP		20
#define	CMTIME		21
#define	CMFILE		22
#define	CMCHATTY	23
#define	CMRETICENT	24
#define	CMTYPE		25
#define	CMCOPY		26
#define	CMHELP		27
#define	CMSET		28
#define	CMEND		29
#define	CMQUIT		30
#define	CMUNDEL		31
#define	CMDCL		32
#define	CMSPAWN		33
#define	CMTEST		34
#define	CMCASE		35
#define	CMTAB		36
#define	CMXLATE		37
#define	CMSAVE		38
#define	CMQQUIT		39
#define	CMREGIS		40
#define	CMECHO		41
#define	CMZAP		42
#define	CMDIR		43
#define	CMPURGE		44
#define	CMERASE		45
#define	CMRULE		46
#define CMTST		47
#define	CMEXAM		48
#define	CMNONE		0

#define	then
#define	SPACE	040
#define	TAB	011

#define	ARG_NO	00
#define	ARG_LO	01
#define	ARG_HI	02
#define	ARG_TA	04
#define	ARG_FI	010
#define	ARG_AL	017
#define	NOPARSE	0100
#define	NO_VT	0200
#define	DIR_WR	0400
#define	DIR_RD	01000



struct	cmd	{
		char name[10] ;
		int idx ;
		int minlen ;
		int flags ;
		} ;

/*	The entries WILDCARD, LNMENU and COMMAND are present so that	*/
/*	the help command can find them.	They are not really commands.	*/

static
struct cmd cmdlist[] =	{
	"WILDCARD"	,CMNONE		,2	,ARG_NO			,
	"LNMENU"	,CMNONE		,2	,ARG_NO			,
	"COMMAND"	,CMNONE		,3	,ARG_NO			,
	"LIST"		,CMLIST		,1	,ARG_LO+ARG_HI+ARG_FI+DIR_WR ,
	"VTEDIT"	,CMVTEDIT	,1	,ARG_FI+NO_VT		,
	"SCOPE"		,CMVTEDIT	,2	,ARG_FI+NO_VT		,
	"LEN"		,CMLEN		,3	,ARG_LO+ARG_HI		,
	"INSERT"	,CMINSERT	,1	,ARG_LO+ARG_FI+DIR_RD	,
	"DELETE"	,CMDELETE	,1	,ARG_LO+ARG_HI+ARG_FI+DIR_WR ,
	"DUMP"		,CMDUMP		,3	,ARG_NO			,
	"STATS"		,CMSTAT		,3	,ARG_NO			,
	"CHANGE"	,CMCHANGE	,1	,ARG_LO+ARG_HI+ARG_FI+DIR_RD ,
	"MOVE"		,CMMOVE		,1	,ARG_LO+ARG_HI+ARG_TA	,
	"SEARCH"	,CMSEARCH	,1	,ARG_AL+DIR_WR		,
	"REPLACE"	,CMREPLACE	,1	,ARG_LO+ARG_HI+ARG_TA+DIR_WR ,
	"ASCII"		,CMASCII	,2	,ARG_LO+ARG_HI 		,
	"ADD"		,CMADD		,1	,ARG_FI+DIR_RD		,
	"APPEND"	,CMAPPEND	,3	,ARG_LO+ARG_HI+ARG_FI+DIR_RD ,
	"DUPLICATE"	,CMDUP		,3	,ARG_LO+ARG_HI		,
	"TRIM"		,CMTRIM		,3	,ARG_LO+ARG_HI+ARG_TA	,
	"PLACE"		,CMPLACE	,1	,ARG_LO+ARG_HI		,
	"CDELETE"	,CMCHARDEL	,2	,ARG_LO+ARG_HI		,
	"XCHANGE"	,CMXCHANGE	,1	,ARG_LO+ARG_HI		,
	"TAPPEND"	,CMTAPP		,2	,ARG_LO+ARG_HI		,
	"TIME"		,CMTIME		,1	,ARG_NO			,
	"DATE"		,CMTIME		,2	,ARG_NO			,
	"FILE"		,CMFILE		,1	,ARG_NO			,
	"CHATTY"	,CMCHATTY	,4	,ARG_NO			,
	"VERBOSE"	,CMCHATTY	,3	,ARG_NO			,
	"RETICENT"	,CMRETICENT	,3	,ARG_NO			,
	"QUIET"		,CMRETICENT	,4	,ARG_NO			,
	"TYPE"		,CMTYPE		,2	,ARG_FI+DIR_RD+NOPARSE	,
	"COPY"		,CMCOPY		,2	,ARG_LO+ARG_HI+ARG_TA	,
	"CPY"		,CMCOPY		,2	,ARG_LO+ARG_HI+ARG_TA	,
	"HELP"		,CMHELP		,1	,ARG_FI+NOPARSE		,
	"SET"		,CMSET		,1	,ARG_FI+NOPARSE		,
	"QUIT"		,CMQUIT		,1	,ARG_NO+NO_VT		,
	"END"		,CMEND		,1	,ARG_NO+NO_VT		,
	"EXIT"		,CMEND		,3	,ARG_NO+NO_VT		,
	"UNDELETE"	,CMUNDEL	,1	,ARG_LO			,
	"$"		,CMSPAWN	,1	,ARG_FI+NOPARSE		,
	"SPAWN"		,CMSPAWN	,2	,ARG_FI+NOPARSE		,
	"DCL"		,CMDCL		,2	,ARG_FI+NOPARSE		,
	"TST"		,CMTST		,3	,ARG_LO+ARG_HI		,
	"TEST"		,CMTEST		,4	,ARG_LO+ARG_HI+ARG_TA	,
	"CASE"		,CMCASE		,3	,ARG_NO			,
	"TAB"		,CMTAB		,3	,ARG_NO			,
	"XLATE"		,CMXLATE	,3	,ARG_NO			,
	"SAVE"		,CMSAVE		,2	,ARG_NO			,
	"QQUIT"		,CMQQUIT	,2	,ARG_NO			,
	"REGIS"		,CMREGIS	,3	,ARG_NO			,
	"ECHO"		,CMECHO		,3	,ARG_NO			,
	"ZAP"		,CMZAP		,3	,ARG_FI+NOPARSE		,
	"DIRECTORY"	,CMDIR		,3	,ARG_FI+NOPARSE		,
	"PURGE"		,CMPURGE	,3	,ARG_FI+NOPARSE		,
	"ERASE"		,CMERASE	,3	,ARG_FI+NOPARSE		,
	"RULER"		,CMRULE		,3	,ARG_NO			,
	"EXAM"		,CMEXAM		,3	,ARG_FI+NOPARSE		,
	"JUNK"		,CMNONE		,0	,ARG_NO
			} ;

static
struct	cmd nullcmd = { "",0,0,0 } ;







ldedit()

/*	For PDP version, get VTEDIT to reload EDIT overlay	*/

{
	return(1) ;
}



execommand()
{

	extern struct textline inline ;
	extern int cmdlun,dovtedit,kblun,indlun,iniecho,sts_one,stvtedit ;
	register int status ;

	dovtedit = stvtedit ;
	while ( ( sts_one & ed_quit ) == 0 ) {
		status = 0 ;
		if ( dovtedit && ( cmdlun == kblun ) )
		  then	{
			inline.c[0] = 'V' ;
			inline.len = 1 ;
			dovtedit = 0 ;
			}
		  else	{
			while ( status != sys_normal ) {
				resumeoutput() ;
				if ( cmdlun == kblun ) then xprintf("EDIT> ") ;
				status = getline(cmdlun,inline.c,&inline.len) ;
				if ( status == er_eof && cmdlun != kblun )
			  	  then	{
					closef( cmdlun ) ;
					cmdlun = kblun ;
					if ( dovtedit )
					  then	{
						inline.len = 0 ;
						status = sys_normal ;
						}
					}
				}
			}
		if ( iniecho && inline.len && (cmdlun == indlun) )
		  then	{
			putbin("EDIT> ",0) ;
			putbin(inline.c,inline.len) ;
			}
		if ( (inline.len = cvtstring(inline.c,inline.len,04)) != 0 )
		  then	{
			inline.c[inline.len] = 0 ;
			if ( inline.c[0] == '@' )
			  then	{
			    if (inline.c[1] == 0)
			      then tederror("Need a filename to open") ;
			      else
			        if (openfi(&inline.c[1],indlun)==sys_normal)
				  then cmdlun = indlun ;
				  else tederror("Can't open command file") ;
				}
			  else
			    if (inline.c[0]=='/' && toupper(inline.c[1])=='L')
				then lastline() ;
				else teddocommand(inline.c) ;
			}
	}
}


teddocommand(s)
char *s ;
{
	struct cmd *findcommand() ;
	register struct cmd *cmdp ;
	register int status ;
	extern int argstat,filopen,kblun,cmdlun,sts_one ;
	


	if ( (cmdp = findcommand(s,&cmdlist)) == &nullcmd )
	  then	{
		if ( cmdlun != kblun ) then tederror(s) ;
		tederror("Unknown TED command");
		}
	  else	{
		if ( (status = getarg(s,cmdp->flags)) == 0 )
		  then	tederror("Invalid command format") ;
		  else
		   if ( checkarg() == 0 )
		     then tederror("Illegal command line arguments") ;
		     else
		       if ( (argstat & comp(cmdp->flags)) != 0 )
			 then tederror("Extra arguments for command");
		         else
			 if ((sts_one & _vtedit) && (cmdp->flags & NO_VT))
			   then tederror("Command not accessable from VTEDIT");
			   else
			   if ( setfile(cmdp->flags) == 0 )
			     then file_error("Can't access that file");
			     else {
				status = dispatch(cmdp->idx) ;
				clrfile() ;
				}
		}
	return(status) ;

}




static clrfile()
{
	extern int filopen,cmdlun,kblun ;

	if ( filopen != kblun && filopen != cmdlun ) then closef(filopen) ;
	filopen = kblun ;
}


static setfile(flag)
int flag ;
{
	register int lun,status ;
	extern int argstat,filopen ;
	extern char argfile[] ;
	extern int cmdlun,inlun,outlun,kblun ;

	filopen = cmdlun ;
	if ( (argstat & ARG_FI) == 0 ) then return(sys_normal) ;
	if ( (flag & DIR_WR) != 0 )
	  then	{
		if ( flookup(argfile) )
		  then	{
			if ( getyesno("Supercede file <YES> ? ","YES") )
			  then	{
				status = openfi(argfile,outlun) ;
				lun = outlun ;
				}
			  else status = 0 ;
			}
		   else	{
			status = openfi(argfile,outlun) ;
			lun = outlun ;
			}
		}
	  else	{
		if ( (flag & DIR_RD) != 0 )
		  then	{
			status = openfi(argfile,inlun) ;
			lun = inlun ;
			}
		  else	{
			status = sys_normal ;
			lun = cmdlun ;
			}
		}
	if ( status != sys_normal ) then status = 0 ;
	if ( status == sys_normal )
	  then	filopen = lun ;
	  else	filopen = cmdlun ;
	return(status) ;
}





static dispatch(idx)
int idx ;
{
	extern int filopen,iniecho,lowlim,highlim,*maxline,sts_one,target ;
	extern char argfile[] ;

	switch(idx) {
	  case CMVTEDIT:
		ldvtedit() ;
		if ( (sts_one & ed_end) != 0 ) then cend() ;
	return(1) ;
		break ;
	  case CMLEN:
		clength() ;
		break ;
	  case CMINSERT:
		cinsert(filopen) ;
		break ;
	  case CMLIST:
		clist(filopen) ;
		break ;
	  case CMDELETE:
		cdelete(filopen) ;
		break ;
	  case CMDUMP:
		dumpindex() ;
		break ;
	  case CMSTAT:
		dumpstats() ;
		break ;
	  case CMMOVE:
		cmove() ;
		break ;
	  case CMCHANGE:
		cchange(filopen) ;
		break ;
	  case CMREPLACE:
		creplace(filopen) ;
		break ;
	  case CMSEARCH:
		csearch(filopen) ;
		break ;
	  case CMASCII:
		cascii() ;
		break ;
	  case CMADD:
		cadd(filopen) ;
		break ;
	  case CMDUP:
		cduplicate() ;
		break ;
	  case CMAPPEND:
		cappend(filopen) ;
		break ;
	  case CMTRIM:
		ctrim() ;
		break ;
	  case CMPLACE:
		cplace() ;
		break ;
	  case CMCHARDEL:
		cchardel() ;
		break ;
	  case CMXCHANGE:
		cxchange() ;
		break ;
	  case CMTAPP:
		ctxtappend() ;
		break ;
	  case CMTIME:
		ctime() ;
		break ;
	  case CMFILE:
		cfile() ;
		break ;
	  case CMCHATTY:
		cchatty() ;
		break ;
	  case CMRETICENT:
		creticent() ;
		break ;
	  case CMTYPE:
		ctype(filopen) ;
		break ;
	  case CMCOPY:
		ccopy() ;
		break ;
	  case CMHELP:
		tedhelp(argfile) ;
		break ;
	  case CMSET:
		cset() ;
		break ;
	  case CMEND:				/* Write output and exit     */
		cend() ;
		break ;
	  case CMQUIT:				/* Abort the current edit    */
		cquit() ;
		break ;
	  case CMQQUIT:				/* Unconditionally abort     */
		sts_one = sts_one | ed_quit ;
		break ;
	  case CMUNDEL:				/* Undelete the last line    */
		cundel() ;			/* deleted.		     */
		break ;
	  case CMSPAWN:				/* Execute a DCL command.    */
	  case CMDCL:				/* The screen editor has a   */
		dclcommand(argfile) ;		/* more powerful version of  */
		putbin("\015\012",2) ;		/* this command which inserts*/
		break ;				/* the dcl output into file. */
	  case CMTEST:				/* For testing things out.   */
		testcommand() ;
		break ;
	  case CMTST:
		test1command() ;
		break ;
	  case CMCASE:				/* Processing for CASE, TAB   */
		swicase() ;			/* and XLATE will be found in */
		break ;				/* EDSET.C		      */
	  case CMXLATE:				/* They are located there as  */
		swixlate() ;			/* their functions would be   */
		break ;				/* better served as SET cmds  */
	  case CMTAB:				/* They are included here for */
		switab() ;			/* compatibility with the old */
		break ;				/* PDP-11 Macro-11 version.   */
	  case CMSAVE:
		csave() ;
		break ;
	  case CMREGIS:
		cregis() ;
		break ;
	  case CMECHO:
		iniecho = 1 ;
		break ;
	  case CMDIR:
		cdir(argfile) ;
		break ;
	  case CMZAP:
		czap(argfile,0) ;
		break ;
	  case CMERASE:
		czap(argfile,1) ;
		break ;
	  case CMPURGE:
		cpurge(argfile) ;
		break ;
	  case CMRULE:
		cruler() ;
		break ;
	  case CMEXAM:
		cexam(argfile) ;
		break ;
		}
}




char *expcommand(s)
char *s ;
{
	extern struct cmd *findcommand() ;
	register struct cmd *cp ;

	cp = findcommand(s,&cmdlist) ;
	return( cp->name ) ;
}


static struct cmd *findcommand(s,list)
char *s ;
struct cmd *list ;
{
	register char *cp ;
	register struct cmd *cmdp ;
	register int len ;
	int match ;
	char text[10] ;

	cmdp = list ;
	cp = s ;
	while ( *cp == SPACE || *cp == TAB ) cp++ ;
	for ( len=0; len < 10 && (isletter(*cp) || *cp == '$') ; len++ )
		text[len] = *cp++ ;
	text[len] = 0 ;
	cmdp = list ;
	match = 0 ;
	while ( cmdp->minlen != 0 && match == 0 ) {
		if ( len >= cmdp->minlen )
		  then
		    match = (finstr(cmdp->name,strlen(cmdp->name),text,len)==1);
		if ( match == 0 ) then cmdp++ ;
		}
	return( (match) ? cmdp:&nullcmd ) ;
}	


#define	M_DIG	0
#define	M_COM	1
#define	M_QUO	2
#define	M_COL	3
#define	M_LET	4
#define	M_OTH	5
#define	M_NUL	6
#define	M_STA	7
#define	M_PER	8
#define	M_SPA	9
#define	N_MAPS	10

/*			dig  com  '/'  ':'  let  oth  null '*'  '%' SPACE */
static
int	state_table[] = {12  ,-1  ,57  ,5   ,1   ,-1  ,0   ,68  ,1    ,1 ,
			 2   ,3   ,57  ,5   ,-1  ,-1  ,0   ,2   ,-1   ,2 ,
			 24  ,-1  ,-1  ,-1  ,-1  ,-1  ,-1  ,74  ,-1   ,3 ,
			 4   ,-1  ,57  ,5   ,-1  ,-1  ,0   ,4   ,-1   ,4 ,
			 36  ,-1  ,-1  ,-1  ,-1  ,-1  ,-1  ,86  ,-1   ,5 ,
			 6   ,-1  ,57  ,-1  ,-1  ,-1  ,0   ,6   ,-1   ,6 ,
			 0   ,0   ,0   ,0   ,0   ,0   ,0   ,0   ,0    ,7 ,
			 -1  ,3   ,57  ,5   ,-1  ,-1  ,0   ,8   ,-1   ,8  } ;


static getarg(s,flags)
register char *s ;
int flags ;
{
	extern int argstat,lowlim,highlim,*maxline,target,trimarg ;
	extern char argfile[] ;
	int i ;
	register int state,action ;

	lowlim = 1 ;
	highlim = *maxline - 1 ;
	trimarg = 0 ;
	target = 0 ;
	argfile[0] = 0 ;
	argstat = 0 ;

	if ( ( flags & NOPARSE ) != 0 )
	  then	{
		while ( isletter(*s) || *s == '$' ) s++ ;
		while ( *s == SPACE || *s == TAB ) s++ ;
		if ( *s == '/' ) then s++ ;
		for (i=0; i < 63 && (argfile[i] = *s++) != 0; i++);
		argstat = ARG_FI ;
		return( 1 ) ;
		}

	state = 1 ;
	while ( state > 0 ) {
		state = state_table[ mapch(*s) + N_MAPS*(state-1) ] ;
		if ( state > 0 )
		  then	{
			action = state/10 ;
			state = state % 10 ;
			switch( action ) {
			  case 1:
				lowlim = val(s) ;
				highlim = lowlim ;
				argstat |= ARG_LO ;
				break ;
			  case 2:
				highlim = val(s) ;
				argstat |= ARG_HI ;
				break ;
			  case 3:
				target = val(s) ;
				trimarg = target ;
				argstat |= ARG_TA ;
				break ;
			  case 4:
				break ;
			  case 5:
				strcpy(argfile,++s) ;
				argstat |= ARG_FI ;
				break ;
			  case 6:
				lowlim = *maxline - 1 ;
				highlim = lowlim ;
				argstat |= ARG_LO ;
				break ;
			  case 7:
				highlim = *maxline - 1 ;
				argstat |= ARG_HI ;
				break ;
			  case 8:
				target = *maxline - 1 ;
				argstat |= ARG_TA ;
				break ;
			  default:
				break ;
				}	/* end case  */
			s++ ;
			}		/* end then  */
		}			/* end while */
	return( ( state==0 ) ? 1:0 ) ;
}					/* end getarg*/


checkarg()
{
	extern int highlim,lowlim,*maxline,target ;

	if ( target >= *maxline ) then target = 0 ;
	return ( !(   highlim >= *maxline || lowlim > highlim || lowlim <= 0
		   || target < 0 || target >= *maxline ) ) ;
}



static val(s)
register char *s ;
{
	register int i ;
	i = 0 ;
	while ( isdigit(*s) ) i = i*10 + (*s++ - '0') ;
	return(i) ;
}

static mapch(ch)
register char ch ;
{
	register int map ;

	if ( isletter(ch) ) then return(M_LET) ;
	if ( isdigit(ch)  ) then return(M_DIG) ;

	switch( ch ) {
	  case SPACE:
	  case TAB:
		map = M_SPA ;
		break ;
	  case ',':
		map = M_COM ;
		break ;
	  case '/':
		map = M_QUO ;
		break ;
	  case '\'':
		map = M_QUO ;
		break ;
	  case '\0':
		map = M_NUL ;
		break ;
	  case ':':
		map = M_COL ;
		break ;
	  case '*':
		map = M_STA ;
		break ;
	  case '%':
		map = M_PER ;
		break ;
	  default:
		map = M_OTH ;
		break ;
		}
	return(map) ;
}





static lastline()
{
	extern int *maxline ;

	xprintf("Last line is %d\n",*maxline-1);
}



static cruler()
{
	int i ;
	xprintf("        ") ;
	for (i=1;i<72;i++) xprintf("%d",i%10) ;
	xprintf("\n") ;
}

static ctime()
{
	char s[30] ;
	gettim(s) ;
	xprintf("%s\n",s) ;
}

static creticent()
{
	extern int verbose ;
	verbose = 0 ;
}

static cchatty()
{
	extern int verbose ;
	verbose = 1 ;
}

static cfile()
{
	extern char *infile[] ;
	xprintf("%s\n",infile[0]) ;
}



static comp(i)
int i ;
{
	return(~i) ;
}


#if	VAXVMS
static testcommand()
{
	extern int lowlim,highlim ;
	register int i,junk ;
	extern struct	textline *textpointer() ;
	register struct	textline *tp ;

	for (i=lowlim;i<=highlim;i++) tp = textpointer(i) ;
}
static test1command() 
{
	extern int lowlim,highlim ;
	register int i,junk ;
	extern struct   textline *w_l_address[] ;
	register struct	textline *tp ;

	for (i=lowlim;i<=highlim;i++) tp = w_l_address[findline(i)];
}

#else
testcommand()
{
	extern int mapcnt ;
	xprintf("mapcnt %d\n",mapcnt) ;
}

test1command() {} ;
#endif


static file_error(e)
char *e ;
{
	char s[80] ;
	geterror(s) ;
	xprintf("%s\n %s\n",e,s) ;
}

