Google
 

Trailing-Edge - PDP-10 Archives - BB-R775E-BM - sources/edt/prparcom.bli
There are 10 other files named prparcom.bli in the archive. Click here to see a list.
 %TITLE 'PRPARCOM - parse a command'
MODULE PRPARCOM (				! Parse a command
		IDENT = '3-016'			! File: PRPARCOM.BLI Edit:GB3016
) =
BEGIN
!
!			  COPYRIGHT (c) 1983, 1985 BY
!	      DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
!		ALL RIGHTS RESERVED.
!
! THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED
! ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH  LICENSE AND WITH THE
! INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR  ANY  OTHER
! COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
! OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY
! TRANSFERRED.
!
! THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE  WITHOUT  NOTICE
! AND  SHOULD  NOT  BE  CONSTRUED  AS  A COMMITMENT BY DIGITAL EQUIPMENT
! CORPORATION.
!
! DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF  ITS
! SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
!

!++
! FACILITY:	EDT -- The DEC Standard Editor
!
! ABSTRACT:
!
!	Parse a command.
!
! ENVIRONMENT:	Runs on TOPS-20 only
!
! AUTHOR: Chris Gill, CREATION DATE: March 1, 1983
!
! MODIFIED BY:
!
! 3-001 - Created. CJG 1-Mar-1983
! 3-002 - Change the way that filespecs are handled. CJG 28-Jun-1983
! 3-003 - Add code for PUSH command and tidy up. CJG 25-Sep-1983
! 3-004 - Add PROMPT_LENGTH so that we can get error pointer in right place. CJG 7-Oct-1983
! 3-005 - Add TRACE and XDDT commands. CJG 10-Oct-1983
! 3-006 - Add SET SEARCH IGNORE parsing. CJG 2-Nov-1983
! 3-007 - Apply some modifications required by fixes in PRFILE. CJG 12-Dec-1983
! 3-008 - Fix problem when <ESC> and Control-R interact. CJG 20-Dec-1983
! 3-009 - Make Control-H work remove some old code. CJG 20-Dec-1983
! 3-010 - Check for control-C being typed. CJG 5-Jan-1984
! 3-011 - Allow SUBSTITUTE string to be terminated by <CR>. GB 2-May-1984
! 3-012 - Allow control chars as SUBSTITUTE string delimiters. GB 2-May-1984
! 3-013 - Fix TAB ADJUST to parse a range specification.  GB 20-Jul-1984
! 3-014 - Allow <LF> as a null command. GB 24-Jul-1984
! 3-015 - Fix problems with numeric zero argument on some SET commands. GB 7-Sep-1984
! 3-016 - Fix bug in comment handling which causes command buffer size to be
!	  reduced by 2 for each comment parsed. GB 15-Oct-1984
!--

%SBTTL 'DECLARATIONS'
!
! TABLE OF CONTENTS:
!

REQUIRE 'EDTSRC:TRAROUNAM';

REQUIRE 'EDTSRC:PARLITS';

FORWARD ROUTINE
    EDT$$PA_CMD,
    PA_PARSE;

!
! INCLUDE FILES:
!

REQUIRE 'EDTSRC:EDTREQ';

REQUIRE 'SYS:JSYS';

REQUIRE 'EDTSRC:PARDATA';

!
! EXTERNAL REFERENCES:
!

    EXTERNAL
