Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_1_19910112 - 6-1-exec/exechs.mac
There are no other files named exechs.mac in the archive.
;SRC:<6-1-EXEC>EXECHS.MAC.5, 18-Nov-85 11:05:57, Edit by KNIGHT
; Clean up CENUMB output
;SRC:<6-1-EXEC>EXECHS.MAC.4, 11-Nov-85 08:39:23, Edit by KNIGHT
; Never include / commands in history (edit moved from EXECSU)
;SRC:<6-1-EXEC>EXECHS.MAC.3,  7-Nov-85 16:32:38, Edit by KNIGHT
; Change prompt for current line
;SRC:<6-1-EXEC>EXECHS.MAC.2,  6-Nov-85 11:40:18, Edit by KNIGHT
; Make CENUMB type out command numbers the same as INFORMATION HISTORY
;[SU-SUSHI.ARPA]SHI:<6-1-EXEC>EXECHS.MAC.17, 15-Jul-85 16:43:30, Edit by BILLW
; change some "redo remembers" to "history"
; add STPOUT routine for typing STG style cursor control strings.
;<6-1-EXEC>EXECHS.MAC.15, 21-Jun-85 22:46:57, Edit by WHP4
; ^G acts like ^C in command editor at Stanford
;<6-1-EXEC>EXECHS.MAC.14, 18-May-85 17:44:43, Edit by FMF
; Don't smash needed pointers, be sure to call M.FIX after Meta-Rubout
;<6-1-EXEC>EXECHS.MAC.13, 18-May-85 17:34:50, Edit by FMF
; Fix bug where Meta-Rubout was looping forever (preserve D in call to CEBACK)
;<6-1-EXEC>EXECHS.MAC.12, 13-May-85 15:59:55, Edit by WHP4
; turn on PWSW so that we don't save passwords in history mech.
;<6-1-EXEC>EXECHS.MAC.11, 12-May-85 03:34:52, Edit by WHP4
;read jsys manual more carefully - +n, not -n in ac3 for SOUT in edit 10
;<6-1-EXEC>EXECHS.MAC.10, 12-May-85 03:24:15, Edit by WHP4
; need to print with SOUT to break on .STP when using strings from STG
;this should fix problem with DEL on AVT erasing screen, etc.
;<6-1-EXEC.CE>EXECHS.MAC.17,  3-May-85 23:53:07, Edit by FMF
;<6-1-EXEC.CE>EXECHS.MAC.16,  3-May-85 14:58:40, Edit by FMF
;<6-1-EXEC.CE>EXECHS.MAC.15,  3-May-85 14:55:26, Edit by FMF
; Another try at making METAR work right:  be sure to count chars correctly
;<6-1-EXEC.CE>EXECHS.MAC.14,  3-May-85 14:22:18, Edit by FMF
; Make METAR's AOBJN pointer has a negative left half
; Decrement METAR's byte pointer after checking a character
;<6-1-EXEC.CE>EXECHS.MAC.13,  3-May-85 14:06:23, Edit by FMF
; Sigh, there was already a METAR0 (from METARB)
;<6-1-EXEC.CE>EXECHS.MAC.12,  3-May-85 14:02:20, Edit by FMF
;<6-1-EXEC.CE>EXECHS.MAC.11,  3-May-85 13:54:45, Edit by FMF
; M-S and M-R for search forward/backward for character
;<6-1-EXEC.CE>EXECHS.MAC.10, 23-Apr-85 19:04:11, Edit by WHP4
; sigh, put COMMAND-EDITOR subcommands table in alpha order
;<6-1-EXEC.CE>EXECHS.MAC.9, 23-Apr-85 18:51:30, Edit by WHP4
;<6-1-EXEC.CE>EXECHS.MAC.8, 23-Apr-85 18:14:07, Edit by WHP4
; add SET COMMAND-EDITOR EDIT-MODE, put back SOS mode
;<6-1-EXEC.CE>EXECHS.MAC.7, 10-Apr-85 17:15:13, Edit by WHP4
; fix capitalization, etc.
;<6-1-EXEC.CE>EXECHS.MAC.6, 29-Mar-85 20:35:38, Edit by WHP4
; change CALL FIELD to CALL FIELDX to follow changes elsewhere
;<6-EXEC>EXECHS.MAC.11,  5-Nov-84 01:33:23, Edit by ALMQUIST
; Use new Exectt module for terminal-type-dependent stuff so that this
;  module is portable to other sites
; Fix bug in calculation of numeric arguments
; Make M-$ overwrite the current line
; Rewrite some CU fixes to M-$ that weren't quite right
;<6-EXEC>EXECHS.MAC.10, 11-Oct-84 21:26:43, Edit by ALMQUIST
; By default don't include references to PWDFLG, since Stanford Exec
;   doesn't contain support for it anywhere else
; Fix (break?) Columbia-specific tty stuff so that this compiles at Stanford
; Copy ATICHR routine from Columbia so this will compile.  This needs
;   some sort of conditional to unbreak it at Columbia
;SNARK:<5.EXEC.US>EXECHS.MAC.9,  2-Mar-84 21:00:19, EMACSed by Sy.Bill
;CU146	Add VT102 tty
;SNARK:<5.EXEC.US>EXECHS.MAC.8, 24-Dec-83 00:00:26, EMACSed by Sy.Bill
;CU141	Add Viewpoint tty
;SNARK:<5.EXEC.US>EXECHS.MAC.6, 12-Oct-83 21:18:02, EMACSed by Sy.Bill
;CU135	Make REDO do WILDs in comparing the strings.  Re-order FLDDBs
;	so that CMCFM is before CMTXT.  Reload function after confirm
;	and do correct test for error.
;SNARK:<5.EXEC.US>EXECHS.MAC.5, 30-Sep-83 13:17:18, EMACSed by Sy.Bill
;CU133	Make sure we are NOINT when adding to history list.
;SNARK:<5.EXEC.US>EXECHS.MAC.4,  7-Sep-83 02:43:11, EMACSed by Sy.Bill
;CU129	Add Freedom-100 Terminal type
;SNARK:<5.EXEC.US>EXECHS.MAC.2, 17-Aug-83 00:39:39, EMACSed by Sy.Bill
;CU121	Don't expand % args when etypy'ing info history commands.
;SNARK:<5.EXEC.NEW>EXECHS.MAC.64, 30-Jun-83 04:12:16, EMACSed by Sy.Bill
;CU79	New help message for command editor.
;SNARK:<5.EXEC.NEW>EXECHS.MAC.61, 26-Jun-83 17:52:37, EMACSed by Sy.Bill
;CU79	Change "interrupt-character" to be "edit-character" a more
;	mnemonic name.  Fix problem with M-? causing zillions of weird
;	things from happening, especially don't print two or three help
;	messages.
;SNARK:<5.EXEC.NEW>EXECHS.MAC.60, 23-Jun-83 04:03:51, Edit by OC.CHRIS
;CU79	No funny M-ESC action if at left margin
;SNARK:<5.EXEC.NEW>EXECHS.MAC.59, 23-Jun-83 03:36:32, Edit by OC.CHRIS
;CU97	"Redefine (logical name) sys:" for editing logical name bodies
;SNARK:<5.EXEC.NEW>EXECHS.MAC.56, 22-Jun-83 12:31:40, EMACSed by Sy.Bill
;CU79	Make the editor work properly for terminals with parity set, don't
;	read an extra CR in this case.
;SNARK:<5.EXEC.NEW>EXECHS.MAC.55, 18-Jun-83 10:03:17, EMACSed by Sy.Bill
;CU79	Don't make "/noedit" an invisible keyword
;<5.EXEC.NEW>EXECHS.MAC.52, 18-Jun-83 04:50:34, Edit by OC.CHRIS
;CU79	Change /noedit and /fast to /confirm and /noconfirm
;<5.EXEC.NEW>EXECHS.MAC.40, 14-Jun-83 18:01:00, Edit by OC.CHRIS
;CU79	REDO/FAST is like REDO/NOEDIT but doesn't require extra confirm
;<5.EXEC.NEW>EXECHS.MAC.37, 14-Jun-83 16:41:41, Edit by OC.CHRIS
;CU90	Canonical parsing for SET {NO} REDO INTERRUPT-CHARACTER
;SNARK:<5.EXEC.NEW>EXECHS.MAC.17, 13-Jun-83 20:18:21, EMACSed by Sy.Bill
;CU79	Change syntax to SET {NO} REDO instead of SET REDO {NO}.
;	Repeat 0 SOS mode code.
;	Remove SET REDO EDIT-MODE.
;	Make SET NO REDO REMEMBERED (commands) disable interrupt char
;	 if present.
;SNARK:<5.EXEC.NEW>EXECHS.MAC.16, 10-Apr-83 18:16:42, EMACSed by Sy.Bill
;CU79	Fix problem in METESC when esc esc is typed when cursor is positioned
; 	on non-alphanumeric, the backword, forwardword stuff does not give
;	the correct result.  Try DIR (OF FILES)<esc><esc>.
;SNARK:<5.EXEC.NEW>EXECHS.MAC.6, 10-Apr-83 00:01:59, EMACSed by Sy.Bill
;CU79	New syntax:
;	SET REDO {NO} REMEMBERS {n}
;	SET REDO EDIT-MODE {EMACS | SOS}
;	SET REDO INTERRUPT-CHARACTER
;	INFORMATION PREVIOUS (COMMANDS) replaces HISTORY
;<PA0B.EXEC>EXECHS.MAC.3, 12-Mar-83 20:12:29, Edit by PA0B
;Parse EOL after "Redo -n"
;<PA0B.EXEC>EXECHS.MAC.2, 22-Feb-83 07:46:20, Edit by PA0B
;Turn on channel for editor interrupt character in C2CBUF, to allow
; "Redo /noedit ... CRLF ^Y"
;<PA0B.EXEC>EXECHS.MAC.1, 17-Jan-83 01:36:50, Edit by PA0B
;Created...The change number PA048 is used to denote changes I had to
;make to the UTEXAS code.  The things I did were:
;
; - Rename CEFLAG => CEMODE to be more mneumonic
; - Use a macro to define the TRVAR for the editor (so I don't have
;   to remember to change multiple TRVAR's)
; - Use SAVCMD instead of CSAVE
; - Rename CETSAV to CETBUF, and make it be a synonym for BUF0
; - Make CEBPTR a TRVAR, and ignore its use in the UTEXAS code as a
;   flag like our LINSVD
; - Use HSTLST in place of references to CE1ST and CELAST
; - Use CMDNUM in place of CECNT - 1
; - Hack so that positive command numbers are absolute command numbers
;   and negative ones are relative command numbers (UTEXAS code treated
;   positive numbers as relative and didn't allow absolute
;
;----------------------------------------------------------------------
;
; New module for the command history stuff.
;
; Copyright (C) 1983, 1984 by Philip Almquist
; All rights reserved
;
;	This module has been created to centralize the expanding mass
; of command history stuff in Clexec.  Some of what appears here has
; been moved from other modules (mostly Execsu), and the editor and
; related stuff are new.  The editor is based on the UTEXAS-20 editor
; by Billy Brown (which in turn claims to be based on the "Yale Exec
; Command Editor" by ???).  The editor has been modified by Vince
; Fuller, Mike Blackwell, and myself.  C2CBUF is a stripped down version
; of a routine used by Chris Ryland's command macro facility.  The rest
; of the code is mine.

	SEARCH EXECDE		;Get standard definitions, do TITLE,
	TTITLE EXECHS		; get access to global symbols, etc.

IFNDEF CUSW,<CUSW==0>		;Assume not Columbia
IFN CUSW,<PWSW==1>		;If Columbia, include PWDFLG code
IFN STANSW,<PWSW==1>		;If Stanford, include PWDFLG code
IFNDEF PWSW,<PWSW==0>		;Assume no PWDFLG code

;PA048 Define storage used by command editor:

DEFINE CEDSTG,<
 TRVAR <CADLFG,CEDUMB,CABKFG,CELPOS,CECPOS,CELPTR,CEBPTR,EDITFL,CETTMD,CEORIG>
	>

CETBUF==BUF0			;Command editor uses BUF0 as temp buffer
CETBSZ==1000			;Size of buffer

;Special AC usage:
;
;	Inside the editor, P3 is used as a global repeat count for
; commands.
;	The command history is stored as a doubly-linked list of strings.
; Pointers to the head and tail of the list are stored in the Exec variable
; HSTLST.  Storage is allocated dynamically in the Exec's permanant (XDICT)
; free pool.  HSTLST is described in more detail later.
;
;	The number of commands stored is controlled by the variable
; HISTSW, which contains an integer which is the number of commands to
; store (or zero if the command history facility is disabled).  HISTSW
; is initialized by INITHS and can be changed via the "Set history n"
; and "Set no history" commands.
;
;	HSTCNT contains an integer which is the number of commands
; actually stored.  It may be less than HISTSW if not enough commands
; have been given to fill up the history.  HSTCNT is used to determine
; when it is necessary to discard a command when adding a command to
; the history, and also to determine which direction to move around the
; list from the header for maximum efficiency in accessing a stored
; command.
;
;	The variable CMDNUM is used to number the stored commands.  It
; increases monotonically every time a command is issued (irregardless
; of whether the command history facility is enabled).  The only exception
; to that rule is that commands containing passwords are not counted, but
; there are currently no commands at CMU that take a password as part of
; the first line of the command (at other places, "Login" and maybe a few
; others do).  The reason for the bit about the commands with passwords is
; that the current command numbering scheme requires us to store every
; command that we number (since absolute numbers are converted to relative
; numbers).  That could, of course, be changed.
;
;	The last paragraph hinted that some things are not stored in the
; history.  That is indeed correct.  In particular:
;
; - Nothing is stored while HISTSW is equal to zero (ie, command history
;   is disabled) even though CMDNUM is still incremented)
; - As stated above, any command line containing a password is not stored
; - Only the first line of a command is stored (ie, no subcommands).
; - Commands which are done inside of Take files or are DOCOMMAND'd by
;   PCL commands are not stored.
;
; CMDNUM is not incremented for subcommands or for commands done in Take
; files or by DOCOMMAND in Pcl commands.
;
; The format of HSTLST is:
;
;	tail (oldest record) pointer,,head (newest record) pointer
;
; The format of a history list entry is:
;
;	+0/ previous pointer (or 0),,next pointer (or 0)
;	+1/ size (in words) of the record
;	+2/ command string (ASCIZ)
;	+3/	  .
;		  .
;	+n/	  .
;
; (These should probably be done with DEFSTR's someday...)
;Routine to initialize the command history system
;
INITHS::
	SETZM HSTLST		;No entries in history list yet
	SETZM HSTCNT		;Count of saved commands is zero
	SETZM CMDNUM		;Current command is serial number 0
	SETZM HISTSW		;Default to no history (for now)
	SETZM CEMODE		;Default editing mode is Emacs
	SETOM CEPSIC		;No interrupt character
	SETZM CEMETA		;Assume no meta key
	RET	
;"History" - prints command history

.HISTO::NOISE <of commands>
	MOVEI B,[FLDDB. .CMKEY,,$HISTO,,<all-recorded>,[
		 FLDDB. .CMNUM,CM%SDH,^D10,<Number of commands to print>,,]]
	CALL FLDSKP		;Find out how many
	 ERROR <Length of history not specified>
	CONFIRM
	SKIPN HISTSW		;Is history stuff enabled?
	 ERROR <Command history facility is not enabled>
	SKIPN HSTCNT		;Is there anything to print?
	 ERROR <No commands stored>
	LDB D,[331100,,(C)]	;Good parse, see what got typed
	CAIN D,.CMKEY		;All?
	 MOVE B,HSTCNT		;Yes, get number of entries
	CAMLE B,HSTCNT		;Requested more than we have?
	IFNSK.			;Yes
	  ETYPE <%%Insufficient history stored>	;CU79
	  ETYPE < - partial listing will be printed%_>
	  MOVE B,HSTCNT		;Print this many
	ENDIF.
	SKIPG B			;Request more than 0?
	 ERROR <Requested history length must be greater than 0>
	MOVE A,HSTLST		;Get list header
	MOVE D,CMDNUM		;Get the current command number
HSTLOP:	HRROI C,2(A)		;Get address of string
	CALL CENUMX		;Output command number
	ETYPE <%3M%%_>		;CU121 Type the command
	MOVE A,(A)		;Get next command
	SOS D			;Decrement the command number
	SOSLE B			;Done?
	 JRST HSTLOP		;No, do another
	JRST CMDIN4		;Yep, return to main command loop

$HISTO:	TABLE
IFN CUSW,<
	T all-recorded,,0
>;IFN CUSW
IFE CUSW,<
	T ALL-RECORDED,,0
>;IFE CUSW
	TEND
;"Redo" - re-executes a command from the history

$REDO:	TABLE
IFN CUSW,<
	T confirm,,0		;CU79
	T edit,,777777		;(halfword -1)
	IT fast,,1		;CU79 1 means no edit and no extra confirm
	T noconfirm,,1		;CU79
	T noedit,,0		;CU79
>;IFN CUSW
IFE CUSW,<
	T CONFIRM,,0
	T EDIT,,777777		;(halfword -1)
	T NOCONFIRM,,1
	IT NOEDIT,,0
>;IFE CUSW
	TEND

.REDO::	CEDSTG			;Declare TRVAR's
	NOISE <a previous command>
	SETOM LINSVD		;Say already saved (so "Redo" commands are
				; never saved)
	SETOM CELPOS		;Default to relative command -1 (ie, most
				; recent command)
	MOVE B,REDOFL		;Get "Redo" defaults
	MOVEM B,EDITFL		;Default whether or not to use editor
	MOVEI B,[FLDDB. .CMSWI,,$REDO,,,[
		 FLDDB. .CMNUM,CM%SDH,^D10,<Absolute command number (positive)
  or Relative command number (negative)>,,[
		 FLDDB. .CMCFM,CM%SDH,,,,[
		 FLDDB. .CMTXT,CM%SDH,,<Prefix of previous command (wildcards allowed)
  or Confirm to reexecute the previous command>,,]]]]

	CALL FLDSKP
	 CMERRX
	LDB D,[331100,,(C)]	;Good parse, see what got typed
	CAIE D,.CMSWI		;Switch?
	 JRST REDO0		;No, go on
	CALL GETKEY		;Get which one
	HRREM P3,EDITFL		;Remember which switch we saw
	MOVEI B,[FLDDB. .CMNUM,CM%SDH,^D10,<Absolute command number (positive)
  or Relative command number (negative)>,,[
		 FLDDB. .CMCFM,CM%SDH,,,,[
		 FLDDB. .CMTXT,CM%SDH,,<Prefix of previous command (wildcards allowed)
  or Confirm to reexecute the previous command>,,]]]

	CALL FLDSKP
	 CMERRX
	LOAD D,CM%FNC,.CMFNP(C)	;Good parse, see what got typed
REDO0:	CAIN D,.CMTXT		;String?
	 JRST RDSRCH		;Yes, go handle it
	CAIE D,.CMNUM		;Number?
	 JRST REDO2		;No, better be confirmation
	SKIPGE B		;Absolute command number given?
	 JRST REDO1		;No, relative.  Go confirm
	SUB B,CMDNUM		;Yes, convert to relative
	SOS B			;... (because current is relative -1)
REDO1:	MOVEM B,CELPOS		;Store it
	MOVEI B,[FLDDB. .CMCFM]	;Confirm the command
	CALL FLDSKP		;...
	 CMERRX
	MOVEI D,.CMCFM		;CU135 we just parsed a confirm....
REDO2:	CAIE D,.CMCFM		;CU135 Confirm?
	 ERROR <Not confirmed>
	SKIPN HISTSW		;Is history stuff enabled?
	 ERROR <Command history facility is not enabled>
	SKIPL CELPOS		;Relative command number .gt. 0?
	 JRST CN2BGE		;Yes, user must have given an absolute number
				; that was too big.  Complain
	MOVN A,CELPOS		;Get -(relative command number)
	CAMLE A,HSTCNT		;Have enough history?
	 ERROR <The command history does not go back that far>
	MOVE B,CELPOS		;Get back the relative command number
	ADD B,CMDNUM		;Convert to absolute command number
	AOS B			;...
	EXCH B,CELPOS		;CELPOS needs absolute command number
	LSH A,1			;Multiply relative command number by 2
	CAMLE A,HSTCNT		;Closer to the tail or the head of the history?
	 JRST REDO4		;Closer to the tail
				;Closer to head, fall thru...

;Here to run down the list starting at the head of the list.  B contains
;the relative command number of the desired command:

	HRRZ A,HSTLST		;Get pointer to list of stored commands
REDO3:	AOSL B			;Found right command yet?
	 JRST REDO6		;Yes
	HRRZ A,(A)		;No, get next one
	SKIPE A			;Internal error?
	 JRST REDO3		;No, loop again
	ERROR<Internal error in REDO3 - ran off end of list>

;Here to run down the list starting from the tail.  Virtually identical
;to the above code, but sufficiently different that it would be hard to
;to merge the two cases:

REDO4:	ADD B,HSTCNT		;Make B contain number of links away from
	AOS B			; tail (when we get here it contains - the
				; number away from the head of the list)
	HLRZ A,HSTLST		;Get pointer to list tail
REDO5:	SOSG B			;Found right command yet?
	 JRST REDO6		;Yes
	HLRZ A,(A)		;No, get next one
	SKIPE A			;Check internal consistency
	 JRST REDO5		;Ok, loop again
	ERROR<Internal error in REDO5 - attempt to run off beginning of list>

;Here when we are supposed to match a given string:

RDSRCH:	CONFIRM			;Confirm the command
	SKIPN HISTSW		;Is history stuff enabled?
	 ERROR <Command history facility is not enabled>
REPEAT 0,<			;CU135
	MOVE A,[POINT 7,ATMBUF]	;Get pointer to atom buffer
	MOVE B,A		;Copy the pointer
	DO.			;Compress out whitespace, raise lowercase
	  ILDB C,A		;Get a character
	  CAIL C,"a"		;Lowercase?
	   CAILE C,"z"		;...
	    TRNA		;No
	    SUBI C,40		;Yes, raise it
	  CAIE C,.CHSPC		;Space
	   CAIN .CHTAB		; or tab?
	    LOOP.		;Yes, do next character
	  IDPB C,B		;No, significant, so keep it
	  JUMPE C,ENDLP.	;We're done if null
	  LOOP.			;Otherwise, go around again
	OD.
>;CU135 END REPEAT 0
;CU135 Begin addition

; Scan the atom buffer to make sure it doesn't end with a "%".  As
; long as it doesn't, add a "*".

	MOVE A,[POINT 7,ATMBUF]	; point to the atom buffer
	ILDB B,A		; get a char
	JUMPN B,.-1		; and loop until we hit the null
	SETOM B			; backup by one
	ADJBP B,A		; ...
	LDB C,B			; get the character before the null
	CAIE C,"%"		; all done if it is a special character
	CAIN C,"*"		; already....
	IFSKP.			; No, proceed to tie it off
	 MOVEI C,"*"		; with a star to match
 	 DPB C,A		; the rest of the string
	 SETZM C		; and finally tie it
	 IDPB C,A		;  off with a null
	ENDIF.

;CU135 End addition

	MOVE A,CMDNUM		;Get current command number
	MOVEM A,CELPOS		;Save it
	HRRZ C,HSTLST		;CU135 Get pointer to head of history list
	MOVEM C,CELPTR		;CU135 Save it, too
SEALOP:	ADDI C,2		;CU135 Get pointer to text of history entry
	HRLI C,440700		;CU135 ...
	MOVE B,[POINT 7,ATMBUF]	;Get pointer to atom buffer
	MOVX A,.WLSTR		;CU135 function is wild match
	WILD%
	 ERJMP [ERROR <WILD failed in SEALOP>]
	JUMPE A,SESUCC		;CU135 a match, success! 

REPEAT 0,<			;CU135 
SEALO2:	ILDB C,A		;Get a character from the history entry
	CAIL C,"a"		;Lowercase?
	 CAILE C,"z"		;...
	  TRNA			;No
	  SUBI C,40		;Yes, raise it
	CAIE C,.CHSPC		;Space
	 CAIN C,.CHTAB		; or tab?
	  JRST SEALO2		;Yes, get another character
	ILDB D,B		;Get a character from the atom buffer
	JUMPE D,SESUCC		;If null from atom buffer we're done
	CAMN C,D		;Characters match?
	 JRST SEALO2		;Yes, keep checking
>;CU135 END REPEAT 0

	
	SOS CELPOS		;No, try next command.  Decrement command
				; number
	HRRZ C,@CELPTR		;CU135 Get next history entry
	MOVEM C,CELPTR		;CU135 Save it
	JUMPN C,SEALOP		;CU135 If haven't fallen off end of list,
				; go try this entry
	ERROR <Unable to find a saved command with that prefix>

SESUCC:	MOVE A,CELPTR		;Get address of winning entry
	JRST REDO6		;Go do it

;Here when we've found what we're looking for.  A contains the address of
;the history record:

REDO6:	SKIPL EDITFL		;CU79 Want to edit?
	IFSKP.			;CU79 Yes
	  MOVEM A,D		;Save address of history record
	  HRROI A,CBUF		;Get pointer to CBUF
	  HRROI B,2(D)		;Get pointer to text of command
	  SETZ C,		;Terminate on null
	  SOUT%			;Copy command into CBUF in case ^G typed
	   ERJMP .+1		; to editor later
	  MOVE A,D		;Get address of history record for command
	  MOVE B,CELPOS		;Get absolute command number for the entry
	  SETZ C,		;Start editing at beginning of the line
	  CALL CEDITU		;Go edit it
	ELSE.			;Else just go retrieve command
	  HRROI A,2(A)		;Get pointer to text of command
	  CALL FAKTYP		;Set up the command
	ENDIF.
	SETZM CIPF		;Say no command in progress so that command
				; will be given its right name and (more
				; importantly) it will get saved in the
				; history
;CU79 since FAKTYP was called a prompt was not issued and the terminal
;CU79 interrupt will not be enabled, enable it now.
	HRLZ A,CEPSIC		;CU79 Get interrupt character's code
	HRRI A,CEPCHN		;CU79 Get the channel to use
	SKIPL A			;CU79 CEPSIC contains -1 (ie, none)
	 ATI%			;CU79 No, so assign interrupt
	JRST REPARS		;Go parse it

;Here if user gave absolute command number and number was too big:

CN2BGE:	ERROR <Command number too large - you have not issued that many commands>
;CU79 Set redo remembers n

;"Set history (of commands with length) n"

.SHIST::NOISE <number of commands>
	DECX <Number of commands to store in the command history>
	 CMERRX
	CONFIRM
	CAIGE B,0
	 ERROR <Length must be greater than or equal to zero>
	MOVEM B,HISTSW		;Store the new length
	CAIN B,0		;Length zero?
	 JRST SNHIS2		;Yes, treat as "Set no history"
	SUB B,HSTCNT		;Yes, compute - number of elements to remove
				; from the current history list
	MOVNM B,Q1		;Invert sign and store in a safe place
	JRST SNHIS3		;Join "Set no history" code

; Set no redo remember

.SNHIS::NOISE <commands>
	CONFIRM
	SETZM HISTSW		;Flag history stuff is disabled
SNHIS2:	SETOM CEPSIC		;CU79 get rid of character first
	MOVE Q1,HSTCNT		;Get number of history records we currently
				; have saved (and prepare to nuke them)
SNHIS3:	SKIPG Q1		;More to remove?
	 JRST CMDIN4		;No, we're done
	CALL RMVHST		;Yes, remove one entry
	SOJA Q1,SNHIS3		; and loop

; Info redo

.INRED::NOISE (status)
	CONFIRM
	SKIPE A,HISTSW		; get number of remembered commands
	IFSKP.
	 ETYPE < Set no history%_>
	ELSE.
	 ETYPE < Set history %1Q% (commands)%_>
	ENDIF.
	SKIPL A,CEPSIC		; get character
	IFSKP.
	 ETYPE < Set no redo edit-character%_>
	ELSE.
	 ADDI A,"A"-.CHCNA	;CU90 Convert to printing representation
	 ETYPE < Set redo edit-character ^%1\%%_> ;CU90
	ENDIF.
	RET
;"Set default redo"

.SDRED::MOVEI B,[FLDDB. .CMSWI,,$REDO,,,]
	CALL FLDSKP		;Parse a switch
	 CMERRX
	CALL GETKEY		;Get the data word
	CONFIRM			;Finish it off
	HRREM P3,REDOFL		;Save the value
	RET			;All done

;CU79 "Info default redo"
IFN CUSW,<
.IDRED::HRROI 1,[ASCIZ/confirm/] ;CU79 assume "noedit" is the default
	SKIPGE REDOFL
	 HRROI 1,[ASCIZ/edit/]	;if EDITFL = -1, then it's "edit"
	SKIPLE REDOFL
	 HRROI 1,[ASCIZ/noconfirm/] ;CU79 if EDITFL = 1, don't confirm
	ETYPE < Set default redo /%1M%%_> ;type it out
	RET
>;IFN CUSW,
IFE CUSW,<
.IDRED::HRROI 1,[ASCIZ/CONFIRM/] ;CU79 assume "noedit" is the default
	SKIPGE REDOFL
	 HRROI 1,[ASCIZ/EDIT/]	;if EDITFL = -1, then it's "edit"
	SKIPLE REDOFL
	 HRROI 1,[ASCIZ/NOCONFIRM/] ;CU79 if EDITFL = 1, don't confirm
	ETYPE < SET DEFAULT REDO /%1M%%_> ;type it out
	RET
>;IFE CUSW
;CU1 modify format

; Set redo
; Set no redo

.CEDIT::NOISE <option>
	KEYWD $CEDIT
	  0
	 JRST CERR
	JRST 0(P3)

$CEDIT:	TABLE
IFN CUSW,<
	T edit-character,,.SCEIC
	IT interrupt-character,,.SCEIC
	T remembers,,.SHIST		;CU79
>;IFN CUSW
IFE CUSW,<
	T EDIT-MODE,,.SCEDM
	T ENTERED-ON-CHARACTER,,.SCEIC
	IT INTERRUPT-CHARACTER,,.SCEIC
>;IFE CUSW
	TEND

.CEDNO::KEYWD $CEDNO
	 0
	 JRST CERR
	JRST 0(P3)

$CEDNO:	TABLE
IFN CUSW,<
	T  edit-character,,.SNCEI
	IT interrupt-character,,.SNCEI
	t remembered,,.snhist		;CU79
>;IFN CUSW
IFE CUSW,<
	T  ENTER-EDITOR-CHARACTER,,.SNCEI
	IT INTERRUPT-CHARACTER,,.SNCEI
>;IFE CUSW
	TEND
IFE CUSW,<
;SET COMMAND-EDITOR EDIT-MODE (TO)
.SCEDM:	NOISE (TO)
	KEYWD $CEMOD
	 0
	 JRST CERR		;parsing error
	JRST (P3)		;dispatch to proper function

$CEMOD:	TABLE
	T EMACS,,.SCEMA
	T SOS-ALTER-MODE,,.SCSOS
	TEND

.SCEMA:	CONFIRM
	SETZM CEMODE		;EMACS Mode
	RET

.SCSOS:	CONFIRM
	SETOM CEMODE		;SOS/EDIT Mode
	RET
>;IFE CUSW

;CU79 Set Redo Interrupt-Character

;"Set command-editor interrupt-character (to) char" command

.SCEIC: NOISE (to)
	STKVAR <ICHAR>		;CHARACTER TO INTERRUPT ON
	CALL ATICHR		;CU90 parse a character for ATI%
	 ERROR <Invalid terminal interrupt character> ;CU90 
	MOVEM A,ICHAR		;CU90 save it
	NOISE (enters command editor)
	CONFIRM			;CONFIRM THE COMMAND
	SKIPN HISTSW		;CU79 is history enabled?
	 ERROR <Not remembering any commands - use "set history" first>
	HRLZ A,ICHAR		;GET THE NEW ONE
	HLRZM A,CEPSIC		;SAVE IT
	RET			;DONE

.SNCEI:	NOISE (for command editor)
	CONFIRM			;COMFIRM "SET NO INTERRUPT-CHARACTER"
	SETOM CEPSIC		;SAY WE DON'T HAVE ONE
	RET			;DONE
;CU90 Begin addition - single character parsing routines

; This break mask when used with .CMUQS allows all characters except special
; editing characters.

brkall:	brini. 0,0,0,0		; Initialize the mask
	brkch. (0,177)		; Break on everything
	unbrk. (.chspc)		;  except white space
	unbrk. (.chtab)
	exp w0.,w1.,w2.,w3.

; At this point let me suggest that there be a user interface to the comnd
; routine which matches a specified number of characters.  Or maybe just one
; that matches a single arbitrary character...

;xx defines a keyword table entry, but differs from T macro in that the
; data may be only 18 bits wide (saves a word)

define xx (key,value,flags) <
ifb <flags>,<xwd [asciz @key@],value>
ifnb <flags>,<xwd [exp flags!cm%fw, asciz @key@],value>
>

ctrlkw==.chdel+1		; larger than any single character
				;  indicates "CONTROL" keyword.
chrtbl:	TABLE
	xx b,"b",cm%inv
	xx break,.chnul
	xx c,"c",cm%inv
	xx control,ctrlkw	; allow CONTROL "A"
	xx d,"d",cm%inv
	xx delete,.chcrb
	xx e,"e",cm%inv
	xx escape,.chesc
	xx n,"n",cm%inv
	xx null,.chnul
	xx s,"s",cm%inv
	xx space,.chspc
	xx ^,"^",cm%inv
	xx ^A,.chcna
	xx ^B,.chcnb
	xx ^C,.chcnc
	xx ^D,.chcnd
	xx ^E,.chcne
	xx ^F,.chcnf
	xx ^G,.chbel
	xx ^H,.chbsp
	xx ^I,.chtab
	xx ^J,.chlfd
	xx ^K,.chvtb
	xx ^L,.chffd
	xx ^M,.chcrt
	xx ^N,.chcnn
	xx ^O,.chcno
	xx ^P,.chcnp
	xx ^Q,.chcnq
	xx ^R,.chcnr
	xx ^S,.chcns
	xx ^T,.chcnt
	xx ^U,.chcnu
	xx ^V,.chcnv
	xx ^W,.chcnw
	xx ^X,.chcnx
	xx ^Y,.chcny
	xx ^Z,.chcnz
	xx ^\,.chcbs
	xx ^^,.chccf
	xx ^_,.chcun
	TEND

; More than just characters that can be ATI'ed, it also is a table
;  of characters you would want to ATI.  CR, LF, SPACE, ESCAPE, DELETE
;  are not present for this reason.

atitbl:	TABLE
	xx break,.chnul
	xx control,ctrlkw	; allow CONTROL "A"
	xx null,.chnul
	xx ^,"^",cm%inv
	xx ^A,.chcna
	xx ^B,.chcnb
	xx ^D,.chcnd
	xx ^E,.chcne
	xx ^F,.chcnf
	xx ^G,.chbel
	xx ^H,.chbsp
	xx ^I,.chtab
	xx ^J,.chlfd
	xx ^K,.chvtb
	xx ^L,.chffd
	xx ^P,.chcnp
	xx ^Q,.chcnq
	xx ^R,.chcnr
	xx ^S,.chcns
	xx ^U,.chcnu
	xx ^V,.chcnv
	xx ^W,.chcnw
	xx ^X,.chcnx
	xx ^Y,.chcny
	xx ^Z,.chcnz
	TEND

ctbmsk:	brini. keyb0.,keyb1.,keyb2.,keyb3. ; same as keyword
	unbrk. "^"
	unbrk. "_"
	unbrk. "\"
	exp w0.,w1.,w2.,w3.
;ATICHR - parses a single character which is reasonable for ATI%
;
; Returns
;  +1: failure
;  +2: success with character code in A
;
; This routine could be expanded to allow SP and DEL, but these
; have non-intuitive terminal interrupt codes, and aren't very likely
; choices anyway.
;

atichr::movei a,[flddb. .cmqst,cm%sdh,,<quoted control character>,,[
		 fldbk. .cmkey,,atitbl,<single control character or>,,ctbmsk]]
	call prsone		; read the character
	 ret			; oops, single character parse failed
	caig a,.tices		; characters up through ESC are ATI-able
	cain a,.ticcc		; ^C probably couldn't hurt, but disallow
	 ret
	caie a,.ticct		; make sure it's not ^T
	cain a,.ticco		;  or ^O, since we don't want those turned off
	 ret			; it's one of those, so reject it
	caie a,.ticcm		; these would probably make bad journal-
	cain a,.ticcj		;  toggle characters
	 ret
	retskp			; return failure

; ONECHR - parses a single character multiple ways
;
; Returns +1 on parse error, +2 on success with char in A
;

onechr::movei a,[flddb. .cmqst,cm%sdh,,<quoted control character>,,[
		 fldbk. .cmkey,,chrtbl,<single character or>,,ctbmsk]]
	callret prsone

; a/ flddb

prsone:	acvar <thechr,thefld>
	movem a,thefld		; save the flddb to parse with
	move b,thefld		; get back the flddbs to parse
	call fldskp		; try and parse that
	ifnsk. (callret onesch)	; failed, try one single character
	load c,cm%fnc,.cmfnp(c) ; get the function
	cain c,.cmqst		; a quoted string?
	 callret oneqst	; yes, verify and return
	hrrz a,(b)		; else keyword, get data
	cain a,ctrlkw		; special "CONTROL" keyword?
	 callret oneckw		;  yes, proceed with second part
	retskp			; else simply a char, return it

; Here to parse one single character using a break mask

onesch:	movei b,[flddb. .cmuqs,,brkall,<a single character>]
	call fldskp		; parse it
	 ret			; can't happen (proof left as an exercise)
	move b,sblock+.cmptr	; this is the evil delimiter
	ildb a,b
	caie a,.chtab		; a tab?
	cain a,.chspc		; or space?
	 jrst onesch		; yes, skip it
	cain a,.chlfd		; make sure they didn't type some sort
	 ret			;  of EOL character 
	caie a,.chffd		; formfeed is sometimes EOL
	cain a,.chcrt
	 ret			; return failure if that's it
	setzm thechr		; initialize this short string
	dpb a,[point 7,thechr,6] ; deposit its one character
	movei b,[flddb. .cmtok,,<point 7,thechr>]
	call fldskp		; parse it as a token
	 ret			; shouldn't happen
	ldb a,[point 7,thechr,6] ; get the character back
	retskp			; and return

; here, verify that the quoted string was only one character long

oneqst:	move b,[point 7,atmbuf]	; get a pointer to the character
	ildb a,b		; first char is it
	ildb c,b		; next char should be null 
	jumpe c,rskp		; yes, so return now
	caie a,"^"		; is it possible they said "^X"
	 ret			; no, return failure
	move a,c		; copy the second character
	cail a,"a"		; now check for lower case and
	caile a,"z"		; fold to upper case
	 skipa			; not lower case
	trz a,40		; is lower case, so make it upper
	subi a,"A"-.CHCNA	; controlify it for them
	ildb c,b		; and now check for the null
	jumpn c,r		; no... sigh, fail then
	retskp			; else return with the controlified char.

; here on CONTROL keyword, parse a single character in quotes

oneckw:	movei b,[flddb. .cmqst,cm%sdh,,
			<character in double quotes, or a single character>]
	call fldskp		; get a quoted string
	ifskp.			; got it...
	 call oneqst		; make sure it is in correct form
	  error <Not a single quoted character>
	else.
	 call onesch		; it is not, parse a single character
	  ret			; that didn't work... fail return
	 cail a,"a"		; now check for lower case and
	 caile a,"z"		; fold to upper case
	  skipa			; not lower case
	 trz a,40		; is lower case, so make it upper
	endif.
	subi a,"A"-.CHCNA	; otherwise controlify it
	skipge a		; check for proper control character
	 error <Can't CONTROLify that character>
	retskp			; and return it

	endav.

;CU90 End addition
;Routine to maybe make the current contents of CBUF be the most recent history
;entry.  Does nothing unless the user is keeping a history and the command
;is a top-level command (ie, we are not inside a PCL or a TAKE file or
;doing subcommands).  May remove the oldest command in the history list
;if the new addition would otherwise overflow the history list.
;
;Takes:
;	HISTSW/	0 if user doesn't want a history
;	HSTCNT/	Number of elements in the history list already
;	CBUF/	Command string to be saved (ASCIZ)
;Returns:
;	+1/	always (prints warning or does not return on error)
;Outputs:
;	HSTCNT/	incremented if no element was removed from the list
;	history list (HSTLST)/	updated to include new element
;Clobbers:
;	A
;
SAVHST::

;First decide whether we want to save the command in SCBUF.  Note: if
;we decide not to save the command in SCBUF we assume we don't want to
;save it in the history.  The command is saved in SCBUF if:
;
; - it does not contain any fields that were not echoed (ie, passwords)
; - it contains non-whitespace characters
; - it was input from .PRIIN (intended to weed out DOCOMMAND's and TAKE files)
IFN NICSW,<
; - it does not begin with a slash
>;IFN NICSW
;
IFN PWSW,<
	SKIPE PWDFLG		;Password on this line?
	 JRST SAVDON		;Yes, don't save this command
>;IFN PWSW
IFN NICSW,<
	LDB A,[POINT 7,CBUF,6]	;[NIC1017] GET FIRST CHARACTER IN COMMAND BUFFER
	CAIN A,"/"		;[NIC1017] IS IT THE EDIT CHARACTER?
	 JRST SAVDON		;[NIC1017] YES, SO IGNORE THIS COMMAND
>;IFN NICSW
	HRROI A,CBUF		;Get pointer to command
	CALL CKREAL		;Is there really a command to save?
	 JRST SAVDON		;No, return now
	MOVE A,CIJFN		;Get input JFN
	CAIE A,.PRIIN		;From terminal?
	 JRST SAVDON		;No, don't save
	MOVE A,[CBUF,,SCBUF]	;Yes, get set to copy CBUF into SCBUF
	BLT A,SCBUFE		;Do the copy

;Here if we decided the command was good enough to be saved in SCBUF.  We
;now make additional checks to see if it should also be saved in the
;command history:
;
; - The command must be a top-level command (ie not a subcommand)
; - It must not have already been saved in the history
; - We must not be in a PCL command and parsing after a PROMPT statement
; - The command history facility must be turned on
;
	SKIPE LINSVD		;This command already saved in the history?
	 JRST SAVDON		;Yes, don't try to save it again (this is
				; the test that prevents the saving of
				; subcommands)
;;This test doesn't work to detect that we are parsing after a PROMPT
;;statement if no PARSE EOL was done before the PROMPT (if a PARSE EOL
;;was done, we probably take the JRST above).  PCL should be fixed to
;;make PROMPT do an implicit PARSE EOL if necessary...
;;	MOVE A,TAKLEN		;Get current pointer to TAKE JFNS
;;	CAILE A,1		;Top of command stack?
;;	 JRST SAVDON		;No, don't save inside TAKE's and PCL's
	SKIPN HISTSW		;Keeping a history?
	 JRST [	AOS CMDNUM	;No, but record one more command done anyway
		JRST SAVDON ]	;All done
				;...
	CALL PIOFF		;CU133 don't allow interrupts
	CALL SVALWS		;CU133 collect command line
	CALL PION		;CU133 allow interrupts again
	RET			;CU133 all done

;Enter here by falling through from above or from the command editor.
;We will now save the command in the history come hell or high water
;(unless the Exec is out of permanent free space)

SVALWS:	AOS CMDNUM		;Record one more command done
	PUSH P,B		;Save the AC's we'll use
	PUSH P,C		;...
	PUSH P,D		;...
	MOVE A,HSTCNT		;Get number of history entries
	CAML A,HISTSW		;Have enough already?
	  CALL RMVHST		;Yes, remove one
	HRROI A,CBUF		;Get address of the command
	CALL MKHREC		;Make a history record for it
	  JRST [ETYPE<%@ %%Insufficient space for history entry - proceeding%_>
		SOS CMDNUM	;Don't think we have commands that we don't
		JRST SAVHDN]	;Skip it
	CALL ADDHST		;Make it the most recent in the history list
SAVHDN:	POP P,D			;Restore the AC's
	POP P,C			;...
	POP P,B			;...
SAVDON:	SETOM LINSVD		;Don't try to save this line again
	RET
;Routine to do the same as the above routine except that it is called from
;the error handling code.  It null-terminates CBUF and is generally more
;paranoid about the state of the word that the above routine.

SAVEHS::
	JRST SAVHST		;Do nothing special...

;Routine to check whether what is pointed to by an asciz string is
;substantive enough to be considered a real command.  It determines this
;by looking to see whether there are any characters in the command which
;are not whitespace (currently spaces and tabs).
;
;Takes:
;	A/ pointer to string (-1,,address ok)
;Returns:
;	+1/	don't save it
;	+2/	save it
;Clobbers:
;	A

CKREAL:	CALL FIXPT		;Make it a nice byte pointer
	SAVEAC <B>
CKLOOP:	ILDB B,A		;Load a character
	SKIPN B			;Null?
	 RET			;Yep, nothing of substance found
	CAIE B,.CHSPC		;Space?
	 CAIN B,.CHTAB		; or tab?
	  JRST CKLOOP		;Get another character
	CAIE B,.CHCRT		;CR?
	 CAIN B,.CHLFD		; or LF?
	  JRST CKLOOP		;Get another character
	RETSKP			;Found something, say to save the line

;Routine to create a new new history entry.
;Takes:
;	A/	byte pointer to command to be added (ASCIZ string)
;Returns:
;	+1/	error (probably insufficient space)
;	+2/	success
;Outputs:
;	A/	address of history record
;Clobbers:
;	B,C,D

MKHREC:	STKVAR <STRADR>
	MOVEM A,STRADR		;Save address of string
	CALL BCOUNT		;Find out how many words we need to save string
	ADDI A,2		;Add 2 words for overhead
	MOVX B,XDICT		;Say we want permanent space
	CALL GETMEM		;Allocate it
	  RET
	MOVEM A,1(B)		;Save size of block (for later disposal)
	HRRZ A,STRADR		;Get address of command
	HRLI A,440700		;Make it a byte pointer
	PUSH P,B		;Save address of the record for a minute
	MOVEI B,2(B)		;Get destination of string.
	HRLI B,440700		;Make it a byte pointer
MKHLOP:	ILDB C,A		;Get a character from the command
	SKIPN C			;If a null
	 JRST MKHLO3		;We're done, remove trailing whitespace
	IDPB C,B		;Otherwise put it into the history record
	JRST MKHLOP		;Do next character
MKHLO2:	SETO C,			;Say one byte
	ADJBP C,B		;Back up the destination byte pointer 1 byte
	MOVEM C,B		;Put the byte pointer back
MKHLO3:	LDB C,B			;Get a byte
	CAIE C,15		;CR?
	 CAIN C,12		; or LF?
	  JRST MKHLO2		;Strip from the history
;;	CAIE C,40		;Space?
;;	 CAIN C,11		; or tab?
;;	  JRST MKHLO2		;Yes, back up some more
	CAIE C,33		;<ESC>?
	 CAIN C,6		; or ^F?
	  JRST MKHLO2		;Yes, recognition are nasty so we'll nuke them
	CAIE C,"?"		;Question mark?
	 CAIN C,22		; or ^R?
	  JRST MKHLO2		;Yes, not quite as nasty but nuke them anyway
	CAIE C,.CHFFD		;Formfeed?
;;	 CAIN C,","		;Comma seems to cause trouble, too (why?)
	 TRNA			;;
	  JRST MKHLO2		; so strip it off, too
	SETZ C,			;Deposit a null at the end
	IDPB C,B		; of the string
	POP P,A			;Get back address of the record
	RETSKP

;Add a new element as the most recent element in the history list.
;Takes:
;	A/	address of history element
;	HSTLST/	address of oldest (tail),,address of newest (head)
;	HSTCNT/	number of history entries
;Returns:
;	+1 always
;Outputs:
;	HSTCNT/	incremented
;	HSTLST/	unchanged,,address of new element
;	(previous first element)/ address of new element,,unchanged
;Clobbers:
;	A,B

ADDHST:	AOS HSTCNT		;Bump count of commands in the history
	HRRZ B,HSTLST		;Get address of newest history entry
	HRRM A,HSTLST		;New element is now at the beginning of list
	HRRZM B,(A)		;Old first is now next of new element, and
				; new element has no previous
	SKIPE B			;If the list wasn't empty
	 HRLM A,(B)		; then previous of old first is new first
	SKIPN B			;Else (if it was empty)
	 HRLM A,HSTLST		; then new element is also new tail
	RET
;RMVHST - Removes the oldest element from the history list.
;RMVFST - Removes the newest element from the history list.
;Takes:
;	HSTLST/	address of oldest (tail),,address of newest (head)
;	HSTCNT/	number of history entries
;Returns:
;	+1 always (does not return if underflow)
;Outputs:
;	HSTCNT/	decremented
;	HSTLST/	address of new tail element,,unchanged
;	(previous first element)/ address of new element,,unchanged

RMVFST:	SAVEAC <Z>		;Don't let RETMEM clobber CTCLF1 before
				; .CEPSI or CEDESC do PION
	SKIPA A,[-1]		;Flag this is RMVFST
RMVHST:	SETZ A,			;Flag this is RMVHST
	SOSGE HSTCNT		;Underflow?
	 JRST RMVUFL		;Yes
	SKIPE A			;Is this RMVHST?
	IFSKP.			;Yes,
	  HLRZ B,HSTLST		; get address of oldest history entry
	ELSE.			;No,
	  HRRZ B,HSTLST		; get address of newest history entry
	ENDIF.
	JUMPE B,RMVUFL		;Check for underflow
	MOVE C,B		;Save address of element to nuke
	SKIPE A			;Is this RMVFST?
	 SOS CMDNUM		;Yes, set to absolute command number of newest
				; command still stored
	SKIPG HSTCNT		;Removing last element?
	 JRST [	SETZM HSTLST	;Yes, indicate list empty
		JRST RMVH2 ]	;Dispose of the removed element
	SKIPE A			;Is this RMVHST?
	IFSKP.			;Yes
	  HLRZ B,(B)		;Get address of new last element
	  HRLM B,HSTLST		;Make tail pointer point at it
	  HLLZS (B)		;Zero new last element's next pointer
	ELSE.			;No (from RMVFST)
	  HRRZ B,(B)		;Get address of new first element
	  HRRM B,HSTLST		;Make head pointer point to it
	  HRRZS (B)		;Zero new first element's previous pointer
	ENDIF.
RMVH2:	MOVE A,1(C)		;Get size of the block
	MOVE B,C		;Get address of the block
	MOVX C,XDICT		;Return it to permanent storage
	CALL RETMEM		;...
	RET

;Here on underflow of history list.

RMVUFL:	ERROR <Internal error in RMVHST: history list underflow>
;Routine which takes a string pointer and acts as if the user had typed
;it in.  It types the prompt, sticks the command into CBUF, and echos the
;command.  The command is not confirmed unless the string has a CRLF at the
;end.
;
;Takes:
;	1/ byte pointer to string (-1,,address is ok)
;Returns:
;	+1 always
;Outputs:
;	See description above

FAKTYP:	STKVAR <<CCSAV,2>,LINPTR> ;Saved CCOC words, saved pointer to
				; line to be FAKTYP'd
	MOVEM A,LINPTR		;Save pointer to string
	SETO B,			;Flag we want the prompt typed
	CALL C2CBUF		;Put the command into it
	SKIPG EDITFL		;CU79 Is this /fast?
	IFSKP.			;CU79 Yes
	 SKIPG CESCHK		;CU79 And not doing funny M-$ stuff?
	  CALL ADDCFM		;CU79 Yes, make this command confirm itself
	ENDIF.			;CU79
	MOVE A,COJFN		;Get output designator
	RFCOC%			;Read CCOC words
	DMOVEM B,CCSAV		;Save them
	TXZE C,3B19		;Don't echo <Esc>
	 SFCOC%			;...
	MOVE A,COJFN		;Echo to standard output
;CU79	MOVE B,LINPTR		;Get back command line
	MOVE B,CMPTR		;CU79 Use csb pointer in case doing /fast
				;CU79  (i.e. extra confirm in buffer)
	SETZ C,			;Terminate on null
	SOUT%			;Echo the string
	 ERCAL CJERR
	DMOVE B,CCSAV		;Get back saved CCOC words
	TXNE C,3B19		;Was <Esc> being echo'd before?
	 SFCOC%			;Yes, set it back
	RET			;Go to CIN1 by way of our caller
; C2CBUF - Copies a string into CBUF; properly hacking the pointers so
; that COMND% believes it was typed in
; Called with:
;  A/	pointer to the string
;  B/   non-zero if we should type the prompt when we do the CMINI
; Returns with:
;  command state block and buffer adjusted to contain the string

C2CBUF:	TRVAR <CMNDBP,CMNDLN,PMTFLG,IOJSAV> ;Byte pointer to string to move,
				; its length in (36 bit) words, and
				; a place to save the arg in B, and
				; a place for saving the .CMIOJ word
	MOVEM A,CMNDBP		;Save pointer to command string
	MOVEM B,PMTFLG		;Save print prompt flag
	CALL CMDINI		;Set up SBLOCK (shouldn't be necessary, but is)
	SKIPE PMTFLG		;Suppressing prompt?
	IFSKP.			;Yes
	  MOVE A,CMIOJ		;Get .CMIOJ word from SBLOCK
	  MOVEM A,IOJSAV	;Save it
	  HRRI A,.NULIO		;Make output be .NULIO to
	  MOVEM A,CMIOJ		; suppress the prompt
	ENDIF.
	MOVX A,CMINI		;Do CMINI (don't call READY because it
	MOVEM A,CMFNP		; destroys to many things
	MOVEI B,FBLOCK		;SPECIFY FUNCTION BLOCK ADDRESS
	CALL FIELDX		;TYPE THE PROMPT
	SKIPE PMTFLG		;Did we suppress the prompt?
	IFSKP.			;Yes
	  MOVE A,IOJSAV		;Get back saved .CMIOJ word
	  MOVEM A,CMIOJ		;Restore it
	ENDIF.
	MOVE A,CMNDBP		;Get back pointer to command
	CALL BCOUNT		;Count length of string
	MOVEM A,CMNDLN		;Save length in words
	MOVE A,B		;Get length in bytes
	MOVEM A,CMINC		;Save as count of unparsed characters
	MOVEI B,CBUFL*5		;Announce how much room for typein there is
	SUB B,A			;The unparsed characters take up space
	MOVEM B,CMCNT		;Save amount still free
	SKIPGE CMCNT		;Negative amount of buffer still left?
	 ERROR <Internal error in C2CBUF: string will not fit in CBUF>
	HRROI A,CBUF		;Get pointer to next field
	MOVEM A,CMPTR		;Store it
	HRL A,CMNDBP		;Get address of string to move
	HRRI A,CBUF		;Make source,,destination
	MOVEI B,CBUF		;Compute end for BLT
	ADD B,CMNDLN		;...
	BLT A,@B		;Move the string
	RET			;All done
;PA048 Command editor interrupt character PSI routine

.CEPSI::MOVE A,[POINT 7,CBUF]	;LOOK AT THE COMMAND BUFFER
	ILDB B,A		;GET THE NEXT CHARACTER
	JUMPN B,.-1		;KEEP LOOKING FOR A NULL
	SETO C,			;FOUND IT
	ADJBP C,A		;BACK UP ONE CHARACTER
	MOVEI A,.PRIIN		;LOOK AT THE TERMINAL
	SIBE			;ANYTHING THERE?
	 JRST [	MOVE A,C	;YES, ADD IT TO THE BUFFER
		MOVE B,[RD%RIE+^D80]
		SETZ C,		;NO PROMPT, QUIT WHEN TTY BUFFER IS EMPTY
		RDTTY		;GET IT
		 ETYPE <%_%%Can not find rest of command, Continuing>
		IDPB C,A	;ASCIZ THE STRING
		JRST .+1 ]	;READY TO GO NOW
	HRROI A,CBUF		;PA048 Point to command buffer
	SETO C,			;PA048 Assume line was not empty
IFN PWSW,<
	SKIPN PWDFLG		;PA048 Parsing a password line?
>;IFN PWSW
	 CALL CKREAL		;PA048  or line is entirely whitespace?
	  JRST [MOVE A,[SCBUF,,CBUF] ;PA048 Yes, edit saved command line
		BLT A,CBUFE	;PA048  instead
IFN PWSW,<
		SETZM PWDFLG	;PA048 Hopefully user won't type
				; sensitive info into the editor
>;IFN PWSW
		SETZ C,		;PA048 Always start editing at the beginning
				; of the line for old saved commands
		JRST .+1 ]	;PA048 ...	
	PUSH P,P		;SAVE THE STACK POINTER
	CEDSTG			;PA048 Define TRVAR's for editor
	TYPE <
>				;PA048 Put out a blank line here since we
				; no longer do at the beginning of CEDITU
	CALL PIOFF		;PA048 Don't allow ^C while history list munged
	PUSH P,C		;PA048
	CALL SVALWS		;PA048 Save CBUF in a temporary history entry
	POP P,C			;PA048
	HRRZ A,HSTLST		;PA048 Get pointer to most recent history entry
	MOVE B,CMDNUM		;PA048 Get its command number
	CALL CEDITU		;GO TO THE EDITOR
	CALL RMVFST		;PA048 Remove the temporary entry from the
				; history list (a permenent one will be made
				; later by the normal methods by which such
				; things are done)
	CALL PION		;PA048 Allow ^C again
	POP P,P			;FLUSH THE TRVARS
	MOVE A,LEV3PC		;PA048 GET THE RETURN ADDRESS
	HRRI A,REPARS		;CHANGE IT
	TXO A,PC%USR		;RETURN TO USER CODE
	MOVEM A,LEV3PC		;PA048 RESTORE FIXED PC
	DEBRK			;PARSE EDITED COMMAND
;PA048 Entry from EXECSU after M-$ has been done

CEDESC::SETZM CESCHK		;Don't accidently come back here
	MOVE A,CMPTR		;Get pointer to the rest of the input line
	CALL FIXPT		;Make sure not -1,,foo pointer
	MOVE B,CMINC		; and the number of unparsed characters
	ADJBP B,A		;Make B point to end of the command
	SETO A,			;Make A point to last character
	ADJBP A,B		; of the command
	LDB C,B			;Get last character in buffer
;CU79	CAIE C,.CHSPC		;A space?
	MOVE A,B		;No, don't overwrite it

	PUSH P,A		;Save good pointer
	SETZ B,			;Get null
	IDPB B,A		;Null-terminate the string
	HRROI A,CBUF		;Get pointer to command
	CALL BCOUNT		;Find out how long it is
	MOVEM B,D		;Save length
	MOVE A,[POINT 7,CEROCB]	;Get pointer to rest of command
	DO.			;Loop
	  ILDB B,A		;Get a character
	  CAIE B,.CHSPC		;Space?
	   CAIN B,.CHTAB	; or tab?
	    AOJA D,TOP.		;Yes, want to position cursor past whitespace
	OD.
	POP P,A			;Get back pointer to end of string
	HRROI B,CEROCB		;Get pointer to rest of command
	SETZ C,
	SKIPE CEROCB		;Anything there?
	 SOUT%			;Yes, append it to the end of the command
	CEDSTG			;PA048 Define TRVAR's for editor
;;	CALL LM			;PA048 Get to left margin
	CALL PIOFF		;PA048 Don't allow ^C while history list munged
	PUSH P,D		;PA048 Save column to start editing in
	CALL SVALWS		;PA048 Save CBUF in a temporary history entry
	HRRZ A,HSTLST		;PA048 Get pointer to most recent history entry
	MOVE B,CMDNUM		;PA048 Get its command number
	POP P,C			;PA048 Cursor position is length of stuff
				; in CBUF after M-$ done
	CALL CEDITU		;GO TO THE EDITOR
	CALL RMVFST		;PA048 Remove the temporary entry from the
				; history list (a permenent one will be made
				; later by the normal methods by which such
				; things are done)
	CALL PION		;PA048 Allow ^C again
	JRST REPARS		;Go execute command
;	UTEXAS-20 COMMAND LINE EDITOR

;Takes:
;	A/ Pointer to history entry of command to be edited
;	B/ Absolute command number of command to be edited
;	C/ Starting column number (0=beginning of line, n=column
;	   n (n > 0), and -1=end of line)

CEDITU:	MOVEM A,CELPTR		;PA048 Point to command to be edited
	MOVEM A,CEORIG		;PA048 Save a copy so we can find which
				; we started out editing in CEABRT
	MOVEM B,CELPOS		;PA048 Store its command number
	MOVEM C,CECPOS		;PA048 Store starting column
	MOVEI A,.CTTRM		;GET OLD MODE WORD
	RFMOD
	MOVEM B,CETTMD		;PA048 SAVE THIS FOR LATER
	TXZ B,TT%IGN		;MAKE SURE IT SEES TT%WAK BITS
	TXO B,TT%WAK		;WAKE ON EVERYTHING
	TXZ B,TT%ECO		;TURN OFF ECHOING
	TXZ B,TT%PGM		;TURN OFF PAGING (^S, ^Q)
	TXZ B,TT%TAB		;SPACES INSTEAD OF TAB
	SFMOD
	STPAR
	MOVE B,[052525,,553125]	;PASS CR, ^I, FORMAT LF, NO NULLS
	MOVE C,[252525,,652400]	;FORMAT ESCAPE
	SFCOC
	MOVEI A,.FHJOB
	SETZ B,			;NO TERMINAL INTERRUPTS
	STIW
	 ERJMP [ETYPE <%%Can't set up terminal for editing - %?%%_> ;PA048
		JRST CEABRT ]	;PA048 Pretend user typed ^G
	SETZM CEDUMB		;ASSUME SMART TERMINAL
	JRST CETNCR		;CU79 only EMACS mode

CETOP:	TYPE <
>				;CR
	SETZM CECPOS		;PA040 Reset current column (moved up
				; above CETNCR from below)

CETNCR:				;PA048
	MOVEI A,.CHCRT		;Make sure at left margin
	PBOUT%			;...
	CALL EEOLN		;ERRASE TO END OF LINE
	MOVE A,CELPTR		;POINT TO THE CURRENT LINE
	ADDI A,2		;PA048 Skip past the header
	HLL A,[POINT 7,0]	;MAKE IT A POINTER
	MOVE B,[POINT 7,CETBUF]	;POINT TO THE TEMP BUFFER
	SETZ D,			;PA048 Length is zero
CETOP0:	ILDB C,A		;GET NEXT BYTE
	AOS D			;PA048 Count one more
;PA048	HRRZ D,A		;CHECK FOR WRAP AROUND
;PA048	CAIE D,CEBFEN		;TOO FAR?
;PA048	 JRST CETOP1		;NO
;PA048	MOVE A,[POINT 7,CESAVE]	;YES, RESET THE POINTER
;PA048	JRST CETOP0		;AND START OVER

CETOP1:	IDPB C,B		;MOVE IT
	SKIPE C			;END ON NULL BYTE
	 JRST CETOP0		;DO THE REST
	SOS D			;PA048 Don't count null in length
	SKIPG A,CECPOS		;PA048 Absolute starting column requested?
	IFSKP.			;PA048
	  CAMLE A,D		;PA048 Yes.  Too big?
	   MOVEM D,CECPOS	;PA048 Yes, starting col is rightmost
	ELSE.			;PA048
	  SKIPE CECPOS		;PA048 Want to start at beginning?
	   MOVEM D,CECPOS	;PA048 No, must want to start at end
	ENDIF.			;PA048
	MOVE A,CECPOS		;PA048 Get starting column
	ADJBP A,[POINT 7,CETBUF] ;PA048 GET A POINTER TO IT
	MOVEM A,CEBPTR		;SAVE IT
	SKIPN CEDUMB		;WRITE LINE FOR DUMB TERMINALS
	 JRST CETOP2
	CALL CENUMB
;;PA048	MOVE A,CEBPTR
	HRROI A,CETBUF		;PA048
	PSOUT
	TYPE <
>
CETOP2:	TYPE <     >		;PA048 MAKE ROOM FOR THE LINE NUMBER
;;PA048	MOVE A,CEBPTR
	HRROI A,CETBUF		;PA048
	SKIPN CEDUMB		;EMACS OR SMART ALTER MODE?
	 PSOUT			;YES, WRITE IT OUT
	MOVEI A,CR
	PBOUT			;BACK TO THE BEGINNING
	CALL CENUMB		;WRITE THE NUMBER
	MOVE A,COJFN		;PA048 Get output jfn
	HRROI B,CETBUF		;PA048 Get pointer to current line
	MOVN C,CECPOS		;PA048 Get negative of current column
	SKIPE C			;PA048 Unless column 0
	 SOUT%			;PA048 Move cursor to correct column
	JRST CEINC		;GET COMMAND INPUT CHARACTER

CENUMX:	SAVEAC <A,B,C>		;PA048 "History" enters here
	MOVE A,COJFN		;PA048 Output to terminal
	MOVE B,D		;PA048 Get command number
	JRST CENUM2		;PA048 Join common code

CENUMB:
IFN NICSW,<
	ETYPE <[>
>;IFN NICSW
	MOVEI A,.CTTRM		;OUTPUT LINE# AS "DD:"
;PA048	MOVN B,CELPOS		;GET (NEGATIVE) LINE NUMBER
	MOVE B,CELPOS		;PA048 Get absolute command number
;PA048	JUMPE B,CENUM1		;DO CURRENT LINE DIFFERENT
	CAMN B,CMDNUM		;PA048 Current command?
	 JRST CENUM1		;PA048 Yes, do differently
CENUM2:				;PA048
	MOVE C,[NO%LFL!NO%OOV!NO%AST!FLD(3,NO%COL)!FLD(12,NO%RDX)]
        NOUT
	 JFCL
IFN NICSW,<
	ETYPE <]>
>;IFN NICSW
IFE NICSW,<
	TYPE <: >		;PA048
>;IFE NICSW
	RET			;ALL DONE

IFE NICSW,<
CENUM1:	TYPE < **: >		;PA048 FOR CURRENT LINE
>;IFE NICSW
IFN NICSW,<
CENUM1:	TYPE <***]>		;PA048 FOR CURRENT LINE
>;IFN NICSW
	RET
; Get the next input character

CEINC:	
IFN CUSW,<
	 JRST ECEINC		;CU79 Always emacs use, different commands
>;IFN CUSW
IFE CUSW,<
	SKIPN CEMODE		;EMACS MODE?
	 JRST ECEINC		;YES, GO TO HANDLER
				;NO, MUST BE ALTER MODE
	SETZ P3,		;ASSUME NO NUMERIC ARGUMENT
ACEINC:	PBIN			;GET ALTER MODE COMMAND
	CAIL A,"0"		;BIGGER THAN 0?
	 CAILE A,"9"		;SMALLER THAT 9?
	  JRST ACEIN1		;NOT A NUMBER, KEEP LOOKING
	IMULI P3,^D10		;NUMBER, UPDATE THE COUNT
	ADD P3,A		;ADD THIS ONE IN
	SUBI P3,"0"		;CONVERT TO BINARY
	JRST ACEINC		;GET THE REST OF THE COMMAND

ACEIN1:	CAIN A,CR		;^M - EXIT AND DO COMMAND
	 JRST CEEXIT
	CAIE A,"E"		;E - EXIT AND DO COMMAND
	 CAIN A,"e"
	  JRST CEEXIT
	CAIN A,.CHCNU		;^U - START OVER
	 JRST CETOP
	CAIN A,.CHLFD		;FL - NEXT LINE
	 JRST CEDOWN
	CAIN A,.CHESC		;ESC - PREVIOUS LINE
	 JRST CEUP
	CAIN A,.CHCNR		;^R - RETYPE LINE
	 JRST CATYPE
	CAIE A,"L"		;^L - TYPE LINE AND START OVER
	 CAIN A,"l"
	  JRST CARTYP
	CAIE A,"P"		;P - RETYPE LINE
	 CAIN A,"p"
	  JRST CATYPE
	CAIE A,"Q"		;Q - ABORT
	 CAIN A,"q"
	  JRST CEQUIT
	CAIN A,.CHCNC		;^C - ABORT
	 JRST CEQUIT
	CAIE A,"D"		;D - DELETE CHARACTERS
	 CAIN A,"d"
	  JRST CADEL
	CAIE A,"H"		;"H" - DELETE TO END, THEN INSERT
	 CAIN A,"h"
	  JRST CAHACK
	CAIE A,"I"		;"I" - ENTER INSERT MODE
	 CAIN A,"i"
	  JRST CAINST

;	CONTINUED ON NEXT PAGE
	CAIE A,"R"		;"R" - DELETE THEN INSERT
	 CAIN A,"r"
	  JRST CADEIN
	CAIE A,"W"		;"W" - MOVE OVER WORDS
	 CAIN A,"w"
	  JRST CAFORW
	CAIE A,"X"		;"X" - EXTEND LINE
	 CAIN A,"x"
	  JRST CAEXTN
	CAIE A,"Z"		;"Z" - DELETE WORDS
	 CAIN A,"z"
	  JRST CADELZ
	CAIN A,":"		;":" - DELETE REST OF LINE
	 JRST CACOLN
	CAIN A,"\"		;"\" - TRANSPOSE PREVIOUS TWO CHARS
	 JRST CETRAN
	CAIN A,.CHDEL		;RUB - MOVE CURSOR LEFT
	 JRST CALEFT
	CAIN A," "		;SPACE - MOVE CURSOR RIGHT
	 JRST CARIGH
	CAIN A,.CHTAB		;TAB - MOVE TO END OF LINE
	 JRST CAEOLN
	CAIN A,"?"		;? - GIVE HELP MESSAGE
	 JRST CAHELP
	CALL CEBELL		;ERROR, RING THE BELL
	JRST CEINC		;TRY AGAIN
;	HERE TO ENTER INSERT MODE

CAINST:	CALL CAFLSH		;FLUSH ANYTHING WE HAD GOING
CANST0:	PBIN			;GET NEXT CHARACTER
	CAIN A,.CHESC		;ESCAPE?
	 JRST CEINC		;YES, EXIT
	CAIN A,.CHTAB		;A TAB?
	 JRST CAINOK		;YES, LET IT PASS
	CAIN A,.CHCNC		;CONTROL C?
	 JRST CEQUIT		;YES, QUIT
	CAIL A," "		;SOME CONTROL CODE?
	 CAIN A,.CHDEL		;OR RUBOUT?
	  SKIPA			;YES, ERROR
	   JRST CAINOK		;ITS OK
	CALL CEBELL		;ERROR, RING BELL
	JRST CANST0		;AND TRY AGAIN

CAINOK:	MOVE C,CEBPTR		;GET THE POINTER
	SKIPE CEDUMB		;DUMP TERMINAL?
	 PBOUT			;YES, DISPLAY THE CHARACTER
CAINS1:	ILDB B,C		;GET ONE THAT WAS THERE
	SKIPN CEDUMB		;SMART TERMINAL?
	 PBOUT			;YES, OUTPUT IT
	DPB A,C			;REPLACE IT
	JUMPE A,CAINS2		;EXIT AFTER A NULL BYTE
	MOVE A,B		;SET UP TO REINSERT THE ONE
	JRST CAINS1
CAINS2:	AOS CECPOS		;UPDATE OUR POSITION
	IBP CEBPTR		;AND OUR POINTER
	SKIPE CEDUMB		;SMART TERMINAL
	 JRST CAINST		;NO, GET SOME MORE
	ETYPE <
>		;POSITION THE CURSOR
	CALL CENUMB		;MOVE PAST THE LINE NUMBER
	MOVE A,COJFN		;POINT TO THE TERMINAL
	HRROI B,CETBUF		;POINT TO THE STRING
	MOVN C,CECPOS		;GET COUNT
	SKIPE C			;DON'T GO FOREVER HERE
	 SOUT			;MOVE PAST THE OLD CHARACTERS
	JRST CAINST		;DONE, GET SOME MORE


;	HERE TO DELETE N CHARACTERS

CADEL:	CALL ALTDEL		;DO ALTER MODE DELETE
	JRST CEINC		;DONE


;	HERE TO DELETE N CHARACTERS THEN INSERT TEXT

CADEIN:	CALL ALTDEL		;DO ALTER MODE DELETE
	CALL CAFLDE		;SIGNAL END OF DELETE
	JRST CAINST		;SO THE INSERT

;	ALTER MODE DELETE ROUTINE

ALTDEL:	MOVE A,CEBPTR
	ILDB B,A
	SKIPN B
	 RET
	CALL CAFLBK		;FLUSH BACKSPACE MARKER
	SKIPG P3		;ZERO OR BAD ARGUMENT?
	 MOVEI P3,1		;YES, MAKE IT THE DEFAULT
	SETZ C,			;NEW COUNTER
	SKIPE CEDUMB		;SMART TERMINAL
	 CALL CADELF		;NO, SIGNAL DELETE
	MOVE B,CEBPTR		;GET THE POINTER
ALTDL1:	ILDB A,B		;GET NEXT CHARACTER
	JUMPE A,ALTD1A		;END?
	AOS C			;NO, INCREMENT COUNT
	SKIPE CEDUMB		;SMART TERMINAL?
	 PBOUT			;NO, ECHO CHARACTER
	SOJG P3,ALTDL1
	JRST ALTDL2
ALTD1A:	SETO A,			;WENT TOO FAR, BACKUP POINTER
	ADJBP A,B
	MOVEM A,B
ALTDL2:	SKIPN C
	 RET
	MOVE A,CEBPTR
ALTDL3:	ILDB C,B		;GET FIRST CHARACTER
	IDPB C,A		;SAVE IN NEW POSITION
	JUMPN C,ALTDL3
	SKIPE CEDUMB		;SMART TERMINAL?
	 RET			;NO, DONE
ALTDL4:	MOVE A,CEBPTR		;REWRITE THE SCREEN
	PSOUT
	CALL EEOLN
	ETYPE <
>		;POSITION THE CURSOR
	CALL CENUMB		;MOVE PAST THE LINE NUMBER
	MOVE A,COJFN		;POINT TO THE TERMINAL
	HRROI B,CETBUF		;POINT TO THE STRING
	MOVN C,CECPOS		;GET COUNT
	SKIPE C			;DON'T GO FOREVER HERE
	 SOUT			;MOVE PAST THE OLD CHARACTERS
	RET
;	HERE TO RETYPE THE LINE

CATYPE:	CALL CAFLSH		;FLUSH EVERYTHING
	SKIPN CEDUMB		;SMART TERMINAL?
	 JRST CEDISP		;YES, THIS IS A JOB FOR EMACS
	MOVE A,CEBPTR		;FINISH THE LINE
	PSOUT
	ETYPE <
>				;GO TO NEW LINE
	JRST	CINST1		;WRITE IT OUT




;	HERE TO FINISH TYPING THE LINE AND START OVER

CARTYP:	CALL CAFLSH
	SETZM CECPOS		;RESET CHARACTER PSOITION
	SKIPN CEDUMB		;SMART TERMINAL?
	 JRST CARTP1		;YES
	MOVE A,CEBPTR		;FINISH THE LINE
	PSOUT
CARTP1:	MOVE A,[POINT 7,CETBUF]	;RESET POINTER
	MOVEM A,CEBPTR
	ETYPE <
>				;NEW LINE
	JRST CETOP2		;AND START OVER





;	HERE TO HACK AND INSERT

CAHACK:	CALL CAFLBK
	SKIPN CEDUMB		;SMART TERMINAL?
	JRST CAHAK1		;YES, DO IT THE EASY WAY
	CALL CADELF		;SIGNAL DELETE
	MOVE A,CEBPTR		;GET THE REST OF THE STRING
	PSOUT			;OUTPUT IT
	TYPE <\\>		;END OF DELETE
	SETZM CADLFG
CAHAK1:	SETZ A,			;CHOP OFF THE REST OF THE STRING
	MOVE B,CEBPTR		;GET COPY OF POINTER
	IDPB A,B		;CURSOR IS ONE POSITION PAST POINTER
	CALL EEOLN		;JUST IN CASE
	JRST CAINST		;START INSERTING

;	HERE TO MOVE OVER WORDS

CAFORW:	CALL CAFLSH
	SKIPG P3
	 MOVEI P3,1
CAFRW1:	CALL F.WORD		;GET COUNT TO NEXT WORD
	ADDM B,CECPOS		;UPDATE POSITION
	MOVN C,B		;GET NEGATIVE COUNT
	MOVE A,COJFN		;MOVE OVER
	MOVE B,CEBPTR
	SKIPE C
	 SOUT			;WRITE IT OUT
	MOVEM B,CEBPTR
	SOJG P3,CAFRW1
	JRST CEINC		;DONE



;	HERE TO DELETE N WORDS

CADELZ:	CALL CAFLBK
	PUSH P,CEBPTR		;SAVE THE POINTER
	SKIPG P3		;ZERO OR NO ARGUMENT?
	 MOVEI P3,1		;YES, MAKE IT THE DEFAULT
	SETZ D,			;KEEP COUNT HERE
CADLZ1:	CALL F.WORD		;GET COUNT TO NEXT WORD
	SUB D,B			;KEEP NEGATIVE COUNT
	ADJBP B,CEBPTR		;UPDATE POINTER
	MOVEM B,CEBPTR
	SOJG P3,CADLZ1
	SKIPE A,CEDUMB		;SMART TERMINAL?
	JRST CADLZ2		;NO.
	MOVE A,CEBPTR		;DESTINATION POINTER
	POP P,CEBPTR		;SOURCE POINTER
	JRST M.FIX		;FIX IT UP
CADLZ2:	CALL CADELF		;SIGNAL DELETE
	MOVE A,COJFN		;WRITE OUT DELETED STUFF
	MOVE B,(P)		;POINT TO DELETED STUFF
	MOVE C,D		;NUMBER OF CHARACTERS
	SKIPE C			;SKIP IF NONE
	 SOUT
	POP P,CEBPTR		;FIX THE POINTER
	MOVE A,CEBPTR
CADLZ3:	ILDB C,B		;GET FIRST CHARACTER
	IDPB C,A		;SAVE IN NEW POSITION
	JUMPN C,CADLZ3
	JRST CEINC		;DONE
;	HERE TO EXTEND THE LINE

CAEXTN:	CALL CAFLSH
	MOVE A,CEBPTR		;GET THE POINTER
	PSOUT			;WRITE IT OUT
	SETO B,			;BACKUP THE POINTER
	ADJBP B,A
	SETZ A,			;GET COUNT TOO
CAXTN1:	ILDB A,CEBPTR		;GET NEXT CHARACTER
	JUMPE A,CAXTN2
	AOS CECPOS		;UPDATE POSITION
	JRST CAXTN1
CAXTN2:	MOVEM B,CEBPTR		;SAVE NEW POINTER
	JRST CAINST		;GO TO INSERT MODE



;	HERE TO JUMP TO THE END OF A LINE

CAEOLN:	CALL CAFLSH
	MOVE A,CEBPTR		;GET POINTER
	PSOUT			;WRITE IT OUT
	SETO B,			;BACK IT UP
	ADJBP B,A
	SETZ A,			;GET COUNT TOO
CAEOL1:	ILDB A,CEBPTR		;GET NEXT CHARACTER
	JUMPE A,CAEOL2
	AOS CECPOS		;UPDATE POSITION
	JRST CAEOL1
CAEOL2:	MOVEM B,CEBPTR		;SAVE NEW POINTER
	JRST CEINC		;DONE



;	HERE TO DELETE THE REST OF THE LINE

CACOLN:	CALL CAFLBK
	SKIPN CEDUMB		;SMART TERMINAL?
	JRST CACLN1		;YES, SKIP THIS
	CALL CADELF		;SIGNAL DELETE
	MOVE A,CEBPTR		;GET POINTER
	PSOUT			;WRITE THE RESTO OF THE STRING
	TYPE <\\>		;SIGNAL NO MORE DELETE
	SETZM CADLFG
CACLN1:	SETZ A,			;CHOP OFF THE REST OF THE STRING
	MOVE B,CEBPTR		;GET COPY OF POINTER
	IDPB A,B		;CURSOR IS ONE POSITION PAST POINTER
	CALL EEOLN		;JUST IN CASE
	JRST CEINC		;ALL DONE
;	HERE TO MOVE TO RIGHT

CARIGH:	CALL CAFLSH
	SKIPG P3		;ARGUMENT OK?
	 MOVEI P3,1		;FIX IT UP
CARIG1:	ILDB A,CEBPTR		;GET NEXT CHARACTER
	JUMPE A,CARIG2		;END OF LINE
	AOS CECPOS		;UPDATE POSITION
	PBOUT			;MOVE OVER
	SOJG P3,CARIG1		;DO THE REST
	JRST CEINC		;DONE

CARIG2:	SETO A,			;WENT TOO FAR
	ADJBP A,CEBPTR		;BACK UP
	MOVEM A,CEBPTR
	JRST CEINC		;DONE





;	HERE TO MOVE TO THE LEFT

CALEFT:	CALL CAFLDE
	SKIPN CECPOS		;BEGINNING OF LINE?
	 JRST CEINC		;YES, SKIP
	SKIPN P3		;NO ARGUMENT?
	 MOVEI P3,1		;MAKE IT A 1
	CAML P3,CECPOS		;ARGUMENT TOO BIG?
	 MOVE P3,CECPOS		;YES, TRIM IT DOWN
	SKIPE CEDUMB		;SMART TERMINAL
	 JRST CALFT1		;NO
	MOVN C,P3		;FIX THE POINTER
	ADJBP C,CEBPTR
	MOVEM C,CEBPTR
	MOVN A,P3		;FIX POSITION
	ADDM A,CECPOS
	JRST CINST1		;POSITION CURSOR

CALFT1:	CALL CABAKF		;SIGNAL BACK MOVEMENT
CALFT2:	LDB A,CEBPTR		;GET THIS CHARACTER
	PBOUT			;OUTPUT IT
	SETO B,			;MOVE THE POINTER BACK
	ADJBP B,CEBPTR		;BACK UP THE POINTER
	MOVEM B,CEBPTR
	SOS CECPOS
	SOJG P3,CALFT2		;DO THE REST
	JRST CEINC		;GET NEXT COMMAND
; ROUTINES TO PRINT \ AND \\ FOR DUMB TERMINAL ALTER MODE


CAFLSH:	CALL CAFLBK		;FLUSH OUT BACKSPACE CHARACTER
	CALL CAFLDE		;FLUSH OUT DELETE CHARACTER
	RET



CAFLBK:	SKIPN CEDUMB
	 RET
	SKIPN CABKFG		;WERE WE BACKSPACING?
	 RET			;NO, NOTHING TO DO
	SETZM CABKFG		;RESET THE FLAG
	TYPE <\>		;SIGNAL END OF BACKSPACE
	RET



CAFLDE:	SKIPN CEDUMB		;DUMB TERMINAL?
	 RET			;YES, RETURN
	SKIPN CADLFG		;WERE WE IN A DELETE?
	 RET			;NO
	SETZM CADLFG		;RESET FLAG
	TYPE <\\>		;SIGNAL END OF DELETE
	RET


CABAKF:	SKIPN CEDUMB
	 RET
	SKIPN CABKFG		;SET?
	ETYPE <\>		;NO, SIGNAL
	SETOM CABKFG		;SET BACKSPACE FLAG
	RET


CADELF:	SKIPN CEDUMB
	 RET
	SKIPN CADLFG		;SET?
	ETYPE <\\>		;NO, SIGNAL
	SETOM CADLFG		;SET DELETE FLAG
	RET


>;IFE CUSW
;	EMACS MODE BEGINS HERE

ECEINC:	MOVEI P3,1		;PA048 Default repeat count is one
ECEIN2:				;PA048 Enter here from argument (^U)
				; handler, with P3 already set up
	MOVEI A,.CTTRM		;ALLOW 8 BIT INPUT
	RFMOD			;GET THE MODE WORD
	PUSH P,B		;SAVE IT
	TXZ B,TT%DAM		;BINARY MODE
	SFMOD
	PBIN			;GET EDIT CHARACTER
	POP P,B			;RESTORE MODE WORD
	PUSH P,A		;SAVE CHARACTER
	MOVEI A,.CTTRM
	SFMOD
	POP P,A			;RESTORE CHARACTER
	SKIPN CEMETA		;META KEY IN USE?
	 TRZ A,200		;NO, TRIM PARITY BIT
	TRZE A,200		;META KEY USED?
	 JRST METAN1		;YES, PROCESS IT
	CAIN A,CR		;^M - EXIT AND DO EDITED COMMAND
	 JRST CECRLF		;PA048 Eat LF and then exit
	CAIN A,.CHCNP		;^P - EDIT PREVIOUS COMMAND
	JRST CEUP
IFE STANSW,<
	CAIN A,.CHBEL		;PA048 ^G?
	 JRST CEABRT		;PA048 Yes, abort editing
>;IFE STANSW
IFN STANSW,<
	CAIE A,.CHBEL		;^G?  If so, act like ^C typed
>;IFN STANSW
	CAIN A,.CHCNC		;PA048 ^C?
	 JRST CECTLC		;PA048 Yes, abort editing and goto ^C handler
	CAIN A,.CHCNU		;PA048 ^U?
	 JRST CECTLU		;PA048 Go handle
	CAIN A,.CHDEL		;RUBOUT - DELETE CHAR AT LEFT OF CURSOR
	 JRST CERUB		;EM74
	CAIN A,.CHCNB		;^B - CURSOR LEFT
	 JRST CELEFT
	CAIN A,.CHCNF		;^F - CURSOR RIGHT
	 JRST CERIGH
	CAIN A,.CHCNN		;^N - CURSOR DOWN
	 JRST CEDOWN
	CAIN A,.CHCND		;^D - DELETE CHARACTER AT CURSOR
	 JRST CERMSP
	CAIN A,.CHCNE		;^E - MOVE TO END OF LINE
	 JRST CEMEND
	CAIN	A,.CHCNA	;^A - MOVE TO BEGINNING OF LINE
	 JRST CEBEGN
	CAIN A,.CHVTB		;^K - KILL TO END OF LINE
	 JRST CECTLK		;PA048
	CAIN A,.CHCNT		;^T - TRANSPOSE CHARACTERS
	 JRST CETRAN
	CAIN A,.CHCNW		;^W - SAME AS M-RUB
	 JRST METARB
	CAIN A,.CHCUN		;^_ - HELP MESSAGE
	 JRST CEHELP

	CAIN A,.CHFFD		;PA048 ^L - Redisplay line
	 JRST CERDSP		;PA048 Rewrite line (on top of old line if
				; terminal is smart enough)
	CAIN A,.CHTAB		;TAB - INSERT WITHOUT V
	 JRST CINSRT
	CAIN A,.CHESC		;<ESC> - META PREFIX
	 JRST METAIN
	CAIE A,.CHCNQ		;^Q - TAKE NEXT CHAR LITERALLY
	 CAIN A,.CHCNV		;^V - TAKE NEXT CHAR LITERALLY
	  JRST CRTLV
	CAIL A," "		;PA048 SOME OTHER CONTROL CHARACTER?
	 JRST CINSRT		;PA048 No, must be self-inserting
	CALL CEBELL		;PA048 Yes, error.  Beep at user
	JRST CEINC		;PA048 Get another command

CRTLV:	PBIN			;GET THE CHARACTER
	JRST CINSRT		;PROCESS IT


; An escape has been entered, get the next command character

METAIN:	PBIN			;GET THE NEXT WORD
METAN1:	CAIE A,"F"		;M-F - FORWARD TO END OF WORD
	 CAIN A,"f"
	  JRST METAF
	CAIE A,"B"		;M-B - BACK TO BEGINNING OF WORD
	 CAIN A,"b"
	  JRST METAB
	CAIE A,"D"		;M-D - DELETE TO END OF WORD
	 CAIN A,"d"
	  JRST METAD
	CAIE A,"S"		;M-S - SEARCH FORWARD FOR CHARACTER
	 CAIN A,"s"
	  JRST METAS
	CAIE A,"R"		;M-R - SEARCH BACKWARD FOR CHARACTER
	 CAIN A,"r"
	  JRST METAR
	CAIN A,.CHDEL		;M-RUB - DELETE BACK TO START OF WORD
	 JRST METARB
;CU79	CAIN A,.CHESC		;M-ESC - STUFF COMMAND WITH <ESC>
;CU79	 JRST METAES
;CU79 Begin addition
	CAIE A,.CHESC		;M-ESC?
	IFSKP.			;Yes...
;;	  SKIPE CECPOS		;Are we at the left margin?
	   JRST METAES		;No, go do recognition
;;	  CALL CEBELL		;Yes, no recognition available here
;;	  JRST CEINC		;Go get another character
	ENDIF.
;CU79 End addition
	CAIN A,"?"		;M-? - STUFF COMMAND WITH ?
	 JRST METAQU
	CAIN A,.CHCNC		;PA048 M-^C?
	 JRST CECTLC		;PA048 Yes, treat as ^C
	CAIE A,"-"		;PA048 M-Minus?
	 CAIN A,.CHCNU		;PA048  or M-^U?
	  JRST CEAARG		;PA048 Yes, go do autoarg processing
	CAIL A,"0"		;PA048 M-Digit?
	 CAILE A,"9"		;PA048  ...
	  TRNA			;PA048 No
	  JRST CEAARG		;PA048 Yes, go do autoarg processing
	CALL CEBELL		;ERROR, RING BELL
	JRST CEINC		;TRY AGAIN

;PA048 A M-digit command has been typed.  Treat as autoarg:

CEAARG:	JRST CECLU5		;PA048

;PA048 A ^U has been typed.  Read the argument and set up the
;count word P3:

CECTLU:	MOVEI P3,4		;PA048 Assume value of 4
CECLU2:	PBIN			;PA048 Read another character
	CAIE A,.CHCNU		;PA048 Another ^U?
	IFSKP.			;PA048 Yes
	  IMULI P3,4		;PA048 Multiply current repeat count
				;PA048  by 4
	  JRST CECLU2		;PA048 Loop some more
	ENDIF.			;PA048
	CAIN A,"-"		;PA048 Minus
	 JRST CECLU3		;PA048 Yes, go handle number
	CAIL A,"0"		;PA048 Digit?
	 CAILE A,"9"		;PA048 ...
	  IFSKP.		;PA048
	    JRST CECLU3		;PA048 Yes, go handle number
	  ENDIF.		;PA048
	JRST CECLU9		;PA048 No, must be command.  Go do it

;Here on a number after an arbitrary number or ^U's.  We have to divide
;the current repeat count by 4, since the first ^U doesn't multiply the
;argument by 4 if there are numbers given.  Then we have to get the
;number (the first character of which is in A) and multiply the repeat
;count by it:

CECLU3:	IDIVI P3,4		;PA048 Divide current repeat count by 4
				; to forget first ^U
	JRST CECLU5		;PA048 Go handle number in A

;Here after we no longer have to worry about the initial ^U garbage
;(ie, we have seen a digit or a "-" and have done the hack to forget
;the initial ^U).  Also enter here (at CECLU5) for autoarg (ie, M-digit
;and M-minus commands) processing:

CECLU4:	PBIN%			;PA048 Get next character
CECLU5:	CAIE A,"-"		;PA048 Minus?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, switch sign of repeat count
	  JRST CECLU4		;PA048 Loop
	ENDIF.			;PA048
	CAIE A,.CHCNU		;PA048 ^U?
	IFSKP.			;PA048
	  IMULI P3,4		;PA048 Yes, multiply current repeat count
				; by 4
	  JRST CECLU4		;PA048 Loop
	ENDIF.			;PA048
	CAIL A,"0"		;PA048 Digit?
	 CAILE A,"9"		;PA048  ...
	  JRST CECLU9		;PA048 No, we must be done

;Here to handle strings of digits.  Accumulate number in D, and then
;multiply the repeat count by it after we've gotten the whole thing:

	SUBI A,"0"		;PA048 Make it a number
	MOVE D,A		;PA048 Initialize number accumulator
CECLU6:	PBIN%			;PA048 Get another character
	CAIL A,"0"		;PA048 Digit?
	 CAILE A,"9"		;PA048  ...
	  JRST CECLU7		;PA048 No, go finish up
	SUBI A,"0"		;PA048 Yes, make it a number
	IMULI D,^D10		;PA048 Accumulate number in D
	ADDM A,D		;PA048 ...
	JRST CECLU6		;PA048 Go try for another digit

CECLU7:	IMULM D,P3		;PA048 Multiply repeat count by accumulated
				; number
	JRST CECLU5		;PA048 Go read some more (next char to be
				; processed is already in A)

;Here when we read something which we don't recognise.  Assume it must be
;the actual command, so unread it and goto the command loop

CECLU9:	MOVX A,.PRIIN		;PA048 Get source of input
	BKJFN%			;PA048 Back up so we can reread command in
	 ERJMP .+1		; binary mode
	JRST ECEIN2		;PA048 Go do command


; Here to insert a character into the command line

CINSRT:	JUMPLE P3,CEINC		;PA048 Done on non-positive repeat count
	MOVE D,A		;PA048 Save the character
CINSR0:	MOVE C,CEBPTR		;PA048 Get the pointer
CINST:	HRRZ B,C		;PA048 Get address field of the pointer
	CAIGE B,CETBUF+CETBSZ-1	;PA048 About to overflow the buffer
	IFSKP.			;PA048
	  CALL CEBELL		;PA048 Yes, ring bell
	  JRST CINST1		;PA048 Abort inserting
	ENDIF.			;PA048
	ILDB B,C		;GET ONE THAT WAS THERE
	DPB A,C			;REPLACE IT
	JUMPE A,CINST0		;EXIT AFTER A NULL BYTE
;;PA048	PBOUT			;OUTPUT IT
	MOVE A,B		;SET UP TO REINSERT THE ONE
	JRST CINST
CINST0:	AOS A,CECPOS		;UPDATE EVERYTHING
	IBP CEBPTR
	MOVE A,D		;PA048 Get back the character
	PBOUT%			;PA048 Write the character
	SOJG P3,CINSR0		;PA048 Repeat if haven't done enough yet
	MOVE A,CEBPTR		;PA048 Get pointer to rest of line
	PSOUT%			;PA048 Write it

CINST1:	MOVE B,CEBPTR		;EM74 See what we're supposed to point to
	ILDB A,B		;EM74 If we're supposed to be at the end
	JUMPE A,CEINC		;EM74 of the line, we're already there!
	MOVEI A,CR
	PBOUT			;POSITION THE CURSOR
	CALL CENUMB		;MOVE PAST THE LINE NUMBER
	MOVE A,COJFN		;POINT TO THE TERMINAL
	HRROI B,CETBUF		;POINT TO THE STRING
	MOVN C,CECPOS		;GET COUNT
	SKIPE C			;DON'T GO FOREVER HERE
	 SOUT			;MOVE PAST THE OLD CHARACTERS
	JRST CEINC		;DONE


; Move the cursor to the left

CELEFT:	JUMPE P3,CEINC		;PA048 We're done if repeat count is zero
	SKIPL P3		;PA048 Negative repeat count?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make repeat count positive
	  JRST CERIGH		;PA048 Move cursor to the right
	ENDIF.			;PA048
	CAIG P3,1		;PA048 Repeat count greater than one?
	IFSKP.			;PA048
	  MOVE B,P3		;PA048 Yes, get number of positions to move
	  MOVEI P3,1		;PA048 Only move once
	  JRST METAB0		;PA048 Join M-B code
	ENDIF.			;PA048

;Here to move one position to the left:

	SKIPN CECPOS		;AT BEGINNING OF BUFFER?
	JRST CEINC		;YES, DO NOTHING
	LDB C,CEBPTR		;GET CHARACTER WE ARE GOING TO
	SETO B,
	ADJBP B,CEBPTR		;DECR BYTE PTR
	MOVEM B,CEBPTR
	SOS CECPOS		;DECR CHARACTER POSITION
	CAIGE C," "		;SOME CONTROL CHARACTER?
	 JRST CINST1		;YES, DON'T MESS UP
	CALL CEBACK		;BACK UP
	JRST CEINC

;EM74 **** Begin ****
; Erase last character

CERUB:	JUMPE P3,CEINC		;PA048 If repeat count is 0 we're done
	SKIPL P3		;PA048 Repeat count negative?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make it positive
	  JRST CERMSP		;PA048 Treat as ^D
	ENDIF.			;PA048
	SKIPN CECPOS		;At beginning of buffer?
	 JRST CEINC		;Yep, don't do anything
	CAIN P3,1		;PA048 Repeat count is one?
	IFSKP.			;PA048
	  MOVE B,P3		;PA048 Get number of chars to back up
	  MOVEI P3,1		;PA048 Do this only once
	  JRST METAR0		;PA048 Join M-<del> code
	ENDIF.			;PA048

;Here to delete exactly one character:

	MOVE A,CEBPTR
	ILDB C,A		;Get character to see if we're at EOL
	SETO A,
	ADJBP A,CEBPTR		;Decrement byte pointer
	MOVEM A,CEBPTR
	SOS CECPOS		;And decrement character position
	JUMPN C,CERMSP		;If not at end of line, retype whole line
	ILDB B,A		;CU79 Get character we're deleting
	CAIL B," "		;CU79 Are we deleting a control character
	IFSKP.			;CU79 yes...
	 CAIE B,.CHESC		;CU79 and not escape (single character)
	  CALL CEBACK		;CU79 Yes, we have to back up over two chars
	ENDIF.			;CU79
	CALL CEBACK		;Back up some
	JRST CEKILL		;And nuke end of line
;EM74 **** End ****

; Move the cursor to the end of the line

CEMEND:	MOVE B,CEBPTR		;SEE IF WE'RE POINTING AT ZERO BYTE
	ILDB A,B
	JUMPE A,CEMND1		;AT END OF LINE, QUIT
	AOS CECPOS
	PBOUT			;MOVE OVER
	JRST CEMEND+1
CEMND1:	MOVNI C,1
	ADJBP C,B
	MOVEM C,CEBPTR		;MAKE BYTE POINTER AGREE WITH CURSOR
	JRST CEINC


; Move the cursor to the right

CERIGH:	JUMPE P3,CEINC		;PA048 We're done if repeat count is zero
	SKIPL P3		;PA048 Negative repeat count?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make repeat count positive
	  JRST CELEFT		;PA048 Move cursor to the left
	ENDIF.			;PA048
	CAIG P3,1		;PA048 Repeat count greater than one?
	IFSKP.			;PA048
	  MOVE B,P3		;PA048 Yes, get number of positions to move
	  MOVEI P3,1		;PA048 Only move once
	  JRST METAF0		;PA048 Join M-F code
	ENDIF.			;PA048

;Here to move one position to the right:

	MOVE B,CEBPTR		;SEE IF WE'RE POINTING AT ZERO BYTE
	ILDB A,B
	JUMPE A,CEINC		;AT END OF BUFFER, DO NOTHING
	PBOUT			;MOVE OVER
	AOS CECPOS		;INCR CHARACTER POSITION
	IBP CEBPTR		;INCREMENT POINTER
	JRST CEINC



; Move to the next command line

CADOWN:	MOVEI P3,1		;PA048 In SOS the repeat count is always 1
CEDOWN:	JUMPE P3,CETOP		;PA048 Done if repeat count 0
	SKIPL P3		;PA048 Repeat count negative?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make it positive
	  JRST CEUP		;PA048 Treat as ^P
	ENDIF.			;PA048
	SOS P3			;PA048 Decrement repeat count
	HLRZ A,@CELPTR		;PA048 Get newer command line
	SKIPN A			;CHECK FOR END OF LIST
	 JRST CEDWN1		;NOT AT END, SKIP THIS
	AOS CELPOS		;PA048 Increment THE LINE NUMBER
	MOVEM A,CELPTR		;UPDATE POINTER
	JRST CEDOWN		;PA048 Loop in case repeat count not 1

CEDWN1:
;PA048	MOVE A,CE1ST		;END OF LIST, GO BACK TO THE FIRST LINE
	HLRZ A,HSTLST		;PA048 End of list, use oldest command
	MOVEM A,CELPTR		;RESET THE POINTER
;PA048	MOVE A,CECNT		;GET RIGHT LINE NUMBER
;PA048	SOS A
	MOVE A,CMDNUM		;PA048 Get current line number
	SUB A,HSTCNT		;PA048 Comput command number of first entry
	AOS A			;PA048  in history list
	MOVEM A,CELPOS		;SET IT
	JRST CEDOWN		;PA048 Loop in case repeat count not 1



; Move to the previous command line

CAUP:	MOVEI P3,1		;PA048 In SOS the repeat count is always 1
CEUP:	JUMPE P3,CETOP		;PA048 Done if repeat count 0
	SKIPL P3		;PA048 Repeat count negative?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make it positive
	  JRST CEDOWN		;PA048 Treat as ^N
	ENDIF.			;PA048
	SOS P3			;PA048 Decrement repeat count
	HRRZ A,@CELPTR		;PA048 TAKE THE LEFT HAND LINK
	SKIPN A			;CHECK FOR END OF LIST
	 JRST CEUP1		;NOT AT END
	SOS CELPOS		;PA048 Decrement THE LINE NUMBER
	MOVEM A,CELPTR		;UPDATE POINTER
	JRST CEUP		;PA048 Loop in case argument was not 1

CEUP1:
;PA048	MOVE A,CELAST		;END OF LIST, GO BACK TO THE FIRST LINE
	HRRZ A,HSTLST		;PA048 End of list, get newest command
	MOVEM A,CELPTR		;RESET THE POINTER
;PA048	SETZM CELPOS		;RESET LINE NUMBER
	MOVE A,CMDNUM		;PA048 Get right line number
	MOVEM A,CELPOS		;PA048 Reset line number
	JRST CEUP		;PA048 Loop in case argument was not 1


; Here to delete the character at the cursor

CERMSP:	JUMPE P3,CEINC		;PA048 If repeat count is 0 we're done
	SKIPL P3		;PA048 Repeat count negative?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make it positive
	  JRST CERUB		;PA048 Treat as <Del>
	ENDIF.			;PA048
	CAIG P3,1		;PA048 Repeat count greater than one?
	IFSKP.			;PA048
	  MOVE B,P3		;PA048 Yes, get number of characters to delete
	  MOVEI P3,1		;PA048 Delete them only once
	  JRST METAD0		;PA048 Go join the M-D code
	ENDIF.			;PA048

;Here if repeat count is one:

	MOVE B,CEBPTR		;GET DESTINATION POINTER
	MOVEI A,1
	ADJBP A,CEBPTR		;POINTER TO SOURCE
	LDB C,A			;ZERO BYTE?
	JUMPE C,CEINC		;EM74 (Fix bug (check C, not A)) YES, QUIT
	SETZ C,			;NO, MOVE THE TEXT
	SIN
	MOVEI A,CR
	PBOUT			;START OVER
	CALL CENUMB		;WRITE THE LINE NUMBER
	HRROI A,CETBUF		;AND THE LINE
	PSOUT
	CALL EEOLN
	JRST CINST1		;POSITION THE CURSOR



; Here to move the cursor to the beginning of the line

CEBEGN:	MOVEI A,CETBUF		;FIX POINTER
	HLL A,[POINT 7,0]
	MOVEM A,CEBPTR
	SETZM CECPOS		;RESET POINTER TO BEGINNING OF LINE
	MOVEI A,CR
	PBOUT			;MOVE CURSOR TO BEGINNING
	CALL CENUMB		;WRITE THE LINE NUMBER
	JRST CEINC		;GET NEXT COMMAND



;PA048 Here on ^K command

CECTLK:	SKIPLE P3		;PA048 Argument strictly positive?
	 JRST CEKILL		;PA048 Yes, kill to end of line
	MOVE B,CECPOS		;PA048 No, get number of chars to kill
	JRST METAR0		;PA048 Kill to beginning of line



; Here to kill everything to the right of the cursor

CEKILL:	SETZ A,			;CHOP OFF THE REST OF THE STRING
	MOVE B,CEBPTR		;GET COPY OF POINTER
	IDPB A,B		;CURSOR IS ONE POSITION PAST POINTER
	CALL EEOLN		;ERRASE IT FROM THE SCREEN
	JRST CEINC		;GET NEXT COMMAND



; Here to swap the character at the cursor and the one before it

CATRAN:	MOVEI P3,1		;PA048 In SOS, arg is always 1
CETRAN:	JUMPE P3,CEINC		;PA048 Done if repeat count zero
	SKIPG P3		;PA048 Repeat count negative?
	 JRST CETRA3		;PA048 Yes, do differently

;Here if repeat count is positive:

	SKIPN CECPOS		;BEGINNING OF LINE?
	 JRST CEINC		;YES, SKIP
	MOVE B,CEBPTR
	ILDB A,B		;END OF LINE?
	JUMPE A,CEINC
CETRA2:	MOVE B,CEBPTR		;GET LOCAL POINTER
	MOVEI A,1		;SCOOT OVER ONE
	ADJBP A,B
	MOVEM A,CEBPTR		;PA048 Save updated pointer
	AOS CECPOS		;PA048 Move to the right
	LDB C,A			;CHANGE THE CHARACTERS IN THE BUFFER
	LDB D,B
	DPB D,A
	DPB C,B
	SOJE P3,CETRA9		;PA048 Done if repeat count exceeded
	MOVE B,CEBPTR		;PA048
	ILDB A,B		;PA048 End of line?
	JUMPE A,CETRA9		;PA048 Yes, we can do no more
	JRST CETRA2		;PA048 No, keep going

;PA048 Here if repeat count is negative:

CETRA3:	MOVE A,CECPOS		;Get line position
	CAIG A,1		;Too close to the beginning of the line?
	 JRST CEINC		;Yes, skip
CETRA4:	MOVE B,CEBPTR		;GET LOCAL POINTER
	SETO A,			;SCOOT OVER ONE
	ADJBP A,B
	MOVEM A,CEBPTR		;PA048 Save updated pointer
	SOS CECPOS		;PA048 Move to the left
	LDB C,B			;CHANGE THE CHARACTERS IN THE BUFFER
	LDB D,A
	DPB D,B
	DPB C,A
	AOJE P3,CETRA9		;PA048 Done if repeat count exceeded
	MOVE A,CECPOS		;PA048 Get line position
	CAIG A,1		;PA048 Too close to the beginning?
	 JRST CETRA9		;PA048 Yes, we can do no more
	JRST CETRA4		;PA048 No, keep going

;PA048 Here when done (repeat count hit zero or we ran into an end
;of the line):

CETRA9:				;PA048
	MOVEI A,CR
	PBOUT			;REWRITE THE LINE
	CALL CENUMB
	HRROI A,CETBUF
	PSOUT
	JRST CINST1		;POSITION CURSOR



; Here to move to the beginning of the next word

METAF:	JUMPE P3,CEINC		;PA048 Stop if repeat count is zero
	SKIPL P3		;PA048 Repeat count less than zero?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make it positive
	  JRST METAB		;PA048 Go do a M-B
	ENDIF.			;PA048
	CALL F.WORD		;GET DESTINATION

;PA048 ^F with an argument greater than 1 enters here:

METAF0:				;PA048
	ADDM B,CECPOS		;UPDATE POSITION
	JUMPE B,CEINC		;NO MOVEMENT, STOP
	MOVN C,B		;PA048, EM74 - Number of characters to move
	ADJBP B,CEBPTR		;UPDATE POINTER
	PUSH P,B		;EM74 And save it
	MOVE B,CEBPTR		;EM74 Start of what we want to type
	MOVE A,COJFN		;EM74
	SOUT			;EM74 Print over one word
	POP P,CEBPTR		;EM74 Update pointer
	JRST CEINC		;EM74


; Here to move to the beginning of the previous word

METAB:	JUMPE P3,CEINC		;PA048 Stop if repeat count is zero
	SKIPL P3		;PA048 Repeat count less than zero?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make it positive
	  JRST METAF		;PA048 Go do a M-F
	ENDIF.			;PA048
	CALL B.WORD		;GET DESTINATION

;PA048 ^B with an argument greater than 1 joins here:

METAB0:				;PA048
	JUMPE B,CEINC		;SKIP IF NO MOVEMENT
	MOVNS B			;MAKE IT NEGATIVE
	MOVE C,B		;GET A COPY OF IT
	ADJBP C,CEBPTR		;UPDATE THE POINTER
	MOVEM C,CEBPTR
	ADDM B,CECPOS		;UPDATE POSITION
METAB1:	PUSH P,B		;EM74 Save number of chars to back up
	CALL CEBACK		;EM74 Back up one
	POP P,B			;EM74
	AOJN B,METAB1		;EM74
	JRST CEINC		;EM74

; Here to delete up to the beginning of the next word

METAD:	JUMPE P3,CEINC		;PA048 Stop if repeat count is zero
	SKIPL P3		;PA048 Repeat count less than zero?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make it positive
	  JRST METARB		;PA048 Go do a M-<Del>
	ENDIF.			;PA048
	CALL F.WORD		;GET DESTINATION

;PA048 ^D with an argument graeter than 1 joins here:

METAD0:				;PA048
	MOVE A,B		;GET COPY OF OFFSET
	ADJBP A,CEBPTR		;POINTER TO DESTINATION
	JRST M.FIX		;MOVE EVERYTHING


; Here to delete back to the beginning of the previous (or this) word

METARB:	JUMPE P3,CEINC		;PA048 Stop if repeat count is zero
	SKIPL P3		;PA048 Repeat count less than zero?
	IFSKP.			;PA048
	  MOVNS P3		;PA048 Yes, make it positive
	  JRST METAD		;PA048 Go do a M-D
	ENDIF.			;PA048
	CALL B.WORD		;GET DESTINATION

;PA048 <Del> with an argument greater than 1 enters here.  So does
; ^K with a negative argument:

METAR0:				;PA048
	MOVE A,CEBPTR		;PA048, EM74
	ILDB D,A		;PA048, EM74 See if next char is end of line
	PUSH P,D		;PA048, EM74 Save it
	MOVN D,B		;MAKE IT NEGATIVE
	MOVE A,D
	ADDM A,CECPOS		;FIX UP POSITION
	ADJBP A,CEBPTR		;GET DESTINATION POINTER
	EXCH A,CEBPTR		;FOOL M.FIX - WE ARE NOW A M-D
	PUSH P,D		;SAVE HOW MANY CHARS TO DELETE
	PUSH P,A		;SAVE THE POINTER
METAR1:	JUMPE D,METAR2		;NEED TO MOVE THE CURSOR OVER
	PUSH P,D		;SAVE LOOP COUNTER
	CALL CEBACK		;BACK UP
	POP P,D			;RESTORE LOOP COUNTER
	AOJA D,METAR1
METAR2:	POP P,A			;RESTORE THE POINTER
	POP P,D			;GET BACK HOW MANY CHARS WE DELETED
	POP P,B			;EM74 Get char we saved
	JUMPE B,CEKILL		;EM74 If we were at EOL, just kill it
	JRST M.FIX		;OTHERWISE DELETE THE CHARS

;M-S - Search forward for a character

METAS:	JUMPE P3,CEINC		;Stop if repeat count is zero
	SKIPL P3		;Repeat count less than zero?
	IFSKP.			;Yes...
	  MOVNS P3		;Make it positive
	  JRST METAR		;And go do a M-R
	ENDIF.
	PBIN			;Get the character to search for
	CAIL A,"a"		;Lowercase letter?
	 CAILE A,"z"
	  TRNA			;No
	   SUBI A,"a"-"A"	;Yes, make it uppercase
	MOVE C,CEBPTR		;Get local copy of pointer
	SETZ B,			;Zero the count of chars we moved past
METAS0:	ILDB D,C		;Get the next char
	IFE. D			;If it's a null
	  CALL CEBELL		;Feep the person
	  JRST CEINC		;And go try again for another command
	ENDIF.
	CAIL D,"a"		;Lowercase letter?
	 CAILE D,"z"
	  TRNA
	   SUBI D,"a"-"A"	;Yes, make it uppercase
	AOS B			;Count another char we did
	CAME A,D		;Do they match?
	 JRST METAS0		;No, go get the next
	SOJG P3,METAS0		;Go until we find that many
	JRST METAF0		;And go forward that many chars

;M-R - Search backward for a character

METAR:	JUMPE P3,CEINC		;Stop if repeat count is zero
	SKIPL P3		;Repeat count less than zero?
	IFSKP.			;Yes...
	  MOVNS P3		;Make it positive
	  JRST METAS		;And go do a M-S
	ENDIF.
	PBIN			;Get the character to search for
	CAIL A,"a"		;Lowercase letter?
	 CAILE A,"z"
	  TRNA			;No
	   SUBI A,"a"-"A"	;Yes, make it uppercase
	MOVE C,CEBPTR		;Get local copy of pointer
	MOVN B,CECPOS		;Get -number of chars we're at
	HRLZS B			;Make an AOBJN pointer for the position
	IFE. B			;If already at the beginning
	  CALL CEBELL		;Feep the person
	  JRST CEINC		;And go back
	ENDIF.
MTAR.0:	LDB D,C			;Get the char we're pointing to
	CAIL D,"a"		;Lowercase letter?
	 CAILE D,"z"
	  TRNA
	   SUBI D,"a"-"A"	;Yes, make it uppercase
	CAMN A,D		;Do they match?
	 JRST MTAR.1		;Yes, see if we're done
MTAR.2:	SETO D,			;Want to decrement the pointer
	ADJBP D,C		;Decrement it
	MOVE C,D		;Get it in the right ac
	AOBJN B,MTAR.0		;Go on if there are more chars to do
	CALL CEBELL		;Otherwise feep the person
	JRST CEINC		;And go back

MTAR.1:	SOJG P3,MTAR.2		;Continue if we need more, check char count
	HRRZS B			;Isolate the character count
	AOS B			;Fudge to move back at least one char
	JRST METAB0		;And go back that many chars

; Here to fix things up after Metad, Metarb, or Alter mode delete

M.FIX:	MOVE B,A		;GET COPY OF DESTINATION POINTER
	SKIPN CEDUMB		;EMACS OR SMART ALTER?
	 PSOUT			;YES, OVERWRITE THE SCREEN
	CALL EEOLN		;CLEAN THINGS UP
	MOVE A,CEBPTR		;GET CURRENT POINTER
M.FIX1:	ILDB C,B		;GET FIRST CHARACTER
	IDPB C,A		;SAVE IN NEW POSITION
	JUMPN C,M.FIX1		;DONE?
	JRST CINST1		;POSITION THE CURSOR



; Subroutine to return number of spaces until start of next word

F.WORD:	SAVEAC <P3>		;PA048 Don't clobber repeat count
	SETZ B,			;INITIALIZE COUNT
	MOVE C,CEBPTR		;GET LOCAL COPY OF POINTER
	ILDB A,C		;GET THIS CHARACTER
	JUMPE A,[RET]		;END OF LINE, QUIT
	CALL SKPNAN		;PA048 Check if alphanumeric
	 JRST F.WRD2		;EM74 It is
F.WRD1:	ILDB A,C		;GET NEXT CHARACTER
	AOS B			;UPDATE COUNT
	JUMPE A,[RET]		;END OF LINE
	CALL SKPNAN		;PA048 Alphanumeric?
	 JRST F.WRD2		;EM74 Yes
	JRST F.WRD1		;EM74
F.WRD2:	ILDB A,C		;GET NEXT CHARACTER
	AOS B			;INCREMENT COUNT
	JUMPE A,[RET]		;END OF LINE
	CALL SKPNAN		;PA048 Alphanumeric?
	 JRST F.WRD2		;EM74 Yes
	SOJG P3,F.WRD1		;PA048 Skip if repeat count still positive
	RET			;No, DONE.


; Subroutine to return number of spaces until start of previous word

B.WORD:	SAVEAC <P3>		;PA048 Don't clobber repeat count
	SETZ B,			;INITIALIZE COUNT
	MOVE C,CEBPTR		;GET LOCAL COPY OF POINTER
	MOVE D,CECPOS		;LOCAL COPY OF POSITION
BWRD00:				;PA048
	JUMPE D,[RET]		;BEGINNING OF LINE, EXIT
	ILDB A,C		;GET THIS CHARACTER
	CALL SKPNAN		;PA048 Alphanumeric?
	 JRST B.WRD0		;EM74 Yes
	JRST B.WRD1
B.WRD0:	LDB A,CEBPTR		;GET CHARACTER BEFORE THIS ONE
	CALL SKPNAN		;PA048 Alphanumeric?
	 JRST B.WRD2		;EM74 Yes
B.WRD1:	SETO A,			;BACKUP THE POINTER
	ADJBP A,C
	MOVE C,A
	LDB A,C			;GET NEXT ONE
	SOS D			;UPDATE COUNT
	AOS B			;UPDATE THIS TOO
	JUMPE D,[RET]		;CHECK FOR BEGINNING OF LINE
	CALL SKPNAN		;PA048 Alphanumeric?
	 JRST B.WRD2		;EM74 Yes
	JRST B.WRD1		;EM74 No
B.WRD2:	SETO A,			;BACKUP THE POINTER
	ADJBP A,C
	MOVE C,A
	LDB A,C			;GET NEXT CHARACTER
	SOS D			;UPDATE EVERYTHING
	AOS B
	JUMPE D,[RET]		;CHECK FOR BEGINNING OF LINE
	CALL SKPNAN		;PA048 Alphanumeric?
	 JRST B.WRD2		;EM74 Yes
	SOSG P3			;PA048 Want to repeat some more?
	IFSKP.			;PA048
	  SETO A,		;PA048 Yes
	  ADJBP A,C		;PA048 Back up the byte pointer one more
	  MOVEM A,C		;PA048 Save it
	  SOS D			;PA048 Remember column
	  JRST BWRD00		;PA048 Loop
	ENDIF.			;PA048
	SOS B			;ADJUST IF NOT BEGINNING OF LINE
	RET			;ALL DONE



;PA048 Subroutine which skips if a character is not alphanumeric
;
;Takes:
;	A/ character
;Returns:
;	+1/ character is alphanumeric
;	+2/ otherwise
;Clobbers:
;	No AC's
;
SKPNAN:	CAIL A,"a"		;Lowercase letter?
	 CAILE A,"z"		; ...
	  TRNA			;No
	  RET			;Yes, return false
	CAIL A,"A"		;Uppercase letter?
	 CAILE A,"Z"		; ...
	  TRNA			;No
	  RET			;Yes return false
	CAIL A,"0"		;Digit?
	 CAILE A,"9"		; ...
	  RETSKP		;No, must be alphanumeric so return true
	  RET			;Yes, so return false


; Here to stick an Escape or question mark on the end of the command

METAES:	SKIPGE P3		;Argument negative?
	 JRST METAE2		;Yes, handle differently

	CAIN P3,0		;Argument of zero
	 MOVEI P3,1		;Use argument of one
REPEAT 0,<
	CAIE P3,1		;CU79 simple case?
	IFSKP.			;CU79 yes..
	 LDB A,CEBPTR		;CU79 get char before cursor
	 CALL SKPNAN		;CU79 alphanumeric?
	  SKIPA			;CU79 yes...
	 JRST METAE3		;CU79 no, skip this M-F, M-B stuff
	ENDIF.			;CU79
>;REPEAT 0
	PUSH P,P3		;Save argument
	MOVE B,CEBPTR		;Get a copy of current position pointer
	ILDB A,B		;Advance it one
	SKIPN A			;Got a null (ie, at end of line)?
	IFSKP.
	  MOVEM B,CEBPTR	;No, save updated pointer
	  AOS CECPOS		;Update column, too.  This hack makes us do
				; the right thing if we start out on top of
				; the first char of a word...
	ENDIF.
	MOVEI P3,1		;First, back up a word
	CALL B.WORD		;...
	MOVNS B			;Negate amount to move backwards
	ADDM B,CECPOS		;Update current column
	ADJBP B,CEBPTR		;Update current char byte pointer
	MOVEM B,CEBPTR		;Save updated pointer
	POP P,P3		;Get back argument
	CALL F.WORD		;Compute how far to move forward
	ADDM B,CECPOS		;Update current column
	ADJBP B,CEBPTR		;Update current char byte pointer
	MOVEM B,CEBPTR		;Save updated pointer
	JRST METAE3		;Go stick in <Esc> and go for it

METAE2:	PUSH P,P3		;Save the argument
	MOVNS P3		;Make argument positive
	AOS P3			;Add fudge factor
	CALL B.WORD		;Compute amount to back up
	MOVNS B			;Negate amount to move backwards
	ADDM B,CECPOS		;Update current column
	ADJBP B,CEBPTR		;Update current char byte pointer
	MOVEM B,CEBPTR		;Save updated pointer
	MOVEI P3,1		;Now move to end of current word
	CALL F.WORD		;Compute distance
	ADDM B,CECPOS		;Update current column
	ADJBP B,CEBPTR		;Update current char byte pointer
	MOVEM B,CEBPTR		;Save updated pointer
	POP P,P3		;Get back argument

;Here with CEBPTR pointing to the place to deposit the <Esc>.  Save
;the part of the command  which is after the cursor position, deposit
;an <Esc> and a null at the cursor position, and go do the command:

METAE3:
	MOVE B,CEBPTR		;CU79 Get copy of cursor pointer
	ILDB A,B		;CU79 Get char under cursor
	DO.
	  SKIPE A		;CU79 Null (ie, reached end of buffer)?
REPEAT 0,<
	   CALL SKPNAN		;CU79  or alphanumeric?
	    JRST ENDLP.		;CU79 Yes, go on
	  CAIE A,.CHSPC		;CU79 Space?
	   CAIE A,.CHTAB	;CU79  or tab?
	    JRST ENDLP.		;CU79 Yes, go on
	  CAIN A,"/"		;CU79 Slash is also ok (I think)
	    JRST ENDLP.		;CU79
>
	  CAIE A,")"		;CU79 Field suffix?
	   CAIN A,":"		;CU79
	    TRNA		;CU79
	   JRST ENDLP.		;CU79
	  MOVEM B,CEBPTR	;CU79 No, remember we moved forward
	  AOS CECPOS		;CU79 Remember where we are
	  ILDB A,B		;CU79 Move forward past punctuation
	  LOOP.			;CU79 And around again
	OD.			;CU79
	HRROI A,CEROCB		;Get pointer to place to save string
	MOVE B,CEBPTR		;Get pointer to remainder of command
	SETZ C,
	SOUT%			;Save the rest of the command
	MOVE A,CEBPTR		;Get back pointer to where to put <Esc>
	MOVEI B,.CHESC		;Get an <Esc>
	IDPB B,A		;Stash it at the end of the buffer
	SETZ B,			;Then a null
	IDPB B,A		;...
	MOVEI A,2		;We want to allow one reparse (because
	MOVEM A,CESCHK		; we exit from the editor via REPARS)
	CALL CEQUIT		;Go back to regular tty modes
	HRROI A,CETBUF		;Get pointer to command line
	SETZ B,			;Don't want prompt typed
	CALL C2CBUF		;Copy line to atom buffer
	RET			;Go do the command

; M-? Comes here

METAQU:	SETZM EDITFL		; Don't do a confirm
	MOVEI B,"?"		; STUFF ? WITH THE COMMAND
METAEQ:	ILDB A,CEBPTR		; LOOK FOR THE END OF THE LINE
	JUMPE A,METEQ1
	JRST METAEQ		; TRY AGAIN
METEQ1:	DPB B,CEBPTR		; STUFF THE NEW CHARACTER
	IDPB A,CEBPTR		; ADD A ZERO BYTE
	CALL CEQUIT		;Go back to regular tty modes
	HRROI A,CETBUF		;Get pointer to command line
	CALL FAKTYP		;Copy line to atom buffer and echo it
	RET			;Go do the command


; Here when done. Stuff the edited command into the terminals input buffer

;CU79 On terminals which have parity set this code to read the LF does not
;CU79   work properly because the monitor will not add LF to a CR+PARITY.
;CU79   Allow this case by checking to see if a character is present before
;CU79	looking for the LF.

CECRLF:	MOVX A,.PRIIN		;CU79 Check terminal for
	SIBE%			;CU79 any characters present.
	 SKIPA			;CU79 yes, check it out for LF
	JRST CEEXIT		;CU79 otherwise continue
	PBIN%			;PA048 Read the LF
	CAIN A,.CHLFD		;PA048 Really a LF
	IFSKP.			;PA048 No (is this possible???)
	  MOVX A,.PRIIN		;PA048
	  BKJFN%		;PA048 Unread the character
	ENDIF.			;PA048
CEEXIT:	MOVEI C,CETBUF		;POINT TO CURRENT LINE
	HRLI C,440700
;;PA048	MOVEI A,.CTTRM		;GET THE TERMINAL DESIGNATOR
;;PA048	CFIBF
CEEX2:	ILDB B,C		;GET NEXT CHAR
	JUMPE B,CEEX3		;END ON A ZERO BYTE
;;PA048	STI			;STUFF IT
	JRST    CEEX2		;DO THE REST

CEEX3:
	MOVEI B,CR
;;PA048	STI
	DPB B,C			;;PA048 Drop a CR on top of the nul
	MOVEI B,.CHLFD		;;PA048 Then add
	DPB B,C			;;PA048  a LF
	SETZ B,			;;PA048 Load a null
	IDPB B,C		;;PA048 Null-terminate the string
	MOVEI A,CETBUF		;;PA048 Point to current line again
	HRLI A,440700		;;PA048 ...
	SETZ B,			;;PA048 Don't type a prompt
	CALL C2CBUF		;;PA048 Stick command in the command buffer
				;; without echoing
	TYPE <
>				;;PA048 Type a CRLF for neatness

CEQUIT: MOVEI Q1,ETTYMD		;LOAD EXEC TTY MODES
	CALL LTTYMD
	MOVEI A,.CTTRM		;RESTORE PAGE MODE IF WE NEED TO
	MOVE B,CETTMD		;PA048 Get terminal modes
	STPAR
;PA048	SETOM CEBPTR		;DON'T SAVE THIS
;PA048	ETYPE <
;PA048>
	RET

;PA048 Here on ^G in Emacs or Q in SOS - forget about all editing, retype
; line which we started out editing, and quit

CEABRT:	SETZM CESCHK		;CU79 Make sure we don't come back here
	SETZM EDITFL		;CU79 Turn of /noconfirm or /edit action
	CALL CEQUIT		;PA048 Fix TTY modes
	MOVE A,CEORIG		;PA048 Get pointer to history entry we
				; were editing
	HRROI A,2(A)		;PA048 Get pointer to text of command
	CALL FAKTYP		;PA048 Display it and copy it into CBUF
	RET			;PA048 All done

;PA048 Here on ^C in either editor.  Fixes tty modes and then simulates
;typein of a ^C (which, if ^C's are allowed, is handled by Exec's ^C
;handler since we've gotten ourselves out of binary mode)

CECTLC:	CALL CEQUIT		;Fix tty modes
	MOVEI A,.CTTRM		;Point at controlling tty
	CFIBF%			;Clear typeahead
	 ERJMP .+1
; This does not work... Try
;  "daytime<esc>^X<esc><esc>^C^X^C"
;	MOVX B,.CHCNC		;Get ^C
;	STI%			;"Type" it
	MOVEI A,.FHSLF		;CU79 interrupt self
	MOVX B,1B1		;CU79 on ^C channel
	IIC%			;CU79
	 ERJMP .+1		;CU79
	RET			;Return if ^C currently disabled

; Routine to redisplay the line

CERDSP:	MOVEI A,.CHCRT		;PA048 Get CR
	PBOUT%			;PA048 Get to beginning of line
	SKIPE CEDUMB		;PA048 Go to new line only on stupid ttys
CEDISP:	TYPE <
>				;PA048 (Use TYPE instead of ETYPE) for simple
				; stuff) GO TO A NEW LINE
	CALL EEOLN		;JUST TO BE SURE
	CALL CENUMB		;DO THE LINE NUMBER
	HRROI A,CETBUF		;POINT TO COMMAND LINE
	PSOUT			;WRITE IT OUT
	JRST CINST1		;POSITION THE CURSOR



; Routine to send a bell to the terminal

CEBELL:	MOVE A,COJFN		;REDO THE CCOC
	RFCOC
	PUSH P,B		;SAVE MODE
	TLC B,1B32!1B33		;SEND ACTUAL CODE
	SFCOC
	MOVEI B,.CHBEL		;SEND THE BELL
	BOUT
	POP P,B			;RESTORE
	SFCOC
	RET


; Routine to back the cursor up one place

CEBACK:	MOVE A,COJFN		;GET THE TERMINAL TYPE
	RFMOD			;GET MODE WORD
	PUSH P,B		;SAVE IT
	TXZ B,TT%DAM		;NO TRANSLATION
	SFMOD
	GTTYP
REPEAT 0,<			;Old way...
	HRROI A,[ASCIZ //]	;ASSUME NORMAL TERMINAL
	CAIE B,.TT100		;GET THE VT100 TYPES OUT OF THE WAY
	 CAIN B,.TT125
	  HRROI A,[ASCIZ //]
	CAIN B,.TTK10		;CU79
	  HRROI A,[ASCIZ //]
	CAIE B,.TTK10
	 CAIN B,.TTANS
	  HRROI A,[ASCIZ //]
	CAIN B,.TTAMB
	 HRROI A,[ASCIZ //]
	CAIN B,.TTB10		;BEEHIVES
	 HRROI A,[ASCIZ /D/]
>;REPEAT 0
REPEAT 1,<			;New way...
	CAIG B,NTTTYP		;Type number bigger than we know about?
	SKIPN B,TTYPE1(B)	;Get address of table entry for this tty type
	 JRST EEOLN2		;None - do nothing
	SKIPN A,.CURBK(B)	;Get cursor backup sequence
	 JRST EEOLN2		;None - do nothing
	TLNE A,-1		;String or 0,,address of string?
	 HRROI A,.CURBK(B)	;String - point to it instead
	HRLI A,(<POINT 8,0>)	;Make 8-bit pointer
CEBAK2:
>;REPEAT 1	
	MOVE B,A		;use the string pointer we made
	MOVE A,COJFN		;output to terminal
.STP==377			;USED IN EXECTT
	CALL STPOUT		;shove that string out
	MOVE A,COJFN		;RESTORE MODE WORD
	POP P,B			;GET OLD MODE
	SFMOD			;DO IT
	RET

CEBAK3:	HRROI A,[ASCIZ //]	;No table entry, assume normal terminal
	JRST CEBAK2

; Routine to errase all characters to the end of line

EEOLN:	PUSH P,A		;SAVE THIS
	PUSH P,B		;THIS TOO
	MOVE A,COJFN		;CURRENT OUTPUT JFN
	RFMOD			;GET MODE WORD
	PUSH P,B		;SAVE IT
	TXZ B,TT%DAM		;NO TRANSLATION
	SFMOD
	GTTYP			;GET TERMINAL TYPE
REPEAT 0,<			;Old way...
	CAIG B,EOLNMX		;ALL WE KNOW ABOUT NOW
	SKIPN A,EEOLTB(B)	;GET STRING TO DUMP
	 JRST EEOLN2		;NONE - DO NOTHING
	TLNN A,-1		;STRING OR PNTR?
	 TLOA A,-1		;PNTR TO TEXT
	  HRROI A,EEOLTB(B)	;STRING - POINT TO IT INSTEAD
>;REPEAT 0
REPEAT 1,<			;New way...
	CAIG B,NTTTYP		;Type number bigger than we know about?
	SKIPN B,TTYPE1(B)	;Get address of table entry for this tty type
	 JRST EEOLN2		;None - do nothing
	SKIPN A,.CUREL(B)	;Get clear-to-end-of-line sequence
	 JRST EEOLN2		;None - do nothing
	TLNE A,-1		;String or 0,,address of string?
	 HRROI A,.CUREL(B)	;String - point to it instead
	HRLI A,(<POINT 8,0>)	;Make 8-bit pointer
>;REPEAT 1	
	MOVE B,A		;use the string pointer we made
	MOVE A,COJFN		;output to terminal
	CALL STPOUT		;shove that string out
EEOLN2:	MOVE A,COJFN		;RESTORE MODE WORD
	POP P,B			;GET OLD MODE
	SFMOD			;DO IT
	POP	P,B		;RESTORE THIS
	POP	P,A		;THIS TOO
	RET

;STPOUT souts a STG style cursor control string to the termial.  The
;problem is that we DONT want to output the termination character (.STP),
;as it can have undesireable side effects!  This code assumes that the
;string is relatively short. (it counts characters one at a time...)
STPOUT:	PUSH P,B
	SETZB C,D
STPOU1:	ILDB D,B		;get a character
	CAIE D,.STP		;is it the terminator?
	IFSKP.
	 POP P,B		;get back pointer to beginning of string
	 SOUT
	 RET
	ENDIF.
	SOJA C,STPOU1		;increment count, step though string
; ERRASE TO END OF LINE TABLE

REPEAT 0,<			;No longer used

EEOLTB:	0			;(0) Tty 33
	0			;(1) Tty 35
	0			;(2) Tty 37
	0			;(3) TI
	0			;(4)
	0			;(5)
	0			;(6)
	0			;(7)
	0			;(8) System default
	0			;(9) Ideal
	BYTE(7) 36,0		;(10) VT05
	BYTE(7) .CHESC,"K",0	;(11) VT50
	0			;(12) LA30
	0			;(13) GT40
	0			;(14) LA36
	BYTE(7) .CHESC,"K",0	;(15) VT52
	BYTE(7) .CHESC,"[","K",0 ;(16) VT100
	0			;(17) LA38
	0			;(18) LA120
	BYTE(7) .CHESC,"K",0	;(19) Regent-20
	BYTE(7) .CHESC,"I",0	;(20) IBM 3101
	0			;(21)
	0			;(22)
;CU79 Columbia terminal types
	BYTE(7) 33,"U",33,"U"-"@",0 ;(23) Concept-100
	BYTE(7) .CHESC,"I",0	;(24) Fox
	BYTE(7) .CHCRB,0	;(25) Datamedia 1520A
	0			;(26) Glass
	BYTE(7) .CHESC,"K",0	;(27) DM30xx (like VT52's)
	BYTE(7) .CHESC,"K",0	;(28) HP 26xx
	BYTE(7) 13,0		;(29) Infoton-Vista
	[BYTE(7) .CHESC,"I",.CHDEL,.CHDEL,.CHDEL,.CHDEL,.CHDEL,0] ;(30) Bantam
	BYTE(7) .CHESC,"K",0	;(31) Heath-19
	BYTE(7) .CHESC,"K",0	;(32) Telray
	BYTE(7) .CHESC,"t",0	;CU129 (33) Freedom-100
	BYTE(7) .CHESC,"K",0	;CU141 (34) Viewpoint erase to EOL.
	0			;CU146 (35) VT125
	0			;CU146 (36) VK100
	BYTE(7) .CHESC,"[","K",0 ;CU146 (37) VT102
EOLNMX== .-EEOLTB-1

>;REPEAT 0
;	Routine to type a help message for Emacs mode


CEHELP:	CALL	BLANK1		;CLEAR THE SCREEN
	HRROI A,HLPMS0		;CU79 get the help message
	PSOUT
	PBIN			;CU79 want next display?
	CAIE A," "		;CU79 well?
	IFSKP.			;CU79 yes...
	 CALL BLANK1		;CU79 so blank the screen
	 HRROI A,HLPMS1		;CU79 get next page
	 PSOUT			;CU79 and output it
	ENDIF.			
	JRST CEDISP		;CU79 and redisplay the line


;CU79 New help message

HLPMS0:	ASCIZ/
The following commands can be used while in the command editor:

RETURN		Execute edited command
CTRL-C		Exit from the command editor
CTRL-G		Exit from the command editor, but enter the command
CTRL-N		Edit the next (more recent) command line
CTRL-P		Edit the previous command line
CTRL-F		Move forward one character
CTRL-B		Move back one character
CTRL-L		Redisplay the command line
CTRL-E		Move to the end of the line
CTRL-A		Move to the beginning of the line
CTRL-T		Swap the character at the cursor with the one before it
CTRL-D		Delete the character at the cursor
CTRL-K		Delete everything to the right of the cursor
CTRL-Q		Quote the next character for insert

							---MORE---/
HLPMS1:	ASCIZ /

DELETE		Delete the character to the left of the cursor
ESCAPE F	Move to the beginning of the next word
ESCAPE B	Move to the beginning of the previous word
ESCAPE D	Delete up to the beginning of the next word
ESCAPE DELETE	Delete back to the beginning of the previous word
ESCAPE S <char>	Search forward for <char> (case insensitive)
ESCAPE R <char>	Search backward for <char> (case insensitive)
ESCAPE ESCAPE	Perform recognition on current word
ESCAPE ?	Add a question mark to the end of the command and exit

Any other character will be inserted into the command before the cursor.
/
; ROUTINE TO TYPE HELP MESSAGE FOR ALTER MODE

CAHELP:	CALL BLANK1		;TRY TO BLANK THE SCREEN
	HRROI A,ALTHLP		;POINT TO THE STRING
	PSOUT			;WRITE IT OUT
	JRST CETOP

ALTHLP:	ASCIZ /
This is the Alter mode command editor.

Return		Execute edited command
E		Execute edited command
Q		Return to command level
Line Feed	Edit the next command line
Escape		Edit the previous command line
Control-U	Ignore editing up to now and start over
I		Enter insert mode (exit with an escape)
nSPACE		Move forward n characters
nRUB		Move back n characters
nW		Move forward n words
Tab		Move to the end of the line
X		Move to the end of the line and enter insert mode
Control-L	Redisplay the command line, move cursor to beginning
Control-R	Redisplay the command line, stay at current cursor position
P		Redisplay the command line, stay at current cursor position
\		Swap the character at the cursor with the one before it
nD		Delete n characters at the cursor
nR		Delete n characters then enter insert mode
:		Delete everything to the right of the cursor
H		Delete the rest of the line and enter insert mode/

;CU79 Begin addition
;
; ADDCFM - add a confirm to the contents of the command buffer
;
; Returns +1 always, preserves all registers
;
addcfm:	atsave			;save the temp cells
	move a,cmptr		;get the pointer to next field to be parsed
	tlc a,-1		;fix up hrroi-style pointer
	tlcn a,-1
	 hrli a,(point 7,)
	move b,cminc		;and the number of characters left to parse
	adjbp b,a		;make a byte pointer to the end of the string
	ldb a,b			;get the last byte
	caie a,.chlfd		;is it a linefeed?
	cain a,.chcrt		;or carriage return?
	 ret			;yes, already confirmed so do nothing
	cain a,.chffd		;formfeed?
	 ret			;yes, that confirms as well
	movei a,.chcrt		;not confirmed, so get a carriage return
	idpb a,b		;deposit it
	movei a,.chlfd		;get a linefeed character
	idpb a,b		;deposit on the end of the string
	setz a,			;get a null
	idpb a,b		;tie off the command buffer
	movei a,2		;we lengthened the buffer by two, so
	addm a,cminc		; increment the character count appropriately
	ret			;and return

;CU79 End addition
;CU97 Redefine (logical name) sys:

.redef::saveac <p1>		;command length goes here (can't use a stkvar)
	stkvar <ln,<lnbody,100>>
	noise (logical name)
	strx <logical name to edit> ;parse a logical name
	 cmerrx
	call bufff		;buffer it up
	confirm			;get a confirm
	movem a,ln		;save the pointer to the logical name
	call bcount		;get its length
	movei p1,^d14(b)	;calculate length of "define foo: (as) "
	movei a,.lnsjb		;a/ want a job-wide logical definition
	move b,ln		;b/ pointer to the logical name
	hrroi c,lnbody		;c/ destination pointer
	lnmst%			;get the logical name body
	ifnsk.			;if not a job-wide logical...
	  movei a,.lnssy	;a/ want a system-wide logical
	  move b,ln		;b/ pointer to the logical name
	  hrroi c,lnbody	;c/ pointer to the destination
	  lnmst%		;get the logical name body
	   setzm lnbody		;not defined, so make body null
	endif.
	move a,[point 7,buf0]	;use buf0 as a temporary string buffer
	movem a,cojfn		;divert etype output to buf0
	move 1,ln		;1/ logical name string
	hrroi 2,lnbody		;2/ logical name definition
	etype <define %1\: (as) %2\> ;if you change this, update p1 above
	call fixio		;restore cojfn
	move a,[point 7,buf0]	;get a pointer to the command to edit
	call mkhrec		;make a history record
	 error <EXEC free space exhausted>
	call addhst		;add it to the history list
	cedstg			;set up local variable context for ceditu
	call pioff		;don't allow ^C while we much things around
	hrrz a,hstlst		;a/ pointer to the history list entry
	move b,cmdnum		;b/ the command number
	move c,p1		;c/ the column we want to start in
	call ceditu		;call the command editor
	call rmvfst		;remove the history list entry
	call pion		;allow ^C again
;Since FAKTYP was called a prompt was not issued and the terminal
; interrupt will not be enabled, enable it now.
	hrlz a,cepsic		;get interrupt character's code
	hrri a,cepchn		;get the channel to use
	skipl a			;CEPSIC contains -1 (ie, none)
	 ati%			;no, so assign interrupt
	setzm cipf		;say no command in progress
	jrst repars		;go fix things up and parse the command

;CU97 End addition

	END