!	CMD_BUF,			! Command line buffer.
	CMD_PTR,			! Pointer into command buffer.
	CMD_END,			! Pointer to end of current command.
	CMD_LEN,			! Length of command.
	VFY,				! verify switch
	INP_SRC,			! Source of input
	DEFKEY,				! Flag for DEFINE KEY
	TAB_SIZ,			! Size of a tab
	TI_WID,				! Terminal width
	PA_CURCMD : REF NODE_BLOCK,	! Current command node
	PA_CURTOK,			! start of the current token
	PA_CURTOKLEN,			! Length of current token
	PA_CURRNG,			! Current range node
	PA_MORE,			! More on command line
	PA_ERRNO,			! Error number of parsing error.
	PA_SP,				! Parse stack pointer
	PROMPT_LENGTH,			! Length of prompt
	WRT_NAM : BLOCK,		! Descriptor for WRITE command
	OUT_NAM : BLOCK,		! Descriptor for EXIT command
	INC_NAM : BLOCK,		! Descriptor for INCLUDE command
	TEMP_BUFFER,			! Temp string buffer
	HELP_DFLT,			! Help defaults for PA_FILE
	CMD_DFLT,			! Command defaults for PA_FILE
	CC_WAIT,			! ^C may be typed and should be handled
	CC;				! Control-C flag

    EXTERNAL ROUTINE
	EDT$$FMT_CRLF,			! Terminate an output line
	EDT$$FMT_CH,
	EDT$$FMT_LIT,
	EDT$$MSG_TOSTR,
	EDT$$PA_TSTMACCAL,		! Test atom for being a macro name
	EDT$$PA_NEW_NOD,		! Create a new node
	EDT$$PA_SCANTOK : NOVALUE,	! Find length of current atom
	EDT$$PA_SWITCH,			! Parse a switch
	EDT$$PA_GET_KEY,		! Parse a key name
	EDT$$PA_GET_CHAR,		! Get a single character
	EDT$$PA_FILE,			! Parse a filespec
	EDT$$PA_BUFFER,			! Parse a buffer name
	EDT$$PA_NUMBER,			! Parse a decimal number
	EDT$$PA_COLON,			! Parse a colon
	EDT$$PA_RANGE;			! Parse a range specifier

!
! MACROS:
!
!	NONE
!
!
! OWN STORAGE
!
!	NONE
!

%SBTTL 'EDT$$PA_CMD  - parse a command'

GLOBAL ROUTINE EDT$$PA_CMD(
		PROMPT,
		PRLEN) = 			! Parse a command

BEGIN
!++
! FUNCTIONAL DESCRIPTION:
!
!	This routine is called to parse a single command on the current command 
!	line. The command will be read from the relevent file or the terminal
!	which allows for full recognition. In this case, a copy of the command
!	is returned in the command buffer. If the parse is successful, a 1 is
!	is returned and the parsing stack contains a description of the command.
!	CMD_PTR  is left pointing at the '\' or <CR> which are are the only
!	valid terminators of commands.  If an error occurs, a 0 is returned,
!	and PA_MORE is left as zero to indicate that no more data exists on the
!	command line.
!
! FORMAL PARAMETERS:
!
!	NONE
!
! IMPLICIT INPUTS:
!
!	CMD_BUF
!	CMD_PTR
!	CMD_END
!	CMD_LEN
!	VFY
!	INP_SRC
!
! IMPLICIT OUTPUTS:
!
!	PA_CURCMD
!	PA_SP
!	PA_CURTOK
!	PA_ERRNO
!
! ROUTINE VALUE:
!
!	1 = parse was successful
!	0 = parse failed, PA_ERRNO  set
!
! SIDE EFFECTS:
!
!	MANY
!
!--

    BEGIN

    LOCAL
	C_FLAG,				! COMND flags
	C_DATA,				! COMND data pointer
	C_FDB,				! COMND actual FDB used
	STS : INITIAL (0);


    MESSAGES ((UNXCHRAFT, UNRCOM));

!+
! Indicate that if a control-C is typed it should be handled by aborting
! the COMND JSYS.
!-

    CC_WAIT = -1;

!+
! Initialise the COMND JSYS ready for a command. This is only done if
! there is no more data in the rescan buffer.
!-

    IF (.PA_MORE EQL 0) THEN
	BEGIN
	IF (.PRLEN NEQ 0) THEN PROMPT_LENGTH = .PRLEN;
	CH$WCHAR (0, CH$MOVE (.PRLEN, .PROMPT, CH$PTR (TEMP_BUFFER,, BYTE_SIZE)));
	CSB [$CMRTY] = CH$PTR (TEMP_BUFFER,, BYTE_SIZE);
	IF (NOT COMMAND (FD_INI))
	THEN
	    BEGIN
	    CC_WAIT = 0;
	    RETURN (0);
	    END;
	IF (.CC NEQ 0) THEN STS = -1;
	END;

!+
! Loop around the parser as long as a reparse is required. When an error
! occurs or the command is accepted, then continue.
!-

    PA_MORE = 0;
    WHILE (.STS EQL 0) DO
	BEGIN
!+
! Initialize the command node pointer and the parsing stack pointer.
!-
	PA_CURCMD = 0;
	PA_SP = -1;
	PA_ERRNO = 0;

	STS = PA_PARSE ();			! Parse a command

	IF (.STS EQL 1) THEN
	    BEGIN

!+
! The command has been parsed - make sure that it ends correctly.
!-

	    IF (NOT COMMAND (FD_END))
	    THEN
		BEGIN
		CC_WAIT = 0;
		RETURN (0);
		END;
	    IF (.CC NEQ 0)
	    THEN
		STS = -1
	    ELSE
		BEGIN
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN STS = 0;
		IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN 
		    BEGIN
		    PA_ERRNO = EDT$_UNXCHRAFT;
		    STS = -1;
		    END;
		END;
	    END;
	END;

!+
! If the command ended with '\', then indicate more to come
!-

	IF (.STS EQL 1) THEN
	    BEGIN
	    IF (.C_FDB<0,18> EQL FD_END) THEN
		BEGIN
		PA_CURTOK = .CSB [$CMPTR];
		PA_CURTOKLEN = .CSB [$CMINC];
		PA_MORE = 1;
		END;

	    CMD_LEN = 256 - .CSB [$CMCNT];
	    CC_WAIT = 0;
	    RETURN (1);
	    END;

!+
! There was an error - if it occured because of control-C then tidy up,
! go to a new line for the message, and exit now. (Assume no other errors)
!-

    IF (.CC NEQ 0) THEN
	BEGIN
	PA_MORE = 0;
	PA_ERRNO = 0;
	CC_WAIT = 0;
	EDT$$FMT_CRLF ();
	RETURN (0);
	END;

!+
! The command failed to parse correctly - indicate the error
!-

    IF (.PA_ERRNO EQL 0) THEN PA_ERRNO = EDT$_UNRCOM;

!+
! Print the command with an indication of where the error is. If the
! user ended the bad field with an escape, then send <CR><LF> first.
! Also take account of the prompt length so we get the pointer in the
! right place.
!-

    IF ((.INP_SRC NEQ INP_TERM) AND (.VFY EQL 0)) THEN
	BEGIN
	EDT$$FMT_CH (%C' ');
	EDT$$FMT_LIT (CH$PTR (CMD_BUF,, BYTE_SIZE), .CMD_LEN);
	EDT$$FMT_CRLF ();
	END;

    IF ((.CSB [$CMFLG] AND CM_ESC) NEQ 0) THEN EDT$$FMT_CRLF ();

    DECR I FROM (CH$DIFF (.CSB [$CMPTR], CH$PTR (CMD_BUF,, BYTE_SIZE)) +
	.PROMPT_LENGTH) TO 0 DO EDT$$FMT_CH (%C' ');
    EDT$$FMT_CH (%C'^');
    EDT$$FMT_CRLF ();
    PROMPT_LENGTH = 0;

!+
! Print the corresponding error message and ensure that other commands
! on this line are not parsed.
!-

    EDT$$MSG_TOSTR (.PA_ERRNO);
    EDT$$FMT_CRLF ();
    PA_MORE = 0;
    CC_WAIT = 0;
    RETURN (0);
    END;

END;

%SBTTL 'PA_PARSE - Parse the individual commands'

ROUTINE PA_PARSE =			! Start parsing a command

BEGIN

!+
! This routine parses the command keyword and dispatches to the relevent
! subroutine to parse the rest of the command. If a reparse is required,
! the value of the routine is set to 0, if an error occurs, it is set to
! -1, else it is set to 1.
!-


    OWN
	PARSED_FILE : BLOCK [DSC$K_SIZE];	! Space for parsed files

    LOCAL
	C_FLAG,				! COMND flags
	C_DATA,				! COMND data pointer
	C_FDB,				! COMND actual FDB used
	CMDTYP,				! Command type or subtype
	STS;

    LITERAL				! Filespec parsing flags
	F_REQD   = 1,			! Filespec required
	F_EXIT   = 2,			! EXIT command
	F_OUTPUT = 4,			! Parse an output filespec
	F_RELEAS = 8;			! Release the JFN when done

    MESSAGES ((ASREQ, QUOSTRREQ, MACKEYREQ, INVPARFOR, NUMVALREQ, NUMVALILL,
		UNXCHRAFT, UNRCOM, INVVALSET, ENTMUSTBE, NONALPNUM,
		SUBSTRNUL, INVSTR));

    BEGIN

!+
! Parse the command keyword
!-

    STS = 0;
    IF (NOT COMMAND (FD_CMD)) THEN RETURN (-1);
    IF (.CC NEQ 0) THEN RETURN (-1);
    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
    IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);

!+
! If the atom ended in an escape, then don't try to match it with a buffer
! name (we can't do recognition on these). If the atom parsed OK and it is
! not a buffer name, then treat it as a good command. Otherwise, try to
! make a range node out of it. If the command is just a carriage return,
! then default to NULL, ignore the command if it is a comment.
!-

    SELECTONE .C_FDB<0,18> OF

	SET

    [ FD_CMD ] :

	BEGIN
!+
! Found a valid command keyword. If recognition was not used, then see
! if it is a macro name. Otherwise, see to it.
!-
	IF ((.C_FLAG AND CM_ESC) EQL 0)
	THEN
	    BEGIN
	    EDT$$PA_SCANTOK (0,1);
	    IF (EDT$$PA_TSTMACCAL ()) THEN RETURN (1);
	    END;
	CMDTYP = .(.C_DATA)<0,18>;
	END;

    [ FD_CMM ] :

	BEGIN
!+
! Found an alphanumeric field. If it is not a macro name then fail, if
! it was empty, then try to parse a range.
!-
	STS = 1;
	EDT$$PA_SCANTOK (0,1);
	IF (.PA_CURTOKLEN NEQ 0) THEN

	    BEGIN
	    IF (EDT$$PA_TSTMACCAL ()) THEN RETURN (1);
	    CMDTYP = CH$RCHAR (.PA_CURTOK);
	    IF (.CMDTYP GEQ %C'@') THEN RETURN (-1);
	    CSB [$CMINC] = .CSB [$CMINC] + .PA_CURTOKLEN;	! Backup
	    CSB [$CMPTR] = .PA_CURTOK;
	    CSB [$CMCNT] = .CSB [$CMCNT] + .PA_CURTOKLEN;
	    END;

	CMDTYP = COM_NULL;
	END;

    [ FD_CMT ] :

	BEGIN

!+
! Set the command type appropriately, and backup to the <CR><LF> so that
! the end of line parsing will work.
!-

	LOCAL
	    PTR,
	    LEN;

	LEN = CH$DIFF (.CSB [$CMPTR], CH$PTR (CMD_BUF,, BYTE_SIZE));
	IF (.LEN LEQ 2) THEN
	    CMDTYP = COM_NULL
	ELSE
	    CMDTYP = -1;
	PTR = CH$PLUS (.CSB [$CMPTR], -1);
	WHILE (CH$RCHAR (.PTR) EQL %O'15') OR (CH$RCHAR (.PTR) EQL %O'12') DO
		    BEGIN
		    CSB [$CMINC] = .CSB [$CMINC] + 1;
		    CSB [$CMPTR] = .PTR;
		    CSB [$CMCNT] = .CSB [$CMCNT] + 1;
		    PTR = CH$PLUS (.PTR, -1);
		    END;
	END;

    TES;

!+
! Get a new parse node for this command
!-

	IF (.PA_CURCMD NEQ 0) THEN PA_CURCMD [ NEXT_COM ] = .PA_SP;

	IF ((PA_CURCMD = EDT$$PA_NEW_NOD (COM_NODE, .CMDTYP)) EQL 0) THEN RETURN (0);
	IF (.CMDTYP EQL -1) THEN RETURN (1);

	CASE .CMDTYP FROM COM_NULL TO LAST_COM OF
	    SET

	    [ COM_NULL ] :

		BEGIN
		IF .STS
		THEN
		    RETURN (EDT$$PA_RANGE (1))		! Just parse a range
		ELSE
		    CSB [$CMCNT] = .CSB [$CMCNT] + 2;	! Fix the counter
		END;

	    [ COM_CHANGE, COM_FILL, COM_FIND, COM_INSERT, COM_REPLACE ] :

		BEGIN
		RETURN (EDT$$PA_RANGE (1));		! Just parse a range
		END;

	    [ COM_COPY, COM_MOVE ] :

		BEGIN
		STS = EDT$$PA_RANGE (2);		! Parse a range subcommand
		IF (.STS LEQ 0) THEN RETURN (.STS);
		IF (NOT COMMAND (FD_RTO)) THEN RETURN (-1);	! Parse 'TO'
		IF (.CC NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		IF (.C_FDB<0,18> EQL FD_RTO) THEN
		    BEGIN

!+
! If a '%' was found then try to parse 'TO'
!-

		    IF (NOT COMMAND (FD_RT1)) THEN RETURN (-1);	! Parse 'TO'
		    IF (.CC NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		    IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		    END;
		STS = EDT$$PA_RANGE (1);		! Parse second range
		IF (.STS LEQ 0) THEN RETURN (.STS);
		RETURN (EDT$$PA_SWITCH (
			    IF (.CMDTYP EQL COM_COPY) THEN
				FD_COP
			    ELSE
				FD_DEL
			    ));
		END;

	    [ COM_DEFINE, COM_DEF_MAC ] :

		BEGIN
		PA_ERRNO = EDT$_MACKEYREQ;
		IF (NOT COMMAND (FD_DEF)) THEN RETURN (-1);
		IF (.CC NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		CMDTYP = .(.C_DATA)<0,18>;
		PA_CURCMD [COM_NUM] = .CMDTYP;
		SELECTONE .CMDTYP OF
		    SET

		[ COM_DEFINE ] :

		    BEGIN

!+
! Get the key number from the command
!-

		    STS = EDT$$PA_GET_KEY ();
		    IF (.STS LEQ 0) THEN RETURN (.STS);
		    PA_ERRNO = EDT$_ASREQ;
		    DEFKEY = 0;

!+
! Parse 'AS "string" '
!-

		    IF (NOT COMMAND (FD_AS)) THEN RETURN (-1);
		    IF (.CC NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		    PA_ERRNO = EDT$_QUOSTRREQ;
		    IF (NOT COMMAND (FD_QST)) THEN RETURN (-1);
		    IF (.CC NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);

!+
! Store the length and pointer to the string
!-

		    EDT$$PA_SCANTOK (1,0);
		    PA_CURCMD [AS_STR] = .PA_CURTOK;
		    PA_CURCMD [AS_LEN] = .PA_CURTOKLEN;
		    END;

		[ COM_DEF_MAC ] :

		    BEGIN

!+
! Parse a buffer name (same format as macro name)
!-

		    STS = EDT$$PA_BUFFER ();
		    IF (.STS LEQ 0) THEN RETURN (.STS);
		    PA_CURCMD [RANGE1] = .PA_CURRNG;
		    END;

		    TES;
		END;

	    [ COM_CLEAR ] :

		BEGIN
		STS = EDT$$PA_BUFFER ();		! Parse a buffer name
		IF (.STS LEQ 0) THEN RETURN (.STS);
		PA_CURCMD [RANGE1] = .PA_CURRNG;
		END;

	    [ COM_DELETE ] :

		BEGIN
		STS = EDT$$PA_RANGE (1);		! Parse a range
		IF (.STS LEQ 0) THEN RETURN (.STS);
		RETURN (EDT$$PA_SWITCH (FD_DEL));	! Parse /QUERY
		END;

	    [ COM_EXIT ] :

		BEGIN
		STS = EDT$$PA_FILE (OUT_NAM, F_EXIT + F_OUTPUT, 0);
		IF (.STS LEQ 0) THEN RETURN (.STS);
		RETURN (EDT$$PA_SWITCH (FD_EXI));	! Parse /SAVE or /SEQUENCE
		END;

	    [ COM_INCLUDE, COM_PRINT, COM_WRITE ] :

		BEGIN
		STS = (IF (.CMDTYP EQL COM_INCLUDE)
		    THEN EDT$$PA_FILE (INC_NAM, F_REQD, 0)
		    ELSE EDT$$PA_FILE (WRT_NAM, F_REQD + F_OUTPUT, 0));
		IF (.STS LEQ 0) THEN RETURN (.STS);
		STS = EDT$$PA_RANGE (1);	
		IF ((.STS LEQ 0) OR (.CMDTYP NEQ COM_WRITE)) THEN RETURN (.STS);
		RETURN (EDT$$PA_SWITCH (FD_RES));
		END;

	    [ COM_QUIT ] :

		BEGIN
		RETURN (EDT$$PA_SWITCH (FD_QIT));	! Only look for /SAVE
		END;

	    [ COM_RESEQ ] :

		BEGIN
		STS = EDT$$PA_RANGE (1);
		IF (.STS LEQ 0) THEN RETURN (.STS);
		RETURN (EDT$$PA_SWITCH (FD_RES));	! Parse /SEQUENCE
		END;

	    [ COM_SET ] :

		BEGIN
		PA_ERRNO = EDT$_INVPARFOR;

!+
! Clear out PARSED_FILE in case this is SET HELP or SET COMMAND.
!-

		PARSED_FILE [DSC$A_DEVICE] = 0;
		PARSED_FILE [DSC$A_DIRECT] = 0;
		PARSED_FILE [DSC$A_FNAME]  = 0;
		PARSED_FILE [DSC$A_FEXTN]  = 0;

!+
! Parse the SET option
!-

		IF (NOT COMMAND (FD_SET)) THEN RETURN (-1);
		IF (.CC NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);

!+
! Save the option number
!-

		CMDTYP = .(.C_DATA)<0,18>;
		PA_CURCMD [SET_TYPE] = .CMDTYP;

!+
! Perform any extra argument parsing that may be required
!-

		CASE .CMDTYP FROM 1 TO MAX_SET OF
		    SET

		[ SET_WRAP, SET_SCRN, SET_LINES, SET_TAB ] :

		    BEGIN
		    PA_ERRNO = EDT$_NUMVALREQ;

!+
! A decimal number is required
!-

		    STS = EDT$$PA_NUMBER ();
		    IF (.STS LSS 0) THEN RETURN (.STS);
		    PA_ERRNO = EDT$_NUMVALILL;
		    IF (.STS GEQ 256) THEN RETURN (-1);
		    PA_CURCMD [SET_VAL] = .STS;
		    END;

		[ SET_CASE, SET_SRCH, SET_TERM, SET_MODE, SET_NTITY,
		  SET_TEXT, SET_WORD, SET_PARA, SET_PROMPT ] :

		    BEGIN
		    PA_ERRNO = EDT$_INVVALSET;
		    IF (NOT COMMAND (
				SELECTONE .CMDTYP OF
				    SET
				[ SET_CASE ] : FD_CAS;
				[ SET_SRCH ] : FD_SCH;
				[ SET_TERM ] : FD_TRM;
				[ SET_MODE ] : FD_MOD;
				[ SET_NTITY] : FD_ENT;
				[ SET_TEXT ] : FD_TEX;
				[ SET_WORD ] : FD_WRD;
				[ SET_PARA ] : FD_PAR;
				[SET_PROMPT] : FD_PRO;
				    TES)
					) THEN RETURN (-1);
		    IF (.CC NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		    IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		    PA_CURCMD [SET_VAL] = .(.C_DATA)<0,18>;
		    IF ((.CMDTYP EQL SET_NTITY) OR
			(.CMDTYP EQL SET_TEXT) OR
			(.CMDTYP EQL SET_PROMPT) OR
			((.CMDTYP EQL SET_SRCH) AND (.(.C_DATA)<0,18> EQL SET_SIGN))) THEN

!+
! SET ENTITY, TEXT, or PROMPT also take a string
!-

			BEGIN
			PA_ERRNO = EDT$_QUOSTRREQ;
			IF (NOT COMMAND (FD_QST)) THEN RETURN (-1);
			IF (.CC NEQ 0) THEN RETURN (-1);
			IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
			IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);

			EDT$$PA_SCANTOK (1,0);
			PA_CURCMD [AS_STR] = .PA_CURTOK;
			PA_CURCMD [AS_LEN] = .PA_CURTOKLEN;
			END;
		    END;

		[ SET_HELP ] :

		    BEGIN
		    STS = EDT$$PA_FILE (PARSED_FILE, F_REQD + F_RELEAS, HELP_DFLT);
		    IF (.STS LEQ 0) THEN RETURN (.STS);
		    END;

		[ SET_COMND ] :

		    BEGIN
		    STS = EDT$$PA_FILE (PARSED_FILE, F_REQD + F_RELEAS, CMD_DFLT);
		    IF (.STS LEQ 0) THEN RETURN (.STS);
		    END;

		[ SET_CURSR ] :

		    BEGIN
		    PA_ERRNO = EDT$_NUMVALREQ;
		    STS = EDT$$PA_NUMBER ();
		    IF (.STS LSS 0) THEN RETURN (.STS);
		    PA_ERRNO = EDT$_NUMVALILL;
		    IF (.STS GEQ 32768) THEN RETURN (-1);
		    PA_CURCMD [SET_VAL1] = .STS;
		    STS = EDT$$PA_COLON (1);
		    IF (.STS LEQ 0) THEN RETURN (.STS);
		    PA_ERRNO = EDT$_NUMVALREQ;
		    STS = EDT$$PA_NUMBER ();
		    IF (.STS LSS 0) THEN RETURN (-1);
		    PA_ERRNO = EDT$_NUMVALILL;
		    IF (.STS GEQ 32768) THEN RETURN (-1);
		    PA_CURCMD [SET_VAL] = .STS;
		    END;

		[ INRANGE ] :

		    ;

		TES;
		RETURN (1);
		END;

	    [ COM_SHOW ] :

		BEGIN
		PA_ERRNO = EDT$_INVPARFOR;
		IF (NOT COMMAND (FD_SHO)) THEN RETURN (-1);
		IF (.CC NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		CMDTYP = .(.C_DATA)<0,18>;
		PA_CURCMD [SET_TYPE] = .CMDTYP;
		SELECTONE .CMDTYP OF
		    SET

		[ SHO_NTITY, SHO_PROMPT, SHO_TEXT ] :

		    BEGIN
		    PA_ERRNO = EDT$_ENTMUSTBE;
		    IF (NOT COMMAND (
				SELECTONE .CMDTYP OF
				    SET
				[ SHO_NTITY ] : FD_ENT;
				[ SHO_PROMPT] : FD_PRO;
				[ SHO_TEXT  ] : FD_TEX;
				    TES)
					) THEN RETURN (-1);
		    IF (.CC NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		    IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		    PA_CURCMD [SET_VAL] = .(.C_DATA)<0,18>;
		    END;

		[ SHO_KEY ] :

		    BEGIN
		    RETURN (EDT$$PA_GET_KEY ());
		    END;

		[ OTHERWISE ] :

		    ;

		    TES;
		RETURN (1);
		END;

	    [ COM_SUBS, COM_SUBS_NEXT ] :

		BEGIN

		LOCAL
		    STRNODE : REF NODE_BLOCK,		! Node pointer
		    QCHAR;				! Quote character

!+
! If the command was SUBSTITUTE NEXT, then set CMDTYP and make sure the
! command node is correctly set.
!-

		IF (.CMDTYP EQL COM_SUBS) THEN
		    BEGIN
		    IF (NOT COMMAND (FD_SNX)) THEN RETURN (-1);
		    IF (.CC NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		    IF ((.C_FLAG AND CM_NOP) EQL 0) THEN CMDTYP = COM_SUBS_NEXT;
		    PA_CURCMD [COM_NUM] = .CMDTYP;
		    END;

!+
! If the command was [SUBSTITUTE] NEXT, then it can be terminated by <CR>
!-

		IF (.CMDTYP EQL COM_SUBS_NEXT) THEN
		    IF ((.C_FLAG AND CM_EOC) NEQ 0) THEN RETURN (1);

!+
! Create a new node
!-

		IF ((STRNODE = EDT$$PA_NEW_NOD (STR_NODE, 0)) EQL 0) THEN
		    RETURN (-1);
		PA_CURCMD [STR_PNT] = .STRNODE;

!+
! Use the next character as the quote character - unless its alphanumeric
!-

		QCHAR = EDT$$PA_GET_CHAR ();
		IF (.QCHAR LEQ 0) THEN RETURN (.QCHAR);
		PA_ERRNO = EDT$_NONALPNUM;
		IF (((.QCHAR GEQ %C'0') AND (.QCHAR LEQ %C'9')) OR
		    ((.QCHAR GEQ %C'A') AND (.QCHAR LEQ %C'Z')) OR
		    ((.QCHAR GEQ %C'a') AND (.QCHAR LEQ %C'z'))) THEN RETURN (-1);

!+
! Now set the break mask for the new break character
!-

		BREAK_MASK [0] = %O'20000000';
		BREAK_MASK [1] = 0;
		BREAK_MASK [2] = 0;
		BREAK_MASK [3] = 0;
		BREAK_MASK [.QCHAR/32] = 1 ^ (35 - (.QCHAR MOD 32)) OR 
				.BREAK_MASK [.QCHAR/32];

!+
! Parse an unquoted string - up to the break or <CR>
!-

		STRNODE [SRCHADDR] = .CSB [$CMPTR];
		IF (NOT COMMAND (FD_UQS)) THEN RETURN (-1);
		IF (.CC NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);

!+
! Save the length. Die if <CR> was the terminator
!-

		STRNODE [SRCHLEN] = CH$DIFF (.CSB [$CMPTR], .STRNODE [SRCHADDR]);
		CSB [$CMINC] = .CSB [$CMINC] - 1;
		PA_ERRNO = EDT$_INVSTR;
		IF (CH$RCHAR_A (CSB [$CMPTR]) EQL ASC_K_CR) THEN RETURN (-1);

!+
! Parse another unquoted string
!-

		STRNODE [REPADDR] = .CSB [$CMPTR];
		IF (NOT COMMAND (FD_UQS)) THEN RETURN (-1);
		IF (.CC NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (-1);

!+
! Save the length of the replacement and make sure the aren't null
!-

		STRNODE [REPLEN] = CH$DIFF (.CSB [$CMPTR], .STRNODE [REPADDR]);
		PA_ERRNO = EDT$_SUBSTRNUL;
		IF ((.STRNODE [REPLEN] EQL 0) AND (.STRNODE [SRCHLEN] EQL 0))
		    THEN RETURN (-1);
		CSB [$CMINC] = .CSB [$CMINC] - 1;
		CSB [$CMCNT] = .CSB [$CMCNT] - 1;
		CSB [$CMPTR] = CH$PLUS (.CSB [$CMPTR], 1);

!+
! For a SUBSTITUTE command, then next atoms can be a range and switches.
!-

		IF (.CMDTYP EQL COM_SUBS) THEN
		    BEGIN
		    QCHAR = EDT$$PA_RANGE (1);
		    IF (.QCHAR LEQ 0) THEN RETURN (.QCHAR);
		    RETURN (EDT$$PA_SWITCH (FD_SUB));
		    END;
		END;

	    [ COM_TYPE ] :

		BEGIN
		STS = EDT$$PA_RANGE (1);
		IF (.STS LEQ 0) THEN RETURN (.STS);
		RETURN (EDT$$PA_SWITCH (FD_TYP));
		END;

	    [ COM_HELP ] :

		BEGIN
		IF (NOT COMMAND (FD_TXT)) THEN RETURN (-1);
		IF (.CC NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN
		    PA_CURCMD [FSPCLEN] = 0
		ELSE
		    BEGIN
		    EDT$$PA_SCANTOK (0,0);
		    PA_CURCMD [FILSPEC] = .PA_CURTOK;
		    PA_CURCMD [FSPCLEN] = .PA_CURTOKLEN;
		    END;
		END;

	    [ COM_TADJ ] :

		BEGIN
		PA_ERRNO = EDT$_NUMVALREQ;
		IF (NOT COMMAND (FD_ADJ)) THEN RETURN (-1);
		IF (.CC NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		IF (.C_FDB<0,18> EQL FD_ADJ) THEN
		    BEGIN
		    IF (NOT COMMAND (FD_VAL)) THEN RETURN (-1);
		    IF (.CC NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		    IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		    END;
		PA_ERRNO = EDT$_NUMVALILL;
		STS = 1;
		IF (.C_DATA LSS 0) THEN 
		    BEGIN
		    STS = -1;
		    C_DATA = - .C_DATA;
		    END;
		IF ((.C_DATA GEQ 32768) OR (.C_DATA * .TAB_SIZ GEQ 256)) THEN
		    RETURN (-1);
		PA_CURCMD [TAB_COUNT] = .STS * .C_DATA;
		STS = EDT$$PA_RANGE (1);
		IF (.STS LEQ 0) THEN RETURN (.STS);
		END;

	    [ COM_TRACE ] :

		BEGIN
		PA_ERRNO = EDT$_INVPARFOR;
		IF ( NOT COMMAND (FD_TRC)) THEN RETURN (-1);
		IF (.CC NEQ 0) THEN RETURN (-1);
		IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		CMDTYP = .(.C_DATA)<0,18>;

		PA_CURCMD [SET_TYPE] = .CMDTYP;
		PA_CURCMD [AS_STR] = 0;			! Preset

		IF (((.CMDTYP EQL TRC_ON) OR (.CMDTYP EQL TRC_OFF)) AND
		    ((.C_FLAG AND CM_EOC) EQL 0))
		THEN
		    BEGIN
		    IF ( NOT COMMAND (FD_TRR)) THEN RETURN (-1);
		    IF (.CC NEQ 0) THEN RETURN (-1);
		    IF ((.C_FLAG AND CM_RPT) NEQ 0) THEN RETURN (0);
		    IF ((.C_FLAG AND CM_NOP) NEQ 0) THEN RETURN (-1);
		    EDT$$PA_SCANTOK (1, 0);
		    PA_CURCMD [AS_LEN] = .PA_CURTOKLEN;
		    PA_CURCMD [AS_STR] = .PA_CURTOK;

		    IF (.CMDTYP EQL TRC_ON) THEN EDT$$PA_SWITCH (FD_TRS);
		    END;

		END;

	    [ COM_XDDT , COM_MAC_CALL , COM_PUSH ] :

		;

	    TES;

	RETURN (1);
	END;

    END;


END
ELUDOM