[comp.sys.amiga] uEMACS

wecker@cookie.dec.com.UUCP (02/21/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	overview
#	makefile
#	uemacs.hlp
#	ebind.h
#	edef.h
#	efunc.h
#	epath.h
#	estruct.h
# This archive created: Fri Feb 20 17:44:26 1987
echo shar: extracting overview
sed 's/^XX//' << \SHAR_EOF > overview
XX    This set of 4 shar files contains my own version of micro EMACS that I have
XX    been using for over a year. I am making this software available because it
XX    has been so useful to me.... however:
XX
XX	 I WILL NOT SUPPORT IT!!!   (caveat emptor)
XX
XX    The file uemacs.hlp is the only documentation that exists.
XX
XX    Editors are kind of a religous issue... so let's not get into word fights.
XX    I like EMACS. I do not like mice/keypads/function keys while editing. If
XX    you want a good portable EMACS, take a look at this kit.
XX
XX    This is an UNSUPPORTED version (my own).. but is the ONLY editor I use on
XX    the AMIGA, VMS and ULTRIX. You only need to change one define in estruct.h
XX    (the machine you're on) and recompile (I use Manx on the Amiga).
XX
XX    It includes:
XX
XX	-	Full regular expression pattern matching
XX	-	My own micro-lisp for batch mode editing
XX	-	sub-process windows (under ULTRIX)
XX	-	Keypad support on VMS and ULTRIX (which I never use so I
XX		never got around to checking it out on the AMIGA)
XX	-	Any size window on VMS and ULTRIX (number of rows)
XX	-	Only 75k in size
XX	-	Built in Modes:
XX			WRAP	- auto wrap
XX			EXACT	- exact (case-sensitive) searching
XX			LISP	- language mode
XX			MODULA	- language mode
XX			C	- language mode
XX			SLOW	- slow speed (1200 baud) terminal optimizations
XX			VIEW	- read only mode
XX	-	LOTS AND LOTS of bug fixes from the standard PD version
XX	-	Too many other features to list.. take a look at UEMACS.HLP
XX
XX    Again, I WILL NOT SUPPORT THIS EDITOR. It is for my own personal use,
XX    but you are welcome to use it however you see fit.
XX
XX    dave    decwrl!cookie.dec.com!wecker
XX
XX
SHAR_EOF
if test 1618 -ne "`wc -c overview`"
then
echo shar: error transmitting overview '(should have been 1618 characters)'
fi
echo shar: extracting makefile
sed 's/^XX//' << \SHAR_EOF > makefile
XXCFLAGS = -O
XXLFLAGS = -O -ltermcap -lc
XX
XXOFILES =	ansi.o basic.o bind.o buffer.o display.o file.o \
XX		fileio.o line.o lisp.o lock.o main.o random.o region.o \
XX		search.o spawn.o tcap.o termio.o window.o word.o
XX
XXHFILES =	estruct.h edef.h efunc.h epath.h ebind.h
XX
XXuemacs :	$(OFILES)
XX		$(CC) -o uemacs $(OFILES) $(LFLAGS)
XX
XX#$(OFILES):	$(HFILES)
XX
XXinstall :
XX		install -c -m 775 uemacs /staff/bin/uemacs
XX
XX
SHAR_EOF
if test 398 -ne "`wc -c makefile`"
then
echo shar: error transmitting makefile '(should have been 398 characters)'
fi
echo shar: extracting uemacs.hlp
sed 's/^XX//' << \SHAR_EOF > uemacs.hlp
XX========================Micro EMACS Help File================================
XX
XXBindings:	^  = Control
XX		M- = <ESC> prefix
XX		K- = ansi keypad character
XX		G- = ansi keypad character (with GOLD prefix)
XX
XXCommands: 
XX   meta prefix:                 "M-100 ^Xl"	        would go to line 100
XX   numeric params come first: 	"^U 100 ^Xl" 		would go to line 100
XX   extended commands:		"^U 100 M-X goto-line" 	would go to line 100
XX   init files:                  "(100 goto-line)"	would go to line 100
XX	(type Bindings as defined above (e.g. ^C for <control-C>) in files)
XX
XXModes:		WRAP  - perform word wrapping when the fill-column is reached
XX		SLOW  - do searches interactively (for slow speed terminals)
XX		EXACT - do all searching with exact case matching
XX		CMODE - do automatic indentation of C code
XX		MMODE - do automatic indentation of MODULA code
XX		LISP  - do automatic indentation of LISP code
XX		VIEW  - set buffer to read-only
XX
XXSearching:	In SLOW mode use ^F to go forward, ^R to reverse, ^G to abort
XX		   or any other character to terminate search and draw screen
XX		All searching is done with (limited) regular expressions:
XX		^    = match beginning of line (if beginning of search)
XX		$    = match end of line (if end of search)
XX		[or] = match one of "or" (see below)
XX		[^or]= match anything BUT "or" (see below)
XX		.    = match any one character
XX		*    = match zero or more of previous
XX		+    = match 1 or more of previous
XX		\( \)= bracket sub expressions
XX		\    = quote next character (except parens (above))
XX
XX		"or" = string of characters or ranges:
XX			[abcde] = [a-e] = [ab-de] = [a-cd-e]
XX
XXReplacing:	\0   = entire match
XX		\n   = nth bracketed [\( \)] sub-expression (1 <= n <= 9)
XX
XX		y    = do the replacement (in query mode) 
XX		n    = dont' do this replacement, but keep looking
XX		.    = stop replacing and go back to start
XX		^G   = stop replacing and stary where you are
XX
XX		NOTE: searches can NOT cross lines, but replacements CAN.
XX
XXmicro-LISP:
XX  - only 1 buffer may be executed at a time (no recursive buffer executes).
XX  - The entire contents of a buffer are viewed as a LISP progn.
XX  - Values may be either INTEGERS or STRINGS (and are interchangable).
XX  - All functions return a value. Non-LISP functions return success or
XX    failure via a return value of 0 or 1.
XX  - The startup file is .uemacsrc and is executed as a micro-LISP progn.
XX  - The batch file option (-b filename) is also a LISP progn.
XX  - Program statments (lists) may be arbitrarily nested.
XX  - If the head of a list evaluates to an integer then this number is used
XX    as a repeat count/numeric argument.
XX  - Symbols are single lower case letters (a-z), and may contain any value.
XX  - Progn labels may be either integers or strings.
XX  - Comments run from a semi-colon (;) until the end of the line
XX  - LISTS may only be used as program statements (not data) and are enclosed
XX    in parenthesis (with whitespace between elements).
XX  - SYMBOLS are the lower case letters a through z.
XX  - SUBRS are all built in functions (there are NO user functions).
XX  - INTEGERS are strings of the digits 0-9 with an optional leading "-".
XX  - STRINGS are enclosed in double quotes (") and may contain:
XX	normal characters
XX	\r = return, \n = newline, \t = tab, \e = escape, \" = ", \\ = \
XX	\#, \##, \### = ascii value where # = a digit between 0 and 7
XX  - Note that strings ARE allowed to cross line boundaries
XX  - All arithmetic/logic functions (except not) take 2 arguments and the
XX    arguments are ALWAYS evaluated (even for "and" and "or").
XX
XXExample program:
XX	; First ask the user what to search for
XX
XX	(setq a (ask "Search for what? "))
XX
XX	; Keep searching until the user says to stop, or there are no more
XX	; occurrances of the string in the buffer
XX
XX	"Loop"
XX	(if (not (search-forward a)) (go "Done"))
XX	(if (eq (ask "Continue [y] ? ") "n") (go "Done") (go "Loop"))
XX
XX	; Now show the user the first five characters on the line
XX
XX	"Done"
XX	(beginning-of-line)
XX	(set-mark)
XX	(5 forward-character)
XX	(copy-region)
XX	(setq b (yank-string))
XX	(ask "Line starts with: <" b "> ")
XX	(return)
XX
XXKeypad:				+--PF1--+--PF2--+--PF3--+--PF4--+
XX   PF1	G-			| GOLD  | HELP  | FIND  | DEL L |
XX   PF2	K-Q G-Q			|       | DESKEY| REVFND| YANK  |
XX   PF3	K-R G-R			+---7---+---8---+---9---+-------+
XX   PF4	K-S G-S			| F-PARA| B-PARA|COPY-  | DEL W |
XX   0	K-p G-p			| COMMND| FILPAR| REGION| YANK  |
XX   1	K-q G-q			+---4---+---5---+---6---+---,---|
XX   2	K-r G-r			| F-SCRL| B-SCRL| CUT   | DEL C |
XX   3	K-s G-s			| BOTTM | TOP   | YANK  | YANK  |
XX   4	K-t G-t			+---1---+---2---+---3---+-ENTER-+
XX   5	K-u G-u			| F-WORD| EOL   | F-CHAR|       |
XX   6	K-v G-v			| UPCASE| D-EOL | QUOTE | ENTER |
XX   7	K-w G-w			+-------0-------+---.---+	|
XX   8	K-x G-x			| BEGIN OF LINE | MARK  | SUBS  |
XX   9	K-y G-y			|    OPEN LINE  | XCHG  |       |
XX   -	K-m G-m			+---------------+-------+-------+
XX   ,	K-l G-l
XX   .	K-n G-n
XX   ENT	K-M G-M
XX
XXCommand name              Description (* = LISP function)
XX-----------------------	  -----------------------------------------------
XX+ - * / % & |             * Arith: add,sub,mult,div,mod,and,or
XX= != > >= < <=            * Logical comparisons (for numeric arguments)
XXadd-mode                  Add or delete a mode for the buffer
XXadjust-mode               Add or delete a mode for the buffer
XXand                       * Logical and operator
XXask                       * Ask for input, paramaters concatenated for prompt
XXbackward-character 	  Move the cursor
XXbegin-macro               Start remembering keystrokes
XXbeginning-of-file         Move cursor to top of buffer (sets mark)
XXbegining-of-line          Cursor to beginning of line
XXbind-to-key               Define a function to a key
XXbuffer-position           Report on current buffer stats
XXcase-region-lower         Translate between dot and mark to lower case
XXcase-region-upper         Translate between dot and mrak to upper case
XXcase-word-capitalize      Capitalize one word
XXcase-word-lower           Downcase one word
XXcase-word-upper           Upcase one word
XXchange-file-name          Change the filename associated with a buffer
XXclear-and-redraw          Refresh the screen
XXcopy-region               Copy between dot and mark to the kill buffer
XXcurbuf			  * Return current buffer name as a string
XXcurchr,curcol,curlin	  * Return current char,column,line number as an int
XXdelete-blank-lines        Delete surrounding blank lines
XXdelete-buffer             Delete an entire buffer
XXdelete-mode               Change a mode for a buffer
XXdelete-next-character     Delete forward
XXdelete-next-word          Delete forward one word
XXdelete-other-windows      Go back to 1 window display
XXdelete-previous-character Remove character in front of cursor
XXdelete-previous-word      Delete word before cursor
XXdelete-window		  Delete the current window
XXdescribe-bindings         Give list of all key bindings
XXdescribe-key              Describe a specific key
XXend-macro                 End defining a macro started with ^X(
XXend-of-file               Move cursor to end of buffer (sets mark)
XXend-of-line               Move cursor to end of line
XXeq			  * Compare two strings/integers for equality
XXexchange-point-and-mark   Jump between dot and mark
XXexecute-buffer		  Execute a buffer as a list of commands
XXexecute-command-line	  Execute a single command line (not implemented)
XXexecute-file		  Execute a file as a list of commands
XXexecute-macro             Execute a macro defined byt ^X( ^X)
XX
XXexecute-named-command     Execute any of the commands in the 1st column
XXexit-emacs                Get out of emacs
XXfill-paragraph            Fill the surrounding paragraph
XXfind-file                 Read a file into the current buffer
XXforward-character         Move cursor forward
XXgo			  * Goto a label in a LISP progn statment
XXgoto-line                 Jump to a specific line number
XXgrow-window               Make window bigger
XXhandle-tab                Insert a tab (different in diff modes)
XXhelp                      Type this file
XXif			  * LISP if (true if int != 0 or string != "")
XXinsert-file               Insert a file at dot
XXkill-region               Kill region between dot and mark
XXkill-to-end-of-line       Kill text (put in kill buffer)
XXlist-buffers              Show all buffers
XXmove-window-down          Scroll the current window up
XXmove-window-up            Scroll the current window down
XXname-buffer               Change the name for a buffer
XXnewline                   Insert a <CR> (different in diff modes)
XXnewline-and-indent        End line and indent next line
XXnext-line                 Move cursor down one line
XXnext-page                 Scroll screen up
XXnext-paragraph            Move to next paragraph
XXnext-window               Jump to the next window (move cursor)
XXnext-word                 Move to next word
XXnot			  * Logical not operator
XXopen-line                 Open up a blank line at cursor
XXor			  * Logical or operator
XXprevious-line             Cursor up
XXprevious-page             Scroll screen down
XXprevious-paragraph        Move cursor back
XXprevious-window           Go to the previous window on the screen
XXprevious-word             Move cursor back
XXprinc			  * Insert all arguments into the current buffer
XXprogn			  * LISP progn
XXquery-replace-string      Replace text interactively (sets mark)
XXquick-exit                Save files and leave editor
XXquote-character           Quote the next character
XXread-file                 Read a file in to the buffer (READONLY)
XXredraw-display            Reposition display (center on current line)
XXreplace-string 	          Replace text without asking (sets mark)
XXreturn			  * Leave a LISP progn (optional return value)
XXsave-file                 Save the current file (checkpoint)
XXscroll-next-up            Scroll other window up
XXscroll-next-down          Scroll other window down
XXsearch-forward            Search forward for text (sets mark)
XXsearch-reverse            Search backward for text (sets mark)
XXselect-buffer             Pick a buffer to display
XXset-fill-column           Change the fill column
XXset-mark                  Set the mark
XXsetq			  * Set a LISP variable (a-z) to concat. of parameters
XXshell			  Sprout a subprocess
XXshell-command		  Execute a one line command in a sub shell
XXshell-quote		  Send the next character to a sub-shell
XXshrink-window             Make the window smaller
XXsplit-current-window      Divide the current window in half
XXsuspend-emacs             Pause emacs (on unix)
XXtranspose-characters      Flip characters before/under cursor
XXunbind-key                Delete a key binding
XXvisit-file                Bring a file in (in a new buffer)
XXvisit-tag		  Bring a file in (via the current tagged word)
XXwrite-file                Write file to a new name
XXyank                      Yank back from the kill buffer
XXyank-string		  * Yank the kill buffer into a LISP string
XX
XXadd-mode                 ^X^M       adjust-mode              ^X^M       
XXbackward-character       ^B,K-D     begin-macro              ^X(        
XXbegining-of-file         M-<,G-u    begining-of-line         ^A,K-p     
XXbind-to-key                         buffer-position          ^X=        
XXcase-region-lower        ^X^L       case-region-upper        ^X^U       
XXcase-word-capitalize     M-C        case-word-lower          M-L        
XXcase-word-upper          M-U,G-q    change-file-name         ^XN        
XXclear-and-redraw         ^L         copy-region              M-W,K-y,G-y
XXdelete-blank-lines       ^X^O       delete-buffer            ^XK        
XXdelete-mode              ^X^M       delete-next-character    ^D,K-l     
XXdelete-next-word         M-D,K-m    delete-other-windows     ^X1        
XXdelete-previous-character^H,^?      delete-previous-word     M-^H,M-^?   
XXdelete-window            ^XD        describe-bindings        M-?        
XXdescribe-key             ^X?,G-Q    end-macro                ^X)        
XXend-of-file              M->,G-t    end-of-line              ^E,K-r     
XXexchange-point-and-mark  ^X^X,G-n   execute-buffer                      
XXexecute-command-line                execute-file                        
XXexecute-macro            ^Z,^XE     execute-named-command    M-X,G-w    
XXexit-emacs               ^X^C       fill-paragraph           M-G,G-x    
XXfind-file                ^X^R       forward-character        K-C,K-s    
XXgoto-line                ^XL        grow-window              ^X>,^X^,^XZ
XXhandle-tab               ^I         help                     K-Q        
XXinsert-file              ^X^I       kill-region              ^W,K-v,K-3 
XXkill-to-end-of-line      ^K,K-S,G-r list-buffers             ^X^B       
XXmove-window-down         ^X^N       move-window-up                      
XXname-buffer              M-^N       newline                  ^M,K-M     
XXnewline-and-indent       ^J         next-line                ^N,K-B     
XXnext-page                ^V,K-t,K-6 next-paragraph           M-N,K-w    
XXnext-window              ^XO        next-word                M-F,K-q    
XXopen-line                ^O,K-2,G-p previous-line            ^P,K-A     
XXprevious-page           M-V,K-u,K-5 previous-paragraph       M-P,K-x    
XXprevious-window          ^XP        previous-word            M-B        
XXquery-replace-string   M-^R,M-Q,G-M quick-exit               ^X^F,M-Z   
XXquote-character          ^],G-s     read-file                ^XR        
XXredraw-display           M-^L,M-!   replace-string           M-R        
XXsave-file                ^XS        scroll-next-up           M-^Z       
XXscroll-next-down         M-^V       search-forward           ^F,K-R,K-1 
XXsearch-reverse           ^R,G-R     select-buffer            ^XB        
XXset-fill-column          ^XF        set-mark     ^XM,^XX,M- ,M-.,K-n,K-4
XXshell-quote              ^C         shell-command            ^X!        
XXshrink-window            ^X^Z,^X<   split-current-window     ^X2        
XXsuspend-emacs            ^X^P       transpose-characters     ^T         
XXunbind-key               M-^C       visit-file               ^X^V       
XXvisit-tag                ^X^T       write-file               ^X^W       
XXyank       ^Y,G-S,G-l,G-m,G-v
XX
XX
XX
XX
XXG-M    query-replace-string      G-Q    describe-key              
XXG-R    search-reverse            G-S    yank                     
XXG-m    yank                      G-p    open-line                 
XXG-q    case-word-upper           G-r    kill-to-end-of-line       
XXG-s    quote-character           G-t    end-of-file               
XXG-u    begining-of-file          G-v    yank                     
XXG-x    fill-paragraph            G-y    copy-region               
XX
XXK-1    search-forward            K-2    open-line                 
XXK-3    kill-region               K-4    set-mark                  
XXK-5    previous-page             K-6    next-page                 
XXK-A    previous-line             K-B    next-line                 
XXK-C    forward-character         K-D    backward-character        
XXK-M    newline                   K-Q    help                     
XXK-S    kill-to-end-of-line       K-l    delete-next-character     
XXK-m    delete-next-word          K-n    set-mark                  
XXK-p    begining-of-line          K-q    next-word                 
XXK-r    end-of-line               K-s    forward-character         
XXK-t    next-page                 K-u    previous-page             
XXK-v    kill-region               K-w    next-paragraph     
XXK-x    previous-paragraph        K-y    copy-region               
XXM-     set-mark                  M-!    redraw-display            
XXM-.    set-mark                  M-<    begining-of-file          
XXM->    end-of-file               M-?    describe-bindings         
XXM-B    previous-word             M-C    case-word-capitalize      
XXM-D    delete-next-word          M-F    next-word                 
XXM-N    next-paragraph            M-P    previous-paragraph        
XXM-Q    query-replace-string      M-R    replace-string            
XXM-U    case-word-upper           M-V    previous-page             
XXM-W    copy-region               M-X    execute-named-command     
XXM-Z    quick-exit                M-^C   unbind-key                
XXM-^H   delete-previous-word      M-^L   redraw-display            
XXM-^N   name-buffer               M-^R   query-replace-string      
XXM-^V   scroll-next-down          M-^Z   scroll-next-up            
XXM-^?   delete-previous-word      ^A     begining-of-line          
XX^B     backward-character        ^C     shell-quote    
XX^D     delete-next-character     ^E     end-of-line               
XX^F     search-forward            ^H     delete-previous-character 
XX^I     handle-tab                ^J     newline-and-indent        
XX^K     kill-to-end-of-line       ^L     clear-and-redraw          
XX^M     newline                   ^N     next-line                 
XX^O     open-line                 ^P     previous-line             
XX^R     search-reverse            ^T     transpose-characters      
XX^V     next-page                 ^W     kill-region               
XX^X!    shell-command             ^X(    begin-macro               
XX^X)    end-macro                 ^X1    delete-other-windows      
XX^X2    split-current-window      ^X<    shrink-window     
XX^X=    buffer-position           ^X>    grow-window    
XX^X?    describe-key              ^XB    select-buffer             
XX^XD    delete-window             ^XE    execute-macro             
XX^XF    set-fill-column           ^XK    delete-buffer             
XX^XL    goto-line                 ^XM    set-mark                  
XX^XN    change-file-name          ^XO    next-window               
XX^XP    previous-window           ^XR    read-file                 
XX^XS    save-file                 ^XX    set-mark                  
XX^XZ    grow-window               ^X^    grow-window               
XX^X^B   list-buffers              ^X^C   exit-emacs                
XX^X^F   quick-exit                ^X^I   insert-file               
XX^X^L   case-region-lower         ^X^M   add-mode                  
XX^X^M   adjust-mode               ^X^M   delete-mode               
XX^X^N   move-window-down          ^X^O   delete-blank-lines        
XX^X^P   suspend-emacs             ^X^R   find-file                 
XX^X^T   visit-tag                 ^X^U   case-region-upper         
XX^X^V   visit-file                ^X^W   write-file                
XX^X^X   exchange-point-and-mark   ^X^Z   shrink-window             
XX^Y     yank                      ^]     quote-character           
XX^?     delete-previous-character 
SHAR_EOF
if test 18356 -ne "`wc -c uemacs.hlp`"
then
echo shar: error transmitting uemacs.hlp '(should have been 18356 characters)'
fi
echo shar: extracting ebind.h
sed 's/^XX//' << \SHAR_EOF > ebind.h
XX/*	EBIND:		Initial default key to function bindings for
XX *	MicroEMACS
XX */
XX
XX/*
XX * Command table.
XX * This table  is *roughly* in ASCII order, left to right across the
XX * characters of the command. This expains the funny location of the
XX * control-X commands.
XX
XX */
XXKEYTAB keytab[NBINDS] = {
XX	CTRL|']',	quote,
XX        CTRL|'A',	gotobol,
XX        CTRL|'B',	backchar,
XX#if ULTRIX
XX	CTRL|'C',	shellquote,
XX#endif
XX        CTRL|'D',	forwdel,
XX        CTRL|'E',	gotoeol,
XX        CTRL|'F',	forwsearch,
XX        CTRL|'G',	ctrlg,
XX        CTRL|'H',	backdel,
XX        CTRL|'I',	tab,
XX        CTRL|'J',	indent,
XX        CTRL|'K',	killtext,
XX        CTRL|'L',	refresh,
XX        CTRL|'M',	newline,
XX        CTRL|'N',	forwline,
XX        CTRL|'O',	openline,
XX        CTRL|'P',	backline,
XX        CTRL|'R',	backsearch,
XX        CTRL|'T',	twiddle,
XX        CTRL|'V',	forwpage,
XX        CTRL|'W',	killregion,
XX        CTRL|'Y',	yank,
XX        CTRL|'Z',	ctlxe,
XX        CTLX|CTRL|'B',	listbuffers,
XX        CTLX|CTRL|'C',	quit,
XX        CTLX|CTRL|'F',	quickexit,
XX	CTLX|CTRL|'I',	insfile,
XX        CTLX|CTRL|'L',	lowerregion,
XX	CTLX|CTRL|'M',	adjustmode,
XX        CTLX|CTRL|'N',	mvdnwind,
XX        CTLX|CTRL|'O',	deblank,
XX#if ULTRIX
XX        CTLX|CTRL|'P',	bktoshell,
XX#endif
XX        CTLX|CTRL|'R',	filefind,
XX	CTLX|CTRL|'T',	visittag,
XX        CTLX|CTRL|'U',	upperregion,
XX	CTLX|CTRL|'V',	visitfile,
XX        CTLX|CTRL|'W',	filewrite,
XX        CTLX|CTRL|'X',	swapmark,
XX        CTLX|CTRL|'Z',	shrinkwind,
XX	CTLX|'?',	deskey,
XX        CTLX|'!',	spawn,
XX        CTLX|'<',	shrinkwind,
XX        CTLX|'=',	showcpos,
XX	CTLX|'>',	enlargewind,
XX        CTLX|'(',	ctlxlp,
XX        CTLX|')',	ctlxrp,
XX	CTLX|'^',	enlargewind,
XX        CTLX|'1',	onlywind,
XX        CTLX|'2',	splitwind,
XX        CTLX|'B',	usebuffer,
XX	CTLX|'D',	delwind,
XX        CTLX|'E',	ctlxe,
XX        CTLX|'F',	setfillcol,
XX        CTLX|'K',	killbuffer,
XX	CTLX|'L',	gotoline,
XX	CTLX|'M',	setmark,
XX        CTLX|'N',	filename,
XX	CTLX|'O',	nextwind,
XX        CTLX|'P',	prevwind,
XX	CTLX|'R',	fileread,
XX	CTLX|'S',	filesave,
XX	CTLX|'X',	setmark,
XX        CTLX|'Z',	enlargewind,
XX	META|CTRL|'C',	unbindkey,
XX        META|CTRL|'H',	delbword,
XX	META|CTRL|'L',	reposition,
XX	META|CTRL|'N',	namebuffer,
XX	META|CTRL|'R',	qreplace,
XX	META|CTRL|'V',	scrnextdw,
XX	META|CTRL|'Z',	scrnextup,
XX	META|' ',	setmark,
XX	META|'?',	desbind,
XX        META|'!',	reposition,
XX        META|'.',	setmark,
XX        META|'>',	gotoeob,
XX        META|'<',	gotobob,
XX        META|'B',	backword,
XX        META|'C',	capword,
XX        META|'D',	delfword,
XX        META|'F',	forwword,
XX	META|'G',	fillpara,
XX        META|'L',	lowerword,
XX	META|'N',	gotoeop,
XX	META|'P',	gotobop,
XX	META|'Q',	qreplace,
XX	META|'R',	sreplace,
XX        META|'U',	upperword,
XX        META|'V',	backpage,
XX        META|'W',	copyregion,
XX	META|'X',	namedcmd,
XX	META|'Z',	quickexit,
XX        META|0x7F,	delbword,
XX	SPEC|'A',	backline,
XX	SPEC|'B',	forwline,
XX	SPEC|'C',	forwchar,
XX	SPEC|'D',	backchar,
XX	SPEC|'M',	newline,	/* enter*/
XX	SPEC|'Q',	help,		/* PF2 */
XX	SPEC|'R',	forwsearch,	/* PF3 */
XX	SPEC|'S',	killtext,	/* PF4 */
XX	SPEC|'l',	forwdel,	/* , */
XX	SPEC|'m',	delfword,	/* - */
XX	SPEC|'n',	setmark,	/* . */
XX	SPEC|'p',	gotobol,	/* 0 */
XX	SPEC|'q',	forwword,	/* 1 */
XX	SPEC|'r',	gotoeol,	/* 2 */
XX	SPEC|'s',	forwchar,	/* 3 */
XX	SPEC|'t',	forwpage,	/* 4 */
XX	SPEC|'u',	backpage,	/* 5 */
XX	SPEC|'v',	killregion,	/* 6 */
XX	SPEC|'w',	gotoeop,	/* 7 */
XX	SPEC|'x',	gotobop,	/* 8 */
XX	SPEC|'y',	copyregion,	/* 9 */
XX	SPEC|'1',	forwsearch,
XX	SPEC|'2',	openline,
XX	SPEC|'3',	killregion,
XX	SPEC|'4',	setmark,
XX	SPEC|'5',	backpage,
XX	SPEC|'6',	forwpage,
XX	GOLD|'M',	qreplace,	/* enter*/
XX	GOLD|'Q',	deskey,		/* PF2 */
XX	GOLD|'R',	backsearch,	/* PF3 */
XX	GOLD|'S',	yank,		/* PF4 */
XX	GOLD|'l',	yank,		/* , */
XX	GOLD|'m',	yank,		/* - */
XX	GOLD|'n',	swapmark,	/* . */
XX	GOLD|'p',	openline,	/* 0 */
XX	GOLD|'q',	upperword,	/* 1 */
XX	GOLD|'r',	killtext,	/* 2 */
XX	GOLD|'s',	quote,		/* 3 */
XX	GOLD|'t',	gotoeob,	/* 4 */
XX	GOLD|'u',	gotobob,	/* 5 */
XX	GOLD|'v',	yank,		/* 6 */
XX	GOLD|'w',	namedcmd,	/* 7 */
XX	GOLD|'x',	fillpara,	/* 8 */
XX	GOLD|'y',	copyregion,	/* 9 */
XX        0x7F,		backdel,
XX	0,		NULL
XX	};
SHAR_EOF
if test 4038 -ne "`wc -c ebind.h`"
then
echo shar: error transmitting ebind.h '(should have been 4038 characters)'
fi
echo shar: extracting edef.h
sed 's/^XX//' << \SHAR_EOF > edef.h
XX/*	EDEF:		Global variable definitions for MICROEmacs */
XX
XX#ifdef	maindef
XX
XX/* for MAIN.C */
XX
XX/* initialized global definitions */
XX
XXint	batchmode = FALSE;		/* batch mode switch */
XXint	fillcol = 72;                   /* Current fill column */
XXshort	kbdm[NKBDM] = {CTLX|')'};       /* Macro */
XXchar	pat[NPAT];                      /* Search pattern */
XXchar	rpat[NPAT];			/* replacement pattern */
XXchar	sarg[NSTRING] = "";		/* string argument for line exec*/
XXint	eolexist = TRUE;		/* does clear to EOL exist */
XXchar	*modename[] =			/* name of modes */
XX	{ "WRAP", "CMODE", "SLOW", "EXACT", "VIEW", "MMODE", "LISP" };
XXchar	modecode[] = "WCSEVML";		/* letters to represent modes */
XXint	sgarbf  = TRUE;                 /* TRUE if screen is garbage */
XXint	mpresf  = FALSE;                /* TRUE if message in last line */
XXint	clexec	= FALSE;		/* command line execution flag */
XXint	slowterm= FALSE;		/* are we running a slow speed term*/
XXBUFFER	*procbuf= NULL;			/* process buffer pointer */
XX
XX/* uninitialized global definitions */
XX
XXint	currow;                 /* Cursor row */
XXint	curcol;                 /* Cursor column */
XXint	thisflag;               /* Flags, this command */
XXint	lastflag;               /* Flags, last command */
XXint	curgoal;                /* Goal for C-P, C-N */
XXWINDOW	*curwp;                 /* Current window */
XXBUFFER	*curbp;                 /* Current buffer */
XXWINDOW	*wheadp;                /* Head of list of windows */
XXBUFFER	*bheadp;                /* Head of list of buffers */
XXBUFFER	*blistp;                /* Buffer for C-X C-B */
XXshort	*kbdmip;                /* Input pointer for above */
XXshort	*kbdmop;                /* Output pointer for above */
XX
XXBUFFER	*bfind();               /* Lookup a buffer by name */
XXWINDOW	*wpopup();              /* Pop up window creation */
XXLINE	*lalloc();              /* Allocate a line */
XXint	pid;			/* process id of sub process */
XXint	outchannel;		/* output channel to sub process */
XXint	inchannel;		/* input channel from sub process */
XX#else
XX
XX/* for all the other .C files */
XX
XX/* initialized global external declarations */
XX
XXextern	int	batchmode;		/* batch mode switch */
XXextern	int     fillcol;                /* Fill column */
XXextern	short   kbdm[];                 /* Holds kayboard macro data */
XXextern	char    pat[];                  /* Search pattern */
XXextern	char	rpat[];			/* Replacement pattern */
XXextern	char	sarg[];			/* string argument for line exec*/
XXextern	int	eolexist;		/* does clear to EOL exist? */
XXextern	char	*modename[];		/* text names of modes */
XXextern	char	modecode[];		/* letters to represent modes */
XXextern	KEYTAB	keytab[];		/* key bind to functions table */
XXextern	NBIND	names[];		/* name to function table */
XXextern	int     sgarbf;                 /* State of screen unknown */
XXextern	int     mpresf;                 /* Stuff in message line */
XXextern	int	clexec;			/* command line execution flag */
XXextern	int	slowterm;		/* are we running a slow speed term*/
XXextern	BUFFER	*procbuf;		/* process buffer pointer */
XX
XX/* initialized global external declarations */
XX
XXextern int     currow;                 /* Cursor row */
XXextern int     curcol;                 /* Cursor column */
XXextern int     thisflag;               /* Flags, this command */
XXextern int     lastflag;               /* Flags, last command */
XXextern int     curgoal;                /* Goal for C-P, C-N */
XXextern WINDOW  *curwp;                 /* Current window */
XXextern BUFFER  *curbp;                 /* Current buffer */
XXextern WINDOW  *wheadp;                /* Head of list of windows */
XXextern BUFFER  *bheadp;                /* Head of list of buffers */
XXextern BUFFER  *blistp;                /* Buffer for C-X C-B */
XXextern short   *kbdmip;                /* Input pointer for above */
XXextern short   *kbdmop;                /* Output pointer for above */
XX
XXextern BUFFER  *bfind();               /* Lookup a buffer by name */
XXextern WINDOW  *wpopup();              /* Pop up window creation */
XXextern LINE    *lalloc();              /* Allocate a line */
XXextern int	pid;			/* process id of sub process */
XXextern int	outchannel;		/* output channel to sub process */
XXextern int	inchannel;		/* input channel from sub process */
XX
XX#endif
XX
XX/* terminal table defined only in TERM.C */
XX
XX#ifndef	termdef
XXextern TERM    term;                   /* Terminal information. */
XX#endif
XX
XX
SHAR_EOF
if test 4341 -ne "`wc -c edef.h`"
then
echo shar: error transmitting edef.h '(should have been 4341 characters)'
fi
echo shar: extracting efunc.h
sed 's/^XX//' << \SHAR_EOF > efunc.h
XX/*	EFUNC.H:	MicroEMACS function declarations and names */
XX
XX/*	External function declarations */
XX
XXextern	int     ctrlg();	/* Abort out of things */
XXextern	int     quit();		/* Quit */
XXextern	int     ctlxlp();	/* Begin macro */
XXextern	int     ctlxrp();	/* End macro */
XXextern	int     ctlxe();	/* Execute macro */
XXextern	int     fileread();	/* Get a file, read only */
XXextern	int     filefind();	/* Get a file, read write */
XXextern	int     filewrite();	/* Write a file */
XXextern	int     filesave();	/* Save current file */
XXextern	int     filename();	/* Adjust file name */
XXextern	int     getccol();	/* Get current column */
XXextern	int     gotobol();	/* Move to start of line */
XXextern	int     forwchar();	/* Move forward by characters */
XXextern	int     gotoeol();	/* Move to end of line */
XXextern	int     backchar();	/* Move backward by characters */
XXextern	int     forwline();	/* Move forward by lines */
XXextern	int     backline();	/* Move backward by lines */
XXextern	int     forwpage();	/* Move forward by pages */
XXextern	int     backpage();	/* Move backward by pages */
XXextern	int     gotobob();	/* Move to start of buffer */
XXextern	int     gotoeob();	/* Move to end of buffer */
XXextern	int     setfillcol();	/* Set fill column. */
XXextern	int     setmark();	/* Set mark */
XXextern	int     swapmark();	/* Swap "." and mark */
XXextern	int     forwsearch();	/* Search forward */
XXextern	int     backsearch();	/* Search backwards */
XXextern	int	sreplace();	/* search and replace */
XXextern	int	qreplace();	/* search and replace w/query */
XXextern	int     showcpos();	/* Show the cursor position */
XXextern	int     nextwind();	/* Move to the next window */
XXextern	int     prevwind();	/* Move to the previous window */
XXextern	int     onlywind();	/* Make current window only one */
XXextern	int	delwind();	/* Delete the current window */
XXextern	int     splitwind();	/* Split current window */
XXextern	int     mvdnwind();	/* Move window down */
XXextern	int     mvupwind();	/* Move window up */
XXextern	int     enlargewind();	/* Enlarge display window. */
XXextern	int     shrinkwind();	/* Shrink window. */
XXextern	int     listbuffers();	/* Display list of buffers */
XXextern	int     usebuffer();	/* Switch a window to a buffer */
XXextern	int     killbuffer();	/* Make a buffer go away. */
XXextern	int     reposition();	/* Reposition window */
XXextern	int     refresh();	/* Refresh the screen */
XXextern	int     twiddle();	/* Twiddle characters */
XXextern	int     tab();		/* Insert tab */
XXextern	int     newline();	/* Insert CR-LF */
XXextern	int     indent();	/* Insert CR-LF, then indent */
XXextern	int     openline();	/* Open up a blank line */
XXextern	int     deblank();	/* Delete blank lines */
XXextern	int     quote();	/* Insert literal */
XXextern	int     backword();	/* Backup by words */
XXextern	int     forwword();	/* Advance by words */
XXextern	int     forwdel();	/* Forward delete */
XXextern	int     backdel();	/* Backward delete */
XXextern	int     killtext();	/* Kill forward */
XXextern	int     yank();		/* Yank back from killbuffer. */
XXextern	int     upperword();	/* Upper case word. */
XXextern	int     lowerword();	/* Lower case word. */
XXextern	int     upperregion();	/* Upper case region. */
XXextern	int     lowerregion();	/* Lower case region. */
XXextern	int     capword();	/* Initial capitalize word. */
XXextern	int     delfword();	/* Delete forward word. */
XXextern	int     delbword();	/* Delete backward word. */
XXextern	int     killregion();	/* Kill region. */
XXextern	int     copyregion();	/* Copy region to kill buffer. */
XXextern	int     spawncli();	/* Run CLI in a subjob. */
XXextern	int     spawn();	/* Run a command in a subjob. */
XXextern	int	quickexit();	/* low keystroke style exit. */
XXextern	int	adjustmode();	/* set/unset an editor mode */
XXextern	int	gotoline();	/* go to a numbered line */
XXextern	int	namebuffer();	/* rename the current buffer */
XXextern	int	gotobop();	/* go to begining/paragraph */
XXextern	int	gotoeop();	/* go to end/paragraph */
XXextern	int	fillpara();	/* fill current paragraph */
XXextern	int	help();		/* get the help file here */
XXextern	int	deskey();	/* describe a key's binding */
XXextern	int	visitfile();	/* find a file in other window */
XXextern	int	visittag();	/* find a file (using tag) in other window */
XXextern	int	insfile();	/* insert a file */
XXextern	int	scrnextup();	/* scroll next window back */
XXextern	int	scrnextdw();	/* scroll next window down */
XXextern	int	bindtokey();	/* bind a function to a key */
XXextern	int	unbindkey();	/* unbind a key's function */
XXextern	int	namedcmd();	/* execute named command */
XXextern	int	desbind();	/* describe bindings */
XXextern	int	execcmd();	/* execute a command line */
XXextern	int	execbuf();	/* exec commands from a buffer */
XXextern	int	execfile();	/* exec commands from a file */
XXextern	int	l_eval();	/* evaluate a LISP s-expr */
XXextern	int	l_if();		/* LISP if */
XXextern	int	l_progn();	/* LISP progn */
XXextern	int	l_return();	/* LISP return */
XXextern	int	l_setq();	/* LISP setq */
XXextern	int	l_go();		/* LISP go */
XXextern	int	l_yank_str();	/* put the KILL buffer into a LISP string */
XXextern	int	l_ask();	/* ask the user for input */
XXextern	int	l_add();	/* arithmetic function */
XXextern	int	l_sub();	/* arithmetic function */
XXextern	int	l_mul();	/* arithmetic function */
XXextern	int	l_div();	/* arithmetic function */
XXextern	int	l_mod();	/* arithmetic function */
XXextern	int	l_bitand();	/* arithmetic function */
XXextern	int	l_bitor();	/* arithmetic function */
XXextern	int	l_eql();	/* arithmetic function */
XXextern	int	l_neq();	/* arithmetic function */
XXextern	int	l_gt();		/* arithmetic function */
XXextern	int	l_ge();		/* arithmetic function */
XXextern	int	l_lt();		/* arithmetic function */
XXextern	int	l_le();		/* arithmetic function */
XXextern	int	l_not();	/* arithmetic function */
XXextern	int	l_and();	/* arithmetic function */
XXextern	int	l_or();		/* arithmetic function */
XXextern	int	l_eq();		/* arithmetic function */
XXextern	int	l_curchr();	/* current character (returned as an integer) */
XXextern	int	l_curlin();	/* current line number in the buffer */
XXextern	int	l_curcol();	/* current column position */
XXextern	int	l_curbuf();	/* current buffer name */
XXextern	int	l_princ();	/* insert text into the buffer */
XX
XX#if	ULTRIX
XXextern	int	shellquote();	/* send the next character to the sub proc */
XXextern	int	bktoshell();	/* suspend emacs to parent shell*/
XXextern	int	rtfrmshell();	/* return from a suspended state*/
XX#endif
XX
XX/*	Name to function binding table
XX
XX		This table gives the names of all the bindable functions
XX	end their C function address. These are used for the bind-to-key
XX	function.
XX*/
XX
XXNBIND	names[] = {
XX	"+",			l_add,
XX	"-",			l_sub,
XX	"*",			l_mul,
XX	"/",			l_div,
XX	"%",			l_mod,
XX	"&",			l_bitand,
XX	"|",			l_bitor,
XX	"=",			l_eql,
XX	"!=",			l_neq,
XX	">",			l_gt,
XX	">=",			l_ge,
XX	"<",			l_lt,
XX	"<=",			l_le,
XX	"add-mode",		adjustmode,
XX	"adjust-mode",		adjustmode,
XX	"and",			l_and,
XX	"ask",			l_ask,
XX	"backward-character",	backchar,
XX	"begin-macro",		ctlxlp,
XX	"beginning-of-file",	gotobob,
XX	"beginning-of-line",	gotobol,
XX	"bind-to-key",		bindtokey,
XX	"buffer-position",	showcpos,
XX	"case-region-lower",	lowerregion,
XX	"case-region-upper",	upperregion,
XX	"case-word-capitalize",	capword,
XX	"case-word-lower",	lowerword,
XX	"case-word-upper",	upperword,
XX	"change-file-name",	filename,
XX	"clear-and-redraw",	refresh,
XX	"copy-region",		copyregion,
XX	"curbuf",		l_curbuf,
XX	"curchr",		l_curchr,
XX	"curcol",		l_curcol,
XX	"curlin",		l_curlin,
XX	"delete-blank-lines",	deblank,
XX	"delete-buffer",	killbuffer,
XX	"delete-mode",		adjustmode,
XX	"delete-next-character",forwdel,
XX	"delete-next-word",	delfword,
XX	"delete-other-windows",	onlywind,
XX	"delete-previous-character",backdel,
XX	"delete-previous-word",	delbword,
XX	"delete-window",	delwind,
XX	"describe-bindings",	desbind,
XX	"describe-key",		deskey,
XX	"end-macro",		ctlxrp,
XX	"end-of-file",		gotoeob,
XX	"end-of-line",		gotoeol,
XX	"eq",			l_eq,
XX	"eval",			l_eval,
XX	"exchange-point-and-mark",swapmark,
XX	"execute-buffer",	execbuf,
XX	"execute-command-line",	execcmd,
XX	"execute-file",		execfile,
XX	"execute-macro",	ctlxe,
XX	"execute-named-command",namedcmd,
XX	"exit-emacs",		quit,
XX	"fill-paragraph",	fillpara,
XX	"find-file",		filefind,
XX	"forward-character",	forwchar,
XX	"go",			l_go,
XX	"goto-line",		gotoline,
XX	"grow-window",		enlargewind,
XX	"handle-tab",		tab,
XX	"help",			help,
XX	"if",			l_if,
XX	"insert-file",		insfile,
XX	"kill-region",		killregion,
XX	"kill-to-end-of-line",	killtext,
XX	"list-buffers",		listbuffers,
XX	"move-window-down",	mvdnwind,
XX	"move-window-up",	mvupwind,
XX	"name-buffer",		namebuffer,
XX	"newline",		newline,
XX	"newline-and-indent",	indent,
XX	"next-line",		forwline,
XX	"next-page",		forwpage,
XX	"next-paragraph",	gotoeop,
XX	"next-window",		nextwind,
XX	"next-word",		forwword,
XX	"not",			l_not,
XX	"open-line",		openline,
XX	"or",			l_or,
XX	"previous-line",	backline,
XX	"previous-page",	backpage,
XX	"previous-paragraph",	gotobop,
XX	"previous-window",	prevwind,
XX	"previous-word",	backword,
XX	"princ",		l_princ,
XX	"progn",		l_progn,
XX	"query-replace-string",	qreplace,
XX	"quick-exit",		quickexit,
XX	"quote-character",	quote,
XX	"read-file",		fileread,
XX	"redraw-display",	reposition,
XX	"replace-string",	sreplace,
XX	"return",		l_return,
XX	"save-file",		filesave,
XX	"scroll-next-up",	scrnextup,
XX	"scroll-next-down",	scrnextdw,
XX	"search-forward",	forwsearch,
XX	"search-reverse",	backsearch,
XX	"select-buffer",	usebuffer,
XX	"set-fill-column",	setfillcol,
XX	"set-mark",		setmark,
XX	"setq",			l_setq,
XX	"shell",		spawncli,
XX#if	ULTRIX
XX	"shell-quote",		shellquote,
XX#endif
XX	"shell-command",	spawn,
XX	"shrink-window",	shrinkwind,
XX	"split-current-window",	splitwind,
XX#if	ULTRIX
XX	"suspend-emacs",	bktoshell,
XX#endif
XX	"transpose-characters",	twiddle,
XX	"unbind-key",		unbindkey,
XX	"visit-file",		visitfile,
XX	"visit-tag",		visittag,
XX	"write-file",		filewrite,
XX	"yank",			yank,
XX	"yank-string",		l_yank_str,
XX
XX	"",			NULL
XX	};
SHAR_EOF
if test 9741 -ne "`wc -c efunc.h`"
then
echo shar: error transmitting efunc.h '(should have been 9741 characters)'
fi
echo shar: extracting epath.h
sed 's/^XX//' << \SHAR_EOF > epath.h
XX/*   PATH:   This file contains certain info needed to locate the
XX      MicroEMACS files on a system dependant basis. */
XX
XX#if   AMIGA
XX#ifdef INBIND
XXchar *pathname[5] = {
XX   ".uemacsrc",
XX   "uemacs.hlp",
XX   "",
XX   ":c/",
XX   "c:"
XX   };
XX#else
XXextern *pathname[5];
XX#endif
XX#endif
XX
XX#if   ULTRIX
XX#ifdef INBIND
XXchar *pathname[7] = {
XX   ".uemacsrc",
XX   "uemacs.hlp",
XX   "",
XX   "~/",
XX   "~/bin/",
XX   "/staff/bin",
XX   "/usr/local/bin"
XX   };
XX#else
XXextern char *pathname[7];
XX#endif
XX#endif
XX
XX#if   VMS
XX#ifdef INBIND
XXchar *pathname[6] = {
XX   "uemacs.rc",
XX   "uemacs.hlp",
XX   "",
XX   "sys$login:",
XX   "sys$sysexe:",
XX   "sys$library:"
XX   };
XX#else
XXextern char *pathname[6];
XX#endif
XX#endif
XX
XX#define   NPNAMES   (sizeof(pathname)/sizeof(char *))
SHAR_EOF
if test 723 -ne "`wc -c epath.h`"
then
echo shar: error transmitting epath.h '(should have been 723 characters)'
fi
echo shar: extracting estruct.h
sed 's/^XX//' << \SHAR_EOF > estruct.h
XX/*   ESTRUCT:   Structure and preprocesser defined for MicroEMACS */
XX
XX/*   Machine/OS definitions */
XX
XX#define AMIGA   0                       /* AmigaDOS */
XX#define ULTRIX  1                       /* ULTRIX (BSD 4.3) */
XX#define VMS     0                       /* VAX/VMS */
XX
XX/*   Terminal Output and compiler definitions */
XX
XX#if AMIGA
XX#define ANSI      1         /* ANSI escape sequence processing */
XX#define VMSVT     0         /* various VMS terminal entries */
XX#define TERMCAP   0         /* Use TERMCAP */
XX#define AZTEC	  1	    /* Aztec C compiler */
XX#define LATTICE	  0	    /* Lattice C compiler */
XX#endif
XX
XX#if ULTRIX
XX#define ANSI      0         /* ANSI escape sequence processing */
XX#define VMSVT     0         /* various VMS terminal entries */
XX#define TERMCAP   1         /* Use TERMCAP */
XX#define AZTEC	  0	    /* Aztec C compiler */
XX#define LATTICE	  0	    /* Lattice C compiler */
XX#endif
XX
XX#if VMS
XX#define ANSI      0         /* ANSI escape sequence processing */
XX#define VMSVT     1         /* various VMS terminal entries */
XX#define TERMCAP   0         /* Use TERMCAP */
XX#define AZTEC	  0	    /* Aztec C compiler */
XX#define LATTICE	  0	    /* Lattice C compiler */
XX#endif
XX
XX/*   Configuration options */
XX
XX#define	  CVMVAS   1   /* arguments to page forward/back in pages */
XX#define   NFWORD   0   /* forward word jumps to begining of word */
XX#define   CLRMSG   0   /* space clears the message line with no insert */
XX#define   TYPEAH   1   /* type ahead causes update to be skipped */
XX#define   FILOCK   0   /* file locking under unix BSD 4.2 */
XX
XX/*   internal constants */
XX
XX#define NBINDS  180         /* max # of bound keys */
XX#define NFILEN   80         /* # of bytes, file name */
XX#define NBUFN    16         /* # of bytes, buffer name */
XX#define NLINE   256         /* # of bytes, line */
XX#define NSTRING 256         /* # of bytes, string buffers */
XX#define NKBDM   256         /* # of strokes, keyboard macro */
XX#define NPAT    256          /* # of bytes, pattern */
XX#define HUGE    1000        /* Huge number */
XX#define NLOCKS  100         /* max # of file locks active */
XX
XX#define AGRAVE  0x60                    /* M- prefix,   Grave (LK201) */
XX#define METACH  0x1B                    /* M- prefix,   Control-[, ESC */
XX#define CTMECH  0x1C                    /* C-M- prefix, Control-\ */
XX#define EXITCH  0x1D                    /* Exit level,  Control-] */
XX#define CTRLCH  0x1E                    /* C- prefix,   Control-^ */
XX#define HELPCH  0x1F                    /* Help key,    Control-_ */
XX#define CSICH   0x9B                    /* CSI sequence on the AMIGA */
XX
XX#define CTRL    0x0100                  /* Control flag, or'ed in */
XX#define META    0x0200                  /* Meta flag, or'ed in */
XX#define CTLX    0x0400                  /* ^X flag, or'ed in */
XX#define SPEC    0x0800                  /* special key (function keys) */
XX#define GOLD    0x1000			/* gold prefix key (PF1) */
XX
XX#define FALSE   0                       /* False, no, bad, etc. */
XX#define TRUE    1                       /* True, yes, good, etc. */
XX#define ABORT   2                       /* Death, ^G, abort, etc. */
XX
XX#define FIOSUC  0                       /* File I/O, success. */
XX#define FIOFNF  1                       /* File I/O, file not found. */
XX#define FIOEOF  2                       /* File I/O, end of file. */
XX#define FIOERR  3                       /* File I/O, error. */
XX#define FIOLNG  4			/*line longer than allowed len */
XX
XX#define CFCPCN  0x0001                  /* Last command was C-P, C-N */
XX#define CFKILL  0x0002                  /* Last command was a kill */
XX
XX#define   BELL	0x07			/* a bell character */
XX#define   TAB   0x09			/* a tab character */
XX
XX/*
XX * There is a window structure allocated for every active display window. The
XX * windows are kept in a big list, in top to bottom screen order, with the
XX * listhead at "wheadp". Each window contains its own values of dot and mark.
XX * The flag field contains some bits that are set by commands to guide
XX * redisplay; although this is a bit of a compromise in terms of decoupling,
XX * the full blown redisplay is just too expensive to run for every input
XX * character.
XX */
XXtypedef struct  WINDOW {
XX        struct WINDOW *w_wndp;	/* Next window */
XX        struct BUFFER *w_bufp;	/* Buffer displayed in window */
XX        struct LINE *w_linep;	/* Top line in the window */
XX        struct LINE *w_dotp;	/* Line containing "." */
XX        short w_doto;	/* Byte offset for "." */
XX        struct LINE *w_markp;	/* Line containing "mark" */
XX        short w_marko;	/* Byte offset for "mark" */
XX        char w_toprow;	/* Origin 0 top row of window */
XX        char w_ntrows;	/* # of rows of text in window */
XX        char w_force;	/* If NZ, forcing row. */
XX        char w_flag;	/* Flags. */
XX	} WINDOW;
XX
XX#define WFFORCE 0x01	/* Window needs forced reframe */
XX#define WFMOVE  0x02	/* Movement from line to line */
XX#define WFEDIT  0x04	/* Editing within a line */
XX#define WFHARD  0x08	/* Better to a full display */
XX#define WFMODE  0x10	/* Update mode line. */
XX
XX/*
XX * Text is kept in buffers. A buffer header, described below, exists for every
XX * buffer in the system. The buffers are kept in a big list, so that commands
XX * that search for a buffer by name can find the buffer header. There is a
XX * safe store for the dot and mark in the header, but this is only valid if
XX * the buffer is not being displayed (that is, if "b_nwnd" is 0). The text for
XX * the buffer is kept in a circularly linked list of lines, with a pointer to
XX * the header line in "b_linep".
XX *    Buffers may be "Inactive" which means the files accosiated with them
XX * have not been read in yet. These get read in at "use buffer" time.
XX */
XXtypedef struct  BUFFER {
XX        struct	BUFFER *b_bufp;	/* Link to next BUFFER */
XX        struct	LINE *b_dotp;	/* Link to "." LINE structure */
XX        short	b_doto;		/* Offset of "." in above LINE */
XX        struct	LINE *b_markp;	/* The same as the above two, */
XX        short	b_marko;	/* but for the "mark" */
XX        struct	LINE *b_linep;	/* Link to the header LINE */
XX	char	b_active;	/* window activated flag */
XX        char	b_nwnd;		/* Count of windows on buffer */
XX        char	b_flag;		/* Flags */
XX	char	b_mode;		/* editor mode of this buffer */
XX        char	b_fname[NFILEN];/* File name */
XX        char	b_bname[NBUFN];	/* Buffer name */
XX	} BUFFER;
XX
XX#define BFTEMP  0x01	/* Internal temporary buffer */
XX#define BFCHG   0x02	/* Changed since last write */
XX
XX/*   mode flags */
XX#define   NUMMODES   7	/* # of defined modes */
XX
XX#define   MDWRAP   0x0001	/* word wrap */
XX#define   MDCMOD   0x0002	/* C indentation and fence match*/
XX#define   MDSLOW   0x0004	/* slow speed searches */
XX#define   MDEXACT  0x0008	/* Exact matching for searches */
XX#define   MDVIEW   0x0010	/* read-only buffer */
XX#define	  MDMMOD   0x0020	/* Modula indentation mode */
XX#define	  MDLISP   0x0040	/* Lisp indentation mode */
XX
XX/*
XX * The starting position of a region, and the size of the region in
XX * characters, is kept in a region structure.  Used by the region commands.
XX */
XXtypedef struct  {
XX        struct	LINE *r_linep;	/* Origin LINE address. */
XX        short	r_offset;	/* Origin LINE offset. */
XX        int	r_size;		/* Length in characters. */
XX	} REGION;
XX
XX/*
XX * All text is kept in circularly linked lists of "LINE" structures. These
XX * begin at the header line (which is the blank line beyond the end of the
XX * buffer). This line is pointed to by the "BUFFER". Each line contains a the
XX * number of bytes in the line (the "used" size), the size of the text array,
XX * and the text. The end of line is not stored as a byte; it's implied. Future
XX * additions will include update hints, and a list of marks into the line.
XX */
XXtypedef struct  LINE {
XX        struct	LINE *l_fp;	/* Link to the next line */
XX        struct	LINE *l_bp;	/* Link to the previous line */
XX        short	l_size;		/* Allocated size */
XX        short	l_used;		/* Used size */
XX        char	l_text[1];	/* A bunch of characters. */
XX	} LINE;
XX
XX#define lforw(lp)       ((lp)->l_fp)
XX#define lback(lp)       ((lp)->l_bp)
XX#define lgetc(lp, n)    ((lp)->l_text[(n)]&0xFF)
XX#define lputc(lp, n, c) ((lp)->l_text[(n)]=(c))
XX#define llength(lp)     ((lp)->l_used)
XX
XX/*
XX * The editor communicates with the display using a high level interface. A
XX * "TERM" structure holds useful variables, and indirect pointers to routines
XX * that do useful operations. The low level get and put routines are here too.
XX * This lets a terminal, in addition to having non standard commands, have
XX * funny get and put character code too. The calls might get changed to
XX * "termp->t_field" style in the future, to make it possible to run more than
XX * one terminal type.
XX */
XXtypedef struct  {
XX        short t_nrow;		/* Number of rows. */
XX        short t_ncol;		/* Number of columns. */
XX	short t_margin;		/* min margin for extended lines*/
XX	short t_scrsiz;		/* size of scroll region " */
XX        int (*t_open)();	/* Open terminal at the start. */
XX        int (*t_close)();	/* Close terminal at end. */
XX        int (*t_getchar)();	/* Get character from keyboard. */
XX        int (*t_putchar)();	/* Put character to display. */
XX        int (*t_flush)();	/* Flush output buffers. */
XX        int (*t_move)();	/* Move the cursor, origin 0. */
XX        int (*t_eeol)();	/* Erase to end of line. */
XX        int (*t_eeop)();	/* Erase to end of page. */
XX        int (*t_beep)();	/* Beep. */
XX	int (*t_insert)();	/* Insert n blank lines (scroll down) */
XX	int (*t_delete)();	/* Delete n lines (scroll up) */
XX	} TERM;
XX
XX/*   structure for the table of initial key bindings */
XX
XXtypedef struct  {
XX        short k_code;	/* Key code */
XX        int (*k_fp)();	/* Routine to handle it */
XX	} KEYTAB;
XX
XX/*   structure for the name binding table */
XX
XXtypedef struct {
XX   char *n_name;	/* name of function key */
XX   int (*n_func)();	/* function name is bound to */
XX    }   NBIND;
SHAR_EOF
if test 9841 -ne "`wc -c estruct.h`"
then
echo shar: error transmitting estruct.h '(should have been 9841 characters)'
fi
#	End of shell archive
exit 0

wecker@cookie.dec.com.UUCP (02/21/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	ansi.c
#	basic.c
#	bind.c
#	buffer.c
#	display.c
#	file.c
# This archive created: Fri Feb 20 17:44:29 1987
echo shar: extracting ansi.c
sed 's/^XX//' << \SHAR_EOF > ansi.c
XX/*
XX * The routines in this file provide support for ANSI style terminals
XX * over a serial line. The serial I/O services are provided by routines in
XX * "termio.c". It compiles into nothing if not an ANSI device.
XX */
XX
XX#define   termdef   1         /* don't define "term" external */
XX
XX#include        <stdio.h>
XX#include	"estruct.h"
XX#include        "edef.h"
XX
XX#if     ANSI
XX
XX#define	    NROW	23	/* Screen size.                 */
XX#define	    NCOL	77	/* Edit if you want to.         */
XX#define	    MARGIN	8	/* size of minimim margin and   */
XX#define	    SCRSIZ	64	/* scroll size for extended lines */
XX#define	    BEL		0x07	/* BEL character.               */
XX#define	    ESC		0x1B	/* ESC character.               */
XX
XXextern  int     ttopen();	/* Forward references.          */
XXextern  int     ttgetc();
XXextern  int     ttputc();
XXextern  int     ttflush();
XXextern  int     ttclose();
XXextern  int     ansimove();
XXextern  int     ansieeol();
XXextern  int     ansieeop();
XXextern  int     ansibeep();
XXextern  int     ansiopen();
XXextern	int	ansiinsert();
XXextern	int	ansidelete();
XX
XX/*
XX * Standard terminal interface dispatch table. Most of the fields point into
XX * "termio" code.
XX */
XXTERM term = {
XX    NROW-1,
XX    NCOL,
XX    MARGIN,
XX    SCRSIZ,
XX    ansiopen,
XX    ttclose,
XX    ttgetc,
XX    ttputc,
XX    ttflush,
XX    ansimove,
XX    ansieeol,
XX    ansieeop,
XX    ansibeep,
XX    ansiinsert,
XX    ansidelete
XX    };
XX
XXansimove(row, col)
XX    {
XX    if (batchmode) return(TRUE);
XX    ttputc(ESC);
XX    ttputc('[');
XX    ansiparm(row+1);
XX    ttputc(';');
XX    ansiparm(col+1);
XX    ttputc('H');
XX    }
XX
XXansieeol()
XX    {
XX    if (batchmode) return(TRUE);
XX    ttputc(ESC);
XX    ttputc('[');
XX    ttputc('K');
XX    }
XX
XXansieeop()
XX    {
XX    if (batchmode) return(TRUE);
XX    ttputc(ESC);
XX    ttputc('[');
XX    ttputc('J');
XX    }
XX
XXansibeep()
XX    {
XX    if (batchmode) return(TRUE);
XX    ttputc(BEL);
XX    ttflush();
XX    }
XX
XXansiparm(n)
XXregister int    n;
XX    {
XX    register int    q;
XX
XX    if (batchmode) return(TRUE);
XX    q = n/10;
XX    if (q != 0) ansiparm(q);
XX    ttputc((n%10) + '0');
XX    }
XX
XXansiinsert(row,n)
XX    {
XX    if (batchmode) return(TRUE);
XX    ansimove(row,0);
XX    ttputc(ESC);
XX    ttputc('[');
XX    ansiparm(n);
XX    ttputc('L');
XX    mlerase();
XX    }
XX
XXansidelete(row,n)
XX    {
XX    if (batchmode) return(TRUE);
XX    mlerase();
XX    ansimove(row,0);	
XX    ttputc(ESC);
XX    ttputc('[');
XX    ansiparm(n);
XX    ttputc('M');
XX    }
XX
XX#endif
XX
XXansiopen()
XX    {
XX#if ULTRIX
XX    register char *cp;
XX    char *getenv();
XX
XX    if (batchmode) return(TRUE);
XX    if ((cp = getenv("TERM")) == NULL) {
XX	puts("Shell variable TERM not defined!");
XX	exit(1);
XX	}
XX    if (strcmp(cp, "vt100") != 0) {
XX	puts("Terminal type not 'vt100'!");
XX	exit(1);
XX	}
XX#endif
XX    if (batchmode) return(TRUE);
XX    ttopen();
XX    }
SHAR_EOF
if test 2731 -ne "`wc -c ansi.c`"
then
echo shar: error transmitting ansi.c '(should have been 2731 characters)'
fi
echo shar: extracting basic.c
sed 's/^XX//' << \SHAR_EOF > basic.c
XX/*
XX * The routines in this file move the cursor around on the screen. They
XX * compute a new value for the cursor, then adjust ".". The display code
XX * always updates the cursor location, so only moves between lines, or
XX * functions that adjust the top line in the window and invalidate the
XX * framing, are hard.
XX */
XX#include <stdio.h>
XX#include	"estruct.h"
XX#include "edef.h"
XX
XX/*
XX * Move the cursor to the
XX * beginning of the current line.
XX * Trivial.
XX */
XXgotobol(f, n)
XX    {
XX    curwp->w_doto = 0;
XX    return (TRUE);
XX    }
XX
XX/*
XX * Move the cursor backwards by "n" characters. If "n" is less than zero call
XX * "forwchar" to actually do the move. Otherwise compute the new cursor
XX * location. Error if you try and move out of the buffer. Set the flag if the
XX * line pointer for dot changes.
XX */
XXbackchar(f, n)
XXregister int    n;
XX    {
XX    register LINE   *lp;
XX
XX    if (n < 0) return (forwchar(f, -n));
XX    while (n--) {
XX	if (curwp->w_doto == 0) {
XX	    if ((lp=lback(curwp->w_dotp)) == curbp->b_linep) return (FALSE);
XX	    curwp->w_dotp = lp;
XX	    curwp->w_doto = llength(lp);
XX	    curwp->w_flag |= WFMOVE;
XX	    }
XX	else
XX	curwp->w_doto--;
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * Move the cursor to the end of the current line. Trivial. No errors.
XX */
XXgotoeol(f, n)
XX    {
XX    curwp->w_doto = llength(curwp->w_dotp);
XX    return (TRUE);
XX    }
XX
XX/*
XX * Move the cursor forwwards by "n" characters. If "n" is less than zero call
XX * "backchar" to actually do the move. Otherwise compute the new cursor
XX * location, and move ".". Error if you try and move off the end of the
XX * buffer. Set the flag if the line pointer for dot changes.
XX */
XXforwchar(f, n)
XXregister int    n;
XX    {
XX    if (n < 0) return (backchar(f, -n));
XX    while (n--) {
XX	if (curwp->w_doto == llength(curwp->w_dotp)) {
XX	    if (curwp->w_dotp == curbp->b_linep) return (FALSE);
XX	    curwp->w_dotp = lforw(curwp->w_dotp);
XX	    curwp->w_doto = 0;
XX	    curwp->w_flag |= WFMOVE;
XX	    }
XX	else
XX	curwp->w_doto++;
XX	}
XX    return (TRUE);
XX    }
XX
XXgotoline(f, n)	    /* move to a particular line.
XX			argument (n) must be a positive integer for
XX			this to actually do anything */
XX
XX    {
XX    if (n < 1)	    /* if a bogus argument...then leave */
XX		 return(FALSE);
XX
XX    /* first, we go to the start of the buffer */
XX    curwp->w_dotp = lforw(curbp->b_linep);
XX    curwp->w_doto = 0;
XX    return(forwline(f, n-1));
XX    }
XX
XX/*
XX * Goto the beginning of the buffer. Massive adjustment of dot. This is
XX * considered to be hard motion; it really isn't if the original value of dot
XX * is the same as the new value of dot. Normally bound to "M-<".
XX * arg 0 = do not set mark
XX */
XXgotobob(f, n) {
XX    curwp->w_dotp = lforw(curbp->b_linep);
XX    curwp->w_doto = 0;
XX    curwp->w_flag |= WFHARD;
XX    return (TRUE);
XX    }
XX
XX/*
XX * Move to the end of the buffer. Dot is always put at the end of the file
XX * (ZJ). The standard screen code does most of the hard parts of update.
XX * Bound to "M->". arg 0 = don't set mark.
XX */
XXgotoeob(f, n) {
XX    curwp->w_dotp = lback(curbp->b_linep);
XX    curwp->w_doto = curwp->w_dotp->l_used;
XX    curwp->w_flag |= WFHARD;
XX    return (TRUE);
XX    }
XX
XX/*
XX * Move forward by full lines. If the number of lines to move is less than
XX * zero, call the backward line function to actually do it. The last command
XX * controls how the goal column is set. Bound to "C-N". No errors are
XX * possible.
XX */
XXforwline(f, n)
XX    {
XX    register LINE   *dlp;
XX
XX    if (n < 0) return (backline(f, -n));
XX    if ((lastflag&CFCPCN) == 0)             /* Reset goal if last */
XX		 curgoal = curcol;               /* not C-P or C-N */
XX    thisflag |= CFCPCN;
XX    dlp = curwp->w_dotp;
XX    while (n-- && dlp!=curbp->b_linep) dlp = lforw(dlp);
XX    curwp->w_dotp = dlp;
XX    curwp->w_doto = getgoal(dlp);
XX    curwp->w_flag |= WFMOVE;
XX    return (TRUE);
XX    }
XX
XX/*
XX * This function is like "forwline", but goes backwards. The scheme is exactly
XX * the same. Check for arguments that are less than zero and call your
XX * alternate. Figure out the new line and call "movedot" to perform the
XX * motion. No errors are possible. Bound to "C-P".
XX */
XXbackline(f, n)
XX    {
XX    register LINE   *dlp;
XX
XX    if (n < 0) return (forwline(f, -n));
XX    if ((lastflag&CFCPCN) == 0)             /* Reset goal if the */
XX		 curgoal = curcol;               /* last isn't C-P, C-N */
XX    thisflag |= CFCPCN;
XX    dlp = curwp->w_dotp;
XX    while (n-- && lback(dlp)!=curbp->b_linep) dlp = lback(dlp);
XX    curwp->w_dotp = dlp;
XX    curwp->w_doto = getgoal(dlp);
XX    curwp->w_flag |= WFMOVE;
XX    return (TRUE);
XX    }
XX
XXgotobop(f, n)	/* go back to the begining of the current paragraph
XXhere we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
XXcombination to delimit the begining of a paragraph */
XX
XXint f, n;   /* default Flag & Numeric argument */
XX
XX    {
XX    register int suc;	/* success of last backchar */
XX
XX    if (n < 0)	/* the other way...*/
XX		 return(gotoeop(f, -n));
XX
XX    while (n-- > 0) {	/* for each one asked for */ 
XX	/* first scan back until we are in a word */
XX	suc = backchar(FALSE, 1);
XX	while (!inword() && suc) suc = backchar(FALSE, 1);
XX	curwp->w_doto = 0;  /* and go to the B-O-Line */
XX
XX	/* and scan back until we hit a <NL><NL> or <NL><TAB>
XX	or a <NL><SPACE> */
XX	while (lback(curwp->w_dotp) != curbp->b_linep) if (llength(curwp->w_dotp) != 0 && lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
XX	lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
XX	curwp->w_dotp = lback(curwp->w_dotp);
XX	else
XX	break;
XX
XX	/* and then forward until we are in a word */
XX	suc = forwchar(FALSE, 1);
XX	while (suc && !inword()) suc = forwchar(FALSE, 1);
XX	}
XX    curwp->w_flag |= WFMOVE;	/* force screen update */
XX    }
XX
XXgotoeop(f, n)	/* go forword to the end of the current paragraph
XXhere we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
XXcombination to delimit the begining of a paragraph */
XX
XXint f, n;   /* default Flag & Numeric argument */
XX
XX    {
XX    register int suc;	/* success of last backchar */
XX
XX    if (n < 0)	/* the other way...*/
XX		 return(gotobop(f, -n));
XX
XX    while (n-- > 0) {	/* for each one asked for */ 
XX	/* first scan forward until we are in a word */
XX	suc = forwchar(FALSE, 1);
XX	while (!inword() && suc) suc = forwchar(FALSE, 1);
XX	curwp->w_doto = 0;  /* and go to the B-O-Line */
XX	if (suc)    /* of next line if not at EOF */
XX		 curwp->w_dotp = lforw(curwp->w_dotp);
XX
XX	/* and scan forword until we hit a <NL><NL> or <NL><TAB>
XX	or a <NL><SPACE> */
XX	while (curwp->w_dotp != curbp->b_linep) {
XX	    if (llength(curwp->w_dotp) != 0 && lgetc(curwp->w_dotp, curwp->w_doto) != TAB &&
XX	    lgetc(curwp->w_dotp, curwp->w_doto) != ' ')
XX	    curwp->w_dotp = lforw(curwp->w_dotp);
XX	    else
XX	    break;
XX	    }
XX
XX	/* and then backward until we are in a word */
XX	suc = backchar(FALSE, 1);
XX	while (suc && !inword()) {
XX	    suc = backchar(FALSE, 1);
XX	    }
XX	curwp->w_doto = llength(curwp->w_dotp);	/* and to the EOL */
XX	}
XX    curwp->w_flag |= WFMOVE;	/* force screen update */
XX    }
XX
XX/*
XX * This routine, given a pointer to a LINE, and the current cursor goal
XX * column, return the best choice for the offset. The offset is returned.
XX * Used by "C-N" and "C-P".
XX */
XXgetgoal(dlp)
XXregister LINE   *dlp;
XX    {
XX    register int    c;
XX    register int    col;
XX    register int    newcol;
XX    register int    dbo;
XX
XX    col = 0;
XX    dbo = 0;
XX    while (dbo != llength(dlp)) {
XX	c = lgetc(dlp, dbo);
XX	newcol = col;
XX	if (c == '\t') newcol |= 0x07;
XX	else if (c<0x20 || c==0x7F)
XX	++newcol;
XX	++newcol;
XX	if (newcol > curgoal) break;
XX	col = newcol;
XX	++dbo;
XX	}
XX    return (dbo);
XX    }
XX
XX/*
XX * Scroll forward by a specified number of lines, or by a full page if no
XX * argument. Bound to "C-V". The "2" in the arithmetic on the window size is
XX * the overlap; this value is the default overlap value in ITS EMACS. Because
XX * this zaps the top line in the display window, we have to do a hard update.
XX */
XXforwpage(f, n)
XXregister int    n;
XX    {
XX    register LINE   *lp;
XX
XX    if (f == FALSE) {
XX	n = curwp->w_ntrows - 2;        /* Default scroll. */
XX	if (n <= 0)                     /* Forget the overlap */
XX		 n = 1;                  /* if tiny window. */
XX 	}
XX    else if (n < 0)
XX    return (backpage(f, -n));
XX#if CVMVAS
XX    else /* Convert from pages */
XX    n *= curwp->w_ntrows;           /* to lines. */
XX#endif
XX    lp = curwp->w_linep;
XX    while (n-- && lp!=curbp->b_linep) lp = lforw(lp);
XX    curwp->w_linep = lp;
XX    curwp->w_dotp = lp;
XX    curwp->w_doto = 0;
XX    curwp->w_flag |= WFHARD;
XX    return (TRUE);
XX    }
XX
XX/*
XX * This command is like "forwpage", but it goes backwards. The "2", like
XX * above, is the overlap between the two windows. The value is from the ITS
XX * EMACS manual. Bound to "M-V". We do a hard update for exactly the same
XX * reason.
XX */
XXbackpage(f, n)
XXregister int    n;
XX    {
XX    register LINE   *lp;
XX
XX    if (f == FALSE) {
XX	n = curwp->w_ntrows - 2;        /* Default scroll. */
XX	if (n <= 0)                     /* Don't blow up if the */
XX		 n = 1;                  /* window is tiny. */
XX	}
XX    else if (n < 0)
XX    return (forwpage(f, -n));
XX#if CVMVAS
XX    else /* Convert from pages */
XX    n *= curwp->w_ntrows;           /* to lines. */
XX#endif
XX    lp = curwp->w_linep;
XX    while (n-- && lback(lp)!=curbp->b_linep) lp = lback(lp);
XX    curwp->w_linep = lp;
XX    curwp->w_dotp = lp;
XX    curwp->w_doto = 0;
XX    curwp->w_flag |= WFHARD;
XX    return (TRUE);
XX    }
XX
XX/*
XX * Set the mark in the current window to the value of "." in the window. No
XX * errors are possible. Bound to "M-.". arg 0 = do not report mark setting
XX */
XXsetmark(f, n)
XX    {
XX    curwp->w_markp = curwp->w_dotp;
XX    curwp->w_marko = curwp->w_doto;
XX    if (f == FALSE || n != 0) mlwrite("[Mark set]");
XX    return (TRUE);
XX    }
XX
XX/*
XX * Swap the values of "." and "mark" in the current window. This is pretty
XX * easy, bacause all of the hard work gets done by the standard routine
XX * that moves the mark about. The only possible error is "no mark". Bound to
XX * "C-X C-X".
XX */
XXswapmark(f, n)
XX    {
XX    register LINE   *odotp;
XX    register int    odoto;
XX
XX    if (curwp->w_markp == NULL) {
XX	mlwrite("No mark in this window");
XX	return (FALSE);
XX	}
XX    odotp = curwp->w_dotp;
XX    odoto = curwp->w_doto;
XX    curwp->w_dotp = curwp->w_markp;
XX    curwp->w_doto = curwp->w_marko;
XX    curwp->w_markp = odotp;
XX    curwp->w_marko = odoto;
XX    curwp->w_flag |= WFMOVE;
XX    return (TRUE);
XX    }
XX
XX
SHAR_EOF
if test 10190 -ne "`wc -c basic.c`"
then
echo shar: error transmitting basic.c '(should have been 10190 characters)'
fi
echo shar: extracting bind.c
sed 's/^XX//' << \SHAR_EOF > bind.c
XX/* This file is for functions having to do with key bindings,
XX * descriptions, help commands, and command line execution.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#define INBIND TRUE
XX#include "epath.h"
XX
XXextern short doflashing;
XX
XXdeskey(f, n)	/* describe the command for a certain key */
XX    {
XX    register int c;	/* command character to describe */
XX    register char *ptr;	/* string pointer to scan output strings */
XX    register KEYTAB *ktp;   /* pointer into the command table */
XX    register int found;	/* matched command flag */
XX    register NBIND *nptr;   /* pointer into the name binding table */
XX    char outseq[80];	/* output buffer for command sequence */
XX
XX    /* prompt the user to type us a key to describe */
XX    mlwrite(": describe-key ");
XX
XX    /* get the command sequence to describe */
XX    c = getckey();	    /* get a command sequence */
XX
XX    /* change it to something we can print as well */
XX    cmdstr(c, &outseq[0]);
XX
XX    /* and dump it out */
XX    ptr = &outseq[0];
XX    while (*ptr) (*term.t_putchar)(*ptr++);
XX    (*term.t_putchar)(' ');	/* space it out */
XX
XX    /* find the right ->function */
XX    ktp = &keytab[0];
XX    found = FALSE;
XX    while (ktp->k_fp != NULL) {
XX	if (ktp->k_code == c) {
XX	    found = TRUE;
XX	    break;
XX	    }
XX	++ktp;
XX	}
XX
XX    if (!found) strcpy(outseq,"Not Bound");
XX    else {
XX	/* match it against the name binding table */
XX	nptr = &names[0];
XX	strcpy(outseq,"[Bad binding]");
XX	while (nptr->n_func != NULL) {
XX	    if (nptr->n_func == ktp->k_fp) {
XX		strcpy(outseq, nptr->n_name);
XX		break;
XX		}
XX	    ++nptr;
XX	    }
XX	}
XX
XX    /* output the command sequence */
XX    ptr = &outseq[0];
XX    while (*ptr) (*term.t_putchar)(*ptr++);
XX    }
XX
XXcmdstr(c, seq)	/* change a key command to a string we can print out */
XX
XXint c;	    /* sequence to translate */
XXchar *seq;  /* destination string for sequence */
XX
XX    {
XX    char *ptr;	/* pointer into current position in sequence */
XX
XX    ptr = seq;
XX
XX    /* apply GOLD sequence if needed */
XX    if (c & GOLD) {
XX	*ptr++ = 'G';
XX	*ptr++ = '-';
XX	}
XX
XX    /* apply SPEC sequence if needed */
XX    if (c & SPEC) {
XX	*ptr++ = 'K';
XX	*ptr++ = '-';
XX	}
XX
XX    /* apply meta sequence if needed */
XX    if (c & META) {
XX	*ptr++ = 'M';
XX	*ptr++ = '-';
XX	}
XX
XX    /* apply ^X sequence if needed */
XX    if (c & CTLX) {
XX	*ptr++ = '^';
XX	*ptr++ = 'X';
XX	}
XX
XX    /* apply control sequence if needed */
XX    if (c & CTRL) {
XX	*ptr++ = '^';
XX	}
XX
XX    c = c & 255;    /* strip the prefixes */
XX
XX    /* and output the final sequence */
XX
XX    *ptr++ = c;
XX    *ptr = 0;	/* terminate the string */
XX    }
XX
XXhelp(f, n)  /* give me some help!!!!
XX		bring up a fake buffer and read the help file
XX		into it with view mode */
XX    {
XX    register int status;    /* status of I/O operations */
XX    register WINDOW *wp;    /* scnaning pointer to windows */
XX    register int i;	/* index into help file names */
XX    char fname[NSTRING];    /* buffer to construct file name in */
XX
XX    /* search through the list of help files */
XX    for (i=2; i < NPNAMES; i++) {
XX	strcpy(fname, pathname[i]);
XX	strcat(fname, pathname[1]);
XX	status = ffropen(fname);
XX	if (status == FIOSUC) break;
XX	}
XX
XX    if (status == FIOFNF) {
XX	mlwrite("[Help file is not online]");
XX	return(FALSE);
XX	}
XX    ffclose();	/* close the file to prepare for to read it in */
XX
XX    /* split the current window to make room for the help stuff */
XX    if (splitwind(FALSE, 1) == FALSE) return(FALSE);
XX
XX    /* and read the stuff in */
XX    if (getfile(fname, FALSE) == FALSE) return(FALSE);
XX
XX    /* make this window in VIEW mode, update all mode lines */
XX    curwp->w_bufp->b_mode |= MDVIEW;
XX    wp = wheadp;
XX    while (wp != NULL) {
XX	wp->w_flag |= WFMODE;
XX	wp = wp->w_wndp;
XX	}
XX    return(TRUE);
XX    }
XX
XXint (*fncmatch(fname))() /* match fname to a function in the names table
XXand return any match or NULL if none */
XX
XXchar *fname;	/* name to attempt to match */
XX
XX    {
XX    register NBIND *ffp;    /* pointer to entry in name binding table */
XX
XX    /* scan through the table, returning any match */
XX    ffp = &names[0];
XX    while (ffp->n_func != NULL) {
XX	if (strcmp(fname, ffp->n_name) == 0) return(ffp->n_func);
XX	++ffp;
XX	}
XX    return(NULL);
XX    }
XX
XX/* bindtokey:	add a new key to the key binding table
XX */
XX
XXbindtokey(f, n)
XX
XXint f, n;   /* command arguments [IGNORED] */
XX
XX    {
XX    register int c;	/* command key to bind */
XX    register (*kfunc)();    /* ptr to the requexted function to bind to */
XX    register char *ptr;	/* ptr to dump out input key string */
XX    register KEYTAB *ktp;   /* pointer into the command table */
XX    register int found;	/* matched command flag */
XX    char outseq[80];	/* output buffer for keystroke sequence */
XX    int (*getcname())();
XX
XX    /* prompt the user to type in a key to bind */
XX    mlwrite(": bind-to-key ");
XX
XX    /* get the function name to bind it to */
XX    kfunc = getcname();
XX    if (kfunc == NULL) {
XX	mlwrite("[No such function]");
XX	return(FALSE);
XX	}
XX    (*term.t_putchar)(' ');	/* space it out */
XX
XX    /* get the command sequence to bind */
XX    c = getckey();	    /* get a command sequence */
XX
XX    /* change it to something we can print as well */
XX    cmdstr(c, &outseq[0]);
XX
XX    /* and dump it out */
XX    ptr = &outseq[0];
XX    while (*ptr) (*term.t_putchar)(*ptr++);
XX
XX    /* search the table to see if it exists */
XX    ktp = &keytab[0];
XX    found = FALSE;
XX    while (ktp->k_fp != NULL) {
XX	if (ktp->k_code == c) {
XX	    found = TRUE;
XX	    break;
XX	    }
XX	++ktp;
XX	}
XX
XX    if (found) {    /* it exists, just change it then */
XX		 ktp->k_fp = kfunc;
XX	}
XX    else {  /* otherwise we need to add it to the end */
XX	/* if we run out of binding room, bitch */
XX	if (ktp >= &keytab[NBINDS]) {
XX	    mlwrite("Binding table FULL!");
XX	    return(FALSE);
XX	    }
XX
XX	ktp->k_code = c;    /* add keycode */
XX	ktp->k_fp = kfunc;  /* and the function pointer */
XX	++ktp;	/* and make sure the next is null */
XX	ktp->k_code = 0;
XX	ktp->k_fp = NULL;
XX	}
XX
XX    return(TRUE);
XX    }
XX
XX
XX/* unbindkey:	delete a key from the key binding table
XX */
XX
XXunbindkey(f, n)
XX
XXint f, n;   /* command arguments [IGNORED] */
XX
XX    {
XX    register int c;	/* command key to unbind */
XX    register char *ptr;	/* ptr to dump out input key string */
XX    register KEYTAB *ktp;   /* pointer into the command table */
XX    register KEYTAB *sktp;  /* saved pointer into the command table */
XX    register int found;	/* matched command flag */
XX    char outseq[80];	/* output buffer for keystroke sequence */
XX 
XX    /* prompt the user to type in a key to unbind */
XX    mlwrite(": unbind-key ");
XX
XX    /* get the command sequence to unbind */
XX    c = getckey();	    /* get a command sequence */
XX
XX    /* change it to something we can print as well */
XX    cmdstr(c, &outseq[0]);
XX
XX    /* and dump it out */
XX    ptr = &outseq[0];
XX    while (*ptr) (*term.t_putchar)(*ptr++);
XX
XX    /* search the table to see if the key exists */
XX    ktp = &keytab[0];
XX    found = FALSE;
XX    while (ktp->k_fp != NULL) {
XX	if (ktp->k_code == c) {
XX	    found = TRUE;
XX	    break;
XX	    }
XX	++ktp;
XX	}
XX
XX    /* if it isn't bound, bitch */
XX    if (!found) {
XX	mlwrite("[Key not bound]");
XX	return(FALSE);
XX	}
XX
XX    /* save the pointer and scan to the end of the table */
XX    sktp = ktp;
XX    while (ktp->k_fp != NULL) ++ktp;
XX    --ktp;	/* backup to the last legit entry */
XX
XX    /* copy the last entry to the current one */
XX    sktp->k_code = ktp->k_code;
XX    sktp->k_fp = ktp->k_fp;
XX
XX    /* null out the last one */
XX    ktp->k_code = 0;
XX    ktp->k_fp = NULL;
XX    return(TRUE);
XX    }
XX
XX/* namedcmd:	execute a named command even if it is not bound
XX */
XX
XXnamedcmd(f, n)
XX
XXint f, n;   /* command arguments [passed through to command executed] */
XX
XX    {
XX    register int c;	/* command key to bind */
XX    register (*kfunc)();    /* ptr to the requexted function to bind to */
XX    register int found;	/* matched command flag */
XX    int (*getcname())();
XX
XX    /* prompt the user to type a named command */
XX    mlwrite(": ");
XX
XX    /* and now get the function name to execute */
XX    kfunc = getcname();
XX    if (kfunc == NULL) {
XX	mlwrite("[No such function]");
XX	return(FALSE);
XX	}
XX
XX    /* and then execute the command */
XX    return((*kfunc)(f, n));
XX    }
XX
XXdesbind(f, n)	/* describe bindings
XXbring up a fake buffer and list the key bindings
XXinto it with view mode */
XX    {
XX    register WINDOW *wp;    /* scnaning pointer to windows */
XX    register KEYTAB *ktp;   /* pointer into the command table */
XX    register NBIND *nptr;   /* pointer into the name binding table */
XX    register BUFFER *bp;    /* buffer to put binding list into */
XX    register char *strp;    /* pointer int string to send */
XX    register int cpos;	/* current position to use in outseq */
XX    char outseq[80];	/* output buffer for keystroke sequence */
XX
XX    /* split the current window to make room for the binding list */
XX    if (splitwind(FALSE, 1) == FALSE) return(FALSE);
XX
XX    /* and get a buffer for it */
XX    bp = bfind("Binding list", TRUE, 0);
XX    if (bp == NULL || bclear(bp) == FALSE) {
XX	mlwrite("Can not display binding list");
XX	return(FALSE);
XX	}
XX
XX    /* let us know this is in progress */
XX    mlwrite("[Building buffer list]");
XX
XX    /* disconect the current buffer */
XX    if (--curbp->b_nwnd == 0) {             /* Last use. */
XX		 curbp->b_dotp  = curwp->w_dotp;
XX	curbp->b_doto = curwp->w_doto;
XX	curbp->b_markp = curwp->w_markp;
XX	curbp->b_marko = curwp->w_marko;
XX	}
XX
XX    /* connect the current window to this buffer */
XX    curbp = bp;	/* make this buffer current in current window */
XX    bp->b_mode = 0;	/* no modes active in binding list */
XX    bp->b_nwnd++;	/* mark us as more in use */
XX    wp = curwp;
XX    wp->w_bufp = bp;
XX    wp->w_linep = bp->b_linep;
XX    wp->w_flag = WFHARD|WFFORCE|WFHARD;
XX    wp->w_dotp = bp->b_dotp;
XX    wp->w_doto = bp->b_doto;
XX    wp->w_markp = NULL;
XX    wp->w_marko = 0;
XX
XX    /* build the contents of this window, inserting it line by line */
XX    nptr = &names[0];
XX    while (nptr->n_func != NULL) {
XX
XX	/* add in the command name */
XX	strcpy(outseq, nptr->n_name);
XX	cpos = strlen(outseq);
XX
XX	/* search down any keys bound to this */
XX	ktp = &keytab[0];
XX	while (ktp->k_fp != NULL) {
XX	    if (ktp->k_fp == nptr->n_func) {
XX		/* padd out some spaces */
XX		while (cpos < 25) outseq[cpos++] = ' ';
XX
XX		/* add in the command sequence */
XX		cmdstr(ktp->k_code, &outseq[cpos]);
XX		while (outseq[cpos] != 0) ++cpos;
XX
XX		/* and add it as a line into the buffer */
XX		strp = &outseq[0];
XX		while (*strp != 0) linsert(1, *strp++);
XX		lnewline();
XX
XX		cpos = 0;   /* and clear the line */
XX		}
XX	    ++ktp;
XX	    }
XX
XX	/* if no key was bound, we need to dump it anyway */
XX	if (cpos > 0) {
XX	    outseq[cpos] = 0;
XX	    strp = &outseq[0];
XX	    while (*strp != 0) linsert(1, *strp++);
XX	    lnewline();
XX	    }
XX
XX	/* and on to the next name */
XX	++nptr;
XX	}
XX
XX    curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */
XX    curbp->b_flag &= ~BFCHG;	/* don't flag this as a change */
XX    wp->w_dotp = lforw(bp->b_linep);/* back to the begining */
XX    wp->w_doto = 0;
XX    wp = wheadp;	    /* and update ALL mode lines */
XX    while (wp != NULL) {
XX	wp->w_flag |= WFMODE;
XX	wp = wp->w_wndp;
XX	}
XX    mlwrite(""); /* clear the mode line */
XX    return(TRUE);
XX    }
XX
XXgetckey() /* get a command key sequence from the keyboard */
XX
XX    {
XX    register int c;	/* character fetched */
XX    register char *tp;	/* pointer into the token */
XX    char tok[NSTRING];	/* command incoming */
XX
XX    /* check to see if we are executing a command line */
XX    if (clexec) {
XX	nxtarg(tok);	/* get the next token */
XX
XX	/* parse it up */
XX	tp = &tok[0];
XX	c = 0;
XX
XX	/* first the GOLD prefix */
XX	if (*tp == 'G' && *(tp+1) == '-') {
XX	    c |= GOLD;
XX	    tp += 2;
XX	    }
XX
XX	/* next the function prefix */
XX	if (*tp == 'K' && *(tp+1) == '-') {
XX	    c |= SPEC;
XX	    tp += 2;
XX	    }
XX
XX	/* next the META prefix */
XX	if (*tp == 'M' && *(tp+1) == '-') {
XX	    c = META;
XX	    tp += 2;
XX	    }
XX
XX	/* control-x as well... */
XX	if (*tp == '^' && *(tp+1) == 'X') {
XX	    c |= CTLX;
XX	    tp += 2;
XX	    }
XX
XX	/* a control char? */
XX	if (*tp == '^' & *(tp+1) != 0) {
XX	    c |= CTRL;
XX	    ++tp;
XX	    }
XX
XX 	/* make sure we are not lower case */
XX	if (c >= 'a' && c <= 'z') c -= 32;
XX
XX	/* the final sequence... */
XX	c |= *tp;
XX
XX	return(c);
XX	}
XX
XX    /* or the normal way */
XX    c = getkey();	    /* get a command sequence */
XX    if (c == (CTRL|'X'))	/* get control-x sequence */
XX 		 c = CTLX | getctl();
XX    return(c);
XX    }
XX
XX
SHAR_EOF
if test 12210 -ne "`wc -c bind.c`"
then
echo shar: error transmitting bind.c '(should have been 12210 characters)'
fi
echo shar: extracting buffer.c
sed 's/^XX//' << \SHAR_EOF > buffer.c
XX/*
XX * Buffer management.
XX * Some of the functions are internal,
XX * and some are actually attached to user
XX * keys. Like everyone else, they set hints
XX
XX * for the display system.
XX */
XX#include <stdio.h>
XX#include	"estruct.h"
XX#include "edef.h"
XX
XX/*
XX * Attach a buffer to a window. The
XX * values of dot and mark come from the buffer
XX * if the use count is 0. Otherwise, they come
XX * from some other window.
XX */
XXusebuffer(f, n)
XX    {
XX    register BUFFER *bp;
XX    register int    s;
XX    char bufn[NBUFN];
XX
XX    if ((s=mlreply("Use buffer: ", bufn, NBUFN)) != TRUE) return (s);
XX    if ((bp=bfind(bufn, TRUE, 0)) == NULL) return (FALSE);
XX    return(swbuffer(bp));
XX    }
XX
XXswbuffer(bp)	/* make buffer BP current */
XX
XXBUFFER *bp;
XX
XX    {
XX    register WINDOW *wp;
XX
XX    if (--curbp->b_nwnd == 0) {             /* Last use. */
XX	curbp->b_dotp  = curwp->w_dotp;
XX	curbp->b_doto = curwp->w_doto;
XX	curbp->b_markp = curwp->w_markp;
XX	curbp->b_marko = curwp->w_marko;
XX	}
XX    curbp = bp;                             /* Switch. */
XX    if (curbp->b_active != TRUE) {	/* buffer not active yet*/
XX	/* read it in and activate it */
XX	readin(curbp->b_fname, TRUE);
XX	curbp->b_dotp = lforw(curbp->b_linep);
XX	curbp->b_doto = 0;
XX	curbp->b_active = TRUE;
XX	}
XX    curwp->w_bufp = bp;
XX    curwp->w_linep = bp->b_linep;           /* For macros, ignored. */
XX    curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */
XX    if (bp->b_nwnd++ == 0) {                /* First use. */
XX	curwp->w_dotp  = bp->b_dotp;
XX	curwp->w_doto = bp->b_doto;
XX	curwp->w_markp = bp->b_markp;
XX	curwp->w_marko = bp->b_marko;
XX	return (TRUE);
XX	}
XX    wp = wheadp;                            /* Look for old. */
XX    while (wp != NULL) {
XX	if (wp!=curwp && wp->w_bufp==bp) {
XX	    curwp->w_dotp = wp->w_dotp;
XX	    curwp->w_doto = wp->w_doto;
XX	    curwp->w_markp = wp->w_markp;
XX	    curwp->w_marko = wp->w_marko;
XX	    break;
XX	    }
XX	wp = wp->w_wndp;
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * Dispose of a buffer, by name.
XX * Ask for the name. Look it up (don't get too
XX * upset if it isn't there at all!). Get quite upset
XX * if the buffer is being displayed. Clear the buffer (ask
XX * if the buffer has been changed). Then free the header
XX * line and the buffer header. Bound to "C-X K".
XX */
XXkillbuffer(f, n)
XX
XX    {
XX    register BUFFER *bp;
XX    register int    s;
XX    char bufn[NBUFN];
XX
XX    if ((s=mlreply("Kill buffer: ", bufn, NBUFN)) != TRUE) return(s);
XX    if ((bp=bfind(bufn, FALSE, 0)) == NULL) /* Easy if unknown. */
XX		 return (TRUE);
XX    return(zotbuf(bp));
XX    }
XX
XXzotbuf(bp) /* kill the buffer pointed to by bp */
XX
XXregister BUFFER *bp;
XX
XX    {
XX    register BUFFER *bp1;
XX    register BUFFER *bp2;
XX    register int    s;
XX
XX    if (bp->b_nwnd != 0) {                  /* Error if on screen. */
XX	mlwrite("Buffer is being displayed");
XX	return (FALSE);
XX	}
XX
XX#if ULTRIX
XX    if (bp == procbuf) {
XX	kill(pid,9);			    /* kill the sub process */
XX	inchannel = outchannel = pid = 0;
XX	procbuf = NULL;
XX	}
XX#endif
XX
XX    if ((s=bclear(bp)) != TRUE)             /* Blow text away. */
XX	return (s);
XX    free((char *) bp->b_linep);             /* Release header line. */
XX    bp1 = NULL;                             /* Find the header. */
XX    bp2 = bheadp;
XX    while (bp2 != bp) {
XX	bp1 = bp2;
XX	bp2 = bp2->b_bufp;
XX	}
XX    bp2 = bp2->b_bufp;                      /* Next one in chain. */
XX    if (bp1 == NULL)                        /* Unlink it. */
XX	bheadp = bp2;
XX    else
XX    bp1->b_bufp = bp2;
XX    free((char *) bp);                      /* Release buffer block */
XX    return (TRUE);
XX    }
XX
XXnamebuffer(f,n)	    /*	Rename the current buffer */
XX
XXint f, n;	/* default Flag & Numeric arg */
XX
XX    {
XX    register BUFFER *bp;    /* pointer to scan through all buffers */
XX    char bufn[NBUFN];	/* buffer to hold buffer name */
XX
XX    /* prompt for and get the new buffer name */
XX    ask: if (mlreply("Change buffer name to: ", bufn, NBUFN) != TRUE)
XX    return(FALSE);
XX
XX    /* and check for duplicates */
XX    bp = bheadp;
XX    while (bp != NULL) {
XX	if (bp != curbp) {
XX	    /* if the names the same */
XX	    if (strcmp(bufn, bp->b_bname) == 0) goto ask;  /* try again */
XX	    }
XX	bp = bp->b_bufp;    /* onward */
XX	}
XX
XX    strcpy(curbp->b_bname, bufn);   /* copy buffer name to structure */
XX    curwp->w_flag |= WFMODE;	/* make mode line replot */
XX    mlerase();
XX    }
XX
XX/*
XX * List all of the active
XX * buffers. First update the special
XX * buffer that holds the list. Next make
XX * sure at least 1 window is displaying the
XX * buffer list, splitting the screen if this
XX * is what it takes. Lastly, repaint all of
XX * the windows that are displaying the
XX * list. Bound to "C-X C-B".
XX
XX */
XXlistbuffers(f, n)
XX    {
XX    register WINDOW *wp;
XX    register BUFFER *bp;
XX    register int    s;
XX
XX    if ((s=makelist()) != TRUE) return (s);
XX    if (blistp->b_nwnd == 0) {              /* Not on screen yet. */
XX		 if ((wp=wpopup()) == NULL)
XX	return (FALSE);
XX	bp = wp->w_bufp;
XX	if (--bp->b_nwnd == 0) {
XX	    bp->b_dotp = wp->w_dotp;
XX	    bp->b_doto = wp->w_doto;
XX	    bp->b_markp = wp->w_markp;
XX	    bp->b_marko = wp->w_marko;
XX	    }
XX	wp->w_bufp = blistp;
XX	++blistp->b_nwnd;
XX	}
XX    wp = wheadp;
XX    while (wp != NULL) {
XX	if (wp->w_bufp == blistp) {
XX	    wp->w_linep = lforw(blistp->b_linep);
XX	    wp->w_dotp = lforw(blistp->b_linep);
XX	    wp->w_doto = 0;
XX	    wp->w_markp = NULL;
XX	    wp->w_marko = 0;
XX	    wp->w_flag |= WFMODE|WFHARD;
XX	    }
XX	wp = wp->w_wndp;
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * This routine rebuilds the
XX * text in the special secret buffer
XX * that holds the buffer list. It is called
XX * by the list buffers command. Return TRUE
XX * if everything works. Return FALSE if there
XX * is an error (if there is no memory).
XX */
XXmakelist()
XX    {
XX    register char   *cp1;
XX    register char   *cp2;
XX    register int    c;
XX    register BUFFER *bp;
XX    register LINE   *lp;
XX    register int    nbytes;
XX    register int    s;
XX    register int    i;
XX    register int    type;
XX    char b[6+1];
XX    char line[128];
XX
XX    blistp->b_flag &= ~BFCHG;               /* Don't complain! */
XX    if ((s=bclear(blistp)) != TRUE)         /* Blow old text away */
XX		 return (s);
XX    strcpy(blistp->b_fname, "");
XX    if (addline("AC MODES   Size Buffer           File") == FALSE ||
XX        addline("-- ------  ---- ------           ----") == FALSE)
XX    return (FALSE);
XX    bp = bheadp;                            /* For all buffers */
XX    while (bp != NULL) {
XX	if ((bp->b_flag&BFTEMP) != 0) { /* Skip magic ones. */
XX		 bp = bp->b_bufp;
XX	    continue;
XX	    }
XX	cp1 = &line[0];                 /* Start at left edge */
XX
XX	/* output status of ACTIVE flag (has the file been read in? */
XX	if (bp->b_active == TRUE)    /* "@" if activated */
XX		 *cp1++ = '@';
XX	else
XX	*cp1++ = ' ';
XX
XX	/* output status of changed flag */
XX	if ((bp->b_flag&BFCHG) != 0)    /* "*" if changed */
XX		 *cp1++ = '*';
XX	else
XX	*cp1++ = ' ';
XX	*cp1++ = ' ';                   /* Gap. */
XX
XX	/* output the mode codes */
XX	for (i = 0; i < NUMMODES; i++) {
XX	    if (bp->b_mode & (1 << i)) *cp1++ = modecode[i];
XX	    else
XX	    *cp1++ = '.';
XX	    }
XX	*cp1++ = ' ';                   /* Gap. */
XX	nbytes = 0;                     /* Count bytes in buf. */
XX	lp = lforw(bp->b_linep);
XX	while (lp != bp->b_linep) {
XX	    nbytes += llength(lp)+1;
XX	    lp = lforw(lp);
XX	    }
XX	itoa(b, 6, nbytes);             /* 6 digit buffer size. */
XX	cp2 = &b[0];
XX	while ((c = *cp2++) != 0) *cp1++ = c;
XX	*cp1++ = ' ';                   /* Gap. */
XX	cp2 = &bp->b_bname[0];          /* Buffer name */
XX	while ((c = *cp2++) != 0) *cp1++ = c;
XX	cp2 = &bp->b_fname[0];          /* File name */
XX	if (*cp2 != 0) {
XX	    while (cp1 < &line[2+1+5+1+6+1+NBUFN]) *cp1++ = ' ';
XX	    while ((c = *cp2++) != 0) {
XX		if (cp1 < &line[128-1]) *cp1++ = c;
XX		}
XX	    }
XX	*cp1 = 0;                       /* Add to the buffer. */
XX	if (addline(line) == FALSE) return (FALSE);
XX	bp = bp->b_bufp;
XX	}
XX    return (TRUE);                          /* All done */
XX    }
XX
XXitoa(buf, width, num)
XXregister char   buf[];
XXregister int    width;
XXregister int    num;
XX    {
XX    buf[width] = 0;                         /* End of string. */
XX    while (num >= 10) {                     /* Conditional digits. */
XX		 buf[--width] = (num%10) + '0';
XX	num /= 10;
XX	}
XX    buf[--width] = num + '0';               /* Always 1 digit. */
XX    while (width != 0)                      /* Pad with blanks. */
XX		 buf[--width] = ' ';
XX    }
XX
XX/*
XX * The argument "text" points to
XX * a string. Append this line to the
XX * buffer list buffer. Handcraft the EOL
XX * on the end. Return TRUE if it worked and
XX * FALSE if you ran out of room.
XX */
XXaddline(text)
XXchar *text;
XX    {
XX    register LINE   *lp;
XX    register int    i;
XX    register int    ntext;
XX
XX    ntext = strlen(text);
XX    if ((lp=lalloc(ntext)) == NULL) return (FALSE);
XX    for (i=0; i<ntext; ++i) lputc(lp, i, text[i]);
XX    blistp->b_linep->l_bp->l_fp = lp;       /* Hook onto the end */
XX    lp->l_bp = blistp->b_linep->l_bp;
XX    blistp->b_linep->l_bp = lp;
XX    lp->l_fp = blistp->b_linep;
XX    if (blistp->b_dotp == blistp->b_linep)  /* If "." is at the end */
XX		 blistp->b_dotp = lp;            /* move it to new line */
XX    return (TRUE);
XX    }
XX
XX/*
XX * Look through the list of
XX * buffers. Return TRUE if there
XX * are any changed buffers. Buffers
XX * that hold magic internal stuff are
XX * not considered; who cares if the
XX * list of buffer names is hacked.
XX * Return FALSE if no buffers
XX * have been changed.
XX */
XXanycb()
XX    {
XX    register BUFFER *bp;
XX
XX    bp = bheadp;
XX    while (bp != NULL) {
XX	if ( bp != procbuf &&
XX	    (bp->b_flag&BFTEMP) == 0 &&
XX	    (bp->b_flag&BFCHG)  !=0 ) return (TRUE);
XX	bp = bp->b_bufp;
XX	}
XX    return (FALSE);
XX    }
XX
XX/*
XX * Find a buffer, by name. Return a pointer
XX * to the BUFFER structure associated with it. If
XX * the named buffer is found, but is a TEMP buffer (like
XX * the buffer list) complain. If the buffer is not found
XX * and the "cflag" is TRUE, create it. The "bflag" is
XX * the settings for the flags in the buffer.
XX */
XXBUFFER *
XXbfind(bname, cflag, bflag)
XXregister char   *bname;
XX    {
XX    register BUFFER *bp;
XX    register BUFFER *sb;    /* buffer to insert after */
XX    register LINE   *lp;
XX    char *malloc();
XX
XX    bp = bheadp;
XX    while (bp != NULL) {
XX	if (strcmp(bname, bp->b_bname) == 0) {
XX	    if ((bp->b_flag&BFTEMP) != 0) {
XX		mlwrite("Cannot select builtin buffer");
XX		return (NULL);
XX		}
XX	    return (bp);
XX	    }
XX	bp = bp->b_bufp;
XX	}
XX    if (cflag != FALSE) {
XX	if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) return (NULL);
XX	if ((lp=lalloc(0)) == NULL) {
XX	    free((char *) bp);
XX	    return (NULL);
XX	    }
XX	/* find the place in the list to insert this buffer */
XX	if (bheadp == NULL || strcmp(bheadp->b_bname, bname) > 0) {
XX	    /* insert at the begining */
XX	    bp->b_bufp = bheadp;
XX	    bheadp = bp;
XX	    }
XX	else {
XX	    sb = bheadp;
XX	    while (sb->b_bufp != NULL) {
XX		if (strcmp(sb->b_bufp->b_bname, bname) > 0) break;
XX		sb = sb->b_bufp;
XX		}
XX
XX	    /* and insert it */
XX	    bp->b_bufp = sb->b_bufp;
XX
XX	    sb->b_bufp = bp;
XX	    }
XX
XX	/* and set up the other buffer fields */
XX	bp->b_active = TRUE;
XX	bp->b_dotp = lp;
XX	bp->b_doto = 0;
XX	bp->b_markp = NULL;
XX	bp->b_marko = 0;
XX	bp->b_flag = bflag;
XX	bp->b_mode = 0;
XX	bp->b_nwnd = 0;
XX	bp->b_linep = lp;
XX	strcpy(bp->b_fname, "");
XX	strcpy(bp->b_bname, bname);
XX	lp->l_fp = lp;
XX	lp->l_bp = lp;
XX	}
XX    return (bp);
XX    }
XX
XX/*
XX * This routine blows away all of the text
XX * in a buffer. If the buffer is marked as changed
XX * then we ask if it is ok to blow it away; this is
XX * to save the user the grief of losing text. The
XX * window chain is nearly always wrong if this gets
XX * called; the caller must arrange for the updates
XX * that are required. Return TRUE if everything
XX * looks good.
XX */
XXbclear(bp)
XXregister BUFFER *bp;
XX    {
XX    register LINE   *lp;
XX    register int    s;
XX
XX    if ((bp->b_flag&BFTEMP) == 0            /* Not scratch buffer. */
XX		 && (bp->b_flag&BFCHG) != 0              /* Something changed */
XX    && (s=mlyesno("Discard changes")) != TRUE)
XX    return (s);
XX    bp->b_flag &= ~BFCHG;                  /* Not changed */
XX    while ((lp=lforw(bp->b_linep)) != bp->b_linep) lfree(lp);
XX    bp->b_dotp = bp->b_linep;              /* Fix "." */
XX    bp->b_doto = 0;
XX    bp->b_markp = NULL;                     /* Invalidate "mark" */
XX    bp->b_marko = 0;
XX    return (TRUE);
XX    }
XX
XX
SHAR_EOF
if test 12143 -ne "`wc -c buffer.c`"
then
echo shar: error transmitting buffer.c '(should have been 12143 characters)'
fi
echo shar: extracting display.c
sed 's/^XX//' << \SHAR_EOF > display.c
XX/*
XX * The functions in this file handle redisplay. There are two halves, the
XX * ones that update the virtual display screen, and the ones that make the
XX * physical display screen the same as the virtual display screen. These
XX * functions use hints that are left in the windows by the commands.
XX *
XX */
XX
XX#include <stdio.h>
XX#include	"estruct.h"
XX#include "edef.h"
XX
XX#define WFDEBUG 0                       /* Window flag debug. */
XXtypedef struct  VIDEO {
XX    short v_flag;                 /* Flags */
XX    char v_text[1];              /* Screen data. */
XX    }
XXVIDEO;
XX
XX#define VFCHG   0x0001          /* Changed. */
XX#define	VFEXT	0x0002		/* extended (beyond column 80) */
XX#define VFMOD   0x0004		/* change in mode line occurred*/
XX
XXint vtrow   = 0;                    /* Row location of SW cursor */
XXint vtcol   = 0;                    /* Column location of SW cursor */
XXint ttrow   = HUGE;                 /* Row location of HW cursor */
XXint ttcol   = HUGE;                 /* Column location of HW cursor */
XXint lbound  = 0;	    	    /* leftmost column of current line
XXbeing displayed */
XX
XXVIDEO **vscreen;                      /* Virtual screen. */
XXVIDEO **pscreen;                      /* Physical screen. */
XX
XX/*
XX * Initialize the data structures used by the display code. The edge vectors
XX * used to access the screens are set up. The operating system's terminal I/O
XX * channel is set up. All the other things get initialized at compile time.
XX * The original window has "WFCHG" set, so that it will get completely
XX * redrawn on the first call to "update".
XX */
XX
XXvtinit()
XX    {
XX    register int i;
XX    register VIDEO *vp;
XX    char *malloc();
XX
XX    (*term.t_open)();
XX    vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
XX
XX    if (vscreen == NULL) exit(1);
XX
XX    pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
XX
XX    if (pscreen == NULL) exit(1);
XX
XX    for (i = 0; i < term.t_nrow; ++i) {
XX	vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
XX
XX	if (vp == NULL) exit(1);
XX
XX	vp->v_flag = 0;
XX	vscreen[i] = vp;
XX	vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
XX
XX	if (vp == NULL) exit(1);
XX
XX	vp->v_flag = 0;
XX	pscreen[i] = vp;
XX	}
XX    }
XX
XX/*
XX * Clean up the virtual terminal system, in anticipation for a return to the
XX * operating system. Move down to the last line and clear it out (the next
XX * system prompt will be written in the line). Shut down the channel to the
XX * terminal.
XX */
XXvttidy()
XX    {
XX    mlerase();
XX    movecursor(term.t_nrow, 0);
XX    (*term.t_close)();
XX    }
XX
XX/*
XX * Set the virtual cursor to the specified row and column on the virtual
XX * screen. There is no checking for nonsense values; this might be a good
XX * idea during the early stages.
XX */
XXvtmove(row, col)
XX    {
XX    vtrow = row;
XX    vtcol = col;
XX    }
XX
XX/*
XX * Write a character to the virtual screen. The virtual row and column are
XX * updated. If the line is too long put a "$" in the last column. This routine
XX * only puts printing characters into the virtual terminal buffers. Only
XX * column overflow is checked.
XX */
XXvtputc(c)
XXint c;
XX    {
XX    register VIDEO      *vp;
XX
XX    vp = vscreen[vtrow];
XX
XX    if (vtcol >= term.t_ncol) vp->v_text[term.t_ncol - 1] = '$';
XX    else if (c == '\t')
XX	{
XX	do
XX	    {
XX	    vtputc(' ');
XX	    }
XX	while ((vtcol&0x07) != 0 && vtcol < term.t_ncol);
XX	}
XX    else if (c < 0x20 || c == 0x7F)
XX	{
XX	vtputc('^');
XX	vtputc(c ^ 0x40);
XX	}
XX    else
XX    vp->v_text[vtcol++] = c;
XX    }
XX
XX/* put a character to the virtual screen in an extended line. If we are
XXnot yet on left edge, don't print it yet. check for overflow on
XXthe right margin */
XX
XXvtpute(c)
XX
XXint c;
XX
XX    {
XX    register VIDEO      *vp;
XX
XX    vp = vscreen[vtrow];
XX
XX    if (vtcol >= term.t_ncol) vp->v_text[term.t_ncol - 1] = '$';
XX    else if (c == '\t')
XX	{
XX	do
XX	    {
XX	    vtpute(' ');
XX	    }
XX	while (((vtcol + lbound)&0x07) != 0 && vtcol < term.t_ncol);
XX	}
XX    else if (c < 0x20 || c == 0x7F)
XX	{
XX	vtpute('^');
XX	vtpute(c ^ 0x40);
XX	}
XX    else {
XX	if (vtcol >= 0) vp->v_text[vtcol] = c;
XX	++vtcol;
XX	}
XX    }
XX
XX/*
XX * Erase from the end of the software cursor to the end of the line on which
XX * the software cursor is located.
XX */
XXvteeol()
XX    {
XX    register VIDEO      *vp;
XX
XX    vp = vscreen[vtrow];
XX    while (vtcol < term.t_ncol) vp->v_text[vtcol++] = ' ';
XX    }
XX
XX/*
XX * Make sure that the display is right. This is a three part process. First,
XX * scan through all of the windows looking for dirty ones. Check the framing,
XX * and refresh the screen. Second, make sure that "currow" and "curcol" are
XX * correct for the current window. Third, make the virtual and physical
XX * screens the same.
XX */
XXupdate()
XX    {
XX    register LINE *lp;
XX    register WINDOW *wp;
XX    register VIDEO *vp1;
XX    register VIDEO *vp2;
XX    register int i,j,k;
XX    register int c;
XX    int row_p,row_v,n,tryblock;
XX
XX#ifdef TYPEAH
XX    if (typahead()) return;
XX#endif
XX    tryblock = 0;
XX    wp = wheadp;
XX
XX    while (wp != NULL) {
XX	/* Look at any window with update flags set on. */
XX
XX	if (wp->w_flag != 0) {
XX	    /* If not force reframe, check the framing. */
XX
XX	    if ((wp->w_flag & WFFORCE) == 0) {
XX		lp = wp->w_linep;
XX
XX		for (i = 0; i < wp->w_ntrows; ++i) {
XX		    if (lp == wp->w_dotp) goto out;
XX
XX		    if (lp == wp->w_bufp->b_linep) break;
XX
XX		    lp = lforw(lp);
XX		    }
XX		}
XX
XX	    /* Not acceptable, better compute a new value for the line at the
XX	     * top of the window. Then set the "WFHARD" flag to force full
XX	     * redraw.
XX	     */
XX	    i = wp->w_force;
XX
XX	    if (i > 0) {
XX		--i;
XX		if (i >= wp->w_ntrows) i = wp->w_ntrows-1;
XX		}
XX	    else if (i < 0)
XX		{
XX		i += wp->w_ntrows;
XX
XX		if (i < 0) i = 0;
XX		}
XX	    else
XX	    i = wp->w_ntrows/2;
XX
XX	    lp = wp->w_dotp;
XX
XX	    while (i != 0 && lback(lp) != wp->w_bufp->b_linep) {
XX		--i;
XX		lp = lback(lp);
XX		}
XX
XX	    wp->w_linep = lp;
XX	    wp->w_flag |= WFHARD;       /* Force full. */
XX
XX	    out:
XX	    /* Try to use reduced update. Mode line update has its own special
XX	     * flag. The fast update is used if the only thing to do is within
XX	     * the line editing. */
XX	    lp = wp->w_linep;
XX	    i = wp->w_toprow;
XX
XX	    if ((wp->w_flag & ~WFMODE) == WFEDIT) {
XX		while (lp != wp->w_dotp) {
XX		    ++i;
XX		    lp = lforw(lp);
XX		    }
XX
XX		vscreen[i]->v_flag |= VFCHG;
XX		vtmove(i, 0);
XX
XX		for (j = 0; j < llength(lp); ++j) vtputc(lgetc(lp, j));
XX
XX		vteeol();
XX		}
XX	    else if ((wp->w_flag & (WFEDIT | WFHARD)) != 0)
XX		{
XX		tryblock = 1;
XX		while (i < wp->w_toprow+wp->w_ntrows) {
XX		    vscreen[i]->v_flag |= VFCHG;
XX		    vtmove(i, 0);
XX
XX		    /* if line has been changed */
XX		    if (lp != wp->w_bufp->b_linep) {
XX			for (j = 0; j < llength(lp); ++j) vtputc(lgetc(lp, j));
XX			lp = lforw(lp);
XX			}
XX		    vteeol();
XX		    ++i;
XX		    }
XX		}
XX#if ~WFDEBUG
XX	    if ((wp->w_flag&WFMODE) != 0) modeline(wp);
XX
XX	    wp->w_flag = 0;
XX	    wp->w_force = 0;
XX#endif
XX	    }
XX#if WFDEBUG
XX	modeline(wp);
XX	wp->w_flag =  0;
XX	wp->w_force = 0;
XX#endif
XX
XX	/* and onward to the next window */
XX	wp = wp->w_wndp;
XX	}
XX
XX    /* Always recompute the row and column number of the hardware cursor. This
XX     * is the only update for simple moves.
XX     */
XX    lp = curwp->w_linep;
XX    currow = curwp->w_toprow;
XX
XX    while (lp != curwp->w_dotp) {
XX	++currow;
XX	lp = lforw(lp);
XX	}
XX
XX    curcol = 0;
XX    i = 0;
XX
XX    while (i < curwp->w_doto) {
XX	c = lgetc(lp, i++);
XX
XX	if (c == '\t') curcol |= 0x07;
XX	else if (c < 0x20 || c == 0x7F)
XX	++curcol;
XX
XX	++curcol;
XX	}
XX
XX    if (curcol >= term.t_ncol - 1) {          /* extended line. */
XX		 /* flag we are extended and changed */
XX	vscreen[currow]->v_flag |= VFEXT | VFCHG;
XX	updext();	/* and output extended line */
XX	}
XX    else
XX    lbound = 0;		    /* not extended line */
XX
XX    /* make sure no lines need to be de-extended because the cursor is
XX    no longer on them */
XX
XX    wp = wheadp;
XX
XX    while (wp != NULL) {
XX	lp = wp->w_linep;
XX	i = wp->w_toprow;
XX
XX	while (i < wp->w_toprow + wp->w_ntrows) {
XX	    if (vscreen[i]->v_flag & VFEXT) {
XX		/* always flag extended lines as changed */
XX		vscreen[i]->v_flag |= VFCHG;
XX		if ((wp != curwp) || (lp != wp->w_dotp) || (curcol < term.t_ncol - 1)) {
XX		    vtmove(i, 0);
XX		    for (j = 0; j < llength(lp); ++j) vtputc(lgetc(lp, j));
XX		    vteeol();
XX
XX		    /* this line no longer is extended */
XX		    vscreen[i]->v_flag &= ~VFEXT;
XX		    }
XX		}
XX	    lp = lforw(lp);
XX	    ++i;
XX	    }
XX	/* if garbaged then fix up mode lines */
XX	if (sgarbf != FALSE) vscreen[i]->v_flag |= VFMOD|VFCHG;
XX	
XX	/* and onward to the next window */
XX	wp = wp->w_wndp;
XX	}
XX
XX    /* Special hacking if the screen is garbage. Clear the hardware screen,
XX     * and update your copy to agree with it. Set all the virtual screen
XX     * change bits, to force a full update.
XX     */
XX    if (sgarbf != FALSE) {
XX	for (i = 0; i < term.t_nrow; ++i) {
XX	    vscreen[i]->v_flag |= VFCHG;
XX	    vp1 = pscreen[i];
XX	    for (j = 0; j < term.t_ncol; ++j) vp1->v_text[j] = ' ';
XX	    }
XX
XX	(*term.t_putchar)('\033');	/* as good a place as any to force */
XX	(*term.t_putchar)('=');		/* application mode on the terminal */
XX
XX	movecursor(0, 0);               /* Erase the screen. */
XX	(*term.t_eeop)();
XX	sgarbf = FALSE;
XX	mpresf = FALSE;                 /* the message area. */
XX	tryblock = 0;
XX	}
XX
XX    /* If we're going to try a block transfer, make sure at least 1/4
XX     * of the lines DON'T agree
XX     */
XX    if (tryblock) {
XX	n = 0;
XX	j = term.t_ncol >> 2;
XX	k = term.t_ncol >> 1;
XX	for (i = 0; i < term.t_nrow; i++) {
XX	    vp1 = vscreen[i];
XX	    vp2 = pscreen[i];
XX	    if (vp1->v_text[0] != vp2->v_text[0] ||
XX		vp1->v_text[j] != vp2->v_text[j] ||
XX		vp1->v_text[k] != vp2->v_text[k]) n++;
XX	    }
XX	if (n <= (term.t_nrow >> 2)) tryblock = 0;
XX	}
XX
XX    /* First see if we can do a massive "block move" of data... */
XX    if (tryblock) {
XX	row_p = row_v = n = -1;
XX	for (i = currow >= 4 ? currow - 4 : 0;
XX	     i <= currow+4 && i <= term.t_nrow-4; i++) {
XX	    for (j = 0; j < term.t_nrow; j++) {
XX		for (k = 0; k < term.t_nrow-i && k < term.t_nrow-j; k++) {
XX		    vp1 = pscreen[i+k];
XX		    vp2 = vscreen[j+k];
XX		    if (strncmp(vp1->v_text,vp2->v_text,term.t_ncol)
XX			    != 0) break;
XX		    }
XX		if (k > n) {
XX		    n = k;
XX		    row_p = i;
XX		    row_v = j;
XX		    }
XX		}
XX	    }
XX
XX	/* Make sure we got at least 1/4 lines to shift and
XX	    at most 1/4 of the screen to redo */
XX	if (row_p != row_v && n >= (term.t_nrow >> 2) &&
XX	    (term.t_nrow-row_v)-n <= (term.t_nrow >> 2)) {
XX	    if (row_p < row_v) {
XX		(*term.t_insert)(row_p,(row_v-row_p));
XX		j = (term.t_nrow-1) - (row_v-row_p);
XX		for (i=term.t_nrow-1; i >= row_v; i--) {
XX		    vscreen[i]->v_flag |= VFCHG;
XX		    vp1 = pscreen[j--];
XX		    vp2 = pscreen[i];
XX		    strncpy(vp2->v_text,vp1->v_text,term.t_ncol);
XX		    }
XX		for (i=row_p; i < row_v; i++) {
XX		    vscreen[i]->v_flag |= VFCHG;
XX		    vp1 = pscreen[i];
XX		    for(j=0; j < term.t_ncol; j++) vp1->v_text[j] = ' ';
XX		    }
XX		}
XX	    else {
XX		(*term.t_delete)(row_v,(row_p-row_v));
XX		j = row_v;
XX		for (i=row_p; i < term.t_nrow; i++) {
XX		    vscreen[j]->v_flag |= VFCHG;
XX		    vp1 = pscreen[j++];
XX		    vp2 = pscreen[i];
XX		    strncpy(vp1->v_text,vp2->v_text,term.t_ncol);
XX		    }
XX		for (i=j; i < term.t_nrow; i++) {
XX		    vscreen[i]->v_flag |= VFCHG;
XX		    vp1 = pscreen[i];
XX		    for(j=0; j < term.t_ncol; j++) vp1->v_text[j] = ' ';
XX		    }
XX		}
XX	    wp = wheadp;
XX	    while (wp != NULL) {
XX		i = wp->w_toprow+wp->w_ntrows;
XX		if (i >= row_p || i >= row_v)
XX		    vscreen[i]->v_flag |= VFMOD|VFCHG;
XX		wp = wp->w_wndp;
XX		}
XX	    }
XX	else tryblock = 0;
XX	}
XX
XX    /* Make sure that the physical and virtual displays agree. Unlike before,
XX     * the "updateline" code is only called with a line that has been updated
XX     * for sure.
XX     */
XX    for (i = 0; i < term.t_nrow; ++i) {
XX	vp1 = vscreen[i];
XX
XX	if ((vp1->v_flag&VFCHG) != 0) {
XX#ifdef TYPEAH
XX	    if (!tryblock && typahead()) return;
XX#endif
XX	    vp1->v_flag &= ~VFCHG;
XX	    vp2 = pscreen[i];
XX
XX	    if ((vp1->v_flag&VFMOD) != 0) {
XX		updateline(i, &vp1->v_text[0], &vp2->v_text[0],1);
XX		vp1->v_flag &= ~VFMOD;
XX		}
XX	    else updateline(i, &vp1->v_text[0], &vp2->v_text[0],0);
XX
XX	    }
XX	}
XX
XX    /* Finally, update the hardware cursor and flush out buffers. */
XX    movecursor(currow, curcol - lbound);
XX    (*term.t_flush)();
XX    }
XX
XX/* updext: update the extended line which the cursor is currently
XXon at a column greater than the terminal width. The line
XXwill be scrolled right or left to let the user see where
XXthe cursor is
XX */
XX
XXupdext()
XX
XX    {
XX    register int rcursor;   /* real cursor location */
XX    register LINE *lp;	/* pointer to current line */
XX    register int j;	/* index into line */
XX
XX    /* calculate what column the real cursor will end up in */
XX    rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
XX    lbound = curcol - rcursor + 1;
XX
XX    /* scan through the line outputing characters to the virtual screen */
XX    /* once we reach the left edge */
XX    vtmove(currow, -lbound);	/* start scanning offscreen */
XX    lp = curwp->w_dotp;	    /* line to output */
XX    for (j=0; j<llength(lp); ++j)   /* until the end-of-line */
XX		 vtpute(lgetc(lp, j));
XX
XX    /* truncate the virtual line */
XX    vteeol();
XX
XX    /* and put a '$' in column 1 */
XX    vscreen[currow]->v_text[0] = '$';
XX    }
XX
XX/*
XX * Update a single line. This does not know how to use insert or delete
XX * character sequences; we are using VT52 functionality. Update the physical
XX * row and column variables. It does try an exploit erase to end of line. The
XX * RAINBOW version of this routine uses fast video.
XX */
XXupdateline(row, vline, pline, ismode)
XXchar vline[];
XXchar pline[];
XX    {
XX    register char *cp1;
XX    register char *cp2;
XX    register char *cp3;
XX    register char *cp4;
XX    register char *cp5;
XX    register int nbflag;
XX
XX    cp1 = &vline[0];                    /* Compute left match. */
XX    cp2 = &pline[0];
XX
XX    while (cp1!=&vline[term.t_ncol] && cp1[0]==cp2[0]) {
XX	++cp1;
XX	++cp2;
XX	}
XX
XX    /* This can still happen, even though we only call this routine on changed
XX     * lines. A hard update is always done when a line splits, a massive
XX     * change is done, or a buffer is displayed twice. This optimizes out most
XX     * of the excess updating. A lot of computes are used, but these tend to
XX     * be hard operations that do a lot of update, so I don't really care.
XX     */
XX    if (cp1 == &vline[term.t_ncol])             /* All equal. */
XX		 return;
XX
XX    nbflag = FALSE;
XX    cp3 = &vline[term.t_ncol];          /* Compute right match. */
XX    cp4 = &pline[term.t_ncol];
XX
XX    while (cp3[-1] == cp4[-1]) {
XX	--cp3;
XX	--cp4;
XX	if (cp3[0] != ' ')              /* Note if any nonblank */
XX		 nbflag = TRUE;              /* in right match. */
XX	}
XX
XX    cp5 = cp3;
XX
XX    if (nbflag == FALSE && eolexist == TRUE)	/* Erase to EOL ? */
XX	{
XX	while (cp5!=cp1 && cp5[-1]==' ') --cp5;
XX
XX	if (cp3-cp5 <= 3)               /* Use only if erase is */
XX		 cp5 = cp3;                  /* fewer characters. */
XX	}
XX
XX    movecursor(row, cp1-&vline[0]);     /* Go to start of line. */
XX
XX    if (ismode) {
XX	(*term.t_putchar)('\033');
XX	(*term.t_putchar)('[');
XX	(*term.t_putchar)('7');
XX	(*term.t_putchar)('m');
XX	}
XX
XX    while (cp1 != cp5)                  /* Ordinary. */
XX	{
XX	(*term.t_putchar)(*cp1);
XX	++ttcol;
XX	*cp2++ = *cp1++;
XX	}
XX
XX    if (cp5 != cp3)                     /* Erase. */
XX	{
XX	(*term.t_eeol)();
XX	while (cp1 != cp3) *cp2++ = *cp1++;
XX	}
XX
XX    if (ismode) {
XX	(*term.t_putchar)('\033');
XX	(*term.t_putchar)('[');
XX	(*term.t_putchar)('0');
XX	(*term.t_putchar)('m');
XX	}
XX
XX    }
XX
XX/*
XX * Redisplay the mode line for the window pointed to by the "wp". This is the
XX * only routine that has any idea of how the modeline is formatted. You can
XX * change the modeline format by hacking at this routine. Called by "update"
XX * any time there is a dirty window. Also fixes up tabbing.
XX */
XXmodeline(wp)
XXWINDOW *wp;
XX    {
XX    register char *cp;
XX    register int c;
XX    register int n;	/* cursor position count */
XX    register BUFFER *bp;
XX    register i;	/* loop index */
XX    register lchar;	/* character to draw line in buffer with */
XX    register firstm;	    /* is this the first mode? */
XX    char tline[NLINE];	    /* buffer for part of mode line */
XX
XX
XX    n = wp->w_toprow+wp->w_ntrows;      /* Location. */
XX
XX    vscreen[n]->v_flag |= VFCHG|VFMOD;	/* Redraw next time. */
XX
XX    vtmove(n, 0);                       /* Seek to right line. */
XX    bp = wp->w_bufp;
XX    if (wp == curwp) {	/* mark the current buffer */
XX	lchar = '=';
XX	if	((bp->b_mode & (MDCMOD|MDMMOD)) != 0)	tab(FALSE,4);
XX	else if ((bp->b_mode & MDLISP) != 0)	    	tab(FALSE,2);
XX	else						tab(FALSE,0);
XX	}
XX    else
XX	lchar = '-';
XX
XX    vtputc(lchar);
XX
XX    if ((bp->b_flag&BFCHG) != 0)                /* "*" if changed. */
XX	 vtputc('*');
XX    else vtputc(' ');
XX
XX    n = 2;
XX
XX    strcpy(tline, " uEMACS (");	    /* Buffer name. */
XX
XX    /* display the modes */
XX
XX    firstm = TRUE;
XX    for (i = 0; i < NUMMODES; i++)  /* add in the mode flags */
XX		 if (wp->w_bufp->b_mode & (1 << i)) {
XX	if (firstm != TRUE) strcat(tline, " ");
XX	firstm = FALSE;
XX	strcat(tline, modename[i]);
XX	}
XX    strcat(tline,") ");
XX
XX    cp = &tline[0];
XX    while ((c = *cp++) != 0) {
XX	vtputc(c);
XX	++n;
XX	}
XX
XX    vtputc('-');
XX    vtputc('-');
XX    vtputc(' ');
XX    n += 3;
XX    cp = &bp->b_bname[0];
XX
XX    while ((c = *cp++) != 0) {
XX	vtputc(c);
XX	++n;
XX	}
XX
XX    vtputc(' ');
XX    vtputc('-');
XX    vtputc('-');
XX    n += 3;
XX
XX    if (bp->b_fname[0] != 0)            /* File name. */
XX		 {
XX	vtputc(' ');
XX	++n;
XX	cp = "File: ";
XX
XX	while ((c = *cp++) != 0) {
XX	    vtputc(c);
XX	    ++n;
XX	    }
XX
XX	cp = &bp->b_fname[0];
XX
XX	while ((c = *cp++) != 0) {
XX	    vtputc(c);
XX	    ++n;
XX	    }
XX
XX	vtputc(' ');
XX	++n;
XX	}
XX
XX#if WFDEBUG
XX    vtputc(lchar);
XX    vtputc((wp->w_flag&WFMODE)!=0 ? 'M' : lchar);
XX    vtputc((wp->w_flag&WFHARD)!=0 ? 'H' : lchar);
XX    vtputc((wp->w_flag&WFEDIT)!=0 ? 'E' : lchar);
XX    vtputc((wp->w_flag&WFMOVE)!=0 ? 'V' : lchar);
XX    vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : lchar);
XX    n += 6;
XX#endif
XX
XX    while (n < term.t_ncol)             /* Pad to full width. */
XX		 {
XX	vtputc('-');
XX	++n;
XX	}
XX    }
XX
XXupmode() /* update all the mode lines */
XX
XX    {
XX    register WINDOW *wp;
XX
XX    wp = wheadp;
XX    while (wp != NULL) {
XX	wp->w_flag |= WFMODE;
XX	wp = wp->w_wndp;
XX	}
XX    }
XX
XX/*
XX * Send a command to the terminal to move the hardware cursor to row "row"
XX * and column "col". The row and column arguments are origin 0. Optimize out
XX * random calls. Update "ttrow" and "ttcol".
XX */
XXmovecursor(row, col)
XX    {
XX    if (row!=ttrow || col!=ttcol) {
XX	ttrow = row;
XX	ttcol = col;
XX	(*term.t_move)(row, col);
XX	}
XX    }
XX
XX/*
XX * Erase the message line. This is a special routine because the message line
XX * is not considered to be part of the virtual screen. It always works
XX * immediately; the terminal buffer is flushed via a call to the flusher.
XX */
XXmlerase()
XX    {
XX    int i;
XX
XX    movecursor(term.t_nrow, 0);
XX    if (eolexist == TRUE) (*term.t_eeol)();
XX    else {
XX	for (i == 0; i < term.t_ncol - 1; i++) (*term.t_putchar)(' ');
XX	movecursor(term.t_nrow, 1); /* force the move! */
XX	movecursor(term.t_nrow, 0);
XX	}
XX    (*term.t_flush)();
XX    mpresf = FALSE;
XX    }
XX
XX/*
XX * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
XX * ABORT. The ABORT status is returned if the user bumps out of the question
XX * with a ^G. Used any time a confirmation is required.
XX */
XX
XXmlyesno(prompt)
XX
XXchar *prompt;
XX
XX    {
XX    register int s;
XX    int c;		/* input character */
XX    char buf[NPAT];	/* prompt to user */
XX
XX    for (;;) {
XX	/* build and prompt the user */
XX	strcpy(buf, prompt);
XX	strcat(buf, " [y/n]? ");
XX	mlwrite(buf);
XX
XX	/* get the responce */
XX	c = getkey();
XX	if (c & CTRL) c -= (CTRL|'@');
XX	c &= 0x7F;
XX
XX	if (c == BELL)	    /* Bail out! */
XX		 return(ABORT);
XX
XX
XX	if (c=='y' || c=='Y') return(TRUE);
XX
XX	if (c=='n' || c=='N') return(FALSE);
XX	}
XX    }
XX
XX/*
XX * Write a prompt into the message line, then read back a response. Keep
XX * track of the physical position of the cursor. If we are in a keyboard
XX * macro throw the prompt away, and return the remembered response. This
XX * lets macros run at full speed. The reply is always terminated by a carriage
XX * return. Handle erase, kill, and abort keys.
XX */
XX
XXmlreply(prompt, buf, nbuf)
XXchar *prompt;
XXchar *buf;
XX    {
XX    return(mlreplyt(prompt,buf,nbuf,'\n'));
XX    }
XX
XX/* A more generalized prompt/reply function allowing the caller
XXto specify the proper terminator. If the terminator is not
XXa return ('\n') it will echo as "<NL>"
XX */
XXmlreplyt(prompt, buf, nbuf, eolchar)
XX
XXchar *prompt;
XXchar *buf;
XXchar eolchar;
XX
XX    {
XX    register int cpos;
XX    register int i;
XX    register int c;
XX    int anytyped;
XX    
XX    cpos = 0;
XX
XX    if (kbdmop != NULL) {
XX	while ((c = *kbdmop++) != '\0') buf[cpos++] = c;
XX	buf[cpos] = 0;
XX	if (buf[0] == 0) return(FALSE);
XX	return(TRUE);
XX	}
XX
XX    /* check to see if we are executing a command line */
XX    if (clexec) {
XX	nxtarg(buf);
XX	return(TRUE);
XX	}
XX
XX    mlwrite(prompt);
XX
XX    anytyped = FALSE;
XX    for (;;) {
XX	/* get a character from the user. if it is a <ret>, change it
XX	    to a <NL> */
XX	c = getkey();
XX	if (c & CTRL) c -= (CTRL|'@');
XX	c &= 0x7F;
XX
XX	if (c == '\r') c = '\n';
XX
XX	if (c == eolchar) {
XX	    buf[cpos++] = 0;
XX
XX	    if (kbdmip != NULL) {
XX		if (kbdmip+cpos > &kbdm[NKBDM-3]) {
XX		    ctrlg(FALSE, 0);
XX		    (*term.t_flush)();
XX		    return(ABORT);
XX		    }
XX		for (i=0; i<cpos; ++i) *kbdmip++ = buf[i];
XX		}
XX	    (*term.t_putchar)('\r');
XX	    ttcol = 0;
XX	    (*term.t_flush)();
XX	    return(anytyped);
XX	    }
XX	else if (c == BELL) {	/* Bell, abort */
XX	    (*term.t_putchar)('^');
XX	    (*term.t_putchar)('G');
XX	    ttcol += 2;
XX	    ctrlg(FALSE, 0);
XX	    (*term.t_flush)();
XX	    return(ABORT);
XX	    }
XX	else if (c == 0x7F || c == 0x08) {  /* rubout/erase */
XX	    if (cpos != 0) {
XX		(*term.t_putchar)('\b');
XX		(*term.t_putchar)(' ');
XX		(*term.t_putchar)('\b');
XX		--ttcol;
XX		if (buf[--cpos] < 0x20) {
XX		    (*term.t_putchar)('\b');
XX		    (*term.t_putchar)(' ');
XX		    (*term.t_putchar)('\b');
XX		    --ttcol;
XX		    }
XX		if (buf[cpos] == '\n') {
XX		    (*term.t_putchar)('\b');
XX		    (*term.t_putchar)('\b');
XX		    (*term.t_putchar)(' ');
XX		    (*term.t_putchar)(' ');
XX		    (*term.t_putchar)('\b');
XX		    (*term.t_putchar)('\b');
XX		    --ttcol;
XX		    --ttcol;
XX		    }
XX		(*term.t_flush)();
XX		}
XX	    }
XX	else if (c == 0x15) {	/* C-U, kill */
XX	    while (cpos != 0) {
XX		(*term.t_putchar)('\b');
XX		(*term.t_putchar)(' ');
XX		(*term.t_putchar)('\b');
XX		--ttcol;
XX
XX		if (buf[--cpos] < 0x20) {
XX		    (*term.t_putchar)('\b');
XX		    (*term.t_putchar)(' ');
XX		    (*term.t_putchar)('\b');
XX		    --ttcol;
XX		    }
XX		}
XX	    (*term.t_flush)();
XX	    }
XX	else {
XX	    if (cpos < nbuf-1) {
XX		buf[cpos++] = c;
XX
XX		if ((c < ' ') && (c != '\n')) {
XX		    (*term.t_putchar)('^');
XX		    ++ttcol;
XX		    c ^= 0x40;
XX		    }
XX
XX		if (c != '\n') (*term.t_putchar)(c);
XX		else {	/* put out <NL> for <ret> */
XX		    (*term.t_putchar)('<');
XX		    (*term.t_putchar)('N');
XX		    (*term.t_putchar)('L');
XX		    (*term.t_putchar)('>');
XX		    ttcol += 3;
XX		    }
XX		++ttcol;
XX		anytyped = TRUE;
XX		(*term.t_flush)();
XX		}
XX	    }
XX	}
XX    }
XX
XX/*
XX * Write a message into the message line. Keep track of the physical cursor
XX * position. A small class of printf like format items is handled. Assumes the
XX * stack grows down; this assumption is made by the "++" in the argument scan
XX * loop. Set the "message line" flag TRUE.
XX */
XX
XXmlwrite(fmt, arg)
XXchar *fmt;
XX    {
XX    register int c;
XX    register char *ap;
XX
XX    if (eolexist == FALSE) {
XX	mlerase();
XX	(*term.t_flush)();
XX	}
XX
XX    movecursor(term.t_nrow, 0);
XX    ap = (char *) &arg;
XX    while ((c = *fmt++) != 0) {
XX	if (c != '%') {
XX	    (*term.t_putchar)(c);
XX	    ++ttcol;
XX	    }
XX	else
XX	    {
XX	    c = *fmt++;
XX	    switch (c) {
XX		case 'd':
XX		mlputi(*(int *)ap, 10);
XX		ap += sizeof(int);
XX		break;
XX
XX		case 'o':
XX		mlputi(*(int *)ap,  8);
XX		ap += sizeof(int);
XX		break;
XX
XX		case 'x':
XX		mlputi(*(int *)ap, 16);
XX		ap += sizeof(int);
XX		break;
XX
XX		case 'D':
XX		mlputli(*(long *)ap, 10);
XX		ap += sizeof(long);
XX		break;
XX
XX		case 's':
XX		mlputs(*(char **)ap);
XX		ap += sizeof(char *);
XX		break;
XX
XX		default:
XX		(*term.t_putchar)(c);
XX		++ttcol;
XX		}
XX	    }
XX	}
XX    if (eolexist == TRUE) (*term.t_eeol)();
XX    (*term.t_flush)();
XX    mpresf = TRUE;
XX    }
XX
XX/*
XX * Write out a string. Update the physical cursor position. This assumes that
XX * the characters in the string all have width "1"; if this is not the case
XX * things will get screwed up a little.
XX */
XXmlputs(s)
XXchar *s;
XX    {
XX    register int c;
XX
XX    while ((c = *s++) != 0) {
XX	(*term.t_putchar)(c);
XX	++ttcol;
XX	}
XX    }
XX
XX/*
XX * Write out an integer, in the specified radix. Update the physical cursor
XX * position. This will not handle any negative numbers; maybe it should.
XX */
XXmlputi(i, r)
XX    {
XX    register int q;
XX    static char hexdigits[] = "0123456789ABCDEF";
XX
XX    if (i < 0) {
XX	i = -i;
XX	(*term.t_putchar)('-');
XX	}
XX
XX    q = i/r;
XX
XX    if (q != 0) mlputi(q, r);
XX
XX    (*term.t_putchar)(hexdigits[i%r]);
XX    ++ttcol;
XX    }
XX
XX/*
XX * do the same except as a long integer.
XX */
XXmlputli(l, r)
XXlong l;
XX    {
XX    register long q;
XX
XX    if (l < 0) {
XX	l = -l;
XX	(*term.t_putchar)('-');
XX	}
XX
XX    q = l/r;
XX
XX    if (q != 0) mlputli(q, r);
XX
XX    (*term.t_putchar)((int)(l%r)+'0');
XX    ++ttcol;
XX    }
XX
XX/* get a command name from the command line. Command completion means
XXthat pressing a <SPACE> will attempt to complete an unfinished command
XXname if it is unique.
XX */
XX
XXint (*getcname())()
XX
XX    {
XX    register int cpos;	/* current column on screen output */
XX    register int i;
XX    register int c;
XX    register char *sp;	/* pointer to string for output */
XX    register NBIND *ffp;    /* first ptr to entry in name binding table */
XX    register NBIND *cffp;   /* current ptr to entry in name binding table */
XX    register NBIND *lffp;   /* last ptr to entry in name binding table */
XX    char buf[NSTRING];	/* buffer to hold tentative command name */
XX    int (*fncmatch())();
XX
XX    /* starting at the begining of the string buffer */
XX    cpos = 0;
XX
XX    /* if we are executing a keyboard macro, fill our buffer from there,
XX    and attempt a straight match */
XX    if (kbdmop != NULL && *kbdmop != ' ' && *kbdmop != '\t') {
XX	while ((c = *kbdmop++) != '\0') buf[cpos++] = c;
XX
XX	buf[cpos] = 0;
XX
XX	/* return the result of a match */
XX	return(fncmatch(&buf[0]));
XX	}
XX
XX    /* if we are executing a command line get the next arg and match it */
XX    if (clexec) {
XX	nxtarg(buf);
XX	return(fncmatch(&buf[0]));
XX	}
XX
XX    /* build a name string from the keyboard */
XX    while (TRUE) {
XX	c = getkey();
XX	if (c & CTRL) c -= (CTRL|'@');
XX	c &= 0x7F;
XX
XX	/* if we are at the end, just match it */
XX	if (c == 0x0d) {
XX	    buf[cpos] = 0;
XX
XX	    /* save keyboard macro string if needed */
XX	    if (kbdtext(&buf[0]) == ABORT) return(NULL);
XX
XX	    /* and match it off */
XX	    return(fncmatch(&buf[0]));
XX
XX	    }
XX	else if (c == 0x07) {	/* Bell, abort */
XX	    (*term.t_putchar)('^');
XX	    (*term.t_putchar)('G');
XX	    ttcol += 2;
XX	    ctrlg(FALSE, 0);
XX	    (*term.t_flush)();
XX	    return(NULL);
XX
XX	    }
XX	else if (c == 0x7F || c == 0x08) {  /* rubout/erase */
XX	    if (cpos != 0) {
XX		(*term.t_putchar)('\b');
XX		(*term.t_putchar)(' ');
XX		(*term.t_putchar)('\b');
XX		--ttcol;
XX		--cpos;
XX		(*term.t_flush)();
XX		}
XX
XX	    }
XX	else if (c == 0x15) {	/* C-U, kill */
XX	    while (cpos != 0) {
XX		(*term.t_putchar)('\b');
XX		(*term.t_putchar)(' ');
XX		(*term.t_putchar)('\b');
XX		--cpos;
XX		--ttcol;
XX		}
XX
XX	    (*term.t_flush)();
XX
XX	    }
XX	else if (c == ' ') {
XX	    /* attempt a completion */
XX	    buf[cpos] = 0;	/* terminate it for us */
XX	    ffp = &names[0];	/* scan for matches */
XX	    while (ffp->n_func != NULL) {
XX		if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
XX		    /* a possible match! More than one? */
XX		    if ((ffp + 1)->n_func == NULL ||
XX			(strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
XX			/* no...we match, print it */
XX			sp = ffp->n_name + cpos;
XX			while (*sp) (*term.t_putchar)(*sp++);
XX			return(ffp->n_func);
XX			}
XX		    else {
XX			/* try for a partial match against the list */
XX
XX			/* first scan down until we no longer match the 
XX			    current input */
XX			lffp = (ffp + 1);
XX			while ((lffp+1)->n_func != NULL) {
XX			    if (strncmp(buf, (lffp+1)->n_name, strlen(buf))
XX				    != 0) break;
XX			    ++lffp;
XX			    }
XX
XX			/* and now, attempt to partial complete the string,
XX			    char at a time */
XX			while (TRUE) {
XX			    /* add the next char in */
XX			    buf[cpos] = ffp->n_name[cpos];
XX
XX			    /* scan through the candidates */
XX			    cffp = ffp + 1;
XX			    while (cffp <= lffp) {
XX				if (cffp->n_name[cpos] != buf[cpos]) goto onward;
XX				++cffp;
XX				}
XX
XX			    /* add the character */
XX			    (*term.t_putchar)(buf[cpos++]);
XX			    }
XX			}
XX		    }
XX		++ffp;
XX		}
XX
XX	    /* no match.....beep and onward */
XX	    (*term.t_beep)();
XX	    onward:;
XX	    }
XX	else {
XX	    if (cpos < NSTRING-1 && c > ' ') {
XX		buf[cpos++] = c;
XX		(*term.t_putchar)(c);
XX		}
XX
XX	    ++ttcol;
XX	    (*term.t_flush)();
XX	    }
XX	}
XX    }
XX
XXkbdtext(buf)	/* add this text string to the current keyboard macro
XXdefinition */
XX
XXchar *buf;  /* text to add to keyboard macro */
XX
XX    {
XX    /* if we are defining a keyboard macro, save it */
XX    if (kbdmip != NULL) {
XX	if (kbdmip+strlen(buf) > &kbdm[NKBDM-4]) {
XX	    ctrlg(FALSE, 0);
XX	    (*term.t_flush)();
XX	    return(ABORT);
XX	    }
XX
XX	/* copy string in and null terminate it */
XX	while (*buf) *kbdmip++ = *buf++;
XX	*kbdmip++ = 0;
XX	}
XX    return(TRUE);
XX    }
SHAR_EOF
if test 28840 -ne "`wc -c display.c`"
then
echo shar: error transmitting display.c '(should have been 28840 characters)'
fi
echo shar: extracting file.c
sed 's/^XX//' << \SHAR_EOF > file.c
XX/*
XX * The routines in this file
XX * handle the reading and writing of
XX * disk files. All of details about the
XX * reading and writing of the disk are
XX * in "fileio.c".
XX */
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if ULTRIX
XX#include <strings.h>
XX#endif
XX
XX#if AMIGA
XXextern	char	*strcat(),*strncat(),*strcpy(),*strncpy(),
XX		*index(),*rindex();
XX#endif
XX
XX#if VMS
XX#define index(str,chr)	strchr(str,chr)
XX#define rindex(str,chr)	strrchr(str,chr)
XX#endif
XX
XX/*
XX * Read a file into the current
XX * buffer. This is really easy; all you do it
XX * find the name of the file, and call the standard
XX * "read a file into the current buffer" code.
XX * Bound to "C-X C-R".
XX */
XXfileread(f, n)
XX    {
XX    register int    s;
XX    char fname[NFILEN];
XX
XX    if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE) return(s);
XX    return(readin(fname, TRUE));
XX    }
XX
XX/*
XX * Insert a file into the current
XX * buffer. This is really easy; all you do it
XX * find the name of the file, and call the standard
XX * "insert a file into the current buffer" code.
XX * Bound to "C-X C-I".
XX */
XXinsfile(f, n)
XX    {
XX    register int    s;
XX    char fname[NFILEN];
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE) return(s);
XX    return(ifile(fname));
XX    }
XX
XX/*
XX * Select a file for editing.
XX * Look around to see if you can find the
XX * fine in another buffer; if you can find it
XX * just switch to the buffer. If you cannot find
XX * the file, create a new buffer, read in the
XX * text, and switch to the new buffer.
XX * Bound to C-X C-F.
XX */
XXfilefind(f, n)
XX    {
XX    char fname[NFILEN];	/* file user wishes to find */
XX    register int s;	/* status return */
XX
XX    if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE) return(s);
XX    return(getfile(fname, TRUE));
XX    }
XX
XXvisitfile(f, n)	/* visit a file */
XX    {
XX    char fname[NFILEN];	/* file user wishes to find */
XX    register int s;	/* status return */
XX    register WINDOW *wp;    /* scan for windows that need updating */
XX
XX    if ((s=mlreply("Visit file: ", fname, NFILEN)) != TRUE) return (s);
XX    if ((wp = wpopup()) != NULL) {
XX	curwp = wp;
XX	curbp = wp->w_bufp;
XX	}
XX
XX    s = getfile(fname, FALSE);
XX    if (s) {	/* see if we succeed */
XX		 /* scan through and update mode lines of all windows */
XX	wp = wheadp;
XX	while (wp != NULL) {
XX	    wp->w_flag |= WFMODE;
XX	    wp = wp->w_wndp;
XX	    }
XX	}
XX    return(s);
XX    }
XX
XXvisittag(f, n)	/* visit a file (via a sorted tag file) */
XX    {
XX    FILE *fp;
XX    char fname[NFILEN];	    /* file that the user wishes to open */
XX    char tname[40];	    /* tag name to search for */
XX    char sstr[128];	    /* search string */
XX    char istr[128],*ptr;    /* input string */
XX    register WINDOW *wp;    /* scan for windows that need updating */
XX    register LINE *dotp;
XX    register int   doto,i;
XX
XX    /* save the current position */
XX    dotp = curwp->w_dotp;
XX    doto = curwp->w_doto;
XX
XX    /* now get the name of the tag */
XX    while (inword() == FALSE)
XX	if (forwchar(FALSE,1) == FALSE) return(FALSE);
XX    i = 0;
XX    while (inword() == TRUE || lgetc(curwp->w_dotp,curwp->w_doto) == '-') {
XX	tname[i++] = lgetc(curwp->w_dotp,curwp->w_doto);
XX	if (forwchar(FALSE,1) == FALSE) return(FALSE);
XX	}
XX    tname[i] = '\000';
XX    /* restore the buffer position */
XX    curwp->w_dotp = dotp;
XX    curwp->w_doto = doto;
XX    if (i == 0) return(FALSE);
XX
XX    /* now open the tags file */
XX    if ((fp = fopen("tags","r")) == NULL) {
XX	mlwrite("No tags file found");
XX	return(FALSE);
XX	}
XX
XX    /* now search for the tag in the file */
XX    fname[0] = '\000';
XX    ptr = &istr[0];
XX    while (fgets(ptr,127,fp) != NULL) {
XX	if (*ptr == tname[0] && strncmp(ptr,tname,i) == 0) {
XX	    ptr += i;
XX	    sscanf(ptr," %s %127c",fname,sstr);
XX	    break;
XX	    }
XX	}
XX    fclose(fp);
XX    if (fname[0] == '\000') {
XX	mlwrite("Tag not found in tag file");
XX	return(FALSE);
XX	}
XX
XX    /* put the window up */
XX    if ((wp = wpopup()) != NULL) {
XX	curwp = wp;
XX	curbp = wp->w_bufp;
XX	}
XX
XX    /* read the file in */
XX    if (! getfile(fname, FALSE)) return(FALSE);
XX
XX    /* scan through and update mode lines of all windows */
XX    wp = wheadp;
XX    while (wp != NULL) {
XX	wp->w_flag |= WFMODE;
XX	wp = wp->w_wndp;
XX	}
XX
XX    /* get rid of delimeters */
XX    ptr = sstr + strlen(sstr);
XX    while (ptr != sstr && *ptr != '/') ptr--;
XX    if (*ptr == '/') *ptr = '\000';
XX    while ((ptr = index(sstr,'*')) != NULL) *ptr = '.';
XX    while ((ptr = index(sstr,'+')) != NULL) *ptr = '.';
XX    while ((ptr = index(sstr,'[')) != NULL) *ptr = '.';
XX    while ((ptr = index(sstr,']')) != NULL) *ptr = '.';
XX    if ((ptr=index(sstr,'/')) != NULL) ptr++;
XX    else			       ptr = sstr;
XX
XX    /* do the scan (leave pointer at beginning of string) */
XX    strcpy(pat,ptr);
XX    gotobob(FALSE,1);
XX    compile_bcode();
XX    return(dosearch(TRUE,1,FALSE));
XX    }
XX
XXgetfile(fname, lockfl)
XX
XXchar fname[];	    /* file name to find */
XXint lockfl;	/* check the file for locks? */
XX
XX    {
XX    register BUFFER *bp;
XX    register WINDOW *wp;
XX    register LINE   *lp;
XX    register int    i;
XX    register int    s;
XX    char bname[NBUFN];	/* buffer name to put file */
XX
XX    for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
XX	if ((bp->b_flag&BFTEMP)==0 && strcmp(bp->b_fname, fname)==0) {
XX	    swbuffer(bp);
XX	    lp = curwp->w_dotp;
XX	    i = curwp->w_ntrows/2;
XX	    while (i-- && lback(lp)!=curbp->b_linep) lp = lback(lp);
XX	    curwp->w_linep = lp;
XX	    curwp->w_flag |= WFMODE|WFHARD;
XX	    mlwrite("[Old buffer]");
XX	    return (TRUE);
XX	    }
XX	}
XX    makename(bname, fname);                 /* New buffer name. */
XX    while ((bp=bfind(bname, FALSE, 0)) != NULL) {
XX	s = mlreply("Buffer name: ", bname, NBUFN);
XX	if (s == ABORT)                 /* ^G to just quit */
XX		 return (s);
XX	if (s == FALSE) {               /* CR to clobber it */
XX		 makename(bname, fname);
XX	    break;
XX	    }
XX	}
XX    if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
XX	mlwrite("Cannot create buffer");
XX	return (FALSE);
XX	}
XX    if (--curbp->b_nwnd == 0) {             /* Undisplay. */
XX		 curbp->b_dotp = curwp->w_dotp;
XX	curbp->b_doto = curwp->w_doto;
XX	curbp->b_markp = curwp->w_markp;
XX	curbp->b_marko = curwp->w_marko;
XX	}
XX    curbp = bp;                             /* Switch to it. */
XX    curwp->w_bufp = bp;
XX    curbp->b_nwnd++;
XX    return(readin(fname, lockfl));          /* Read it in. */
XX    }
XX
XX/*
XX * Read file "fname" into the current
XX * buffer, blowing away any text found there. Called
XX * by both the read and find commands. Return the final
XX * status of the read. Also called by the mainline,
XX * to read in a file specified on the command line as
XX * an argument. If the filename ends in a ".c", CMODE is
XX * set for the current buffer.
XX */
XXreadin(fname, lockfl)
XX
XXchar fname[];    /* name of file to read */
XXint lockfl;	/* check for file locks? */
XX
XX    {
XX    register LINE   *lp1;
XX    register LINE   *lp2;
XX    register int    i;
XX    register WINDOW *wp;
XX    register BUFFER *bp;
XX    register int    s;
XX    register int    nbytes;
XX    register int    nline;
XX    register char   *sptr;	/* pointer into filename string */
XX    int	    lflag;	/* any lines longer than allowed? */
XX    char line[NLINE];
XX
XX#if	FILOCK
XX    if (lockfl && lockchk(fname) == ABORT) return(ABORT);
XX#endif
XX    bp = curbp;                             /* Cheap. */
XX    if ((s=bclear(bp)) != TRUE)             /* Might be old. */
XX		 return (s);
XX    bp->b_flag &= ~(BFTEMP|BFCHG);
XX    bp->b_mode |= MDEXACT;	/*default to exact */
XX    if (slowterm) bp->b_mode |= MDSLOW;
XX
XX    sptr = fname + strlen(fname) - 4;
XX    if (strlen(fname) > 1 && 
XX	    *(sptr+2) == '.' && 
XX	    *(sptr+3) == 'c' || *(sptr+3) == 'h') {
XX	tab(FALSE,4);
XX	bp->b_mode |= MDCMOD;
XX	}
XX    else if (strlen(fname) > 3 &&
XX	    (*sptr=='.' && *(sptr+1)=='m' && *(sptr+2)=='o' && *(sptr+3)=='d')
XX	||  (*sptr=='.' && *(sptr+1)=='d' && *(sptr+2)=='e' && *(sptr+3)=='f')
XX	||  (*sptr=='.' && *(sptr+1)=='m' && *(sptr+2)=='m' && *(sptr+3)=='4')
XX	||  (*(sptr+1)=='.' && *(sptr+2)=='m' && *(sptr+3)=='4')) {
XX	tab(FALSE,4);
XX	bp->b_mode |= MDMMOD;
XX	}
XX    else if (strlen(fname) > 3 &&
XX	    (*sptr=='.' && *(sptr+1)=='l' && *(sptr+2)=='s' && *(sptr+3)=='p')
XX	||  (*(sptr+2)=='.' && *(sptr+3)=='l')
XX	||  (*(sptr+1)=='.' && *(sptr+2)=='e' && *(sptr+3)=='l')
XX	||  (*(sptr+1)=='.' && *(sptr+2)=='e' && *(sptr+3)=='m')) {
XX	tab(FALSE,2);
XX	bp->b_mode |= MDLISP;
XX	}
XX    else {
XX	tab(FALSE,0);
XX	bp->b_mode |= MDWRAP;
XX	}
XX
XX    strcpy(bp->b_fname, fname);
XX    if ((s=ffropen(fname)) == FIOERR)       /* Hard file open. */
XX		 goto out;
XX    if (s == FIOFNF) {                      /* File not found. */
XX		 mlwrite("[New file]");
XX	goto out;
XX	}
XX    mlwrite("[Reading file]");
XX    nline = 0;
XX    lflag = FALSE;
XX    while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG) {
XX	if (s == FIOLNG) lflag = TRUE;
XX	nbytes = strlen(line);
XX	if ((lp1=lalloc(nbytes)) == NULL) {
XX	    s = FIOERR;             /* Keep message on the */
XX	    break; /* display. */
XX	    }
XX	lp2 = lback(curbp->b_linep);
XX	lp2->l_fp = lp1;
XX	lp1->l_fp = curbp->b_linep;
XX	lp1->l_bp = lp2;
XX	curbp->b_linep->l_bp = lp1;
XX	for (i=0; i<nbytes; ++i) lputc(lp1, i, line[i]);
XX	++nline;
XX	}
XX    ffclose(); /* Ignore errors. */
XX    if (s == FIOEOF) {                      /* Don't zap message! */
XX		 if (nline == 1)
XX	mlwrite("[Read 1 line]");
XX	else
XX	mlwrite("[Read %d lines]", nline);
XX	}
XX    if (lflag) mlwrite("[Read %d line(s), Long lines wrapped]",nline);
XX    out:
XX    for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
XX	if (wp->w_bufp == curbp) {
XX	    wp->w_linep = lforw(curbp->b_linep);
XX	    wp->w_dotp = lforw(curbp->b_linep);
XX	    wp->w_doto = 0;
XX	    wp->w_markp = NULL;
XX	    wp->w_marko = 0;
XX	    wp->w_flag |= WFMODE|WFHARD;
XX	    }
XX	}
XX    if (s == FIOERR || s == FIOFNF)	/* False if error. */
XX		 return(FALSE);
XX    return (TRUE);
XX    }
XX
XX/*
XX * Take a file name, and from it
XX * fabricate a buffer name. This routine knows
XX * about the syntax of file names on the target system.
XX * I suppose that this information could be put in
XX * a better place than a line of code.
XX */
XXmakename(bname, fname)
XXchar bname[];
XXchar fname[];
XX    {
XX    register char   *cp1;
XX    register char   *cp2;
XX
XX    cp1 = &fname[0];
XX    while (*cp1 != 0) ++cp1;
XX
XX#if AMIGA
XX    while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/') --cp1;
XX#endif
XX#if VMS
XX    while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']') --cp1;
XX#endif
XX#if ULTRIX
XX    while (cp1!=&fname[0] && cp1[-1]!='/') --cp1;
XX#endif
XX    cp2 = &bname[0];
XX    while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';') *cp2++ = *cp1++;
XX    *cp2 = 0;
XX    }
XX
XX/*
XX * Ask for a file name, and write the
XX * contents of the current buffer to that file.
XX * Update the remembered file name and clear the
XX * buffer changed flag. This handling of file names
XX * is different from the earlier versions, and
XX * is more compatable with Gosling EMACS than
XX * with ITS EMACS. Bound to "C-X C-W".
XX */
XXfilewrite(f, n)
XX    {
XX    register WINDOW *wp;
XX    register int    s;
XX    char fname[NFILEN];
XX
XX    if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE) return (s);
XX    if ((s=writeout(fname)) == TRUE) {
XX	strcpy(curbp->b_fname, fname);
XX	curbp->b_flag &= ~BFCHG;
XX	wp = wheadp;                    /* Update mode lines. */
XX	while (wp != NULL) {
XX	    if (wp->w_bufp == curbp) wp->w_flag |= WFMODE;
XX	    wp = wp->w_wndp;
XX	    }
XX	}
XX    return (s);
XX    }
XX
XX/*
XX * Save the contents of the current
XX * buffer in its associatd file. No nothing
XX * if nothing has changed (this may be a bug, not a
XX * feature). Error if there is no remembered file
XX * name for the buffer. Bound to "C-X C-S". May
XX * get called by "C-Z".
XX */
XXfilesave(f, n)
XX    {
XX    register WINDOW *wp;
XX    register int    s;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if ((curbp->b_flag&BFCHG) == 0)         /* Return, no changes. */
XX		 return (TRUE);
XX    if (curbp->b_fname[0] == 0) {           /* Must have a name. */
XX		 mlwrite("No file name");
XX	return (FALSE);
XX	}
XX    if ((s=writeout(curbp->b_fname)) == TRUE) {
XX	curbp->b_flag &= ~BFCHG;
XX	wp = wheadp;                    /* Update mode lines. */
XX	while (wp != NULL) {
XX	    if (wp->w_bufp == curbp) wp->w_flag |= WFMODE;
XX	    wp = wp->w_wndp;
XX	    }
XX	}
XX    return (s);
XX    }
XX
XX/*
XX * This function performs the details of file
XX * writing. Uses the file management routines in the
XX * "fileio.c" package. The number of lines written is
XX * displayed. Sadly, it looks inside a LINE; provide
XX * a macro for this. Most of the grief is error
XX * checking of some sort.
XX */
XXwriteout(fn)
XXchar *fn;
XX    {
XX    register int    s;
XX    register LINE   *lp;
XX    register int    nline;
XX
XX    if ((s=ffwopen(fn)) != FIOSUC)          /* Open writes message. */
XX		 return (FALSE);
XX    mlwrite("[Writing..]");	    /* tell us were writing */
XX    lp = lforw(curbp->b_linep);             /* First line. */
XX    nline = 0;                              /* Number of lines. */
XX    while (lp != curbp->b_linep) {
XX	if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC) break;
XX	++nline;
XX	lp = lforw(lp);
XX	}
XX    if (s == FIOSUC) {                      /* No write error. */
XX		 s = ffclose();
XX	if (s == FIOSUC) {              /* No close error. */
XX		 if (nline == 1)
XX	    mlwrite("[Wrote 1 line]");
XX	    else
XX	    mlwrite("[Wrote %d lines]", nline);
XX	    }
XX	}
XX    else /* Ignore close error */
XX    ffclose(); /* if a write error. */
XX    if (s != FIOSUC)                        /* Some sort of error. */
XX		 return (FALSE);
XX    return (TRUE);
XX    }
XX
XX/*
XX * The command allows the user
XX * to modify the file name associated with
XX * the current buffer. It is like the "f" command
XX * in UNIX "ed". The operation is simple; just zap
XX * the name in the BUFFER structure, and mark the windows
XX * as needing an update. You can type a blank line at the
XX * prompt if you wish.
XX */
XXfilename(f, n)
XX    {
XX    register WINDOW *wp;
XX    register int    s;
XX    char fname[NFILEN];
XX
XX    if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT) return (s);
XX    if (s == FALSE) strcpy(curbp->b_fname, "");
XX    else
XX    strcpy(curbp->b_fname, fname);
XX    wp = wheadp;                            /* Update mode lines. */
XX    while (wp != NULL) {
XX	if (wp->w_bufp == curbp) wp->w_flag |= WFMODE;
XX	wp = wp->w_wndp;
XX	}
XX    curbp->b_mode &= ~MDVIEW;	/* no longer read only mode */
XX    return (TRUE);
XX    }
XX
XX/*
XX * Insert file "fname" into the current
XX * buffer, Called by insert file command. Return the final
XX * status of the read.
XX */
XXifile(fname)
XXchar fname[];
XX    {
XX    register LINE   *lp0;
XX    register LINE   *lp1;
XX    register LINE   *lp2;
XX    register int    i;
XX    register WINDOW *wp;
XX    register BUFFER *bp;
XX    register int    s;
XX    register int    nbytes;
XX    register int    nline;
XX    int	    lflag;	/* any lines longer than allowed? */
XX    char line[NLINE];
XX
XX    bp = curbp;                             /* Cheap. */
XX    bp->b_flag |= BFCHG;	    /* we have changed */
XX    bp->b_flag &= ~BFTEMP;	    /* and are not temporary*/
XX    if ((s=ffropen(fname)) == FIOERR)       /* Hard file open. */
XX		 goto out;
XX    if (s == FIOFNF) {                      /* File not found. */
XX		 mlwrite("[No such file]");
XX	return(FALSE);
XX	}
XX    mlwrite("[Inserting file]");
XX
XX    /* back up a line and save the mark here */
XX    curwp->w_dotp = lback(curwp->w_dotp);
XX    curwp->w_doto = 0;
XX    curwp->w_markp = curwp->w_dotp;
XX    curwp->w_marko = 0;
XX
XX    nline = 0;
XX    lflag = FALSE;
XX    while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG) {
XX	if (s == FIOLNG) lflag = TRUE;
XX	nbytes = strlen(line);
XX	if ((lp1=lalloc(nbytes)) == NULL) {
XX	    s = FIOERR;             /* Keep message on the */
XX	    break; /* display. */
XX	    }
XX	lp0 = curwp->w_dotp;	/* line previous to insert */
XX	lp2 = lp0->l_fp;    /* line after insert */
XX
XX	/* re-link new line between lp0 and lp2 */
XX	lp2->l_bp = lp1;
XX	lp0->l_fp = lp1;
XX	lp1->l_bp = lp0;
XX	lp1->l_fp = lp2;
XX
XX	/* and advance and write out the current line */
XX	curwp->w_dotp = lp1;
XX	for (i=0; i<nbytes; ++i) lputc(lp1, i, line[i]);
XX	++nline;
XX	}
XX    ffclose(); /* Ignore errors. */
XX    curwp->w_markp = lforw(curwp->w_markp);
XX    if (s == FIOEOF) {                      /* Don't zap message! */
XX		 if (nline == 1)
XX	mlwrite("[Inserted 1 line]");
XX	else
XX	mlwrite("[Inserted %d lines]", nline);
XX	}
XX    if (lflag) mlwrite("[Inserted %d line(s), Long lines wrapped]",nline);
XX    out:
XX    /* advance to the next line and mark the window for changes */
XX    curwp->w_dotp = lforw(curwp->w_dotp);
XX    curwp->w_flag |= WFHARD;
XX
XX    /* copy window parameters back to the buffer structure */
XX    curbp->b_dotp = curwp->w_dotp;
XX    curbp->b_doto = curwp->w_doto;
XX    curbp->b_markp = curwp->w_markp;
XX    curbp->b_marko = curwp->w_marko;
XX
XX    if (s == FIOERR)                        /* False if error. */
XX		 return (FALSE);
XX    return (TRUE);
XX    }
XX
SHAR_EOF
if test 16669 -ne "`wc -c file.c`"
then
echo shar: error transmitting file.c '(should have been 16669 characters)'
fi
#	End of shell archive
exit 0

wecker@cookie.dec.com.UUCP (02/21/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	region.c
#	search.c
#	spawn.c
#	tcap.c
#	termio.c
#	vmsvt.c
#	window.c
#	word.c
# This archive created: Fri Feb 20 17:44:37 1987
echo shar: extracting region.c
sed 's/^XX//' << \SHAR_EOF > region.c
XX/*
XX * The routines in this file
XX * deal with the region, that magic space
XX * between "." and mark. Some functions are
XX * commands. Some functions are just for
XX * internal use.
XX */
XX#include <stdio.h>
XX#include	"estruct.h"
XX#include "edef.h"
XX
XX/*
XX * Kill the region. Ask "getregion"
XX * to figure out the bounds of the region.
XX * Move "." to the start, and kill the characters.
XX * Bound to "C-W".
XX */
XXkillregion(f, n)
XX    {
XX    register int    s;
XX    REGION region;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if ((s=getregion(&region)) != TRUE) return (s);
XX    if ((lastflag&CFKILL) == 0)             /* This is a kill type */
XX		 kdelete();                      /* command, so do magic */
XX    thisflag |= CFKILL;                     /* kill buffer stuff. */
XX    curwp->w_dotp = region.r_linep;
XX    curwp->w_doto = region.r_offset;
XX    return (ldelete(region.r_size, TRUE));
XX    }
XX
XX/*
XX * Copy all of the characters in the
XX * region to the kill buffer. Don't move dot
XX * at all. This is a bit like a kill region followed
XX * by a yank. Bound to "M-W".
XX */
XXcopyregion(f, n)
XX    {
XX    register LINE   *linep;
XX    register int    loffs;
XX    register int    s;
XX    REGION region;
XX
XX    if ((s=getregion(&region)) != TRUE) return (s);
XX    if ((lastflag&CFKILL) == 0)             /* Kill type command. */
XX		 kdelete();
XX    thisflag |= CFKILL;
XX    linep = region.r_linep;                 /* Current line. */
XX    loffs = region.r_offset;                /* Current offset. */
XX    while (region.r_size--) {
XX	if (loffs == llength(linep)) {  /* End of line. */
XX		 if ((s=kinsert('\n')) != TRUE)
XX	    return (s);
XX	    linep = lforw(linep);
XX	    loffs = 0;
XX	    }
XX	else {                        /* Middle of line. */
XX	    if ((s=kinsert(lgetc(linep, loffs))) != TRUE) return (s);
XX	    ++loffs;
XX	    }
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * Lower case region. Zap all of the upper
XX * case characters in the region to lower case. Use
XX * the region code to set the limits. Scan the buffer,
XX * doing the changes. Call "lchange" to ensure that
XX * redisplay is done in all buffers. Bound to
XX * "C-X C-L".
XX */
XXlowerregion(f, n)
XX    {
XX    register LINE   *linep;
XX    register int    loffs;
XX    register int    c;
XX    register int    s;
XX    REGION region;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if ((s=getregion(&region)) != TRUE) return (s);
XX    lchange(WFHARD);
XX    linep = region.r_linep;
XX    loffs = region.r_offset;
XX    while (region.r_size--) {
XX	if (loffs == llength(linep)) {
XX	    linep = lforw(linep);
XX	    loffs = 0;
XX	    }
XX	else {
XX	    c = lgetc(linep, loffs);
XX	    if (c>='A' && c<='Z') lputc(linep, loffs, c+'a'-'A');
XX	    ++loffs;
XX	    }
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * Upper case region. Zap all of the lower
XX * case characters in the region to upper case. Use
XX * the region code to set the limits. Scan the buffer,
XX * doing the changes. Call "lchange" to ensure that
XX * redisplay is done in all buffers. Bound to
XX * "C-X C-L".
XX */
XXupperregion(f, n)
XX    {
XX    register LINE   *linep;
XX    register int    loffs;
XX    register int    c;
XX    register int    s;
XX    REGION region;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if ((s=getregion(&region)) != TRUE) return (s);
XX    lchange(WFHARD);
XX    linep = region.r_linep;
XX    loffs = region.r_offset;
XX    while (region.r_size--) {
XX	if (loffs == llength(linep)) {
XX	    linep = lforw(linep);
XX	    loffs = 0;
XX	    }
XX	else {
XX	    c = lgetc(linep, loffs);
XX	    if (c>='a' && c<='z') lputc(linep, loffs, c-'a'+'A');
XX	    ++loffs;
XX	    }
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * This routine figures out the
XX * bounds of the region in the current window, and
XX * fills in the fields of the "REGION" structure pointed
XX * to by "rp". Because the dot and mark are usually very
XX * close together, we scan outward from dot looking for
XX * mark. This should save time. Return a standard code.
XX * Callers of this routine should be prepared to get
XX * an "ABORT" status; we might make this have the
XX * conform thing later.
XX */
XXgetregion(rp)
XXregister REGION *rp;
XX    {
XX    register LINE   *flp;
XX    register LINE   *blp;
XX    register int    fsize;
XX    register int    bsize;
XX
XX    if (curwp->w_markp == NULL) {
XX	mlwrite("No mark set in this window");
XX	return (FALSE);
XX	}
XX    if (curwp->w_dotp == curwp->w_markp) {
XX	rp->r_linep = curwp->w_dotp;
XX	if (curwp->w_doto < curwp->w_marko) {
XX	    rp->r_offset = curwp->w_doto;
XX	    rp->r_size = curwp->w_marko-curwp->w_doto;
XX	    }
XX	else {
XX	    rp->r_offset = curwp->w_marko;
XX	    rp->r_size = curwp->w_doto-curwp->w_marko;
XX	    }
XX	return (TRUE);
XX	}
XX    blp = curwp->w_dotp;
XX    bsize = curwp->w_doto;
XX    flp = curwp->w_dotp;
XX    fsize = llength(flp)-curwp->w_doto+1;
XX    while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
XX	if (flp != curbp->b_linep) {
XX	    flp = lforw(flp);
XX	    if (flp == curwp->w_markp) {
XX		rp->r_linep = curwp->w_dotp;
XX		rp->r_offset = curwp->w_doto;
XX		rp->r_size = fsize + curwp->w_marko;
XX		return (TRUE);
XX		}
XX	    fsize += llength(flp)+1;
XX	    }
XX	if (lback(blp) != curbp->b_linep) {
XX	    blp = lback(blp);
XX	    bsize += llength(blp)+1;
XX	    if (blp == curwp->w_markp) {
XX		rp->r_linep = blp;
XX		rp->r_offset = curwp->w_marko;
XX		rp->r_size = bsize - curwp->w_marko;
XX		return (TRUE);
XX		}
XX	    }
XX	}
XX    mlwrite("Bug: lost mark");
XX    return (FALSE);
XX    }
XX
SHAR_EOF
if test 5463 -ne "`wc -c region.c`"
then
echo shar: error transmitting region.c '(should have been 5463 characters)'
fi
echo shar: extracting search.c
sed 's/^XX//' << \SHAR_EOF > search.c
XX/*
XX * The functions in this file implement commands that search in the forward
XX * and backward directions with regular expressions.
XX */
XX
XX#include	<stdio.h>
XX#include	"estruct.h"
XX#include	"edef.h"
XX
XX#if ULTRIX
XX#include	<sys/types.h>
XX#include	<sys/timeb.h>
XX#define		FLASHTIME   200
XX#endif
XX
XX#if VMS
XX#include	<types.h>
XX#include	<timeb.h>
XX#define		FLASHTIME   400
XX#endif
XX
XX/* string search input parameters */
XX
XX#define	PTBEG	1 /* leave the point at the begining on search */
XX#define	PTEND	2 /* leave the point at the end on search */
XX
XX/* byte codes for matching */
XX#define M_NULL	0   /* no op code */
XX#define M_BEGIN	1   /* begin a sub expression */
XX#define M_END	2   /* end a sub expression */
XX#define M_BOL	3   /* match BOL */
XX#define M_EOL	4   /* match EOL */
XX#define M_CHR	5   /* match a range of characters */
XX#define M_ANY	6   /* match any chars inside of brackets */
XX#define M_NONE	7   /* don't match any chars inside of brackets */
XX#define M_DOT	8   /* match one of any character */
XX
XX#define R_NONE  0   /* never try to match */
XX#define R_ONCE	1   /* match once */
XX#define R_ZERO	2   /* match zero or more times */
XX#define R_MANY	3   /* match at least once (and maybe more) */
XX
XXstruct {	/* byte code control for pattern */
XX    unsigned char
XX    code,	/* M_ code */
XX    pos1,	/* pointer into pat */
XX    pos2,	/* pointer into par */
XX    rpt;	/* R_ repeat type */
XX    }
XXbcode[100];
XX
XX
XXchar substr[10][128];	/* successful substring matches */
XXchar outstr[128];   /* scratch output buffer */
XXint inexact;	    /* are we doing inexact matches? */
XX
XXcompile_bcode() {
XX    short pptr,	/* pattern pointer */
XX    bptr, /* byte code pointer */
XX    mptr, /* match pointer */
XX    i,j,k; /* scratch loop counters */
XX
XX    bptr = 0; mptr = 0;
XX    bcode[bptr].code = M_BEGIN;
XX    bcode[bptr].pos1 = mptr++;
XX    bcode[bptr++].rpt = R_ONCE;
XX
XX    for (pptr = 0; pat[pptr] != 0; pptr++) {
XX	bcode[bptr].code = M_NULL;
XX	bcode[bptr].pos1 = 0;
XX	bcode[bptr].pos2 = 0;
XX	bcode[bptr].rpt	    = R_ONCE;
XX	switch (pat[pptr]) {
XX	    case '^':
XX	    if (pptr != 0) goto dochr;
XX	    bcode[bptr++].code = M_BOL;
XX	    break;
XX
XX	    case '$':
XX	    if (pat[pptr+1] != 0) goto dochr;
XX	    bcode[bptr++].code = M_EOL;
XX	    break;
XX
XX	    case '\\':
XX	    if (pat[++pptr] != '(' && pat[pptr] != ')') goto dochr;
XX	    if (pat[pptr] == '(') {
XX		bcode[bptr].code = M_BEGIN;
XX		bcode[bptr++].pos1 = mptr++;
XX		}
XX	    else {
XX		j = 1;
XX		for (i = bptr-1 ; i >= 0 ; i--) {
XX		    if (bcode[i].code == M_END) j++;
XX		    else if (bcode[i].code == M_BEGIN && --j == 0) break;
XX		    }
XX		if (j != 0) {
XX		    mlwrite("Bad matching of \( and \) in pattern");
XX		    return(FALSE);
XX		    }
XX		if (pat[pptr+1] == '*')      {bcode[i].rpt = R_ZERO; pptr++;}
XX		else if (pat[pptr+1] == '+') {bcode[i].rpt = R_MANY; pptr++;}
XX		bcode[bptr].code = M_END;
XX		bcode[bptr].pos1 = bcode[i].pos1;
XX		bcode[bptr].pos2 = i;
XX		bcode[bptr].rpt = bcode[i].rpt;
XX		bcode[i].pos2 = bptr++;
XX		}
XX	    break;
XX
XX	    case '[':
XX	    if (pat[pptr+1] == '^') {bcode[bptr].code = M_NONE; pptr++;}
XX	    else	        bcode[bptr].code = M_ANY;
XX	    if (pat[++pptr] == ']') {
XX		mlwrite("Cannot specify null []");
XX		return(FALSE);
XX		}
XX	    bcode[bptr].pos1 = pptr;
XX	    while (pat[++pptr] != ']' && pat[pptr] != 0) {
XX		if (pat[pptr] == '\\') ++pptr;
XX		}
XX	    if (pat[pptr] == 0) {
XX		mlwrite("No closing ] found");
XX		return(FALSE);
XX		}
XX	    bcode[bptr].pos2 = pptr - 1;
XX	    if (pat[pptr+1] == '*')      {bcode[bptr].rpt = R_ZERO; pptr++;}
XX	    else if (pat[pptr+1] == '+') {bcode[bptr].rpt = R_MANY; pptr++;}
XX	    bptr++;
XX	    break;
XX
XX	    case '.':
XX	    bcode[bptr].code = M_DOT;
XX	    if (pat[pptr+1] == '*') {bcode[bptr].rpt = R_ZERO; pptr++;}
XX	    else if (pat[pptr+1] == '+') {bcode[bptr].rpt = R_MANY; pptr++;}
XX	    bptr++;
XX	    break;
XX
XX	    default:
XX	    dochr:
XX	    bcode[bptr].code = M_CHR;
XX	    bcode[bptr].pos1 = pptr;
XX	    while ( pat[pptr+1] !=  0  &&
XX		    pat[pptr+1] != '\\' &&
XX		    pat[pptr+1] != '*'  &&
XX		    pat[pptr+1] != '+'  &&
XX		    pat[pptr+1] != '['  &&
XX		    pat[pptr+1] != '.'  &&
XX		    pat[pptr+1] != '$' ) pptr++;
XX	    if (pat[pptr+1] == '*' || pat[pptr+1] == '+') {
XX
XX		if (bcode[bptr].pos1 == pptr) {
XX		    bcode[bptr].pos2 = pptr;
XX
XX		    if (pat[++pptr] == '*') bcode[bptr].rpt = R_ZERO;
XX		    else		    bcode[bptr].rpt = R_MANY;
XX		    }
XX		else bcode[bptr].pos2 = --pptr;
XX		}
XX	    else bcode[bptr].pos2 = pptr;
XX	    bptr++;
XX	    break;
XX	    }
XX	}
XX    bcode[bptr].code = M_END;
XX    bcode[bptr].pos1 = bcode[0].pos1;
XX    bcode[bptr].pos2 = 0;
XX    bcode[bptr].rpt = bcode[0].rpt;
XX    bcode[0].pos2 = bptr++;
XX
XX    return(TRUE);
XX    }
XX
XXmatch(lp,so,eo)
XXLINE	*lp;
XXint so,*eo;
XX    {
XX    short i;
XX
XX    switch(bcode[1].code) {
XX	case M_BOL:
XX	if (so != 0) return(FALSE);
XX	break;
XX
XX	case M_CHR:
XX	if (!eq(lgetc(lp,so),pat[bcode[1].pos1])) return(FALSE);
XX	break;
XX	}
XX
XX    for (i = 0; i < 10; i++) substr[i][0] = '\000';
XX    return(do_begin(0,lp,so,eo));
XX    }
XX
XXdo_begin(bptr,lp,so,eo)
XXLINE	*lp;
XXint bptr,so,*eo;
XX    {
XX    short i,j,mptr,rpt,start,retval,prevo,curro,keepgoing,nxtcod;
XX    int nexto,scro;
XX
XX    start = bptr; prevo = so; curro = so;
XX    rpt = bcode[start].rpt;
XX    if (rpt == R_ZERO) retval = TRUE; else retval = FALSE;
XX
XX    while (TRUE) {
XX	switch (bcode[++bptr].code) {
XX	    case M_BEGIN:
XX	    if (!do_begin(bptr,lp,curro,&nexto)) {*eo = prevo; return(retval);}
XX	    bptr = bcode[bptr].pos2;
XX	    prevo = curro;
XX	    curro = nexto;
XX	    break;
XX
XX	    case M_END:
XX	    mptr = bcode[start].pos1;
XX	    j = strlen(substr[mptr]);
XX	    for (i = so; i < curro; i++) {
XX		substr[mptr][j++] = lgetc(lp,i);
XX		}
XX	    substr[mptr][j] = 0;
XX	    if (rpt == R_ONCE) {*eo = curro; return(TRUE); }
XX	    retval = TRUE;
XX	    bptr = start;
XX	    prevo = curro;
XX	    break;
XX
XX	    case M_BOL:
XX	    if (curro != 0) { *eo = prevo; return(retval); }
XX	    break;
XX
XX	    case M_EOL:
XX	    if (curro < llength(lp)) { *eo = prevo; return(retval); }
XX	    break;
XX
XX	    case M_DOT:
XX	    if (curro >= llength(lp)) {
XX		if (bcode[bptr].rpt == R_ZERO) {curro = llength(lp); break;}
XX		*eo = prevo;
XX		return(retval);
XX		}
XX	    if (bcode[bptr].rpt == R_ONCE) nexto = curro + 1;
XX	    else {
XX		if (bcode[bptr].rpt == R_MANY) nexto = curro+1;
XX		else			       nexto = curro;
XX		keepgoing = TRUE;
XX		i = 1;
XX		while (bptr+i < bcode[0].pos2 &&
XX		       bcode[bptr+i].code == M_END) i++;
XX		while (nexto < llength(lp) && keepgoing) {
XX		    switch (bcode[bptr+i].code) {
XX			case M_BEGIN:
XX			if (do_begin(bptr+i,lp,nexto,&scro)) keepgoing = FALSE;
XX			break;
XX
XX			case M_EOL:
XX			case M_END:
XX			nexto = llength(lp);
XX			keepgoing = FALSE;
XX			break;
XX
XX			case M_DOT:
XX			keepgoing = FALSE;
XX			break;
XX
XX			case M_CHR:
XX			if (do_chr(bptr+i,lp,nexto,&scro)) keepgoing = FALSE;
XX			break;
XX
XX			case M_ANY:
XX			if (do_any(bptr+i,lp,nexto,&scro,TRUE)) keepgoing = FALSE;
XX			break;
XX
XX			case M_NONE:
XX			if (do_any(bptr+i,lp,nexto,&scro,FALSE)) keepgoing = FALSE;
XX			break;
XX
XX			default:
XX			break;
XX			}
XX		    if (keepgoing) nexto++;
XX		    }
XX		}
XX	    prevo = curro;
XX	    curro = nexto;
XX	    break;
XX
XX	    case M_CHR:
XX	    if (!do_chr(bptr,lp,curro,&nexto)) {*eo = prevo; return(retval); }
XX	    prevo = curro;
XX	    curro = nexto;
XX	    break;
XX
XX	    case M_ANY:
XX	    if (!do_any(bptr,lp,curro,&nexto,TRUE)) {
XX		*eo = prevo;
XX		return(retval);
XX		}
XX	    prevo = curro;
XX	    curro = nexto;
XX	    break;
XX
XX	    case M_NONE:
XX	    if (!do_any(bptr,lp,curro,&nexto,FALSE)) {
XX		*eo = prevo;
XX		return(retval);
XX		}
XX	    prevo = curro;
XX	    curro = nexto;
XX	    break;
XX	    }
XX	}
XX    }
XX
XXdo_chr(bptr,lp,so,eo)
XXLINE	*lp;
XXint bptr,so,*eo;
XX    {
XX    short rpt,curro,prevo,retval,i;
XX
XX    rpt = bcode[bptr].rpt; prevo = so; curro = so;
XX    if (rpt == R_ZERO) retval = TRUE; else retval = FALSE;
XX
XX    while (TRUE) {
XX	for (i = bcode[bptr].pos1 ; i <= bcode[bptr].pos2 ; i++) {
XX	    if (curro >= llength(lp) || !eq(lgetc(lp,curro++),pat[i])) {*eo = prevo; return(retval);}
XX	    }
XX	if (rpt == R_ONCE) {*eo = curro; return(TRUE); }
XX	retval = TRUE;
XX	prevo = curro;
XX	}
XX    }
XX
XXdo_any(bptr,lp,so,eo,DOANY)
XXLINE	*lp;
XXint bptr,so,*eo,DOANY;
XX    {
XX    char c1,c2,c3;
XX    short rpt,curro,prevo,retval,i;
XX
XX    rpt = bcode[bptr].rpt; prevo = so; curro = so;
XX    if (rpt == R_ZERO) retval = TRUE; else retval = FALSE;
XX
XX    while (TRUE) {
XX	if (curro >= llength(lp)) {*eo = llength(lp); return(retval); }
XX	c3 = lgetc(lp,curro++);
XX	if (inexact && c3 >= 'a' && c3 <= 'z') c3 -= 0x20;
XX
XX	for (i = bcode[bptr].pos1; i <= bcode[bptr].pos2; i++) {
XX	    if (pat[i] == '\\') c1 = pat[++i]; else c1 = pat[i];
XX	    c2 = c1;
XX	    if (pat[i+1] == '-' && pat[i+2] != 0) {
XX		i += 2;
XX		if (pat[i] == '\\') c2 = pat[++i]; else c2 = pat[i];
XX		}
XX	    if (inexact) {
XX		if (c1 >= 'a' && c1 <= 'z') c1 -= 0x20;
XX		if (c2 >= 'a' && c2 <= 'z') c2 -= 0x20;
XX		}
XX	    if (c3 >= c1 && c3 <= c2) {
XX		if (rpt == R_ONCE) {*eo = curro; return(DOANY); }
XX		if (DOANY) {prevo  = curro; retval = TRUE; break; }
XX		*eo = prevo; return(retval);
XX		}
XX	    }
XX	if (DOANY) {
XX	    if (i > bcode[bptr].pos2) {
XX		*eo = prevo;
XX		return(retval);
XX		}
XX	    }
XX	else {
XX	    if (rpt == R_ONCE) {*eo = curro; return(TRUE); }
XX	    prevo = curro;
XX	    retval = TRUE;
XX	    }
XX	}
XX    }
XX
XXforwsearch(f, n)
XX    {
XX    register int status;
XX
XX    /* resolve the repeat count */
XX    if (n == 0) n = 1;
XX    if (n < 1)  return(backsearch(f, -n));
XX
XX    /* ask the user for the text of a pattern */
XX    if ((status = readpattern(pat,"Search",'\006')) != TRUE) return(status);
XX
XX    /* search for the pattern */
XX    while (n-- > 0) {
XX	if ((status = dosearch(TRUE,PTEND,TRUE)) == FALSE) break;
XX	}
XX    if (status == FALSE) mlwrite("Not found"); else mlerase();
XX    return(status);
XX    }
XX
XXbacksearch(f, n)
XX    {
XX    register int status;
XX
XX    /* resolve the repeat count */
XX    if (n == 0) n = 1;
XX    if (n < 1)  return(forwsearch(f, -n));
XX
XX    /* ask the user for the text of a pattern */
XX    if ((status = readpattern(pat,"Reverse Search",'\022')) != TRUE) return(status);
XX
XX    /* search for the pattern */
XX    while (n-- > 0) {
XX	if ((status = dosearch(FALSE,PTBEG,TRUE)) == FALSE) break;
XX	}
XX    if (status == FALSE) mlwrite("Not found"); else mlerase();
XX    return(status);
XX    }
XX
XXdosearch(forward,where,interactive)
XX    {
XX    register LINE *clp;
XX    register int cbo,i,j;
XX    LINE *slp;
XX    int tbo,sbo,doslow;
XX
XX    if ((curwp->w_bufp->b_mode & MDEXACT) == 0) inexact = TRUE;
XX    else inexact = FALSE;
XX
XX    /* make local copies of the starting location */
XX    clp = curwp->w_dotp;
XX    cbo = curwp->w_doto;
XX    if (curwp->w_bufp->b_mode & MDSLOW) doslow = TRUE; else doslow = FALSE;
XX    slp = clp;
XX    sbo = cbo;
XX
XX    for (;;) {
XX	if (!forward) cbo--;
XX	/* if we are at the begining of the line, wrap back around */
XX	if (cbo < 0) {
XX	    clp = lback(clp);
XX	    if (clp == curbp->b_linep) {
XX		mlwrite("Not found");
XX		return (FALSE);
XX		}
XX	    cbo = llength(clp);
XX	    }
XX	if (cbo > llength(clp)) {
XX	    clp = lforw(clp);
XX
XX	    if (clp == curbp->b_linep) {
XX		mlwrite("Not found");
XX		return (FALSE);
XX		}
XX	    cbo = 0;
XX	    }
XX	if (match(clp,cbo,&tbo)) {
XX	    /* A Match!  reset the current cursor */
XX	    if (interactive && doslow) {
XX		j = 0;
XX		for (i = 0; i <= llength(clp); i++) {
XX		    if (i == cbo || i == tbo) {
XX			outstr[j++] = '\033';
XX			outstr[j++] = '[';
XX			if (i == cbo && i != tbo) outstr[j++] = '7';
XX			outstr[j++] = 'm';
XX			}
XX		    if (i < llength(clp)) outstr[j++] = lgetc(clp,i);
XX		    }
XX		outstr[j] = 0;
XX		mlerase(); mlputs(outstr); update(); mpresf = TRUE;
XX		switch (getkey()) {
XX		    case CTRL|'F':
XX		    forward = TRUE;
XX		    where = PTEND;
XX		    break;
XX
XX		    case CTRL|'R':
XX		    forward = FALSE;
XX		    where = PTBEG;
XX		    break;
XX
XX		    case CTRL|'G':
XX		    return(FALSE);
XX
XX		    default:
XX		    mlerase();
XX		    goto movecursor;
XX		    }
XX		}
XX	    else {
XX
XX		movecursor:
XX		curwp->w_dotp = clp;
XX		if (where == PTBEG) curwp->w_doto  = cbo;
XX		else curwp->w_doto  = tbo;
XX		curwp->w_flag |= WFMOVE;
XX		break;
XX		}
XX	    }
XX	if (forward) cbo++;
XX	}
XX    return(TRUE);
XX    }
XX
XX/*
XX * Compare two characters. The "bc" comes from the buffer. It has it's case
XX * folded out. The "pc" is from the pattern.
XX */
XXeq(bc, pc)
XXint bc;
XXint pc;
XX    {
XX    if (inexact) {
XX		if (bc>='a' && bc<='z')	bc -= 0x20;
XX	if (pc>='a' && pc<='z')	pc -= 0x20;
XX	}
XX    if (bc == pc) return (TRUE);
XX    return (FALSE);
XX    }
XX
XX/*
XX * Read a pattern. Stash it in the external variable "pat". The "pat" is not
XX * updated if the user types in an empty line. If the user typed an empty line,
XX * and there is no old pattern, it is an error. Display the old pattern, in the
XX * style of Jeff Lomicka. There is some do-it-yourself control expansion.
XX * change to using supplied char to delemit the end-of-pattern.
XX */
XXreadpattern(result,prompt,c)
XXchar *result,*prompt,c;
XX    {
XX    register int s;
XX    char tpat[NPAT+20],c1[2];
XX
XX    strcpy(tpat, prompt);   /* copy prompt to output string */
XX    strcat(tpat, " {");	    /* build new prompt string */
XX	expandp(&result[0], &tpat[strlen(tpat)], NPAT/2);   /* add old pattern */
XX	strcat(tpat, "} [");
XX    c1[0] = c; c1[1] = 0;
XX    expandp(&c1[0], &tpat[strlen(tpat)], NPAT/2);
XX    strcat(tpat,"]: ");
XX
XX    s = mlreplyt(tpat, tpat, NPAT, c);	/* Read pattern */
XX
XX    if (s == TRUE) {	/* Specified */
XX		 strcpy(result, tpat);
XX	if (result == pat) compile_bcode(); /* compile it */
XX		 }
XX    else if (s == FALSE && result[0] != 0)  /* CR, but old one */
XX    s = TRUE;
XX
XX    return (s);
XX    }
XX
XXsreplace(f, n)	/*  Search and replace (ESC-R) */
XXint f;	    /* default flag */
XXint n;	    /* # of repetitions wanted */
XX    {
XX    return(replaces(FALSE, f, n));
XX    }
XX
XXqreplace(f, n)	/*  search and replace with query (ESC-CTRL-R) */
XXint f;	    /* default flag */
XXint n;	    /* # of repetitions wanted */
XX
XX    {
XX    return(replaces(TRUE, f, n));
XX    }
XX
XX/* replaces:	search for a string and replace it with another
XX    string. query might be enabled (according to kind). */
XX
XXreplaces(kind, f, n)
XXint kind;   /* Query enabled flag */
XXint f;	/* default flag */
XXint n;	/* # of repetitions wanted */
XX    {
XX    int s;	    /* success flag on pattern inputs */
XX    int numsub;	/* number of substitutions */
XX    int nummatch;	/* number of found matches */
XX    int i,j;	/* loop index */
XX    char tmpc;	/* temporary character */
XX    int c;	    /* input char for query */
XX    char tpat[NPAT];	    /* temporary to hold search pattern */
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX
XX    /* check for negative repititions */
XX    if (f && n < 0) return(FALSE);
XX
XX     /* ask the user for the text of a pattern */
XX    if ((s = readpattern(pat, (kind == FALSE ? "Replace" : "Query replace"),'\006')) != TRUE)
XX    return(s);
XX
XX    /* ask for the replacement string */
XX    if ((s = readpattern(rpat,"with",'\006')) == ABORT) return(s);
XX
XX    /* build query replace question string */
XX    strcpy(tpat, "Replace? ");
XX
XX    /* save original . position */
XX    setmark(TRUE,0);
XX
XX    /* scan through the file */
XX    numsub = 0;
XX    nummatch = 0;
XX
XX    if ((curwp->w_bufp->b_mode & MDEXACT) == 0) inexact = TRUE;
XX    else inexact = FALSE;
XX
XX    while (f == FALSE || n > nummatch) {
XX
XX	/* search for the pattern */
XX	if (dosearch(TRUE,PTBEG,FALSE) != TRUE) break; /* all done */
XX		 ++nummatch;   /* increment # of matches */
XX
XX	/* check for query */
XX	if (kind) {
XX	    /* get the query */
XX	    mlerase(); mlputs(&tpat[0]);
XX	    qprompt:
XX	    update(); /* show the proposed place to change */
XX	    c = getkey();	    /* and input */
XX	    mlerase("");	    /* and clear it */
XX
XX	    /* and respond appropriately */
XX	    switch (c) {
XX		case 'Y':
XX		case 'y':   /* yes, substitute */
XX		case ' ':
XX		break;
XX
XX		case 'N':
XX		case 'n':   /* no, onword */
XX		forwchar(FALSE, 1);
XX		continue;
XX
XX		case '!':   /* yes/stop asking */
XX		kind = FALSE;
XX		break;
XX
XX		case '.':   /* abort! and return */
XX		/* restore old position */
XX		swapmark(FALSE,1);
XX
XX		case CTRL|'G':  /* abort! and stay */
XX		mlwrite("Aborted!");
XX		return(FALSE);
XX
XX		default: /* bitch and beep */
XX		(*term.t_beep)();
XX
XX		case '?':   /* help me */
XX		case SPEC|'Q':
XX		mlwrite("(Y)es, (N)o, (!)Do the rest, (^G)Abort, (.)Abort back, (?)Help: ");
XX		goto qprompt;
XX		}
XX	    }
XX
XX	/* delete the sucker */
XX	if (ldelete(strlen(substr[0]), FALSE) != TRUE) {
XX	    /* error while deleting */
XX	    mlwrite("ERROR while deleteing");
XX	    return(FALSE);
XX	    }
XX
XX	/* and insert its replacement */
XX	for (i=0; i<strlen(rpat); i++) {
XX	    tmpc = rpat[i];
XX	    if (tmpc == '\\' && rpat[i+1] >= '0' && rpat[i+1] <= '9') {
XX		tmpc = rpat[++i] - 0x30;
XX		for (j = 0; j<strlen(substr[tmpc]); j++) {
XX		    if (linsert(1,substr[tmpc][j]) != TRUE) {
XX			mlwrite("Out of memory while inserting");
XX			return(FALSE);
XX			}
XX		    }
XX		}
XX	    else {
XX		s = (tmpc == '\n' ? lnewline() : linsert(1, tmpc));
XX		if (s != TRUE) {
XX		    mlwrite("Out of memory while inserting");
XX		    return(FALSE);
XX		    }
XX		}
XX	    }
XX
XX	numsub++; /* increment # of substitutions */
XX	}
XX
XX    /* and report the results */
XX    mlwrite("%d susbstitutions",numsub);
XX    return(TRUE);
XX    }
XX
XX/* expandp:	expand control key sequences for output */
XX
XXexpandp(srcstr, deststr, maxlength)
XXchar *srcstr;	/* string to expand */
XXchar *deststr;	/* destination of expanded string */
XXint maxlength;	/* maximum chars in destination */
XX    {
XX    char c;	/* current char to translate */
XX
XX    /* scan through the string */
XX    while ((c = *srcstr++) != 0) {
XX	if (c == '\n') {	/* its an EOL */
XX		 *deststr++ = '<';
XX	    *deststr++ = 'N';
XX	    *deststr++ = 'L';
XX	    *deststr++ = '>';
XX	    maxlength -= 4;
XX	    }
XX
XX	else if (c < 0x20 || c == 0x7f) {   /* control character */
XX	    *deststr++ = '^';
XX	    *deststr++ = c ^ 0x40;
XX	    maxlength -= 2;
XX	    }
XX
XX	else {	/* any other character */
XX	    *deststr++ = c;
XX	    maxlength--;
XX	    }
XX	if (maxlength < 4) {
XX	    *deststr++ = '$';
XX	    *deststr = '\0';
XX	    return(FALSE);
XX	    }
XX	}
XX    *deststr = '\0';
XX    return(TRUE);
XX    }
XX
XXflash(cchr)
XXchar cchr;
XX    {
XX    register LINE *clp;
XX    register int   cbo;
XX    LINE *oldp;
XX    int oldo,count,i,j,inwindow;
XX    char c,ochr;
XX
XX#if AMIGA == 0
XX    struct timeb tp;
XX    time_t t1;
XX    unsigned short t2;
XX#endif
XX
XX    update();
XX    switch (cchr) {
XX	case ')':   ochr = '('; break;
XX	case '}':   ochr = '{'; break;
XX	case ']':   ochr = '['; break;
XX	case '>':   ochr = '<'; break;
XX	default: return(FALSE);
XX	}
XX
XX    clp = curwp->w_dotp; oldp = clp;
XX    cbo = curwp->w_doto; oldo = cbo;
XX    count = 0; inwindow = TRUE;
XX
XX    while(TRUE) {
XX	while (--cbo < 0) {
XX	    if (ochr == '<' || ochr == '[') return(TRUE);
XX	    if (clp == curwp->w_linep) inwindow = FALSE;
XX	    clp = lback(clp);
XX	    if (clp == curbp->b_linep) {
XX		mlwrite("No matching paren found");
XX		return(FALSE);
XX		}
XX	    cbo = llength(clp);
XX	    }
XX	c = lgetc(clp,cbo);
XX	if (c == ochr && --count < 0) {
XX	    mlwrite("No matching paren found");
XX	    return(FALSE);
XX	    }
XX	else if (c == cchr) ++count;
XX	if (count == 0) {
XX	    if (inwindow) {
XX		curwp->w_dotp = clp;
XX		curwp->w_doto = cbo;
XX		update();
XX#if AMIGA
XX		Delay(10L);
XX#else
XX		ftime(&tp.time);
XX		t1 = tp.time;
XX		t2 = tp.millitm + FLASHTIME;
XX		if (t2 > 1000) {
XX		    t1++;
XX		    t2 -= 1000;
XX		    }
XX		while (1) {
XX		    ftime(&tp.time);
XX		    if (tp.time > t1 ||
XX			(tp.time == t1 && tp.millitm >= t2)) break;
XX		    }
XX#endif
XX		curwp->w_dotp = oldp;
XX		curwp->w_doto = oldo;
XX		update();
XX		return(TRUE);
XX		}
XX	    for (i = 0; i < llength(clp); i++) outstr[i] = lgetc(clp,i);
XX	    outstr[i] = 0;
XX	    mlerase(); mlputs(outstr); update(); mpresf = TRUE;
XX	    return(TRUE);
XX	    }
XX	}
XX    }
XX
SHAR_EOF
if test 19273 -ne "`wc -c search.c`"
then
echo shar: error transmitting search.c '(should have been 19273 characters)'
fi
echo shar: extracting spawn.c
sed 's/^XX//' << \SHAR_EOF > spawn.c
XX/*
XX * The routines in this file are called to create a subjob running a command
XX * interpreter. This code is a big fat nothing on CP/M-86. You lose.
XX */
XX#include    <stdio.h>
XX#include    "estruct.h"
XX#include    "edef.h"
XX
XX#if AMIGA
XX#define NEW   1006
XX#endif
XX
XX#if VMS
XX#define EFN     0                               /* Event flag. */
XX
XX#include <ssdef.h>                       /* Random headers. */
XX#include <stsdef.h>
XX#include <descrip.h>
XX#include <iodef.h>
XX
XXextern int     oldmode[2];                      /* In "termio.c" */
XXextern int     newmode[2];                      /* In "termio.c" */
XXextern short   iochan;                         /* In "termio.c" */
XX#endif
XX
XX#if ULTRIX
XX#include <signal.h>
XX#include <fcntl.h>
XX#include <sys/types.h>
XX#include <sys/stat.h>
XX#include <sys/file.h>
XX
XX#define	IOCPARM_MASK	0x7f		/* parameters must be < 128 bytes */
XX#define	IOC_VOID	0x20000000	/* no parameters */
XX#define	IOC_OUT		0x40000000	/* copy out parameters */
XX#define	IOC_IN		0x80000000	/* copy in parameters */
XX#define	_IO(x,y)	(IOC_VOID|('x'<<8)|y)
XX#define	_IOR(x,y,t)	(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|('x'<<8)|y)
XX#define	_IOW(x,y,t)	(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|('x'<<8)|y)
XX#define	FIONREAD	_IOR(f, 127, int)	/* get # bytes to read */
XX#define	TIOCSPGRP	_IOW(t, 118, int)	/* set pgrp of tty */
XX#define	TIOCNOTTY	_IO(t, 113)		/* void tty association */
XX
XXextern int vttidy();
XX
XX/* Open an available pty, putting descriptor in *ptyv,
XX  and return the file name of the pty.  Return 0 if none available.  */
XX
XXchar ptyname[24];
XX
XXchar *pty(ptyv)
XXint *ptyv;
XX    {
XX    struct stat stb;
XX    register c, i;
XX
XX    for (c = 'p'; c <= 'z'; c++) {
XX	for (i = 0; i < 16; i++) {
XX	    sprintf (ptyname, "/dev/pty%c%x", c, i);
XX	    if (stat (ptyname, &stb) < 0) continue;
XX
XX	    *ptyv = open (ptyname, O_RDWR | O_NDELAY, 0);
XX	    if (*ptyv >= 0) {
XX		/* check to make certain that both sides are available
XX		    this avoids a nasty yet stupid bug in rlogins */
XX		int x;
XX		sprintf (ptyname, "/dev/tty%c%x", c, i);
XX		x = open (ptyname, O_RDWR | O_NDELAY, 0);
XX		if (x < 0) {close (*ptyv); continue; }
XX		close(x);
XX		return ptyname;
XX		}
XX	    }
XX	}
XX    return(NULL);
XX    }
XX
XX/*
XX * Create a sub process in a window (only under ULTRIX)
XX */
XX
XXcreate_process()
XX    {
XX    int sv[2],forkin,forkout;
XX    WINDOW *wp;
XX    char *ptyname;
XX
XX    /* get us a window/buffer to work in */
XX    if ((wp = wpopup()) != NULL) {
XX	curwp = wp;
XX	curbp = wp->w_bufp;
XX	}
XX    if (procbuf != NULL) {
XX	mlwrite("*SHELL* already exists!!");
XX	return(FALSE);
XX	}
XX    if ((procbuf=bfind("*SHELL*",TRUE,0)) == NULL) return(FALSE);
XX    if (swbuffer(procbuf) == FALSE) return(FALSE);
XX
XX    /* now create the process */
XX    ptyname = pty(&inchannel);
XX    outchannel = inchannel;
XX    if (ptyname) {
XX	forkout = forkin = open(ptyname, O_RDWR, 0);
XX	if (forkin < 0) return(FALSE);
XX	}
XX    else {
XX	pipe (sv);
XX	inchannel = sv[0];
XX	forkout = sv[1];
XX	pipe (sv);
XX	outchannel = sv[1];
XX	forkin = sv[0];
XX	}
XX    pid = vfork();
XX    if (pid == 0) {
XX	if (ptyname) {
XX	    int j = open("/dev/tty",O_RDWR,0);
XX	    ioctl(j,TIOCNOTTY,0);
XX	    close(j);
XX	    }
XX	pid = getpid();
XX	close(0);
XX	close(1);
XX	close(2);
XX	dup2(forkin,0);
XX	dup2(forkout,1);
XX	dup2(forkout,2);
XX	setpgrp(pid,pid);
XX	ioctl(0, TIOCSPGRP, &pid);
XX	execl("/bin/csh","uemacs-sub-shell","-is",NULL);
XX	}
XX    close(forkin);
XX    if (forkin != forkout) close(forkout);
XX    return(TRUE);
XX    }
XX
XX/* wait for subprocess data (or a key to be pressed) */
XX
XXreadsubproc() {
XX    extern dotoplevel();
XX    char *bptr,buf[4096];
XX    int i,j,n,c,flags;
XX    BUFFER *bp;
XX
XX    flags = fcntl(0,F_GETFL,0);
XX    fcntl(0,F_SETFL,flags|FASYNC);
XX    while (TRUE) {
XX	/* see if the process has any data */
XX	bptr = &buf[0];
XX	signal(SIGIO,dotoplevel);
XX	i = read(inchannel,bptr,sizeof(buf));
XX	signal(SIGIO,SIG_DFL);
XX	if (i < 1 || procbuf == NULL) {
XX	    procbuf = NULL;
XX	    fcntl(0,F_SETFL,flags);
XX	    return;
XX	    }
XX	bp = curbp;
XX	if (bp != procbuf) swbuffer(procbuf);
XX	if (curwp->w_dotp != curbp->b_linep) gotoeob(TRUE,0);
XX	while (i-- > 0) {
XX	    c = *bptr++ & 0x7F;
XX	    if (c != 0x0A) linsert(1,c); else lnewline();
XX	    }
XX	setmark(TRUE,0);
XX	if (bp != procbuf) swbuffer(bp);
XX	update();
XX	}
XX    }
XX
XX/* insert a line (or region) to a sub shell */
XXpinsert() {
XX    register LINE   *linep;
XX    register int    loffs;
XX    register int    clen,s;
XX    REGION region;
XX
XX    /* get the region to send */
XX    if (curwp->w_markp == NULL) {
XX	region.r_linep  = linep = curwp->w_dotp;
XX	region.r_offset = loffs = 0;
XX	region.r_size   = llength(linep);
XX	while (loffs < llength(linep) && loffs < 20) {
XX	    if (lgetc(linep,loffs) == '%' || lgetc(linep,loffs) == '#') {
XX		region.r_offset += ++loffs;
XX		region.r_size   -= loffs;
XX		break;
XX		}
XX	    ++loffs;
XX	    }
XX	}
XX    else getregion(&region);
XX
XX    linep = region.r_linep;
XX    loffs = region.r_offset;
XX    while (region.r_size--) {
XX	if (loffs == llength(linep)) {
XX	    if (write(outchannel,"\n",1) == -1) {
XX		mlwrite("Write to subprocess failed!!");
XX		procbuf = NULL;
XX		return(FALSE);
XX		}
XX	    linep = lforw(linep);
XX	    loffs = 0;
XX	    }
XX	else {
XX	    if (write(outchannel,&linep->l_text[loffs],1) == -1) {
XX		mlwrite("Write to subprocess failed!!");
XX		procbuf = NULL;
XX		return(FALSE);
XX		}
XX	    loffs++;
XX	    }
XX	}
XX    lnewline();
XX    if (write(outchannel,"\n",1) == -1) {
XX	mlwrite("Write to subprocess failed!!");
XX	procbuf = NULL;
XX	return(FALSE);
XX	}
XX    gotoeob(TRUE,0);
XX    setmark(TRUE,0);
XX    return(TRUE);
XX    }
XX
XX/* send a quoted character to the sub shell */
XXshellquote(f, n)
XX    {
XX    int  c;
XX
XX    if (procbuf == NULL) {
XX	mlwrite("No process to talk to!!");
XX	return(FALSE);
XX	}
XX
XX    /* get the character to quote */
XX    c = getkey();
XX    if (c & CTRL) c -= (CTRL|'@');
XX    c &= 0x7F;
XX
XX    if (write(outchannel,&c,1) == -1) {
XX	mlwrite("Write to subprocess failed!!");
XX	procbuf = NULL;
XX	return(FALSE);
XX	}
XX    return(TRUE);
XX    }
XX
XX#endif
XX
XX/*
XX * Create a subjob with a copy of the command intrepreter in it. When the
XX * command interpreter exits, mark the screen as garbage so that you do a full
XX * repaint. Bound to "C-C". The message at the start in VMS puts out a newline.
XX * Under some (unknown) condition, you don't get one free when DCL starts up.
XX */
XXspawncli(f, n)
XX    {
XX#if AMIGA
XX    long newcli;
XX
XX    newcli = (long)Open("CON:1/1/639/199/MicroEmacs Subprocess",(long)NEW);
XX    mlwrite("[Starting new CLI]");
XX    sgarbf = TRUE;
XX    Execute("", (long)newcli, 0L);
XX    Close((long)newcli);
XX    return(TRUE);
XX#endif
XX
XX#if ULTRIX
XX    register char *cp;
XX    char *getenv();
XX#endif
XX#if VMS
XX    register int s;
XX    movecursor(term.t_nrow, 0);             /* In last line. */
XX    mlputs("[Starting DCL]\r\n");
XX    (*term.t_flush)(); /* Ignore "ttcol". */
XX    s = sys(NULL);			    /* NULL => DCL. */
XX    mlputs("\r\n\n[End]"); /* Pause. */
XX    (*term.t_flush)();
XX    do {
XX	s = getkey();
XX	if (s & CTRL) s -= (CTRL|'@');
XX	s &= 0x7F;
XX	} while (s != ' ' && s != 'y' && s != '\r' && s != '\n');/* Pause. */
XX    sgarbf = TRUE;
XX    return(TRUE);
XX#endif
XX#if ULTRIX
XX    return(create_process());
XX#endif
XX    }
XX
XX#if ULTRIX
XX
XXbktoshell()   /* suspend MicroEMACS and wait to wake up */
XX    {
XX    int pid;
XX
XX    vttidy();
XX    pid = getpid();
XX    kill(pid,SIGTSTP);
XX    }
XX
XXrtfrmshell()
XX    {
XX    ttopen();
XX    curwp->w_flag = WFHARD;
XX    refresh();
XX    }
XX#endif
XX
XX/*
XX * Run a one-liner in a subjob. When the command returns, wait for a single
XX * character to be typed, then mark the screen as garbage so a full repaint is
XX * done. Bound to "C-X !".
XX */
XXspawn(f, n)
XX    {
XX    register int    s;
XX    char line[NLINE];
XX#if AMIGA
XX    long newcli;
XX
XX    if ((s=mlreply("CLI command: ", line, NLINE)) != TRUE) return (s);
XX    newcli = (long)Open("CON:1/1/639/199/MicroEmacs Subprocess",(long)NEW);
XX    Execute(line,0L,(long)newcli);
XX    Close((long)newcli);
XX#endif
XX#if VMS
XX    if ((s=mlreply("DCL command: ", line, NLINE)) != TRUE) return (s);
XX    (*term.t_putchar)('\n'); /* Already have '\r' */
XX
XX    (*term.t_flush)();
XX    s = sys(line);                          /* Run the command. */
XX    mlputs("\r\n\n[End]"); /* Pause. */
XX#endif
XX#if ULTRIX
XX    if ((s=mlreply("! ", line, NLINE)) != TRUE) return (s);
XX    (*term.t_putchar)('\n'); /* Already have '\r' */
XX    (*term.t_flush)();
XX    ttclose(); /* stty to old modes */
XX    system(line);
XX    sleep(2);
XX    ttopen();
XX    mlputs("[End]"); /* Pause. */
XX#endif
XX    (*term.t_flush)();
XX    do {
XX	s = getkey();
XX	if (s & CTRL) s -= (CTRL|'@');
XX	s &= 0x7F;
XX	} while (s != ' ' && s != 'y' && s != '\r' && s != '\n');/* Pause. */
XX    sgarbf = TRUE;
XX    return(TRUE);
XX    }
XX
XX#if VMS
XX/*
XX * Run a command. The "cmd" is a pointer to a command string, or NULL if you
XX * want to run a copy of DCL in the subjob (this is how the standard routine
XX * LIB$SPAWN works. You have to do wierd stuff with the terminal on the way in
XX * and the way out, because DCL does not want the channel to be in raw mode.
XX */
XXsys(cmd)
XXregister char   *cmd;
XX    {
XX    struct dsc$descriptor  cdsc;
XX    struct dsc$descriptor  *cdscp;
XX    long status;
XX    long substatus;
XX    long iosb[2];
XX
XX    status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
XX    oldmode, sizeof(oldmode), 0, 0, 0, 0);
XX    if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) return (FALSE);
XX    cdscp = NULL;                           /* Assume DCL. */
XX    if (cmd != NULL) {                      /* Build descriptor. */
XX       cdsc.dsc$a_pointer = cmd;
XX   cdsc.dsc$w_length = strlen(cmd);
XX   cdsc.dsc$b_dtype = DSC$K_DTYPE_T;
XX   cdsc.dsc$b_class = DSC$K_CLASS_S;
XX   cdscp = &cdsc;
XX   }
XX    status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
XX    if (status != SS$_NORMAL) substatus = status;
XX    status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
XX    newmode, sizeof(newmode), 0, 0, 0, 0);
XX    if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) return (FALSE);
XX    if ((substatus&STS$M_SUCCESS) == 0)     /* Command failed. */
XX       return (FALSE);
XX    return (TRUE);
XX    }
XX#endif
SHAR_EOF
if test 9843 -ne "`wc -c spawn.c`"
then
echo shar: error transmitting spawn.c '(should have been 9843 characters)'
fi
echo shar: extracting tcap.c
sed 's/^XX//' << \SHAR_EOF > tcap.c
XX/* tcap:   Unix V5, V7 and BS4.2 Termcap video driver
XX * for MicroEMACS */
XX
XX#define	termdef	1	    /* don't define "term" external */
XX
XX#include	<stdio.h>
XX#include	"estruct.h"
XX#include "edef.h"
XX
XX#if TERMCAP
XX
XX#define NROW    24
XX#define NCOL    80
XX#define	MARGIN	8
XX#define	SCRSIZ	64
XX#define BEL     0x07
XX#define ESC     0x1B
XX
XXextern int      ttopen();
XXextern int      ttgetc();
XXextern int      ttputc();
XXextern int      ttflush();
XXextern int      ttclose();
XXextern int      tcapmove();
XXextern int      tcapeeol();
XXextern int      tcapeeop();
XXextern int      tcapbeep();
XXextern int      tcapopen();
XXextern int	tcapinsert();
XXextern int	tcapdelete();
XXextern int      tput();
XXextern char     *tgoto();
XX
XX#define TCAPSLEN 315
XXchar tcapbuf[TCAPSLEN];
XXchar *UP, PC, *CM, *CE, *CL;
XX
XXTERM term = {
XX    NROW-1,
XX    NCOL,
XX    MARGIN,
XX    SCRSIZ,
XX    tcapopen,
XX    ttclose,
XX    ttgetc,
XX    ttputc,
XX    ttflush,
XX    tcapmove,
XX    tcapeeol,
XX    tcapeeop,
XX    tcapbeep,
XX    tcapinsert,
XX    tcapdelete
XX    };
XX
XXtcapopen()
XX
XX    {
XX    char *getenv();
XX    char *t, *p, *tgetstr();
XX    char tcbuf[1024];
XX    char *tv_stype;
XX    char err_str[72];
XX
XX    int row,col;
XX
XX    if (batchmode) return(TRUE);
XX
XX    if ((tv_stype = getenv("TERM")) == NULL) {
XX	puts("Environment variable TERM not defined!");
XX	exit(1);
XX	}
XX
XX    if((tgetent(tcbuf, tv_stype)) != 1)
XX	{
XX	sprintf(err_str, "Unknown terminal type %s!", tv_stype);
XX	puts(err_str);
XX	exit(1);
XX	}
XX
XX    row = tgetnum("li") - 1;
XX    if (row < 0) row = NROW - 1;
XX    col = tgetnum("co");
XX    if (col < 0) col = NCOL;
XX    term.t_nrow = row;
XX    term.t_ncol = col;
XX
XX    p = tcapbuf;
XX    t = tgetstr("pc", &p);
XX    if(t)
XX    PC = *t;
XX    CL = tgetstr("cl", &p);
XX    CM = tgetstr("cm", &p);
XX    CE = tgetstr("ce", &p);
XX    UP = tgetstr("up", &p);
XX
XX    if(CL == NULL || CM == NULL || UP == NULL)
XX	{
XX	puts("Incomplete termcap entry\n");
XX	exit(1);
XX	}
XX
XX    if (CE == NULL)	/* will we be able to use clear to EOL? */
XX		 eolexist = FALSE;
XX
XX    if (p >= &tcapbuf[TCAPSLEN]) {
XX	puts("Terminal description too big!\n");
XX	exit(1);
XX	}
XX    ttopen();
XX    }
XX
XXtcapmove(row, col)
XXregister int row, col;
XX    {
XX    if (batchmode) return(TRUE);
XX    putpad(tgoto(CM, col, row));
XX    }
XX
XXtcapeeol()
XX    {
XX    if (batchmode) return(TRUE);
XX    putpad(CE);
XX    }
XX
XXtcapeeop()
XX    {
XX    if (batchmode) return(TRUE);
XX    putpad(CL);
XX    }
XX
XXtcapbeep()
XX    {
XX    if (batchmode) return(TRUE);
XX    ttputc(BEL);
XX    }
XX
XXtcapinsert(row,n)
XX    {
XX    char str[40];
XX
XX    if (batchmode) return(TRUE);
XX    sprintf(str,"\033[%d;%dr\033[%dH",row+1,term.t_nrow,row+1);
XX    putpad(str);
XX    sprintf(str,"\033M");
XX    while (n--) putpad(str);
XX    putpad("\033[r");
XX    mlerase();
XX    }
XX
XXtcapdelete(row,n)
XX    {
XX    char str[40];
XX
XX    if (batchmode) return(TRUE);
XX    mlerase();
XX    sprintf(str,"\033[%d;%dr\033[%dH",row+1,term.t_nrow,term.t_nrow);
XX    putpad(str);
XX    sprintf(str,"\033D");
XX    while (n--) putpad(str);
XX    putpad("\033[r");
XX    }
XX
XXputpad(str)
XXchar *str;
XX    {
XX    if (batchmode) return(TRUE);
XX    tputs(str, 1, ttputc);
XX    }
XX
XXputnpad(str, n)
XXchar *str;
XX    {
XX    if (batchmode) return(TRUE);
XX    tputs(str, n, ttputc);
XX    }
XX
XX#else
XX
XXhello()
XX    {
XX    }
XX
XX#endif TERMCAP
XX
SHAR_EOF
if test 3153 -ne "`wc -c tcap.c`"
then
echo shar: error transmitting tcap.c '(should have been 3153 characters)'
fi
echo shar: extracting termio.c
sed 's/^XX//' << \SHAR_EOF > termio.c
XX/*
XX * The functions in this file negotiate with the operating system for
XX * characters, and write characters in a barely buffered fashion on the display.
XX * All operating systems.
XX */
XX#include <stdio.h>
XX#include   "estruct.h"
XX#include "edef.h"
XX
XX#if AMIGA
XXextern	char	*Open();
XXextern	long	Read(),Write();
XXextern	void	Close();
XX
XX#define NEW 1006L
XX#define AMG_MAXBUF      1024
XXstatic char	*terminal = NULL;
XXstatic char     scrn_tmp[AMG_MAXBUF+1];
XXstatic long      scrn_tmp_p = 0;
XX#endif
XX
XX#if VMS
XX#include <stsdef.h>
XX#include <ssdef.h>
XX#include <descrip.h>
XX#include <iodef.h>
XX#include <ttdef.h>
XX
XX#define NIBUF   128		/* Input buffer size */
XX#define NOBUF   1024		/* MM says bug buffers win! */
XX#define EFN     0		/* Event flag */
XX
XXchar obuf[NOBUF];		/* Output buffer */
XXint nobuf;		/* # of bytes in above */
XXchar ibuf[NIBUF];		/* Input buffer */
XXint nibuf;		/* # of bytes in above */
XXint ibufi;		/* Read index */
XXint oldmode[2];		/* Old TTY mode bits */
XXint newmode[2];		/* New TTY mode bits */
XXshort iochan;		/* TTY I/O channel */
XX#endif
XX
XX#if ULTRIX
XX#undef   CTRL
XX#include <sgtty.h>		/* for stty/gtty functions */
XX#include <signal.h>
XXstruct sgttyb  ostate;		/* saved tty state */
XXstruct sgttyb  nstate;		/* values for editor mode */
XXstruct tchars   otchars;		/* Saved terminal special character set */
XXstruct tchars   ntchars = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
XX/* A lot of nothing */
XX#if ULTRIX
XX#include <sys/ioctl.h>		/* to get at the typeahead */
XXextern   int rtfrmshell();		/* return from suspended shell */
XX#endif
XX#endif
XX/*
XX* This function is called once to set up the terminal device streams.
XX* On VMS, it translates TT until it finds the terminal, then assigns
XX* a channel to it and sets it raw. On CPM it is a no-op.
XX*/
XXttopen()
XX    {
XX#if AMIGA
XX    if (batchmode) return(TRUE);
XX    terminal = Open("RAW:1/1/639/199/MicroEmacs",(long)NEW);
XX#endif
XX#if VMS
XX    struct dsc$descriptor  idsc;
XX    struct dsc$descriptor  odsc;
XX    char oname[40];
XX    int iosb[2];
XX    int status;
XX
XX    if (batchmode) return(TRUE);
XX    odsc.dsc$a_pointer = "TT";
XX    odsc.dsc$w_length = strlen(odsc.dsc$a_pointer);
XX    odsc.dsc$b_dtype = DSC$K_DTYPE_T;
XX    odsc.dsc$b_class = DSC$K_CLASS_S;
XX    idsc.dsc$b_dtype = DSC$K_DTYPE_T;
XX    idsc.dsc$b_class = DSC$K_CLASS_S;
XX    do {
XX	idsc.dsc$a_pointer = odsc.dsc$a_pointer;
XX	idsc.dsc$w_length = odsc.dsc$w_length;
XX	odsc.dsc$a_pointer = &oname[0];
XX	odsc.dsc$w_length = sizeof(oname);
XX	status = LIB$SYS_TRNLOG(&idsc, &odsc.dsc$w_length, &odsc);
XX	if (status!=SS$_NORMAL && status!=SS$_NOTRAN) exit(status);
XX	if (oname[0] == 0x1B) {
XX	    odsc.dsc$a_pointer += 4;
XX	    odsc.dsc$w_length -= 4;
XX	    }
XX	}
XX    while (status == SS$_NORMAL);
XX    status = SYS$ASSIGN(&odsc, &iochan, 0, 0);
XX    if (status != SS$_NORMAL) exit(status);
XX    status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
XX    oldmode, sizeof(oldmode), 0, 0, 0, 0);
XX    if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) exit(status);
XX    term.t_nrow = ((oldmode[1] >> 24) & 0xFF) - 1;
XX    newmode[0] = oldmode[0];
XX    newmode[1] = oldmode[1] | TT$M_PASSALL | TT$M_NOECHO;
XX    status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
XX    newmode, sizeof(newmode), 0, 0, 0, 0);
XX    if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) exit(status);
XX#endif
XX#if ULTRIX
XX    if (batchmode) return(TRUE);
XX    gtty(0, &ostate);		/* save old state */
XX    gtty(0, &nstate);		/* get base of new state */
XX    nstate.sg_flags |= RAW; 
XX    nstate.sg_flags &= ~(ECHO|CRMOD);		/* no echo for now... */
XX    stty(0, &nstate);		/* set mode */
XX    ioctl(0, TIOCGETC, &otchars);		/* Save old characters */
XX    ioctl(0, TIOCSETC, &ntchars);		/* Place new character into K */
XX    signal(SIGTSTP,SIG_DFL);		/* set signals so that we can */
XX    signal(SIGCONT,rtfrmshell);		/* suspend & restart emacs */
XX#endif
XX    }
XX/*
XX* This function gets called just before we go back home to the command
XX* interpreter. On VMS it puts the terminal back in a reasonable state.
XX* Another no-operation on CPM.
XX*/
XXttclose()
XX    {
XX#if AMIGA
XX    if (batchmode) return(TRUE);
XX    amg_flush();
XX    Close(terminal);
XX#endif
XX#if VMS
XX    int status;
XX    int iosb[1];
XX
XX    if (batchmode) return(TRUE);
XX    ttflush();
XX    status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
XX    oldmode, sizeof(oldmode), 0, 0, 0, 0);
XX    if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL) exit(status);
XX    status = SYS$DASSGN(iochan);
XX    if (status != SS$_NORMAL) exit(status);
XX#endif
XX#if ULTRIX
XX    if (batchmode) return(TRUE);
XX    stty(0, &ostate);
XX    ioctl(0, TIOCSETC, &otchars);	/* Place old character into K */
XX#endif
XX    }
XX
XX/*
XX* Write a character to the display. On VMS, terminal output is buffered, and
XX* we just put the characters in the big array, after checking for overflow.
XX* On CPM terminal I/O unbuffered, so we just write the byte out. Ditto on
XX* MS-DOS (use the very very raw console output routine).
XX*/
XXttputc(c)
XX#if AMIGA
XXchar c;
XX#endif
XX    {
XX    if (batchmode) return(TRUE);
XX#if AMIGA
XX    scrn_tmp[scrn_tmp_p++] = c;
XX    if(scrn_tmp_p>=AMG_MAXBUF)
XX    amg_flush();
XX#endif
XX#if VMS
XX    if (nobuf >= NOBUF) ttflush();
XX    obuf[nobuf++] = c;
XX#endif
XX
XX#if ULTRIX
XX    fputc(c, stdout);
XX#endif
XX    }
XX
XX#if AMIGA
XXamg_flush()
XX    {
XX    if (batchmode) return(TRUE);
XX    if(scrn_tmp_p)
XX	Write(terminal,scrn_tmp,(long)scrn_tmp_p);
XX    scrn_tmp_p = 0;
XX    }
XX#endif
XX/*
XX* Flush terminal buffer. Does real work where the terminal output is buffered
XX* up. A no-operation on systems where byte at a time terminal I/O is done.
XX*/
XXttflush()
XX    {
XX#if AMIGA
XX    if (batchmode) return(TRUE);
XX    amg_flush();
XX#endif
XX#if VMS
XX    int status;
XX    int iosb[2];
XX    if (batchmode) return(TRUE);
XX    status = SS$_NORMAL;
XX    if (nobuf != 0) {
XX	status = SYS$QIOW(EFN, iochan, IO$_WRITELBLK|IO$M_NOFORMAT,
XX	iosb, 0, 0, obuf, nobuf, 0, 0, 0, 0);
XX	if (status == SS$_NORMAL) status = iosb[0] & 0xFFFF;
XX	nobuf = 0;
XX	}
XX    return (status);
XX#endif
XX#if ULTRIX
XX    if (batchmode) return(TRUE);
XX    fflush(stdout);
XX#endif
XX    }
XX
XX/*
XX * Read a character from the terminal, performing no editing and doing no echo
XX * at all. More complex in VMS that almost anyplace else, which figures. Very
XX * simple on CPM, because the system can do exactly what you want.
XX */
XXttgetc()
XX    {
XX#if AMIGA
XX    unsigned char ch[2];
XX
XX    if (batchmode) return(TRUE);
XX    amg_flush();
XX    Read(terminal, ch, 1L);
XX    return (ch[0] & 0xFF);
XX#endif
XX#if VMS
XX    int status;
XX    int iosb[2];
XX    int term[2];
XX
XX    if (batchmode) return(TRUE);
XX    while (ibufi >= nibuf) {
XX	ibufi = 0;
XX	term[0] = 0;
XX	term[1] = 0;
XX	status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
XX	iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
XX	if (status != SS$_NORMAL) exit(status);
XX	status = iosb[0] & 0xFFFF;
XX	if (status!=SS$_NORMAL && status!=SS$_TIMEOUT) exit(status);
XX	nibuf = (iosb[0]>>16) + (iosb[1]>>16);
XX	if (nibuf == 0) {
XX	    status = SYS$QIOW(EFN, iochan, IO$_READLBLK,
XX	    iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
XX	    if (status != SS$_NORMAL || (status = (iosb[0]&0xFFFF)) != SS$_NORMAL)
XX	    exit(status);
XX	    nibuf = (iosb[0]>>16) + (iosb[1]>>16);
XX	    }
XX	}
XX    return (ibuf[ibufi++] & 0xFF);		/* Allow multinational */
XX#endif
XX
XX#if ULTRIX
XX    if (batchmode) return(TRUE);
XX    return(127 & fgetc(stdin));
XX#endif
XX    }
XX
XX#if TYPEAH
XX/* typahead:   Check to see if any characters are already in the
XX   keyboard buffer
XX */
XXtypahead()
XX
XX    {
XX#if   ULTRIX
XX    int x;		/* holds # of pending chars */
XX
XX    if (batchmode) return(FALSE);
XX    return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x);
XX#else
XX    return(FALSE);
XX#endif
XX    }
XX#endif
SHAR_EOF
if test 7495 -ne "`wc -c termio.c`"
then
echo shar: error transmitting termio.c '(should have been 7495 characters)'
fi
echo shar: extracting vmsvt.c
sed 's/^XX//' << \SHAR_EOF > vmsvt.c
XX/*
XX * VMS terminal handling routines
XX *
XX * Known types are:
XX * VT52, VT100, and UNKNOWN (which is defined to be an ADM3a)
XX * written by Curtis Smith
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include	"edef.h"
XX
XX#if VMSVT
XX
XX#define	termdef	1	    /* don't define "term" external */
XX
XX#include <ssdef.h>	/* Status code definitions */
XX#include <descrip.h>	    /* Descriptor structures */
XX#include <iodef.h>	/* IO commands */
XX#include <ttdef.h>	/* tty commands */
XX
XXextern int	ttopen();               /* Forward references. */
XXextern int	ttgetc();
XXextern int	ttputc();
XXextern int	ttflush();
XXextern int	ttclose();
XXextern int	vmsopen();
XXextern int	vmseeol();
XXextern int	vmseeop();
XXextern int	vmsbeep();
XXextern int	vmsmove();
XXextern int	vmsinsert();
XXextern int	vmsdelete();
XXextern int	eolexist;
XX
XX#define	NROWS	24	    /* # of screen rolls */
XX#define	NCOLS	80	    /* # of screen columns */
XX#define	MARGIN	8	    /* size of minimim margin and */
XX#define	SCRSIZ	64	    /* scroll size for extended lines */
XX
XX/*
XX * Dispatch table. All the
XX * hard fields just point into the
XX * terminal I/O code.
XX */
XXTERM term    = {
XX    NROWS - 1,
XX    NCOLS,
XX    MARGIN,
XX    SCRSIZ,
XX    &vmsopen,
XX    &ttclose,
XX    &ttgetc,
XX    &ttputc,
XX    &ttflush,
XX    &vmsmove,
XX    &vmseeol,
XX    &vmseeop,
XX    &vmsbeep,
XX    &vmsinsert,
XX    &vmsdelete
XX    };
XX
XXchar * termeop;	/* Erase to end of page string */
XXint eoppad;	    /* Number of pad characters after eop */
XXchar * termeol;	/* Erase to end of line string */
XXint eolpad;	    /* Number of pad characters after eol */
XXchar termtype;	/* Terminal type identifier */
XX
XX
XX/*******
XX * ttputs - Send a string to ttputc
XX*******/
XX
XXttputs(string)
XXchar * string;
XX    {
XX    if (batchmode) return(TRUE);
XX    while (*string != '\0') ttputc(*string++);
XX    }
XX
XX
XX/*******
XX * vmspad - Pad the output after an escape sequence
XX*******/
XX
XXvmspad(count)
XXint count;
XX    {
XX    if (slowterm) return; 
XX    if (batchmode) return(TRUE);
XX
XX    while (count-- > 0) ttputc('\0');
XX    }
XX
XX
XX/*******
XX * vmsmove - Move the cursor
XX*******/
XX
XXvmsmove(row, col)
XX    {
XX    if (batchmode) return(TRUE);
XX    switch (termtype) {
XX	case TT$_UNKNOWN:
XX	ttputc('\033');
XX	ttputc('=');
XX	ttputc(row+' ');
XX	ttputc(col+' ');
XX	break;
XX
XX	case TT$_VT52:
XX	ttputc('\033');
XX	ttputc('Y');
XX	ttputc(row+' ');
XX	ttputc(col+' ');
XX	break;
XX
XX	case TT$_VT100:
XX	    {
XX	    char buffer[24];
XX
XX	    sprintf(buffer, "\033[%d;%dH", row+1, col+1);
XX	    ttputs(buffer);
XX	    vmspad(5);
XX	    }
XX	}
XX    }
XX
XX
XX/*******
XX * vmseeol - Erase to end of line
XX*******/
XX
XXvmseeol()
XX    {
XX    if (batchmode) return(TRUE);
XX    ttputs(termeol);
XX    vmspad(eolpad);
XX    }
XX
XX
XX/*******
XX * vmseeop - Erase to end of page (clear screen)
XX*******/
XX
XXvmseeop()
XX    {
XX    if (batchmode) return(TRUE);
XX    ttputs(termeop);
XX    vmspad(eoppad);
XX    }
XX
XX
XX/*******
XX * vmsbeep - Ring the bell
XX*******/
XX
XXvmsbeep()
XX    {
XX    if (batchmode) return(TRUE);
XX    ttputc('\007');
XX    }
XX
XX
XX/*******
XX * vmsinsert - insert  n blank lines (assumes a vt100)
XX*******/
XX
XXvmsinsert(row, n)
XX    {
XX    char str[40];
XX
XX    if (batchmode) return(TRUE);
XX    sprintf(str,"\033[%d;%dr\033[%dH",row+1,term.t_nrow,row+1);
XX    ttputs(str);
XX    sprintf(str,"\033M");
XX    while (n--) ttputs(str);
XX    ttputs("\033[r");
XX    vmspad(10);
XX    mlerase();
XX    }
XX
XX/*******
XX * vmsdelete - delete n lines (assumes a vt100)
XX*******/
XX
XXvmsdelete(row, n)
XX    {
XX    char str[40];
XX
XX    if (batchmode) return(TRUE);
XX    mlerase();
XX    sprintf(str,"\033[%d;%dr\033[%dH",row+1,term.t_nrow,term.t_nrow);
XX    ttputs(str);
XX    sprintf(str,"\033D");
XX    while (n--) ttputs(str);
XX    ttputs("\033[r");
XX    vmspad(10);
XX    }
XX
XX/*******
XX * vmsopen - Get terminal type and open terminal
XX*******/
XX
XXvmsopen()
XX    {
XX    if (batchmode) return(TRUE);
XX    termtype = vmsgtty();
XX    switch (termtype) {
XX	case TT$_UNKNOWN:   /* Assume ADM3a */
XX	eolexist = FALSE;
XX	termeop = "\032";
XX	eoppad = 0;
XX	break;
XX
XX	case TT$_VT52:
XX	termeol = "\033K";
XX	eolpad = 0;
XX	termeop = "\033H\033J";
XX	eoppad = 0;
XX	break;
XX
XX	case TT$_VT100:
XX	termeol = "\033[K";
XX	eolpad = 1;
XX	termeop = "\033[;H\033[2J";
XX	eoppad = 5;
XX	break;
XX
XX	default:
XX	puts("Terminal type not supported");
XX	exit (SS$_NORMAL);
XX	}
XX    ttopen();
XX    }
XX
XX
XXstruct iosb {	/* I/O status block */
XX    short i_cond;	/* Condition value */
XX    short i_xfer;	/* Transfer count */
XX    long i_info;	/* Device information */
XX    };
XX
XXstruct termchar {	/* Terminal characteristics */
XX    char t_class;	/* Terminal class */
XX    char t_type;	/* Terminal type */
XX    short t_width;	/* Terminal width in characters */
XX    long t_mandl;	/* Terminal's mode and length */
XX
XX    long t_extend;	/* Extended terminal characteristics */
XX    };
XX
XX/*******
XX * vmsgtty - Get terminal type from system control block
XX*******/
XX
XXvmsgtty()
XX    {
XX    /*DBW*/ return (TT$_VT100);
XX    }
XX
XX#else
XX
XXhellovms()
XX
XX    {
XX    }
XX
XX#endif	VMSVT
XX
SHAR_EOF
if test 4763 -ne "`wc -c vmsvt.c`"
then
echo shar: error transmitting vmsvt.c '(should have been 4763 characters)'
fi
echo shar: extracting window.c
sed 's/^XX//' << \SHAR_EOF > window.c
XX/*
XX * Window management. Some of the functions are internal, and some are
XX * attached to keys that the user actually types.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include	"edef.h"
XX
XX/*
XX * Reposition dot in the current window to line "n". If the argument is
XX * positive, it is that line. If it is negative it is that line from the
XX * bottom. If it is 0 the window is centered (this is what the standard
XX * redisplay code does). With no argument it defaults to 1. Bound to M-!.
XX * Because of the default, it works like in Gosling.
XX */
XXreposition(f, n)
XX    {
XX    if (f == FALSE) /* default to top of screen */
XX		 n = 1;
XX    curwp->w_force = n;
XX    curwp->w_flag |= WFFORCE;
XX    return (TRUE);
XX    }
XX
XX/*
XX * Refresh the screen. With no argument, it just does the refresh. With an
XX * argument it recenters "." in the current window. Bound to "C-L".
XX */
XXrefresh(f, n)
XX    {
XX    WINDOW *wp;
XX
XX    if (f == FALSE) sgarbf = TRUE;
XX    else
XX	{
XX	curwp->w_force = 0;             /* Center dot. */
XX	curwp->w_flag |= WFFORCE;
XX	}
XX    wp = wheadp;	    /* update all mode lines */
XX    while (wp != NULL) {
XX	wp->w_flag |= WFMODE;
XX	wp = wp->w_wndp;
XX	}
XX    return (TRUE);
XX    }
XX
XX
XX/*
XX * The command make the next window (next => down the screen) the current
XX * window. There are no real errors, although the command does nothing if
XX * there is only 1 window on the screen. Bound to "C-X C-N".
XX
XX */
XXnextwind(f, n)
XX    {
XX    register WINDOW *wp;
XX
XX    if ((wp = curwp->w_wndp) == NULL) wp = wheadp;
XX
XX    curwp = wp;
XX    curbp = wp->w_bufp;
XX    upmode();
XX    return (TRUE);
XX    }
XX
XX/*
XX * This command makes the previous window (previous => up the screen) the
XX * current window. There arn't any errors, although the command does not do a
XX * lot if there is 1 window.
XX */
XXprevwind(f, n)
XX    {
XX    register WINDOW *wp1;
XX    register WINDOW *wp2;
XX
XX    wp1 = wheadp;
XX    wp2 = curwp;
XX
XX    if (wp1 == wp2) wp2 = NULL;
XX
XX    while (wp1->w_wndp != wp2) wp1 = wp1->w_wndp;
XX
XX    curwp = wp1;
XX    curbp = wp1->w_bufp;
XX    upmode();
XX    return (TRUE);
XX    }
XX
XX/*
XX * This command moves the current window down by "arg" lines. Recompute the
XX * top line in the window. The move up and move down code is almost completely
XX * the same; most of the work has to do with reframing the window, and picking
XX * a new dot. We share the code by having "move down" just be an interface to
XX * "move up". Magic. Bound to "C-X C-N".
XX */
XXmvdnwind(f, n)
XXint n;
XX    {
XX
XX    return (mvupwind(f, -n));
XX    }
XX
XX/*
XX * Move the current window up by "arg" lines. Recompute the new top line of
XX * the window. Look to see if "." is still on the screen. If it is, you win.
XX * If it isn't, then move "." to center it in the new framing of the window
XX * (this command does not really move "."; it moves the frame). Bound to
XX * "C-X C-P".
XX */
XXmvupwind(f, n)
XXint n;
XX    {
XX    register LINE *lp;
XX    register int i;
XX
XX    lp = curwp->w_linep;
XX
XX    if (n < 0) {
XX	while (n++ && lp!=curbp->b_linep) lp = lforw(lp);
XX	}
XX    else
XX	{
XX	while (n-- && lback(lp)!=curbp->b_linep) lp = lback(lp);
XX	}
XX
XX    curwp->w_linep = lp;
XX    curwp->w_flag |= WFHARD;            /* Mode line is OK. */
XX
XX    for (i = 0; i < curwp->w_ntrows; ++i) {
XX	if (lp == curwp->w_dotp) return (TRUE);
XX	if (lp == curbp->b_linep) break;
XX	lp = lforw(lp);
XX	}
XX
XX    lp = curwp->w_linep;
XX    i = curwp->w_ntrows/2;
XX
XX    while (i-- && lp != curbp->b_linep) lp = lforw(lp);
XX
XX    curwp->w_dotp = lp;
XX    curwp->w_doto = 0;
XX    return (TRUE);
XX    }
XX
XX/*
XX * This command makes the current window the only window on the screen. Bound
XX * to "C-X 1". Try to set the framing so that "." does not have to move on the
XX * display. Some care has to be taken to keep the values of dot and mark in
XX * the buffer structures right if the destruction of a window makes a buffer
XX * become undisplayed.
XX */
XXonlywind(f, n)
XX    {
XX    register WINDOW *wp;
XX    register LINE   *lp;
XX    register int    i;
XX
XX    while (wheadp != curwp) {
XX	wp = wheadp;
XX	wheadp = wp->w_wndp;
XX	if (--wp->w_bufp->b_nwnd == 0) {
XX	    wp->w_bufp->b_dotp = wp->w_dotp;
XX	    wp->w_bufp->b_doto = wp->w_doto;
XX	    wp->w_bufp->b_markp = wp->w_markp;
XX	    wp->w_bufp->b_marko = wp->w_marko;
XX	    }
XX	free((char *) wp);
XX	}
XX    while (curwp->w_wndp != NULL) {
XX	wp = curwp->w_wndp;
XX	curwp->w_wndp = wp->w_wndp;
XX	if (--wp->w_bufp->b_nwnd == 0) {
XX	    wp->w_bufp->b_dotp = wp->w_dotp;
XX	    wp->w_bufp->b_doto = wp->w_doto;
XX	    wp->w_bufp->b_markp = wp->w_markp;
XX	    wp->w_bufp->b_marko = wp->w_marko;
XX	    }
XX	free((char *) wp);
XX	}
XX    lp = curwp->w_linep;
XX    i = curwp->w_toprow;
XX    while (i!=0 && lback(lp)!=curbp->b_linep) {
XX	--i;
XX	lp = lback(lp);
XX	}
XX    curwp->w_toprow = 0;
XX    curwp->w_ntrows = term.t_nrow-1;
XX    curwp->w_linep = lp;
XX    curwp->w_flag |= WFMODE|WFHARD;
XX    return (TRUE);
XX    }
XX
XX/*
XX * This command deletes the current window (provided it isn't the only one)
XX */
XXdelwind(f, n)
XX    {
XX    register WINDOW *wp,*prevwp;
XX    register LINE   *lp;
XX    register int    ntr,i;
XX
XX    wp = wheadp;
XX    if (wp->w_wndp == NULL) {
XX	mlwrite("Cannot delete the only window");
XX	return(FALSE);
XX	}
XX    prevwp = NULL;
XX    while (wp != curwp) { prevwp = wp ; wp = wp->w_wndp; }
XX    if (prevwp == NULL)	wheadp = wp->w_wndp;
XX    else		prevwp->w_wndp = wp->w_wndp;
XX	
XX    if (--wp->w_bufp->b_nwnd == 0) {
XX	wp->w_bufp->b_dotp = wp->w_dotp;
XX	wp->w_bufp->b_doto = wp->w_doto;
XX	wp->w_bufp->b_markp = wp->w_markp;
XX	wp->w_bufp->b_marko = wp->w_marko;
XX	}
XX    ntr = wp->w_ntrows + 1;
XX    free((char *) wp);
XX
XX    curwp = wheadp;
XX    curbp = wheadp->w_bufp;
XX    lp = curwp->w_linep;
XX    i = curwp->w_toprow;
XX    while (i!=0 && lback(lp)!=curbp->b_linep) {
XX	--i;
XX	lp = lback(lp);
XX	}
XX    curwp->w_toprow = 0;
XX    curwp->w_ntrows += ntr;
XX    curwp->w_linep = lp;
XX    curwp->w_flag |= WFMODE|WFHARD;
XX    return (TRUE);
XX    }
XX
XX/*
XX * Split the current window. A window smaller than 3 lines cannot be split.
XX * The only other error that is possible is a "malloc" failure allocating the
XX * structure for the new window. Bound to "C-X 2".
XX */
XXsplitwind(f, n)
XX    {
XX    register WINDOW *wp;
XX    register LINE   *lp;
XX    register int    ntru;
XX    register int    ntrl;
XX    register int    ntrd;
XX    register WINDOW *wp1;
XX    register WINDOW *wp2;
XX    char *malloc();
XX
XX    if (curwp->w_ntrows < 3) {
XX	mlwrite("Cannot split a %d line window", curwp->w_ntrows);
XX	return (FALSE);
XX	}
XX    if ((wp = (WINDOW *) malloc(sizeof(WINDOW))) == NULL) {
XX	mlwrite("Cannot allocate WINDOW block");
XX	return (FALSE);
XX	}
XX    ++curbp->b_nwnd; /* Displayed twice. */
XX    wp->w_bufp = curbp;
XX    wp->w_dotp = curwp->w_dotp;
XX    wp->w_doto = curwp->w_doto;
XX    wp->w_markp = curwp->w_markp;
XX    wp->w_marko = curwp->w_marko;
XX    wp->w_flag = 0;
XX    wp->w_force = 0;
XX    ntru = (curwp->w_ntrows-1) / 2;         /* Upper size */
XX    ntrl = (curwp->w_ntrows-1) - ntru;      /* Lower size */
XX    lp = curwp->w_linep;
XX    ntrd = 0;
XX    while (lp != curwp->w_dotp) {
XX	++ntrd;
XX	lp = lforw(lp);
XX	}
XX    lp = curwp->w_linep;
XX    if (ntrd <= ntru) {                     /* Old is upper window. */
XX	if (ntrd == ntru)               /* Hit mode line. */
XX	    lp = lforw(lp);
XX	curwp->w_ntrows = ntru;
XX	wp->w_wndp = curwp->w_wndp;
XX	curwp->w_wndp = wp;
XX	wp->w_toprow = curwp->w_toprow+ntru+1;
XX	wp->w_ntrows = ntrl;
XX	}
XX    else {                                /* Old is lower window */
XX	wp1 = NULL;
XX	wp2 = wheadp;
XX	while (wp2 != curwp) {
XX	    wp1 = wp2;
XX	    wp2 = wp2->w_wndp;
XX	    }
XX	if (wp1 == NULL) wheadp = wp;
XX	else
XX	wp1->w_wndp = wp;
XX	wp->w_wndp = curwp;
XX	wp->w_toprow = curwp->w_toprow;
XX	wp->w_ntrows = ntru;
XX	++ntru; /* Mode line. */
XX	curwp->w_toprow += ntru;
XX	curwp->w_ntrows = ntrl;
XX	while (ntru--) lp = lforw(lp);
XX	}
XX    curwp->w_linep = lp;                    /* Adjust the top lines */
XX    wp->w_linep = lp;                       /* if necessary. */
XX    curwp->w_flag |= WFMODE|WFHARD;
XX    wp->w_flag |= WFMODE|WFHARD;
XX    return (TRUE);
XX    }
XX
XX/*
XX * Enlarge the current window. Find the window that loses space. Make sure it
XX * is big enough. If so, hack the window descriptions, and ask redisplay to do
XX * all the hard work. You don't just set "force reframe" because dot would
XX * move. Bound to "C-X Z".
XX */
XXenlargewind(f, n)
XX    {
XX    register WINDOW *adjwp;
XX    register LINE   *lp;
XX    register int    i;
XX
XX    if (n < 0) return (shrinkwind(f, -n));
XX    if (wheadp->w_wndp == NULL) {
XX	mlwrite("Only one window");
XX	return (FALSE);
XX	}
XX    if ((adjwp=curwp->w_wndp) == NULL) {
XX	adjwp = wheadp;
XX	while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp;
XX	}
XX    if (adjwp->w_ntrows <= n) {
XX	mlwrite("Impossible change");
XX	return (FALSE);
XX	}
XX    if (curwp->w_wndp == adjwp) {           /* Shrink below. */
XX	lp = adjwp->w_linep;
XX	for (i=0; i<n && lp!=adjwp->w_bufp->b_linep; ++i) lp = lforw(lp);
XX	adjwp->w_linep = lp;
XX	adjwp->w_toprow += n;
XX	}
XX    else {                                /* Shrink above. */
XX	lp = curwp->w_linep;
XX	for (i=0; i<n && lback(lp)!=curbp->b_linep; ++i) lp = lback(lp);
XX	curwp->w_linep = lp;
XX	curwp->w_toprow -= n;
XX	}
XX    curwp->w_ntrows += n;
XX    adjwp->w_ntrows -= n;
XX    curwp->w_flag |= WFMODE|WFHARD;
XX    adjwp->w_flag |= WFMODE|WFHARD;
XX    return (TRUE);
XX    }
XX
XX/*
XX * Shrink the current window. Find the window that gains space. Hack at the
XX * window descriptions. Ask the redisplay to do all the hard work. Bound to
XX * "C-X C-Z".
XX */
XXshrinkwind(f, n)
XX    {
XX    register WINDOW *adjwp;
XX    register LINE   *lp;
XX    register int    i;
XX
XX    if (n < 0) return (enlargewind(f, -n));
XX    if (wheadp->w_wndp == NULL) {
XX	mlwrite("Only one window");
XX	return (FALSE);
XX	}
XX    if ((adjwp=curwp->w_wndp) == NULL) {
XX	adjwp = wheadp;
XX	while (adjwp->w_wndp != curwp) adjwp = adjwp->w_wndp;
XX	}
XX    if (curwp->w_ntrows <= n) {
XX	mlwrite("Impossible change");
XX	return (FALSE);
XX	}
XX    if (curwp->w_wndp == adjwp) {           /* Grow below. */
XX		 lp = adjwp->w_linep;
XX	for (i=0; i<n && lback(lp)!=adjwp->w_bufp->b_linep; ++i) lp = lback(lp);
XX	adjwp->w_linep = lp;
XX	adjwp->w_toprow -= n;
XX	}
XX    else {                                /* Grow above. */
XX	lp = curwp->w_linep;
XX	for (i=0; i<n && lp!=curbp->b_linep; ++i) lp = lforw(lp);
XX	curwp->w_linep = lp;
XX	curwp->w_toprow += n;
XX	}
XX    curwp->w_ntrows -= n;
XX    adjwp->w_ntrows += n;
XX    curwp->w_flag |= WFMODE|WFHARD;
XX    adjwp->w_flag |= WFMODE|WFHARD;
XX    return (TRUE);
XX    }
XX
XX/*
XX * Pick a window for a pop-up. Split the screen if there is only one window.
XX * Pick the uppermost window that isn't the current window. An LRU algorithm
XX * might be better. Return a pointer, or NULL on error.
XX */
XXWINDOW *
XXwpopup()
XX    {
XX    register WINDOW *wp;
XX
XX    if (wheadp->w_wndp == NULL              /* Only 1 window */
XX		 && splitwind(FALSE, 0) == FALSE)        /* and it won't split */
XX    return (NULL);
XX    wp = wheadp;                            /* Find window to use */
XX    while (wp!=NULL && wp==curwp) wp = wp->w_wndp;
XX    return (wp);
XX    }
XX
XXscrnextup(f, n)	    /* scroll the next window up (back) a page */
XX
XX    {
XX    nextwind(FALSE, 1);
XX    backpage(f, n);
XX    prevwind(FALSE, 1);
XX    }
XX
XXscrnextdw(f, n)	    /* scroll the next window down (forward) a page */
XX
XX    {
XX    nextwind(FALSE, 1);
XX    forwpage(f, n);
XX    prevwind(FALSE, 1);
XX    }
XX
SHAR_EOF
if test 11068 -ne "`wc -c window.c`"
then
echo shar: error transmitting window.c '(should have been 11068 characters)'
fi
echo shar: extracting word.c
sed 's/^XX//' << \SHAR_EOF > word.c
XX/*
XX * The routines in this file implement commands that work word at a time.
XX * There are all sorts of word mode commands. If I do any sentence and/or
XX * paragraph mode commands, they are likely to be put in this file.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include	"edef.h"
XX
XX/* Word wrap on n-spaces. Back-over whatever precedes the point on the current
XX * line and stop on the first word-break or the beginning of the line. If we
XX * reach the beginning of the line, jump back to the end of the word and start
XX * a new line.  Otherwise, break the line at the word-break, eat it, and jump
XX * back to the end of the word.
XX * Returns TRUE on success, FALSE on errors.
XX */
XXwrapword(n)
XXint n;
XX    {
XX    register int chr;
XX
XX    /* back up until we are in a word,
XX       make sure there is a break in the line */
XX    do {
XX	if (! backchar(0, 1)) return(FALSE);
XX	}
XX    while (! inword());
XX
XX    /* backup past the space */
XX    if (! backword(0, 1)) return(FALSE);
XX
XX    /* backup until we have a space or tab */
XX    chr = lgetc(curwp->w_dotp, curwp->w_doto);
XX    while (chr != ' ' && chr != '\t') {
XX	if (! backchar(0, 1)) return(FALSE);    
XX	chr = lgetc(curwp->w_dotp, curwp->w_doto);
XX	}
XX
XX    /* delete the forward space */
XX    if (! forwdel(0, 1)) return(FALSE);
XX
XX    /* put in an end of line */
XX    if (! newline(0, 1)) return(FALSE);
XX
XX    /* advance past the next word and space and return */
XX    while (inword() != FALSE) {
XX	if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	}
XX
XX    /* and to the end of that line */
XX    curwp->w_doto = llength(curwp->w_dotp);
XX    return(TRUE);
XX    }
XX
XX/*
XX * Move the cursor backward by "n" words. All of the details of motion are
XX * performed by the "backchar" and "forwchar" routines. Error if you try to
XX * move beyond the buffers.
XX */
XXbackword(f, n)
XX    {
XX    if (n < 0) return (forwword(f, -n));
XX    if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX    while (n--) {
XX	while (inword() == FALSE) {
XX	    if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX	while (inword() != FALSE) {
XX	    if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX	}
XX    return (forwchar(FALSE, 1));
XX    }
XX
XX/*
XX * Move the cursor forward by the specified number of words. All of the motion
XX * is done by "forwchar". Error if you try and move beyond the buffer's end.
XX */
XXforwword(f, n)
XX    {
XX    if (n < 0) return (backword(f, -n));
XX    while (n--) {
XX#if NFWORD
XX	while (inword() != FALSE) {
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX#endif
XX	while (inword() == FALSE) {
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX#if NFWORD == 0
XX	while (inword() != FALSE) {
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX#endif
XX	}
XX    return(TRUE);
XX    }
XX
XX/*
XX * Move the cursor forward by the specified number of words. As you move,
XX * convert any characters to upper case. Error if you try and move beyond the
XX * end of the buffer. Bound to "M-U".
XX */
XXupperword(f, n)
XX    {
XX    register int    c;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if (n < 0) return (FALSE);
XX    while (n--) {
XX	while (inword() == FALSE) {
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX	while (inword() != FALSE) {
XX	    c = lgetc(curwp->w_dotp, curwp->w_doto);
XX	    if (c>='a' && c<='z') {
XX		c -= 'a'-'A';
XX		lputc(curwp->w_dotp, curwp->w_doto, c);
XX		lchange(WFHARD);
XX		}
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX	}
XX
XX    return (TRUE);
XX    }
XX
XX/*
XX * Move the cursor forward by the specified number of words. As you move
XX * convert characters to lower case. Error if you try and move over the end of
XX * the buffer. Bound to "M-L".
XX */
XXlowerword(f, n)
XX    {
XX    register int    c;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if (n < 0) return (FALSE);
XX    while (n--) {
XX	while (inword() == FALSE) {
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX	while (inword() != FALSE) {
XX	    c = lgetc(curwp->w_dotp, curwp->w_doto);
XX	    if (c>='A' && c<='Z') {
XX		c += 'a'-'A';
XX		lputc(curwp->w_dotp, curwp->w_doto, c);
XX		lchange(WFHARD);
XX		}
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * Move the cursor forward by the specified number of words. As you move
XX * convert the first character of the word to upper case, and subsequent
XX * characters to lower case. Error if you try and move past the end of the
XX * buffer. Bound to "M-C".
XX */
XXcapword(f, n)
XX    {
XX    register int    c;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if (n < 0) return (FALSE);
XX    while (n--) {
XX	while (inword() == FALSE) {
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    }
XX	if (inword() != FALSE) {
XX	    c = lgetc(curwp->w_dotp, curwp->w_doto);
XX	    if (c>='a' && c<='z') {
XX		c -= 'a'-'A';
XX		lputc(curwp->w_dotp, curwp->w_doto, c);
XX		lchange(WFHARD);
XX		}
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    while (inword() != FALSE) {
XX		c = lgetc(curwp->w_dotp, curwp->w_doto);
XX		if (c>='A' && c<='Z') {
XX		    c += 'a'-'A';
XX		    lputc(curwp->w_dotp, curwp->w_doto, c);
XX		    lchange(WFHARD);
XX		    }
XX		if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX		}
XX	    }
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * Kill forward by "n" words. Remember the location of dot. Move forward by
XX * the right number of words. Put dot back where it was and issue the kill
XX * command for the right number of characters. Bound to "M-D".
XX */
XXdelfword(f, n)
XX    {
XX    register int    size;
XX    register LINE   *dotp;
XX    register int    doto;
XX
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if (n < 0) return (FALSE);
XX    dotp = curwp->w_dotp;
XX    doto = curwp->w_doto;
XX    size = 0;
XX    while (n--) {
XX#if NFWORD
XX	while (inword() != FALSE) {
XX	    if (forwchar(FALSE,1) == FALSE) return(FALSE);
XX	    ++size;
XX	    }
XX#endif
XX	while (inword() == FALSE) {
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    ++size;
XX	    }
XX#if NFWORD == 0
XX	while (inword() != FALSE) {
XX	    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX	    ++size;
XX	    }
XX#endif
XX	}
XX    curwp->w_dotp = dotp;
XX    curwp->w_doto = doto;
XX    return (ldelete(size, TRUE));
XX    }
XX
XX/*
XX * Kill backwards by "n" words. Move backwards by the desired number of words,
XX * counting the characters. When dot is finally moved to its resting place,
XX * fire off the kill command. Bound to "M-Rubout" and to "M-Backspace".
XX */
XXdelbword(f, n)
XX    {
XX    register int    size;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if (n < 0) return (FALSE);
XX    if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX    size = 0;
XX    while (n--) {
XX	while (inword() == FALSE) {
XX	    if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX	    ++size;
XX	    }
XX	while (inword() != FALSE) {
XX	    if (backchar(FALSE, 1) == FALSE) return (FALSE);
XX	    ++size;
XX	    }
XX	}
XX    if (forwchar(FALSE, 1) == FALSE) return (FALSE);
XX    return (ldelete(size, TRUE));
XX    }
XX
XX/*
XX * Return TRUE if the character at dot is a character that is considered to be
XX * part of a word. The word character list is hard coded. Should be setable.
XX */
XXinword()
XX    {
XX    register int    c;
XX
XX    if (curwp->w_doto == llength(curwp->w_dotp)) return (FALSE);
XX    c = lgetc(curwp->w_dotp, curwp->w_doto);
XX    if (c>='a' && c<='z') return (TRUE);
XX    if (c>='A' && c<='Z') return (TRUE);
XX    if (c>='0' && c<='9') return (TRUE);
XX    if (c=='$' || c=='_')                   /* For identifiers */
XX		 return (TRUE);
XX    return (FALSE);
XX    }
XX
XXfillpara(f, n)	/* Fill the current paragraph according to the current
XXfill column */
XX
XXint f, n;   /* deFault flag and Numeric argument */
XX
XX    {
XX    register int c;	    /* current char durring scan */
XX    register int wordlen;	/* length of current word */
XX    register int clength;	/* position on line during fill */
XX    register int i;	    /* index during word copy */
XX    register int newlength;	/* tentative new line length */
XX    register int eopflag;	/* Are we at the End-Of-Paragraph? */
XX    register int firstflag;	/* first word? (needs no space) */
XX    register LINE *eopline;	/* pointer to line just past EOP */
XX    char wbuf[NSTRING];	    /* buffer for current word */
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if (fillcol == 0) {	/* no fill column set */
XX		 mlwrite("No fill column set");
XX	return(FALSE);
XX	}
XX
XX    /* record the pointer to the line just past the EOP */
XX    gotoeop(FALSE, 1);
XX    eopline = lforw(curwp->w_dotp);
XX
XX    /* and back top the begining of the paragraph */
XX    gotobop(FALSE, 1);
XX
XX    /* initialize various info */
XX    clength = curwp->w_doto;
XX    if (clength && curwp->w_dotp->l_text[0] == TAB) clength = 8;
XX    wordlen = 0;
XX
XX    /* scan through lines, filling words */
XX    firstflag = TRUE;
XX    eopflag = FALSE;
XX    while (!eopflag) {
XX	/* get the next character in the paragraph */
XX	if (curwp->w_doto == llength(curwp->w_dotp)) {
XX	    c = ' ';
XX	    if (lforw(curwp->w_dotp) == eopline) eopflag = TRUE;
XX	    }
XX	else
XX	c = lgetc(curwp->w_dotp, curwp->w_doto);
XX
XX	/* and then delete it */
XX	ldelete(1, FALSE);
XX
XX	/* if not a separator, just add it in */
XX	if (c != ' ' && c != '	') {
XX	    if (wordlen < NSTRING - 1) wbuf[wordlen++] = c;
XX	    }
XX	else if (wordlen) {
XX	    /* at a word break with a word waiting */
XX	    /* calculate tantitive new length with word added */
XX	    newlength = clength + 1 + wordlen;
XX	    if (newlength <= fillcol) {
XX		/* add word to current line */
XX		if (!firstflag) {
XX		    linsert(1, ' '); /* the space */
XX		    ++clength;
XX		    }
XX		firstflag = FALSE;
XX
XX		}
XX	    else {
XX		/* start a new line */
XX		lnewline();
XX		clength = 0;
XX		}
XX
XX	    /* and add the word in in either case */
XX	    for (i=0; i<wordlen; i++) {
XX		linsert(1, wbuf[i]);
XX		++clength;
XX		}
XX	    wordlen = 0;
XX	    }
XX	}
XX    /* and add a last newline for the end of our new paragraph */
XX    lnewline();
XX    }
SHAR_EOF
if test 10090 -ne "`wc -c word.c`"
then
echo shar: error transmitting word.c '(should have been 10090 characters)'
fi
#	End of shell archive
exit 0

wecker@cookie.dec.com.UUCP (02/21/87)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	fileio.c
#	line.c
#	lisp.c
#	lock.c
#	main.c
#	random.c
# This archive created: Fri Feb 20 17:44:33 1987
echo shar: extracting fileio.c
sed 's/^XX//' << \SHAR_EOF > fileio.c
XX/*
XX * The routines in this file read and write ASCII files from the disk. All of
XX * the knowledge about files are here. A better message writing scheme should
XX * be used.
XX */
XX#include <stdio.h>
XX#include	"estruct.h"
XX#include "edef.h"
XX
XXFILE *ffp;                           /* File pointer, all functions. */
XX
XX/*
XX * Open a file for reading.
XX */
XXffropen(fn)
XXchar *fn;
XX    {
XX    if ((ffp=fopen(fn, "r")) == NULL) return (FIOFNF);
XX    return (FIOSUC);
XX    }
XX
XX/*
XX * Open a file for writing. Return TRUE if all is well, and FALSE on error
XX * (cannot create).
XX */
XXffwopen(fn)
XXchar *fn;
XX    {
XX#if VMS
XX    register int    fd;
XX
XX    if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0 || (ffp=fdopen(fd, "w")) == NULL) {
XX#else
XX	if ((ffp=fopen(fn, "w")) == NULL) {
XX#endif
XX	    mlwrite("Cannot open file for writing");
XX	    return (FIOERR);
XX	    }
XX	return (FIOSUC);
XX	}
XX
XX    /*
XX     * Close a file. Should look at the status in all systems.
XX */
XX    ffclose()
XX	{
XX#if ULTRIX
XX	if (fclose(ffp) != FALSE) {
XX	    mlwrite("Error closing file");
XX	    return(FIOERR);
XX	    }
XX	return(FIOSUC);
XX#else
XX	fclose(ffp);
XX	return (FIOSUC);
XX#endif
XX	}
XX
XX    /*
XX     * Write a line to the already opened file. The "buf" points to the buffer,
XX     * and the "nbuf" is its length, less the free newline. Return the status.
XX     * Check only at the newline.
XX */
XX    ffputline(buf, nbuf)
XX    char buf[];
XX	{
XX	register int    i;
XX
XX	for (i = 0; i < nbuf; ++i) fputc(buf[i]&0xFF, ffp);
XX
XX	fputc('\n', ffp);
XX
XX	if (ferror(ffp)) {
XX	    mlwrite("Write I/O error");
XX	    return (FIOERR);
XX	    }
XX
XX	return (FIOSUC);
XX	}
XX
XX    /*
XX     * Read a line from a file, and store the bytes in the supplied buffer. The
XX     * "nbuf" is the length of the buffer. Complain about long lines and lines
XX     * at the end of the file that don't have a newline present. Check for I/O
XX     * errors too. Return status.
XX */
XX    ffgetline(buf, nbuf)
XX    register char   buf[];
XX	{
XX	register int    c;
XX	register int    i;
XX
XX	i = 0;
XX
XX	while ((c = fgetc(ffp)) != EOF && c != '\n') {
XX	    if (i >= nbuf-2) {
XX		buf[nbuf - 2] = c;  /* store last char read */
XX		buf[nbuf - 1] = 0;  /* and terminate it */
XX		mlwrite("File has long line");
XX		return (FIOLNG);
XX		}
XX	    buf[i++] = c;
XX	    }
XX
XX	if (c == EOF) {
XX	    if (ferror(ffp)) {
XX		mlwrite("File read error");
XX		return (FIOERR);
XX		}
XX
XX	    if (i != 0) {
XX		mlwrite("File has funny line at EOF");
XX		return (FIOERR);
XX		}
XX	    return (FIOEOF);
XX	    }
XX
XX	buf[i] = 0;
XX	return (FIOSUC);
XX	}
XX    
SHAR_EOF
if test 2446 -ne "`wc -c fileio.c`"
then
echo shar: error transmitting fileio.c '(should have been 2446 characters)'
fi
echo shar: extracting line.c
sed 's/^XX//' << \SHAR_EOF > line.c
XX/*
XX * The functions in this file are a general set of line management utilities.
XX * They are the only routines that touch the text. They also touch the buffer
XX * and window structures, to make sure that the necessary updating gets done.
XX * There are routines in this file that handle the kill buffer too. It isn't
XX * here for any good reason.
XX *
XX * Note that this code only updates the dot and mark values in the window list.
XX * Since all the code acts on the current window, the buffer that we are
XX * editing must be being displayed, which means that "b_nwnd" is non zero,
XX * which means that the dot and mark values in the buffer headers are nonsense.
XX */
XX
XX#include <stdio.h>
XX#include   "estruct.h"
XX#include "edef.h"
XX
XX#define NBLOCK  16                      /* Line block chunk size */
XX#define KBLOCK  1024                    /* Kill buffer block size */
XX
XXchar *kbufp  = NULL;                 /* Kill buffer data */
XXunsigned kused   = 0;                   /* # of bytes used in KB */
XXunsigned ksize   = 0;                   /* # of bytes allocated in KB */
XX
XX/*
XX * This routine allocates a block of memory large enough to hold a LINE
XX * containing "used" characters. The block is always rounded up a bit. Return
XX * a pointer to the new block, or NULL if there isn't any memory left. Print a
XX * message in the message line if no space.
XX */
XXLINE *
XXlalloc(used)
XXregister int    used;
XX    {
XX    register LINE   *lp;
XX    register int    size;
XX    char *malloc();
XX
XX    size = (used+NBLOCK-1) & ~(NBLOCK-1);
XX    if (size == 0)                          /* Assume that an empty */
XX       size = NBLOCK;                  /* line is for type-in. */
XX    if ((lp = (LINE *) malloc(sizeof(LINE)+size)) == NULL) {
XX	mlwrite("Cannot allocate %d bytes", size);
XX	return (NULL);
XX	}
XX    lp->l_size = size;
XX    lp->l_used = used;
XX    return (lp);
XX    }
XX
XX/*
XX * Delete line "lp". Fix all of the links that might point at it (they are
XX * moved to offset 0 of the next line. Unlink the line from whatever buffer it
XX * might be in. Release the memory. The buffers are updated too; the magic
XX * conditions described in the above comments don't hold here.
XX */
XXlfree(lp)
XXregister LINE   *lp;
XX    {
XX    register BUFFER *bp;
XX    register WINDOW *wp;
XX
XX    wp = wheadp;
XX    while (wp != NULL) {
XX	if (wp->w_linep == lp) wp->w_linep = lp->l_fp;
XX	if (wp->w_dotp  == lp) {
XX	    wp->w_dotp = lp->l_fp;
XX	    wp->w_doto = 0;
XX	    }
XX	if (wp->w_markp == lp) {
XX	    wp->w_markp = lp->l_fp;
XX	    wp->w_marko = 0;
XX	    }
XX	wp = wp->w_wndp;
XX	}
XX    bp = bheadp;
XX    while (bp != NULL) {
XX	if (bp->b_nwnd == 0) {
XX	    if (bp->b_dotp  == lp) {
XX		bp->b_dotp = lp->l_fp;
XX		bp->b_doto = 0;
XX		}
XX	    if (bp->b_markp == lp) {
XX		bp->b_markp = lp->l_fp;
XX		bp->b_marko = 0;
XX		}
XX	    }
XX	bp = bp->b_bufp;
XX	}
XX    lp->l_bp->l_fp = lp->l_fp;
XX    lp->l_fp->l_bp = lp->l_bp;
XX    free((char *) lp);
XX    }
XX
XX/*
XX * This routine gets called when a character is changed in place in the current
XX * buffer. It updates all of the required flags in the buffer and window
XX * system. The flag used is passed as an argument; if the buffer is being
XX * displayed in more than 1 window we change EDIT t HARD. Set MODE if the
XX * mode line needs to be updated (the "*" has to be set).
XX */
XXlchange(flag)
XXregister int    flag;
XX    {
XX    register WINDOW *wp;
XX
XX    if (curbp->b_nwnd != 1)                 /* Ensure hard. */
XX       flag = WFHARD;
XX    if ((curbp->b_flag&BFCHG) == 0) {       /* First change, so */
XX	flag |= WFMODE;                 /* update mode lines. */
XX	curbp->b_flag |= BFCHG;
XX	}
XX    wp = wheadp;
XX    while (wp != NULL) {
XX	if (wp->w_bufp == curbp) wp->w_flag |= flag;
XX	wp = wp->w_wndp;
XX	}
XX    }
XX
XX/*
XX * Insert "n" copies of the character "c" at the current location of dot. In
XX * the easy case all that happens is the text is stored in the line. In the
XX * hard case, the line has to be reallocated. When the window list is updated,
XX * take special care; I screwed it up once. You always update dot in the
XX * current window. You update mark, and a dot in another window, if it is
XX * greater than the place where you did the insert. Return TRUE if all is
XX * well, and FALSE on errors.
XX */
XXlinsert(n, c)
XX    {
XX    register char   *cp1;
XX    register char   *cp2;
XX    register LINE   *lp1;
XX    register LINE   *lp2;
XX    register LINE   *lp3;
XX    register int    doto;
XX    register int    i;
XX    register WINDOW *wp;
XX
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX       return(rdonly());   /* we are in read only mode */
XX    lchange(WFEDIT);
XX    lp1 = curwp->w_dotp;                    /* Current line */
XX    if (lp1 == curbp->b_linep) {            /* At the end: special */
XX	if (curwp->w_doto != 0) {
XX	    mlwrite("bug: linsert");
XX	    return (FALSE);
XX	    }
XX	if ((lp2=lalloc(n)) == NULL)    /* Allocate new line */
XX	    return (FALSE);
XX	lp3 = lp1->l_bp;                /* Previous line */
XX	lp3->l_fp = lp2;                /* Link in */
XX	lp2->l_fp = lp1;
XX	lp1->l_bp = lp2;
XX	lp2->l_bp = lp3;
XX	for (i=0; i<n; ++i) lp2->l_text[i] = c;
XX	curwp->w_dotp = lp2;
XX	curwp->w_doto = n;
XX	return (TRUE);
XX	}
XX    doto = curwp->w_doto;                   /* Save for later. */
XX    if (lp1->l_used+n > lp1->l_size) {      /* Hard: reallocate */
XX	if ((lp2=lalloc(lp1->l_used+n)) == NULL)
XX	    return (FALSE);
XX	cp1 = &lp1->l_text[0];
XX	cp2 = &lp2->l_text[0];
XX	while (cp1 != &lp1->l_text[doto]) *cp2++ = *cp1++;
XX	cp2 += n;
XX	while (cp1 != &lp1->l_text[lp1->l_used]) *cp2++ = *cp1++;
XX	lp1->l_bp->l_fp = lp2;
XX	lp2->l_fp = lp1->l_fp;
XX	lp1->l_fp->l_bp = lp2;
XX	lp2->l_bp = lp1->l_bp;
XX	free((char *) lp1);
XX	}
XX    else {                                /* Easy: in place */
XX	lp2 = lp1;                      /* Pretend new line */
XX	lp2->l_used += n;
XX	cp2 = &lp1->l_text[lp1->l_used];
XX	cp1 = cp2-n;
XX	while (cp1 != &lp1->l_text[doto]) *--cp2 = *--cp1;
XX	}
XX    for (i=0; i<n; ++i)                     /* Add the characters */
XX       lp2->l_text[doto+i] = c;
XX    wp = wheadp;                            /* Update windows */
XX    while (wp != NULL) {
XX	if (wp->w_linep == lp1) wp->w_linep = lp2;
XX	if (wp->w_dotp == lp1) {
XX	    wp->w_dotp = lp2;
XX	    if (wp==curwp || wp->w_doto>doto) wp->w_doto += n;
XX	    }
XX	if (wp->w_markp == lp1) {
XX	    wp->w_markp = lp2;
XX	    if (wp->w_marko > doto) wp->w_marko += n;
XX	    }
XX	wp = wp->w_wndp;
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * Insert a newline into the buffer at the current location of dot in the
XX * current window. The funny ass-backwards way it does things is not a botch;
XX * it just makes the last line in the file not a special case. Return TRUE if
XX * everything works out and FALSE on error (memory allocation failure). The
XX * update of dot and mark is a bit easier then in the above case, because the
XX * split forces more updating.
XX */
XXlnewline()
XX    {
XX    register char   *cp1;
XX    register char   *cp2;
XX    register LINE   *lp1;
XX    register LINE   *lp2;
XX    register int    doto;
XX    register WINDOW *wp;
XX
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX       return(rdonly());   /* we are in read only mode */
XX    lchange(WFHARD);
XX    lp1 = curwp->w_dotp;                   /* Get the address and */
XX    doto = curwp->w_doto;                   /* offset of "." */
XX    if ((lp2=lalloc(doto)) == NULL)         /* New first half line */
XX       return (FALSE);
XX    cp1 = &lp1->l_text[0];                  /* Shuffle text around */
XX    cp2 = &lp2->l_text[0];
XX    while (cp1 != &lp1->l_text[doto]) *cp2++ = *cp1++;
XX    cp2 = &lp1->l_text[0];
XX    while (cp1 != &lp1->l_text[lp1->l_used]) *cp2++ = *cp1++;
XX    lp1->l_used -= doto;
XX    lp2->l_bp = lp1->l_bp;
XX    lp1->l_bp = lp2;
XX    lp2->l_bp->l_fp = lp2;
XX    lp2->l_fp = lp1;
XX    wp = wheadp;                            /* Windows */
XX    while (wp != NULL) {
XX	if (wp->w_linep == lp1) wp->w_linep = lp2;
XX	if (wp->w_dotp == lp1) {
XX	    if (wp->w_doto < doto) wp->w_dotp = lp2;
XX	    else
XX		wp->w_doto -= doto;
XX	    }
XX	if (wp->w_markp == lp1) {
XX	    if (wp->w_marko < doto) wp->w_markp = lp2;
XX	    else
XX		wp->w_marko -= doto;
XX	    }
XX	wp = wp->w_wndp;
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * This function deletes "n" bytes, starting at dot. It understands how do deal
XX * with end of lines, etc. It returns TRUE if all of the characters were
XX * deleted, and FALSE if they were not (because dot ran into the end of the
XX * buffer. The "kflag" is TRUE if the text should be put in the kill buffer.
XX */
XXldelete(n, kflag)
XX    {
XX    register char   *cp1;
XX    register char   *cp2;
XX    register LINE   *dotp;
XX    register int    doto;
XX    register int    chunk;
XX    register WINDOW *wp;
XX
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX       return(rdonly());   /* we are in read only mode */
XX    while (n != 0) {
XX	dotp = curwp->w_dotp;
XX	doto = curwp->w_doto;
XX	if (dotp == curbp->b_linep)     /* Hit end of buffer. */
XX	    return (FALSE);
XX	chunk = dotp->l_used-doto;      /* Size of chunk. */
XX	if (chunk > n) chunk = n;
XX	if (chunk == 0) {               /* End of line, merge. */
XX	    lchange(WFHARD);
XX	    if (ldelnewline() == FALSE || (kflag!=FALSE && kinsert('\n')==FALSE))
XX		return (FALSE);
XX	    --n;
XX	    continue;
XX	    }
XX	lchange(WFEDIT);
XX	cp1 = &dotp->l_text[doto];      /* Scrunch text. */
XX	cp2 = cp1 + chunk;
XX	if (kflag != FALSE) {           /* Kill? */
XX	    while (cp1 != cp2) {
XX		if (kinsert(*cp1) == FALSE) return (FALSE);
XX		++cp1;
XX		}
XX	    cp1 = &dotp->l_text[doto];
XX	    }
XX	while (cp2 != &dotp->l_text[dotp->l_used]) *cp1++ = *cp2++;
XX	dotp->l_used -= chunk;
XX	wp = wheadp;                    /* Fix windows */
XX	while (wp != NULL) {
XX	    if (wp->w_dotp==dotp && wp->w_doto>=doto) {
XX		wp->w_doto -= chunk;
XX		if (wp->w_doto < doto) wp->w_doto = doto;
XX		}
XX	    if (wp->w_markp==dotp && wp->w_marko>=doto) {
XX		wp->w_marko -= chunk;
XX		if (wp->w_marko < doto) wp->w_marko = doto;
XX		}
XX	    wp = wp->w_wndp;
XX	    }
XX	n -= chunk;
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX * Delete a newline. Join the current line with the next line. If the next line
XX * is the magic header line always return TRUE; merging the last line with the
XX * header line can be thought of as always being a successful operation, even
XX * if nothing is done, and this makes the kill buffer work "right". Easy cases
XX * can be done by shuffling data around. Hard cases require that lines be moved
XX * about in memory. Return FALSE on error and TRUE if all looks ok. Called by
XX * "ldelete" only.
XX */
XXldelnewline()
XX    {
XX    register char   *cp1;
XX    register char   *cp2;
XX    register LINE   *lp1;
XX    register LINE   *lp2;
XX    register LINE   *lp3;
XX    register WINDOW *wp;
XX
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX       return(rdonly());   /* we are in read only mode */
XX    lp1 = curwp->w_dotp;
XX    lp2 = lp1->l_fp;
XX    if (lp2 == curbp->b_linep) {            /* At the buffer end. */
XX	if (lp1->l_used == 0)           /* Blank line. */
XX	lfree(lp1);
XX	return (TRUE);
XX	}
XX    if (lp2->l_used <= lp1->l_size-lp1->l_used) {
XX	cp1 = &lp1->l_text[lp1->l_used];
XX	cp2 = &lp2->l_text[0];
XX	while (cp2 != &lp2->l_text[lp2->l_used]) *cp1++ = *cp2++;
XX	wp = wheadp;
XX	while (wp != NULL) {
XX	    if (wp->w_linep == lp2) wp->w_linep = lp1;
XX	    if (wp->w_dotp == lp2) {
XX		wp->w_dotp = lp1;
XX		wp->w_doto += lp1->l_used;
XX		}
XX	    if (wp->w_markp == lp2) {
XX		wp->w_markp = lp1;
XX		wp->w_marko += lp1->l_used;
XX		}
XX	    wp = wp->w_wndp;
XX	    }
XX	lp1->l_used += lp2->l_used;
XX	lp1->l_fp = lp2->l_fp;
XX	lp2->l_fp->l_bp = lp1;
XX	free((char *) lp2);
XX	return (TRUE);
XX	}
XX    if ((lp3=lalloc(lp1->l_used+lp2->l_used)) == NULL) return (FALSE);
XX    cp1 = &lp1->l_text[0];
XX    cp2 = &lp3->l_text[0];
XX    while (cp1 != &lp1->l_text[lp1->l_used]) *cp2++ = *cp1++;
XX    cp1 = &lp2->l_text[0];
XX    while (cp1 != &lp2->l_text[lp2->l_used]) *cp2++ = *cp1++;
XX    lp1->l_bp->l_fp = lp3;
XX    lp3->l_fp = lp2->l_fp;
XX    lp2->l_fp->l_bp = lp3;
XX    lp3->l_bp = lp1->l_bp;
XX    wp = wheadp;
XX    while (wp != NULL) {
XX	if (wp->w_linep==lp1 || wp->w_linep==lp2) wp->w_linep = lp3;
XX	if (wp->w_dotp == lp1) wp->w_dotp  = lp3;
XX	else if (wp->w_dotp == lp2) {
XX	    wp->w_dotp = lp3;
XX	    wp->w_doto += lp1->l_used;
XX	    }
XX	if (wp->w_markp == lp1) wp->w_markp  = lp3;
XX	else if (wp->w_markp == lp2) {
XX	    wp->w_markp = lp3;
XX	    wp->w_marko += lp1->l_used;
XX	    }
XX	wp = wp->w_wndp;
XX	}
XX    free((char *) lp1);
XX    free((char *) lp2);
XX    return (TRUE);
XX    }
XX
XX/*
XX * Delete all of the text saved in the kill buffer. Called by commands when a
XX * new kill context is being created. The kill buffer array is released, just
XX * in case the buffer has grown to immense size. No errors.
XX */
XXkdelete()
XX    {
XX    if (kbufp != NULL) {
XX	free((char *) kbufp);
XX	kbufp = NULL;
XX	kused = 0;
XX	ksize = 0;
XX	}
XX    }
XX
XX/*
XX * Insert a character to the kill buffer, enlarging the buffer if there isn't
XX * any room. Always grow the buffer in chunks, on the assumption that if you
XX * put something in the kill buffer you are going to put more stuff there too
XX * later. Return TRUE if all is well, and FALSE on errors.
XX */
XX
XXkinsert(c)
XX    {
XX    register char   *nbufp;
XX    char *realloc();
XX    char *malloc();
XX
XX    if (kused == ksize) {
XX	if (ksize == 0)   /* first time through? */
XX	    nbufp = malloc(KBLOCK);   /* alloc the first block */
XX	else   /* or re allocate a bigger block */
XX	    nbufp = realloc(kbufp, ksize+KBLOCK);
XX
XX	if (nbufp == NULL)   /* abort if it fails */
XX	    return(FALSE);
XX	kbufp = nbufp;       /* point our global at it */
XX	ksize += KBLOCK;    /* and adjust the size */
XX	}
XX    kbufp[kused++] = c;
XX    return (TRUE);
XX    }
XX
XX/*
XX * This function gets characters from the kill buffer. If the character index
XX * "n" is off the end, it returns "-1". This lets the caller just scan along
XX * until it gets a "-1" back.
XX */
XXkremove(n)
XX    {
XX    if (n >= kused) return (-1);
XX    else
XX    return (kbufp[n] & 0xFF);
XX    }
XX
XX
XX#if LATTICE | AZTEC
XX/* we need to have the following functions to manage memory that
XXdon't exist under Lattice */
XX
XX
XXchar *realloc(ptr, size)    /* re-allocate a memory chunk to a
XXdifferent size, copying what can
XXby copied */
XX
XXchar *ptr;  /* pointer to the original block */
XXunsigned size;   /* # of bytes needed in new block */
XX
XX    {
XX    char *newptr;   /* pointer to new block */
XX    unsigned csize; /* size of area to copy from old buffer to new */
XX    char *malloc();
XX
XX    newptr = malloc(size);   /* get the new block */
XX    if (newptr == NULL)       /* if malloc fails....*/
XX       return(NULL);
XX
XX    csize = ksize;  /******THIS IS A CHEAT SINCE WE CAN NOT GET
XX			AT THE SIZE OF THE MALLOCED BLOCK!!
XX			DO NOT USE THIS FUNCTION GENERICALLY!!!*/
XX    if (csize > size)   /* we need to copy some stuff from */
XX       csize = size; /* the old buffer to the new */
XX
XX    movmem(ptr, newptr, csize);   /* copy the availible bytes */
XX    free(ptr);   /* dump the old buffer */
XX    return(newptr);       /* and return the new */
XX    }
XX#endif
XX
XX
SHAR_EOF
if test 14691 -ne "`wc -c line.c`"
then
echo shar: error transmitting line.c '(should have been 14691 characters)'
fi
echo shar: extracting lisp.c
sed 's/^XX//' << \SHAR_EOF > lisp.c
XX/**************************************************************************
XX *
XX * Micro LISP functions for micro EMACS
XX *
XX *	V1.0 DBW 870204	Dave Wecker
XX *
XX *************************************************************************/
XX
XX
XX#include <stdio.h>
XX#include <setjmp.h>
XX
XX#include "estruct.h"
XX#include "edef.h"
XX#include "epath.h"
XX
XXextern short doflashing;
XXextern char  *malloc();
XX
XXjmp_buf	env[10];	/* environments for setjmp/longjmp */
XXstatic	envnum = -1;
XX#define	PROGN_RETURN	1
XX#define PROGN_GO	2
XX
XX/* node definitions */
XX#define NIL	0
XX#define CONS	1
XX#define	INTEGER	2
XX#define STRING	3
XX#define	SUBR	4
XX#define SYMBOL	5
XX
XX#if AMIGA
XX#define MAXNODE 500
XX#else
XX#define MAXNODE	5000
XX#endif
XX
XXtypedef struct node {
XX    char	type;
XX    struct node *car;
XX    struct node	*cdr;
XX    } NODE;
XX
XXtypedef	int INTRTN();
XX
XXextern	NODE	*fncmatch();	/* match a function name with an address */
XX
XX#if AMIGA
XXstatic	NODE	TNODE = { INTEGER, 1L, 0L };
XXstatic	NODE	FNODE = { INTEGER, 0L, 0L };
XX#else
XXstatic	NODE	TNODE = { INTEGER, (NODE *)1L, (NODE *)0L };
XXstatic	NODE	FNODE = { INTEGER, (NODE *)0L, (NODE *)0L };
XX#endif
XX
XXstatic	NODE	*syms[26];	/* symbols A-Z */
XXstatic	NODE	*retval;	/* global return value for procedures */
XXstatic	NODE	*gblpar[20];	/* global parameters for emacs routines */
XXstatic	NODE	**nodes = NULL;	/* nodes available to the system */
XXstatic	int	maxnode = -1;	/* current maximum node index */
XXstatic	int	gblidx = 0;	/* current parameter index */
XXstatic	int	gblnum = 0;	/* maximum parameter count */
XXstatic	int	pushback = -1;
XXstatic	LINE	*c_endp;	/* compile end line pointer */
XXstatic	LINE	*c_dotp;	/* current compile line */
XXstatic	short	c_doto;		/* current compile offset */
XXstatic	INTRTN	*lstfnc = NULL;	/* last function executed */
XX
XX/************************** support routines ***************************/
XX
XXDEBUG_dump(n)
XXNODE	*n;
XX    {
XX    long    l;
XX    char    c;
XX
XX    if (n == NULL) {
XX	printf("NIL");
XX	fflush(stderr);
XX	return;
XX	}
XX    switch (n->type) {
XX	case INTEGER:
XX	printf("%ld ",(long)n->car);
XX	break;
XX
XX	case STRING:
XX	printf("\042%s\042 ",(char *)n->car);
XX	break;
XX
XX	case SYMBOL:
XX	l = (long)n->car + 97L;
XX	c = l;
XX	printf("%c ",c);
XX	break;
XX
XX	case SUBR:
XX	printf("#%lx ",(long)n->car);
XX	break;
XX
XX	case CONS:
XX	printf("(");
XX	DEBUG_dump(n->car);
XX	printf(". ");
XX	DEBUG_dump(n->cdr);
XX	printf(")");
XX	break;
XX	}
XX    fflush(stderr);
XX    }
XX
XXNODE *
XXnewtnode(typ,len)
XXint typ,len;
XX    {
XX    if (nodes == NULL) nodes = (NODE **)malloc(MAXNODE * sizeof(NODE *));
XX    if (++maxnode >= MAXNODE) {
XX	mlwrite("!!!!! RAN OUT OF LISP NODES !!!!!");
XX	maxnode = MAXNODE-1;
XX	}
XX    nodes[maxnode] = (NODE *)malloc(sizeof(NODE));
XX    nodes[maxnode]->type = typ;
XX    if (typ == STRING)	nodes[maxnode]->car = (NODE *)malloc(len+1);
XX    else		nodes[maxnode]->car = NULL;
XX    nodes[maxnode]->cdr = NULL;
XX    return(nodes[maxnode]);
XX    }
XX
XXrettnode()
XX    {
XX    int i;
XX
XX    for (i = 0; i <= maxnode; i++) {
XX	if (nodes[i] != NULL) {
XX	    if (nodes[i]->type == STRING && nodes[i]->car != NULL)
XX		free((char *)nodes[i]->car);
XX	    free((char *)nodes[i]);
XX	    nodes[i] = NULL;
XX	    }
XX	}
XX    if (nodes != NULL) free((char *)nodes);
XX    nodes   = NULL;
XX    maxnode = -1;
XX    for (i = 0; i < 26; i++) syms[i] = NULL;
XX    }
XX
XXNODE *
XXnewnode(typ,len)
XXint typ,len;
XX    {
XX    NODE *n;
XX
XX    n = (NODE *)malloc(sizeof(NODE));
XX    n->type = typ;
XX    if (typ == STRING)	n->car = (NODE *)malloc(len+1);
XX    else		n->car = NULL;
XX    n->cdr = NULL;
XX    return(n);
XX    }
XX
XXretnode(n)
XXNODE *n;
XX    {
XX    NODE *nnew;
XX
XX    while (n != NULL) {
XX	switch (n->type) {
XX	    case CONS:
XX	    retnode(n->car);
XX	    nnew = n->cdr;
XX	    free((char *)n);
XX	    n = nnew;
XX	    break;
XX
XX	    case STRING:
XX	    if (n->car != NULL)	free((char *)n->car);
XX
XX	    default:
XX	    free((char *)n);
XX	    return;
XX	    }
XX	}
XX    }
XX
XX/************************ compilation of LISP code **********************/
XXchar
XXlisp_readchr(instr)
XXint	instr;
XX    {
XX    char    c;
XX
XX    if (pushback != -1) {
XX	c = (char)pushback;
XX	if (pushback != 0) pushback = -1;
XX	return(c);
XX	}
XX
XX    /* compress out comments */
XX    c = ';';
XX    while (c == ';') {
XX	/* do we need to terminate this line */
XX	if (c_doto == llength(c_dotp)) {
XX	    c_doto++;
XX	    if (instr) c = '\n';
XX	    else       c = ' ';
XX	    return(c);
XX	    }
XX	/* are we past the end of line */
XX	while (c_doto >= llength(c_dotp)) {
XX	    c_dotp = c_dotp->l_fp;
XX	    c_doto = 0;
XX	    if (c_dotp == c_endp) {
XX		pushback = 0;
XX		return('\000');
XX		}
XX	    }
XX	c = lgetc(c_dotp,c_doto++);
XX	if (instr) return(c);
XX
XX	/* all white becomes a space */
XX	if (c == '\n' || c == '\r' || c == '\t' || c == '\014') c = ' ';
XX
XX	/* skip comments */
XX	if (c == ';') c_doto = llength(c_dotp) + 1;
XX	else	      return(c);
XX	}
XX    }
XX
XXNODE *
XXlisp_sexpr()
XX    {
XX    char    c,d,str[256];
XX    long    sign,intval;
XX    int	    i;
XX    NODE    *val,*cur,*nxt;
XX
XX    c = ' ';
XX    while (c == ' ') c = lisp_readchr(0);
XX
XX    if (c == '\000' || c == ')') return(NULL);
XX
XX    /* see if we have a list to put together */
XX    if (c == '(') {
XX	val = cur = NULL;
XX	while ((nxt = lisp_sexpr()) != NULL) {
XX	    if (cur == NULL) {
XX		cur = newnode(CONS,0);
XX		val = cur;
XX		}
XX	    else {
XX		cur->cdr = newnode(CONS,0);
XX		cur      = cur->cdr;
XX		}
XX	    cur->car = nxt;
XX	    }
XX	return(val);
XX	}
XX
XX    /* see if we have an integer to gather */
XX    if ((c >= '0' && c <= '9') || c == '-') {
XX	sign	= 1L;
XX	intval	= 0L;
XX	if (c == '-') {
XX	    c = lisp_readchr(0);
XX	    if (c == '\000') return(NULL);
XX
XX	    /* no, it's really the subtraction operator */
XX	    if (c == ' ') {
XX		str[0] = '-';
XX		str[1] = '\000';
XX		val = newnode(SUBR,0);
XX		val->car = fncmatch(str);
XX		if (val->car == NULL) {
XX		    mlwrite("Unknown function: %s",str);
XX		    longjmp(env[0],1);
XX		    }
XX		return(val);
XX		}
XX	    sign = -1L;
XX	    }
XX	while (c >= '0' && c <= '9') {
XX	    intval = (10L * intval) + (long)(c - '0');
XX	    c = lisp_readchr(0);
XX	    if (c == '\000') return(NULL);
XX	    }
XX	if (c != ' ') pushback = c;
XX	intval *= sign;
XX	val = newnode(INTEGER,0);
XX	val->car = (NODE *)intval;
XX	return(val);
XX	}
XX
XX    /* maybe it's a string */
XX    if (c == '"') {
XX	i = 0;
XX	for (c = lisp_readchr(1); c != '"'; c = lisp_readchr(1)) {
XX	    if (c == '\000') return(NULL);
XX	    if (c != '\\') str[i++] = c;
XX	    else {
XX		c = lisp_readchr(1);
XX		if (c == '\000') return(NULL);
XX		switch(c) {
XX		    case 'n':	c = '\n'; break;
XX		    case 'r':	c = '\r'; break;
XX		    case 't':	c = '\t'; break;
XX		    case 'e':	c = '\033'; break;
XX		    default:
XX		    if (c >= '0' && c <= '7') {
XX			c  = (c - '0') * 64;
XX			d  = lisp_readchr(1);
XX			if (d == '\000') return(NULL);
XX			if (d < '0' || d > '7') {
XX			    c /= 64;
XX			    pushback = d;
XX			    break;
XX			    }
XX			c += (d - '0') * 8;
XX			d  = lisp_readchr(1);
XX			if (d == '\000') return(NULL);
XX			if (d < '0' || d > '7') {
XX			    c /= 8;
XX			    pushback = d;
XX			    break;
XX			    }
XX			c += d - '0';
XX			}
XX		    }
XX		str[i++] = c;
XX		}
XX	    if (i > 255) i = 255;
XX	    }
XX	str[i] = '\000';
XX	val = newnode(STRING,strlen(str));
XX	strcpy((char *)val->car,(char *)str);
XX	return(val);
XX	}
XX
XX    /* possibly a symbol */
XX    str[0] = c;
XX    c = lisp_readchr(0);
XX    if (c == '\000') return(NULL);
XX    if (str[0] >= 'a' && str[0] <= 'z' && (c == ' ' || c == ')')) {
XX	val = newnode(SYMBOL,0);
XX	val->car = (NODE *)(str[0] - 'a');
XX	if (c != ' ') pushback = c;
XX	return(val);
XX	}
XX
XX    /* must be a subr */
XX    i = 1;
XX    while (c != ' ' && c != ')') {
XX	str[i++] = c;
XX	c = lisp_readchr(0);
XX	if (c == '\000') return(NULL);
XX	if (i > 255) i = 255;
XX	}
XX    if (c != ' ') pushback = c;
XX    str[i] = '\000';
XX    val = newnode(SUBR,0);
XX    val->car = fncmatch(str);
XX    if (val->car == NULL) {
XX	mlwrite("Unknown function: %s",str);
XX	longjmp(env[0],1);
XX	}
XX    return(val);
XX    }
XX
XXNODE *
XXcompilebuf(bp)
XXBUFFER *bp;
XX    {
XX    int	     i;
XX    WINDOW  *wp;
XX    NODE    *head,*val,*cur,*prv;
XX
XX    mlwrite("Compiling buffer");
XX
XX    /* Now walk through the buffer (compiling s-expers) */
XX    c_endp = bp->b_linep;
XX    c_dotp = bp->b_linep->l_fp;
XX    c_doto = 0;
XX    pushback    = -1;
XX    head	= NULL;
XX    while ((val=lisp_sexpr()) != NULL) {
XX	cur = newnode(CONS,0);
XX	cur->car = val;
XX	cur->cdr = NULL;
XX	if (head == NULL) head = cur;
XX	else		  prv->cdr = cur;
XX	prv = cur;
XX	}
XX    if (head == NULL) {
XX	mlwrite("Compile of buffer failed!");
XX	return(NULL);
XX	}
XX    else mlerase();
XX    return(head);
XX    }
XX
XX/************************ execution of compiled code *********************/
XX
XX/* dobuf:  execute the contents of the buffer pointed to by the passed bp. */
XX
XXdobuf(f,n,bp)
XXint	f,n;
XXBUFFER *bp;
XX    {
XX    NODE    *head;
XX    int	    oldcle,status;
XX
XX    /* first make sure that the buffer is compiled */
XX    if (setjmp(env[0])) return(FALSE);
XX    head = compilebuf(bp);
XX
XX    /* now execute the compiled code (as a progn) */
XX    if (f == FALSE) n = 1;
XX    while (n-- > 0) {
XX	envnum = -1;
XX	status = l_progn(head);
XX	rettnode();
XX	if (status != TRUE) break;
XX	}
XX    retnode(head);
XX    return(status);
XX    }
XX
XXl_progn(head)
XXNODE	*head;
XX    {
XX    NODE    *curr,*scr;
XX    int	    jmp,oldcle,curenv;
XX
XX    curr    = head;
XX    oldcle  = clexec;
XX    curenv  = ++envnum;
XX    if (envnum > 9) {
XX	mlwrite("Too many PROGN nestings");
XX	return(FALSE);
XX	}
XX
XX    /* set up for non-local goto's */
XX    if ((jmp = setjmp(env[curenv])) != 0) {
XX	clexec = oldcle;
XX	if (jmp == PROGN_RETURN) {
XX	    envnum--;
XX	    return(TRUE);
XX	    }
XX	curr = head;
XX	while (curr != NULL) {
XX	    if (curr->type != CONS) {
XX		envnum--;
XX		return(FALSE);
XX		}
XX	    if (curr->car->type == INTEGER && retval->type == INTEGER &&
XX		(long)(curr->car->car) == (long)(retval->car)) break;
XX	    if (curr->car->type == STRING && retval->type == STRING &&
XX		strcmp((char *)(curr->car->car),(char *)(retval->car))
XX		== 0) break;
XX	    curr = curr->cdr;
XX	    }
XX
XX	/* try finding the label at a higher level */
XX	if (curr == NULL) longjmp(env[--envnum],PROGN_GO);
XX	}    
XX
XX    /* actual progn loop */
XX    while (curr != NULL) {
XX	if (l_eval(curr->car) == FALSE) {
XX	    envnum--;
XX	    return(FALSE);
XX	    }
XX	curr = curr->cdr;
XX	}
XX    envnum--;
XX    return(TRUE);
XX    }
XX
XXl_setq(expr)
XXNODE	*expr;
XX    {
XX    long    i;
XX    char    str[256],istr[20];
XX    NODE    *sym;
XX
XX    if (expr == NULL || expr->type != CONS) return(FALSE);
XX    sym = expr->car;
XX    expr = expr->cdr;
XX    if (sym == NULL || sym->type != SYMBOL) return(FALSE);
XX    i = (long)sym->car;
XX    str[0] = '\000';
XX
XX    /* now concatenate parameters */
XX    while (expr != NULL && expr->type == CONS) {
XX	if (l_eval(expr->car) == FALSE) return(FALSE);
XX	if (retval->type == STRING) strcat(str,(char *)retval->car);
XX	else if (retval->type == INTEGER) {
XX	    sprintf(istr,"%ld",(long)retval->car);
XX	    strcat(str,istr);
XX	    }
XX	expr = expr->cdr;
XX	}
XX    retval = newtnode(STRING,strlen(str));
XX    strcpy((char *)retval->car,str);
XX
XX    syms[i] = retval;
XX    return(TRUE);
XX    }
XX
XXl_if(expr)
XXNODE *expr;
XX    {
XX    NODE *thn,*els;
XX    int	 tst,status;
XX
XX    if (expr == NULL || expr->type != CONS) return(FALSE);
XX    tst = 0;
XX    if (l_eval(expr->car) != FALSE)
XX	if ((retval->type == INTEGER && (long)retval->car != 0L) ||
XX	    (retval->type == STRING && *((char *)retval->car) != '\000'))
XX	    tst = 1;
XX
XX    thn	    = expr->cdr;
XX    if (thn != NULL)	els = thn->cdr;
XX    else		els = NULL;
XX
XX    if (tst)		    status = l_eval(thn->car);
XX    else if (els != NULL)   status = l_eval(els->car);
XX    else {
XX	retval = &TNODE;
XX	status = TRUE;
XX	}
XX    return(status);
XX    }
XX
XXl_eval(expr)
XXNODE	*expr;
XX    {
XX    long    i;
XX    int	    p,q,status,oldcle,f,n;
XX    NODE    *func,*par[20];
XX    INTRTN  *fnc;
XX
XX    if (expr == NULL) return(FALSE);
XX    switch (expr->type) {
XX	case INTEGER:
XX	case STRING:
XX	case SUBR:
XX	retval = expr;
XX	return(TRUE);
XX
XX	case SYMBOL:
XX	i = (long)expr->car;
XX	retval = syms[i];
XX	return(TRUE);
XX
XX	case CONS:
XX	if (l_eval(expr->car) == FALSE) return(FALSE);
XX	func   = retval;
XX	if (func != NULL && func->type == INTEGER) {
XX	    f = TRUE;
XX	    i = (long)func->car;
XX	    n = i;
XX	    expr = expr->cdr;
XX	    if (l_eval(expr->car) == FALSE) return(FALSE);
XX	    func = retval;
XX	    }
XX	else {
XX	    f = FALSE;
XX	    n = 1;
XX	    }
XX	if (func == NULL || func->type != SUBR) return(FALSE);
XX	fnc = (INTRTN *)(func->car);
XX	expr = expr->cdr;
XX
XX	/* take care of fsubr's in-line */
XX	if (*fnc == l_progn || *fnc == l_setq || *fnc == l_if) {
XX	    status = TRUE;
XX	    while (n-- > 0) {
XX		gblidx = 0;
XX		status = (*fnc)(expr);
XX		if (status != TRUE) return(status);
XX		}
XX	    return(status);
XX	    }
XX
XX	p = 0;
XX	while (expr != NULL) {
XX	    if (l_eval(expr->car) == FALSE) return(FALSE);
XX	    par[p++] = retval;
XX	    expr = expr->cdr;
XX	    }
XX	for (q = 0; q < p; q++) gblpar[q] = par[q];
XX	gblidx = 0;
XX	gblnum = p;
XX	lstfnc = fnc;
XX	oldcle = clexec;
XX	clexec = TRUE;
XX	retval = NULL;
XX	status = (*fnc)(f,n);
XX	clexec = oldcle;
XX	if (retval == NULL) {
XX	    if (status) retval = &TNODE;
XX	    else	retval = &FNODE;
XX	    status = TRUE;
XX	    }
XX	return(status);
XX	}
XX    }
XX
XXnxtarg(tok)
XXchar *tok;
XX    {
XX    NODE    *cur;
XX    NBIND   *ffp;
XX
XX    if (gblidx >= gblnum) {
XX	ffp = &names[0];
XX	while (ffp->n_func != NULL && ffp->n_func != lstfnc) ++ffp;
XX	if (ffp->n_func != NULL) mlwrite("Missing param for: %s",ffp->n_name);
XX	else			 mlwrite("Missing paramater for function");
XX	longjmp(env[0],1);
XX	}
XX    else cur = gblpar[gblidx++];
XX    if (cur == NULL) {
XX	*tok = '\000';
XX	return(TRUE);
XX	}
XX    if (cur->type == STRING) {
XX	strcpy(tok,(char *)cur->car);
XX	return(TRUE);
XX	}
XX    if (cur->type == INTEGER) {
XX	sprintf(tok,"%ld",(long)cur->car);
XX	return(TRUE);
XX	}
XX    *tok = '\000';
XX    return(TRUE);
XX    }
XX
XXl_go(f,n)
XXint f,n;
XX    {
XX    if (gblpar[0] == NULL) return(FALSE);
XX    retval = gblpar[0];
XX    longjmp(env[envnum],PROGN_GO);
XX    }
XX
XXl_return(f,n)
XXint f,n;
XX    {
XX    retval = gblpar[0];
XX    longjmp(env[envnum],PROGN_RETURN);
XX    }
XX
XXl_yank_str(f,n)
XXint f,n;
XX    {
XX    char    str[256];
XX    int	    i,c;
XX
XX    for (i=0; i < 255 && (c=kremove(i)) >= 0; i++) str[i] = (char)c;
XX    str[i] = '\000';
XX    retval = newtnode(STRING,i);
XX    strcpy((char *)retval->car,str);
XX    return(TRUE);
XX    }
XX
XXl_ask(f,n)
XXint f,n;
XX    {
XX    char    c,str[256],inp[256];
XX    int	    oldcle;
XX
XX    gblidx = 0;
XX    if (gblidx >= gblnum) strcpy(str,"Ask> ");
XX    else		  nxtarg(str);
XX    if (gblidx >= gblnum) inp[0] = '\000';
XX    else		  nxtarg(inp);
XX    while (inp[0] != '\000') {
XX	strcat(str,inp);
XX	if (gblidx >= gblnum) inp[0] = '\000';
XX	else		      nxtarg(inp);
XX	}
XX    oldcle = clexec;
XX    clexec = FALSE;
XX    update();
XX    if (batchmode) {
XX	printf(str);
XX	if (gets(inp) == NULL) inp[0] = '\000';
XX	}
XX    else mlreply(str,inp,255);
XX    clexec = oldcle;
XX    retval = newtnode(STRING,strlen(inp));
XX    strcpy((char *)retval->car,inp);
XX    return(TRUE);
XX    }	
XX
XXlong
XXmake_num(n)
XXNODE	*n;
XX    {
XX    long    i;
XX
XX    if (n == NULL) return(0L);
XX    if (n->type == INTEGER) return((long)n->car);
XX    if (n->type == STRING) {
XX	if (sscanf((char *)n->car," %ld",&i) != 1) return(0L);
XX	return(i);
XX	}
XX    return(0L);
XX    }
XX
XXmath_compute(op)
XXchar	op;
XX    {
XX    long    p1,p2;
XX
XX    p1 = make_num(gblpar[0]);
XX    p2 = make_num(gblpar[1]);
XX    switch(op) {
XX	case '=':   retval = (p1==p2) ? &TNODE : &FNODE; return(TRUE);
XX	case '#':   retval = (p1!=p2) ? &TNODE : &FNODE; return(TRUE);
XX	case '>':   retval = (p1>p2) ?  &TNODE : &FNODE; return(TRUE);
XX	case ']':   retval = (p1>=p2) ? &TNODE : &FNODE; return(TRUE);
XX	case '<':   retval = (p1<p2) ?  &TNODE : &FNODE; return(TRUE);
XX	case '[':   retval = (p1<=p2) ? &TNODE : &FNODE; return(TRUE);
XX	case 'n':   retval = (p1==0) ?  &TNODE : &FNODE; return(TRUE);
XX	case 'a':   retval = (p1&&p2) ? &TNODE : &FNODE; return(TRUE);
XX	case 'o':   retval = (p1||p2) ? &TNODE : &FNODE; return(TRUE);
XX	}
XX    retval = newtnode(INTEGER,0);
XX    switch (op) {
XX	case '+':   retval->car = (NODE *)(p1 + p2); return(TRUE);
XX	case '-':   retval->car = (NODE *)(p1 - p2); return(TRUE);
XX	case '*':   retval->car = (NODE *)(p1 * p2); return(TRUE);
XX	case '/':   retval->car = (NODE *)(p1 / ((p2!=0)?p2:1L)); return(TRUE);
XX	case '%':   retval->car = (NODE *)(p1 % p2); return(TRUE);
XX	case '&':   retval->car = (NODE *)(p1 & p2); return(TRUE);
XX	case '|':   retval->car = (NODE *)(p1 | p2); return(TRUE);
XX	}
XX    return(FALSE);
XX    }
XX
XXl_add(f,n)	{ return(math_compute('+')); }
XXl_sub(f,n)	{ return(math_compute('-')); }
XXl_mul(f,n)	{ return(math_compute('*')); }
XXl_div(f,n)	{ return(math_compute('/')); }
XXl_mod(f,n)	{ return(math_compute('%')); }
XXl_bitand(f,n)	{ return(math_compute('&')); }
XXl_bitor(f,n)	{ return(math_compute('|')); }
XXl_eql(f,n)	{ return(math_compute('=')); }
XXl_neq(f,n)	{ return(math_compute('#')); }
XXl_gt(f,n)	{ return(math_compute('>')); }
XXl_ge(f,n)	{ return(math_compute(']')); }
XXl_lt(f,n)	{ return(math_compute('<')); }
XXl_le(f,n)	{ return(math_compute('[')); }
XXl_not(f,n)	{ return(math_compute('n')); }
XXl_and(f,n)	{ return(math_compute('a')); }
XXl_or(f,n)	{ return(math_compute('o')); }
XX
XXl_eq(f,n)
XXint f,n;
XX    {
XX    retval = &FNODE;
XX    if (gblpar[0] == NULL && gblpar[1] == NULL) retval = &TNODE;
XX    else if (gblpar[0] != NULL && gblpar[1] != NULL &&
XX	     gblpar[0]->type == gblpar[1]->type) {
XX	if (gblpar[0]->type == INTEGER &&
XX	    (long)gblpar[0]->car == (long)gblpar[1]->car) retval = &TNODE;
XX	else if (gblpar[0]->type == STRING &&
XX	    strcmp((char *)gblpar[0]->car,(char *)gblpar[1]->car) == 0)
XX		retval = &TNODE;
XX	}
XX    return(TRUE);
XX    }
XX
XXl_curchr(f,n)
XXint f,n;
XX    {
XX    long    i;
XX
XX    if (curwp->w_doto >= llength(curwp->w_dotp)) i = (long)'\n';
XX    else i = (long)lgetc(curwp->w_dotp,curwp->w_doto);
XX    retval = newtnode(INTEGER,0);
XX    retval->car = (NODE *)i;
XX    return(TRUE);
XX    }
XX
XXl_curlin(f,n)
XXint f,n;
XX    {
XX    long    i;
XX    LINE    *clp;
XX
XX    clp = lforw(curbp->b_linep);
XX    i	= 0L;
XX    while (clp != curwp->w_dotp) {
XX	clp = lforw(clp);
XX	i++;
XX	}
XX    retval = newtnode(INTEGER,0);
XX    retval->car = (NODE *)i;
XX    return(TRUE);
XX    }
XX
XXl_curcol(f,n)
XXint f,n;
XX    {
XX    long    i;
XX
XX    i = (long)getccol(FALSE);
XX    retval = newtnode(INTEGER,0);
XX    retval->car = (NODE *)i;
XX    return(TRUE);
XX    }
XX
XXl_curbuf(f,n)
XXint f,n;
XX    {
XX
XX    retval = newtnode(STRING,strlen(curbp->b_bname));
XX    strcpy((char *)retval->car,curbp->b_bname);
XX    return(TRUE);
XX    }
XX
XXl_princ(f,n)
XXint f,n;
XX    {
XX    char    str[256];
XX    int	    i;
XX
XX    if (f == FALSE) n = 1;
XX    while (n-- > 0) {
XX	gblidx = 0;
XX	if (gblidx >= gblnum) str[0] = '\000';
XX	else		      nxtarg(str);
XX	while (str[0] != '\000') {
XX	    for (i=0; str[i] != '\000'; i++) {
XX		if (str[i] == '\n') lnewline(FALSE,1);
XX		else		    linsert(1,str[i]);
XX		}
XX	    if (gblidx >= gblnum) str[0] = '\000';
XX	    else		  nxtarg(str);
XX	    }
XX	}
XX    return(TRUE);
XX    }
XX
XX
XX/* execute a command line to be typed in */
XXexeccmd(f,n)
XXint f,n;
XX    {
XX    mlwrite("Not implemented yet");
XX    }
XX
XX/* execute the contents of a named buffer */
XXexecbuf(f,n)
XXint f,n;
XX    {
XX    register BUFFER *bp;	/* ptr to buffer to execute */
XX    register int status;	/* status return */
XX    char bufn[NBUFN];	    /* name of buffer to execute */
XX
XX    /* find out what buffer the user wants to execute */
XX    if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE) return(status);
XX
XX    /* find the pointer to that buffer */
XX    if ((bp=bfind(bufn, TRUE, 0)) == NULL) return(FALSE);
XX
XX    /* and now execute it as asked */
XX    if ((status = dobuf(f,n,bp)) != TRUE) return(status);
XX    return(TRUE);
XX    }
XX
XXexecfile(f, n)	/* execute a series of commands in a file */
XXint f, n;   /* default flag and numeric arg to pass on to file */
XX    {
XX    register int status;    /* return status of name query */
XX    char *fname[NSTRING];   /* name of file to execute */
XX
XX    if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE) return(status);
XX
XX    /* otherwise, execute it */
XX    if ((status=dofile(f,n,fname)) != TRUE) return(status);
XX
XX    return(TRUE);
XX    }
XX
XX/* dofile: yank a file into a buffer and execute it
XX    if there are no errors, delete the buffer on exit */ 
XX
XXdofile(f,n,fname)
XXint  f,n;
XXchar *fname;	/* file name to execute */
XX    {
XX    register BUFFER *bp;    /* buffer to place file to exeute */
XX    register BUFFER *cb;    /* temp to hold current buf while we read */
XX    register int status;    /* results of various calls */
XX    char bname[NBUFN];	/* name of buffer */
XX
XX    makename(bname, fname);	/* derive the name of the buffer */
XX    if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
XX		 return(FALSE);
XX
XX    bp->b_mode = MDVIEW;    /* mark the buffer as read only */
XX    cb = curbp;	    /* save the old buffer */
XX    curbp = bp;	    /* make this one current */
XX    /* and try to read in the file to execute */
XX    if ((status = readin(fname, FALSE)) != TRUE) {
XX	curbp = cb; /* restore the current buffer */
XX	return(status);
XX	}
XX
XX    /* go execute it! */
XX    curbp = cb;	    /* restore the current buffer */
XX    if ((status = dobuf(f,n,bp)) != TRUE) return(status);
XX
XX    /* if not displayed, remove the now unneeded buffer and exit */
XX    if (bp->b_nwnd == 0) zotbuf(bp);
XX    return(TRUE);
XX    }
XX
XX/* execute the startup file */
XX
XXstartup()
XX    {
XX    register int status;    /* status of I/O operations */
XX    register int i;	/* index into help file names */
XX    char fname[NSTRING];    /* buffer to construct file name in */
XX
XX    char *homedir;	/* pointer to your home directory */
XX    char *getenv();
XX
XX#if	ULTRIX | AMIGA
XX    /* are we on a slow terminal */    
XX    if (getenv("SLOWTERM") != NULL) slowterm = TRUE;
XX
XX    /* get the HOME from the environment */
XX    if ((homedir = getenv("HOME")) != NULL) {
XX	/* build the file name */
XX	strcpy(fname, homedir);
XX	strcat(fname, "/");
XX	strcat(fname, pathname[0]);
XX
XX	/* and test it */
XX	status = ffropen(fname);
XX	if (status == FIOSUC) {
XX	    ffclose();
XX	    return(dofile(FALSE,1,fname));
XX	    }
XX	}
XX#endif
XX#if	VMS
XX    /* are we on a slow terminal */    
XX    if (getenv("EMACSVAR_SLOWTERM") != NULL) slowterm = TRUE;
XX
XX    /* get the HOME from the environment */
XX    if ((homedir = getenv("SYS$LOGIN")) != NULL) {
XX	/* build the file name */
XX	strcpy(fname, homedir);
XX	strcat(fname, pathname[0]);
XX
XX	/* and test it */
XX	status = ffropen(fname);
XX	if (status == FIOSUC) {
XX	    ffclose();
XX	    return(dofile(FALSE,1,fname));
XX	    }
XX	}
XX#endif
XX
XX    /* search through the list of startup files */
XX    for (i=2; i < NPNAMES; i++) {
XX	strcpy(fname, pathname[i]);
XX	strcat(fname, pathname[0]);
XX	status = ffropen(fname);
XX	if (status == FIOSUC) break;
XX	}
XX
XX    /* if it isn't around, don't sweat it */
XX    if (status == FIOFNF) return(TRUE);
XX
XX    ffclose();	/* close the file to prepare for to read it in */
XX
XX    return(dofile(FALSE,1,fname));
XX    }
XX
SHAR_EOF
if test 22291 -ne "`wc -c lisp.c`"
then
echo shar: error transmitting lisp.c '(should have been 22291 characters)'
fi
echo shar: extracting lock.c
sed 's/^XX//' << \SHAR_EOF > lock.c
XX/* LOCK:   File locking command routines for MicroEMACS
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XX#if FILOCK
XX#if ULTRIX
XX
XXchar *lname[NLOCKS];	/* names of all locked files */
XXint numlocks;	    /* # of current locks active */
XX
XX/* lockchk: check a file for locking and add it to the list */
XX
XXlockchk(fname)
XX
XXchar *fname;	/* file to check for a lock */
XX
XX    {
XX    register int i;	/* loop indexes */
XX    register int status;    /* return status */
XX    char *undolock();
XX
XX    /* check to see if that file is already locked here */
XX    if (numlocks > 0) for (i=0; i < numlocks; ++i)
XX    if (strcmp(fname, lname[i]) == 0) return(TRUE);
XX
XX    /* if we have a full locking table, bitch and leave */
XX    if (numlocks == NLOCKS) {
XX	mlwrite("LOCK ERROR: Lock table full");
XX	return(ABORT);
XX	}
XX
XX    /* next, try to lock it */
XX    status = lock(fname);
XX    if (status == ABORT)    /* file is locked, no override */
XX		 return(ABORT);
XX    if (status == FALSE)    /* locked, overriden, dont add to table */
XX		 return(TRUE);
XX
XX    /* we have now locked it, add it to our table */
XX    lname[++numlocks - 1] = (char *)malloc(strlen(fname) + 1);
XX    if (lname[numlocks - 1] == NULL) {	/* malloc failure */
XX		 undolock(fname);	    /* free the lock */
XX	mlwrite("Cannot lock, out of memory");
XX	--numlocks;
XX	return(ABORT);
XX	}
XX
XX    /* everthing is cool, add it to the table */
XX    strcpy(lname[numlocks-1], fname);
XX    return(TRUE);
XX    }
XX
XX/* lockrel:	release all the file locks so others may edit */
XX
XXlockrel()
XX
XX    {
XX    register int i;	/* loop index */
XX
XX    if (numlocks > 0) for (i=0; i < numlocks; ++i) {
XX	unlock(lname[i]);
XX	free(lname[i]);
XX	}
XX    numlocks = 0;
XX    }
XX
XX/* lock:    Check and lock a file from access by others
XXreturns	TRUE = files was not locked and now is
XXFALSE = file was locked and overridden
XXABORT = file was locked, abort command
XX */
XX
XXlock(fname)
XX
XXchar *fname;	/* file name to lock */
XX
XX    {
XX    register char *locker;  /* lock error message */
XX    register int status;    /* return status */
XX    char msg[NSTRING];	/* message string */
XX    char *dolock();
XX
XX    /* attempt to lock the file */
XX    locker = dolock(fname);
XX    if (locker == NULL)	/* we win */
XX		 return(TRUE);
XX
XX    /* file failed...abort */
XX    if (strncmp(locker, "LOCK", 4) == 0) {
XX	mlwrite(locker);
XX 	return(ABORT);
XX	}
XX
XX    /* someone else has it....override? */
XX     strcpy(msg, "File in use by ");
XX    strcat(msg, locker);
XX    strcat(msg, ", overide?");
XX    status = mlyesno(msg);	/* ask them */
XX    if (status == TRUE) return(FALSE);
XX    else
XX    return(ABORT);
XX    }
XX
XX/* unlock: Unlock a file
XXthis only warns the user if it fails
XX */
XX
XXunlock(fname)
XX
XXchar *fname;	/* file to unlock */
XX
XX    {
XX    register char *locker;  /* undolock return string */
XX    char *undolock();
XX
XX    /* unclock and return */
XX    locker = undolock(fname);
XX    if (locker == NULL) return(TRUE);
XX
XX    /* report the error and come back */
XX    mlwrite(locker);
XX    return(FALSE);
XX    }
XX#endif
XX#else
XXlckhello() /* dummy function */
XX    {
XX    }
XX#endif
XX
SHAR_EOF
if test 3010 -ne "`wc -c lock.c`"
then
echo shar: error transmitting lock.c '(should have been 3010 characters)'
fi
echo shar: extracting main.c
sed 's/^XX//' << \SHAR_EOF > main.c
XX/*
XX* This program is in public domain; written by Dave G. Conroy.
XX* This file contains the main driving routine, and some keyboard processing
XX* code, for the MicroEMACS screen editor.
XX*
XX* REVISION HISTORY:
XX*
XX* 1.0  Steve Wilhite, 30-Nov-85
XX* 2.0  George Jones, 12-Dec-85
XX* 3.0  Daniel Lawrence, 29-Dec-85
XX* xxx  Dave Wecker 29-June-86
XX*/
XX
XX#include <stdio.h>
XX
XX/* make global definitions not external */
XX
XX#define   maindef
XX
XX#include    "estruct.h"	
XX#include    "efunc.h"	
XX#include    "edef.h"	
XX#include    "ebind.h"	
XX
XX#if VMS
XX#include <ssdef.h>
XX#define GOOD    (SS$_NORMAL)
XX#endif
XX
XX#ifndef GOOD
XX#define GOOD    0
XX#endif
XX
XX#if ULTRIX
XX#define	IOCPARM_MASK	0x7f		/* parameters must be < 128 bytes */
XX#define	IOC_OUT		0x40000000	/* copy out parameters */
XX#define	_IOR(x,y,t)	(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|('x'<<8)|y)
XX#define	FIONREAD	_IOR(f, 127, int)	/* get # bytes to read */
XX#endif
XX
XX#if AMIGA
XXextern short int Enable_Abort;
XX#endif
XX
XXshort doflashing = TRUE;
XX
XXmain(argc, argv)
XXchar *argv[];
XX    {
XX    register int    c;
XX    register int    f;
XX    int		    n;
XX    register int    mflag;
XX    register BUFFER *bp;
XX    register int    ffile;  /* first file flag */
XX    register int    carg;   /* current arg to scan */
XX    int basec;		    /* c stripped of meta character */
XX    int viewflag;	    /* are we starting in view mode? */
XX    char bname[NBUFN];      /* buffer name of file to read */
XX    char *bfile;	    /* batch file name */
XX    int		    s;
XX    WINDOW	    *wp;
XX
XX    /* initialize the editor and process the startup file */
XX
XX#if AMIGA
XX    Enable_Abort = 0;
XX#endif
XX
XX    /* pre scan the command line for the batchmode switch */
XX    for (carg = 1; carg < argc; ++carg)
XX	if (argv[carg][0] == '-' && (argv[carg][1]|' ') == 'b') {
XX	    batchmode = TRUE;
XX	    break;
XX	    }
XX
XX    strcpy(bname, "main");  /* default buffer name */
XX    vtinit();		/* Displays. */
XX    edinit(bname);	/* Buffers, windows. */
XX    startup();		/* execute .emacsrc if there */
XX    viewflag = FALSE;
XX    ffile = TRUE;	/* no file to edit yet */
XX    update();		/* let the user know we are here */
XX
XX    /* scan through the command line and get the files to edit */
XX    for (carg = 1; carg < argc; ++carg) {
XX	/* if its a switch, process it */
XX	if (argv[carg][0] == '-') {
XX	    switch (argv[carg][1]|' ') {
XX		case 'v':   /* -v for View File */
XX		viewflag = TRUE;
XX		break;
XX
XX		case 'e':   /* -e for Edit file */
XX		viewflag = FALSE;
XX		break;
XX
XX		case 'b':   /* -b for batch mode */
XX		if (++carg >= argc) exit(1);
XX		bfile = argv[carg];
XX		break;
XX
XX		default: /* unknown switch */
XX		/* ignore this for now */
XX		break;
XX		}
XX	    }
XX	else {   /* process a file name */
XX	    /* set up a buffer for this file */
XX	    makename(bname, argv[carg]);
XX
XX	    /* if this is the first file, read it in */
XX	    if (ffile) {
XX		bp = curbp;
XX		makename(bname, argv[carg]);
XX		strcpy(bp->b_bname, bname);
XX		strcpy(bp->b_fname, argv[carg]);
XX		readin(argv[carg], (viewflag==FALSE));
XX		bp->b_dotp = bp->b_linep;
XX		bp->b_doto = 0;
XX		ffile = FALSE;
XX		}
XX	    else {
XX		/* visit the file */
XX		if ((wp = wpopup()) != NULL) {
XX		    curwp = wp;
XX		    curbp = wp->w_bufp;
XX		    }
XX		if (getfile(argv[carg],FALSE)) {
XX		    wp = wheadp;
XX		    while (wp != NULL) {
XX			wp->w_flag |= WFMODE;
XX			wp = wp->w_wndp;
XX			}
XX		    }
XX		bp = curbp;
XX		}
XX
XX	    /* set the view mode appropriatly */
XX	    if (viewflag) bp->b_mode |= MDVIEW;
XX	    }
XX	}
XX
XX    /* setup to process commands */
XX    lastflag = 0;                           /* Fake last flags. */
XX
XX    /* if in batch mode... do the batch file and get out */
XX    if (batchmode) {
XX	dofile(FALSE,1,bfile);
XX	quit(TRUE,1);
XX	}
XX
XX    update();
XX
XX    while (TRUE) {	/* do top level forever */
XX
XX#if ULTRIX
XX	/* sit in a subprocess wait loop */
XX	if (procbuf != NULL) readsubproc();
XX#endif
XX	/* do the real top level processing */
XX	dotoplevel();
XX	}
XX    }
XX
XXdotoplevel() {
XX    register int c,basec,f,mflag;
XX    int n;
XX
XXloop:
XX    update();
XX
XX#if ULTRIX
XX    ioctl(0,FIONREAD,&n);
XX    if (n < 1 && procbuf != NULL) return;
XX#endif
XX
XX    c = getkey();
XX    if (mpresf != FALSE) {
XX	mlerase();
XX	update();
XX#if CLRMSG
XX	if (c == ' ')                   /* ITS EMACS does this */
XX	goto loop;
XX#endif
XX	}
XX    f = FALSE;
XX    n = 1;
XX
XX    /* do META-# processing if needed */
XX
XX    basec = c & ~META;       /* strip meta char off if there */
XX    if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
XX	f = TRUE;   /* there is a # arg */
XX	n = 0;   /* start with a zero default */
XX	mflag = 1;   /* current minus flag */
XX	c = basec;   /* strip the META */
XX	while ((c >= '0' && c <= '9') || (c == '-')) {
XX	    if (c == '-') {
XX		/* already hit a minus or digit? */
XX		if ((mflag == -1) || (n != 0)) break;
XX		mflag = -1;
XX		}
XX	    else {
XX		n = n * 10 + (c - '0');
XX		}
XX	    if ((n == 0) && (mflag == -1))  /* lonely - */
XX	    mlwrite("Arg:");
XX	    else
XX	    mlwrite("Arg: %d",n * mflag);
XX
XX	    c = getkey();   /* get the next key */
XX	    }
XX	n = n * mflag;   /* figure in the sign */
XX	}
XX
XX    /* do ^U repeat argument processing */
XX
XX    if (c == (CTRL|'U')) {                  /* ^U, start argument */
XX	f = TRUE;
XX	n = 4;                          /* with argument of 4 */
XX	mflag = 0;                      /* that can be discarded. */
XX	mlwrite("Arg: 4");
XX	while ((c=getkey()) >='0' && c<='9' || c==(CTRL|'U') || c=='-'){
XX	    if (c == (CTRL|'U')) n = n*4;
XX	    /*
XX	    * If dash, and start of argument string, set arg.
XX	    * to -1.  Otherwise, insert it.
XX	    */
XX	    else if (c == '-') {
XX		if (mflag) break;
XX		n = 0;
XX		mflag = -1;
XX		}
XX	    /*
XX	    * If first digit entered, replace previous argument
XX	    * with digit and set sign.  Otherwise, append to arg.
XX	    */
XX	    else {
XX		if (!mflag) {
XX		    n = 0;
XX		    mflag = 1;
XX		    }
XX		n = 10*n + c - '0';
XX		}
XX	    mlwrite("Arg: %d", (mflag >=0) ? n : (n ? -n : -1));
XX	    }
XX	/*
XX	* Make arguments preceded by a minus sign negative and change
XX	* the special argument "^U -" to an effective "^U -1".
XX	*/
XX	if (mflag == -1) {
XX	    if (n == 0) n++;
XX	    n = -n;
XX		    }
XX	}
XX    if (c == (CTRL|'X')) {                    /* ^X is a prefix */ 
XX	c = getkey();
XX	if ((c & 0x77) >='a' && (c & 0x77) <= 'z') c -= 0x20;
XX	c |= CTLX;
XX	}
XX
XX    if (kbdmip != NULL) {                   /* Save macro strokes. */
XX	if (c!=(CTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
XX	    ctrlg(FALSE, 0);
XX	    goto loop;
XX	    }
XX	if (f != FALSE) {
XX	    *kbdmip++ = (CTRL|'U');
XX	    *kbdmip++ = n;
XX	    }
XX	*kbdmip++ = c;
XX	}
XX    execute(c, f, n);                       /* Do it. */
XX    goto loop;
XX    }
XX
XX/*
XX* Initialize all of the buffers and windows. The buffer name is passed down
XX* as an argument, because the main routine may have been told to read in a
XX* file by default, and we want the buffer name to be right.
XX*/
XXedinit(bname)
XXchar bname[];
XX    {
XX    register BUFFER *bp;
XX    register WINDOW *wp;
XX    char *malloc();
XX
XX    bp = bfind(bname, TRUE, 0);             /* First buffer */
XX    blistp = bfind("[List]", TRUE, BFTEMP); /* Buffer list buffer */
XX    wp = (WINDOW *) malloc(sizeof(WINDOW)); /* First window */
XX    if (bp==NULL || wp==NULL || blistp==NULL) exit(1);
XX    curbp = bp;                            /* Make this current */
XX    wheadp = wp;
XX    curwp = wp;
XX    wp->w_wndp = NULL;                     /* Initialize window */
XX    wp->w_bufp = bp;
XX    bp->b_nwnd = 1;                        /* Displayed. */
XX    wp->w_linep = bp->b_linep;
XX    wp->w_dotp = bp->b_linep;
XX    wp->w_doto = 0;
XX    wp->w_markp = NULL;
XX    wp->w_marko = 0;
XX    wp->w_toprow = 0;
XX    wp->w_ntrows = term.t_nrow-1;           /* "-1" for mode line. */
XX    wp->w_force = 0;
XX    wp->w_flag = WFMODE|WFHARD;            /* Full. */
XX    }
XX
XX/*
XX* This is the general command execution routine. It handles the fake binding
XX* of all the keys to "self-insert". It also clears out the "thisflag" word,
XX* and arranges to move it to the "lastflag", so that the next command can
XX* look at it. Return the status of command.
XX*/
XXexecute(c, f, n)
XX    {
XX    register KEYTAB *ktp;
XX    register int    status;
XX
XX    ktp = &keytab[0];                       /* Look in key table. */
XX    while (ktp->k_fp != NULL) {
XX	if (ktp->k_code == c) {
XX	    thisflag = 0;
XX	    status = (*ktp->k_fp)(f, n);
XX	    lastflag = thisflag;
XX	    return (status);
XX	    }
XX	++ktp;
XX	}
XX
XX    /*
XX    * If a space was typed, fill column is defined, the argument is non-
XX    * negative, wrap mode is enabled, and we are now past fill column,
XX    * and we are not read-only, perform word wrap.
XX    */
XX    if (c == ' ' && (curwp->w_bufp->b_mode & MDWRAP) && fillcol > 0 && n >= 0 && getccol(FALSE) > fillcol &&
XX    (curwp->w_bufp->b_mode & MDVIEW) == FALSE)
XX    wrapword();
XX
XX    if ((c>=0x20 && c<=0x7E)                /* Self inserting. */
XX    ||  (c>=0xA0 && c<=0xFE)) {
XX	if (n <= 0) {                   /* Fenceposts. */
XX	    lastflag = 0;
XX	    return (n<0 ? FALSE : TRUE);
XX	    }
XX	thisflag = 0;                   /* For the future. */
XX	status = linsert(n, c);
XX	c &= 0x7f;
XX	if (status && doflashing && 
XX	    (c == ')' || c == ']' || c == '}' || c == '>')) flash(c);
XX    lastflag = thisflag;
XX    return (status);
XX    }
XXmlwrite("\007[Key not bound]");       /* complain */
XXlastflag = 0;                           /* Fake last flags. */
XXreturn (FALSE);
XX}
XX
XX/*
XX* Read in a key.
XX* Do the standard keyboard preprocessing. Convert the keys to the internal
XX* character set.
XX*/
XXgetkey()
XX    {
XX    register int    c;
XX    
XX    c = (*term.t_getchar)();
XX    if (c == METACH || c == 0x9B) {         /* Apply M- prefix */
XX	if (c == METACH) c = getctl();
XX	else             c = '[';            /* kludge for the AMIGA CSI*/
XX
XX	if (c == '[' || c == 'O') {
XX	    c = (*term.t_getchar)() & 0x7F;
XX	    if (c == 'P') {
XX		c = (*term.t_getchar)();
XX		if (c != METACH && c != 0x9B) return (META | (c&0x7f));
XX		if (c == METACH) c = getctl(); /* kludge for AMIGA CSI */
XX		else		 c = '[';
XX
XX		if (c == '[' || c == 'O') {
XX		    c = (*term.t_getchar)() & 0x7F;
XX		    if (c != ']') return (GOLD | c);
XX		    c = getctl();
XX		    if (c == '<') return (0x7f);
XX		    return (GOLD | CTRL | c);
XX		    }
XX		return (GOLD | META | c);
XX		}
XX	    if (c != ']') return (SPEC | c);
XX	    c = getctl();
XX	    if (c == '<') return (0x7F);
XX	    return (CTRL | c);
XX	    }
XX	return (META | c);
XX	}
XX    if (c>=0x00 && c<=0x1F)                 /* C0 control -> C- */
XX	c = CTRL | (c+'@');
XX    return (c);
XX    }
XX
XX/*
XX* Get a key.
XX* Apply control modifications to the read key.
XX*/
XXgetctl()
XX    {
XX    register int    c;
XX
XX    c = (*term.t_getchar)();
XX    if (c>='a' && c<='z')                   /* Force to upper */
XX    c -= 0x20;
XX    if (c>=0x00 && c<=0x1F)                 /* C0 control -> C- */
XX    c = CTRL | (c+'@');
XX    return (c);
XX    }
XX
XX/*
XX* Fancy quit command, as implemented by Norm. If the any buffer has
XX* changed do a write on that buffer and exit emacs, otherwise simply exit.
XX*/
XXquickexit(f, n)
XX    {
XX    register BUFFER *bp;    /* scanning pointer to buffers */
XX
XX    bp = bheadp;
XX    while (bp != NULL) {
XX	if ((bp->b_flag&BFCHG) != 0 /* Changed. */
XX	&& (bp->b_flag&BFTEMP) == 0) {   /* Real. */
XX	    curbp = bp;       /* make that buffer cur */
XX	    mlwrite("[Saving %s]",bp->b_fname);
XX	    filesave(f, n);
XX	    }
XX	bp = bp->b_bufp;       /* on to the next buffer */
XX	}
XX    quit(f, n);                             /* conditionally quit */
XX    }
XX
XX/*
XX* Quit command. If an argument, always quit. Otherwise confirm if a buffer
XX* has been changed and not written out. Normally bound to "C-X C-C".
XX*/
XXquit(f, n)
XX    {
XX    register int    s;
XX
XX    if (f != FALSE                          /* Argument forces it. */
XX    || anycb() == FALSE                     /* All buffers clean. */
XX    /* User says it's OK. */
XX    || (s=mlyesno("Modified buffers exist. Leave anyway")) == TRUE) {
XX#if FILOCK
XX	lockrel();
XX#endif
XX	vttidy();
XX	exit(GOOD);
XX	}
XX    mlwrite("");
XX    return (s);
XX    }
XX
XX/*
XX* Begin a keyboard macro.
XX* Error if not at the top level in keyboard processing. Set up variables and
XX* return.
XX*/
XXctlxlp(f, n)
XX    {
XX    if (kbdmip!=NULL || kbdmop!=NULL) {
XX	mlwrite("Not now");
XX	return (FALSE);
XX	}
XX    mlwrite("[Start macro]");
XX    kbdmip = &kbdm[0];
XX    return (TRUE);
XX    }
XX
XX/*
XX* End keyboard macro. Check for the same limit conditions as the above
XX* routine. Set up the variables and return to the caller.
XX*/
XXctlxrp(f, n)
XX    {
XX    if (kbdmip == NULL) {
XX	mlwrite("Not now");
XX	return (FALSE);
XX	}
XX    mlwrite("[End macro]");
XX    kbdmip = NULL;
XX    return (TRUE);
XX    }
XX
XX/*
XX* Execute a macro.
XX* The command argument is the number of times to loop. Quit as soon as a
XX* command gets an error. Return TRUE if all ok, else FALSE.
XX*/
XXctlxe(f, n)
XX    {
XX    register int    c;
XX    register int    af;
XX    register int    an;
XX    register int    s;
XX
XX    if (kbdmip!=NULL || kbdmop!=NULL) {
XX	mlwrite("Not now");
XX	return (FALSE);
XX	}
XX    if (n <= 0) return (TRUE);
XX    do {
XX	kbdmop = &kbdm[0];
XX	doflashing = FALSE;
XX	do {
XX	    af = FALSE;
XX	    an = 1;
XX	    if ((c = *kbdmop++) == (CTRL|'U')) {
XX		af = TRUE;
XX		an = *kbdmop++;
XX		c = *kbdmop++;
XX		}
XX	    s = TRUE;
XX	    }
XX	while (c!=(CTLX|')') && (s=execute(c, af, an))==TRUE);
XX	doflashing = TRUE;
XX	kbdmop = NULL;
XX	}
XX    while (s==TRUE && --n);
XX    return (s);
XX    }
XX
XX/*
XX* Abort.
XX* Beep the beeper. Kill off any keyboard macro, etc., that is in progress.
XX* Sometimes called as a routine, to do general aborting of stuff.
XX*/
XXctrlg(f, n)
XX    {
XX    (*term.t_beep)();
XX    if (kbdmip != NULL) {
XX	kbdm[0] = (CTLX|')');
XX	kbdmip = NULL;
XX	}
XX    mlwrite("[Aborted]");
XX    return (ABORT);
XX    }
XX
XX/* tell the user that this command is illegal while we are in
XX   VIEW (read-only) mode */
XX
XXrdonly()
XX
XX    {
XX    (*term.t_beep)();
XX    mlwrite("[Key illegal in VIEW mode]");
XX    return(FALSE);
XX    }
SHAR_EOF
if test 13526 -ne "`wc -c main.c`"
then
echo shar: error transmitting main.c '(should have been 13526 characters)'
fi
echo shar: extracting random.c
sed 's/^XX//' << \SHAR_EOF > random.c
XX/*
XX * This file contains the command processing functions for a number of random
XX * commands. There is no functional grouping here, for sure.
XX */
XX
XX#include <stdio.h>
XX#include "estruct.h"
XX#include "edef.h"
XX
XXint tabsize;	       /* Tab size (0: use real tabs) */
XX
XX/*
XX * Set fill column to n.
XX
XX */
XXsetfillcol(f, n)
XX    {
XX    fillcol = n;
XX    mlwrite("[Fill column is %d]",n);
XX    return(TRUE);
XX    }
XX
XX/*
XX * Display the current position of the cursor, in origin 1 X-Y coordinates,
XX * the character that is under the cursor (in octal), and the fraction of the
XX * text that is before the cursor. The displayed column is not the current
XX * column, but the column that would be used on an infinite width display.
XX * Normally this is bound to "C-X =".
XX */
XXshowcpos(f, n)
XX    {
XX    register LINE   *clp;
XX    register long   nch;
XX    register int    cbo;
XX    register long   nbc;
XX    register int    cac;
XX    register int    ratio;
XX    register int    col;
XX    register int    i;
XX    register int    c;
XX
XX    clp = lforw(curbp->b_linep);        /* Grovel the data. */
XX    cbo = 0;
XX    nch = 0;
XX    for (;;) {
XX	if (clp==curwp->w_dotp && cbo==curwp->w_doto) {
XX	    nbc = nch;
XX	    if (cbo == llength(clp)) cac = '\n';
XX	    else
XX	    cac = lgetc(clp, cbo);
XX	    }
XX	if (cbo == llength(clp)) {
XX	    if (clp == curbp->b_linep) break;
XX	    clp = lforw(clp);
XX	    cbo = 0;
XX	    }
XX	else
XX	++cbo;
XX	++nch;
XX	}
XX    col = getccol(FALSE);	  /* Get real column. */
XX    ratio = 0;		    /* Ratio before dot. */
XX    if (nch != 0) ratio = (100L*nbc) / nch;
XX    mlwrite("X=%d Y=%d CH=0x%x .=%D (%d%% of %D)",
XX    col+1, currow+1, cac, nbc, ratio, nch);
XX    return (TRUE);
XX    }
XX
XX/*
XX * Return current column.  Stop at first non-blank given TRUE argument.
XX */
XXgetccol(bflg)
XXint bflg;
XX    {
XX    register int c, i, col;
XX    col = 0;
XX    for (i=0; i<curwp->w_doto; ++i) {
XX	c = lgetc(curwp->w_dotp, i);
XX	if (c!=' ' && c!='\t' && bflg)	break;
XX	if (c == '\t')			col |= 0x07;
XX	else if (c<0x20 || c==0x7F)	++col;
XX	++col;
XX	}
XX    return(col);
XX    }
XX
XX/*
XX * Twiddle the two characters on either side of dot. If dot is at the end of
XX * the line twiddle the two characters before it. Return with an error if dot
XX * is at the beginning of line; it seems to be a bit pointless to make this
XX * work. This fixes up a very common typo with a single stroke. Normally bound
XX * to "C-T". This always works within a line, so "WFEDIT" is good enough.
XX */
XXtwiddle(f, n)
XX    {
XX    register LINE   *dotp;
XX    register int    doto;
XX    register int    cl;
XX    register int    cr;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    dotp = curwp->w_dotp;
XX    doto = curwp->w_doto;
XX    if (doto==llength(dotp) && --doto<0) return (FALSE);
XX    cr = lgetc(dotp, doto);
XX    if (--doto < 0) return (FALSE);
XX    cl = lgetc(dotp, doto);
XX    lputc(dotp, doto+0, cr);
XX    lputc(dotp, doto+1, cl);
XX    lchange(WFEDIT);
XX    return (TRUE);
XX    }
XX
XX/*
XX * Quote the next character, and insert it into the buffer. All the characters
XX * are taken literally, with the exception of the newline, which always has
XX * its line splitting meaning. The character is always read, even if it is
XX * inserted 0 times, for regularity. Bound to "C-Q"
XX */
XXquote(f, n)
XX    {
XX    register int    s;
XX    register int    c;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    c = getkey();
XX    if (c & CTRL) c -= (CTRL|'@');
XX    c &= 0x7F;
XX
XX    if (n < 0) return (FALSE);
XX    if (n == 0) return (TRUE);
XX    if (c == '\n') {
XX	do {
XX	    s = lnewline();
XX	    }
XX	while (s==TRUE && --n);
XX	return (s);
XX	}
XX    return (linsert(n, c));
XX    }
XX
XX/*
XX * Set tab size if given non-default argument (n <> 1).  Otherwise, insert a
XX * tab into file.  If given argument, n, of zero, change to true tabs.
XX * If n > 1, simulate tab stop every n-characters using spaces. This has to be
XX * done in this slightly funny way because the tab (in ASCII) has been turned
XX * into "C-I" (in 10 bit code) already. Bound to "C-I".
XX */
XXtab(f, n)
XX    {
XX    register int curcol,newcol,nxttab;
XX
XX    if (n < 0) return (FALSE);
XX    if (n == 0 || n > 1) {
XX	tabsize = n;
XX	return(TRUE);
XX	}
XX    if (! tabsize) return(linsert(1, '\t'));
XX
XX    /* try to compress out spaces whenever possible */
XX    curcol = getccol(FALSE);
XX    newcol = curcol + (tabsize - (curcol % tabsize));
XX    while (curwp->w_doto > 0 && curwp->w_dotp->l_text[curwp->w_doto-1] == ' ')
XX	backdel(FALSE,1);
XX
XX    curcol = getccol(FALSE);
XX    nxttab = 8 - (curcol % 8);
XX    while (nxttab+curcol <= newcol) {
XX	if (linsert(1,'\t') == FALSE) return(FALSE);
XX	curcol += nxttab;
XX	nxttab = 8;
XX	}
XX    if (newcol > curcol) return(linsert(newcol-curcol,' '));
XX    return(TRUE);
XX    }
XX
XX/*
XX * Open up some blank space. The basic plan is to insert a bunch of newlines,
XX * and then back up over them. Everything is done by the subcommand
XX * procerssors. They even handle the looping. Normally this is bound to "C-O".
XX */
XXopenline(f, n)
XX    {
XX    register int    i;
XX    register int    s;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if (n < 0) return (FALSE);
XX    if (n == 0) return (TRUE);
XX    i = n;	            /* Insert newlines. */
XX    do {
XX	s = lnewline();
XX	}
XX    while (s==TRUE && --i);
XX    if (s == TRUE)	    /* Then back up overtop */
XX		 s = backchar(f, n);       /* of them all. */
XX    return (s);
XX    }
XX
XX/*
XX * Insert a newline. Bound to "C-M". If we are in CMODE, do automatic
XX * indentation as specified.
XX */
XXnewline(f, n)
XX    {
XX    register LINE   *lp;
XX    register int    s;
XX
XX    if (curbp->b_mode&MDVIEW)	/* don't allow this command if */
XX		 return(rdonly());	/* we are in read only mode */
XX    if (n < 0) return (FALSE);
XX
XX    /* if we are in C mode and this is a default <NL> */
XX    if (n == 1 && (curbp->b_mode & MDCMOD) && curwp->w_dotp != curbp->b_linep)
XX	return(cinsert());
XX
XX    /* if we are in MODULA mode and this is a default <NL> */
XX    if (n == 1 && (curbp->b_mode & MDMMOD) && curwp->w_dotp != curbp->b_linep)
XX	return(minsert());
XX
XX    /* if we are in LISP mode and this is a default <NL> */
XX    if (n == 1 && (curbp->b_mode & MDLISP) && curwp->w_dotp != curbp->b_linep)
XX	return(lispinsert());
XX
XX#if ULTRIX
XX    /* if we are in a sub shell then send the line */
XX    if (curbp == procbuf) return(pinsert());
XX#endif
XX
XX    /* insert some lines */
XX    while (n--) {
XX	if ((s=lnewline()) != TRUE) return (s);
XX	}
XX    return (TRUE);
XX    }
XX
XXcinsert() /* insert a newline and indentation for C */
XX    {
XX    register char *cptr;    /* string pointer into text to copy */
XX    register int tptr;	/* index to scan into line */
XX    register int i,j;
XX    int gotleft,gotright;
XX
XX    /* grab a pointer to text to copy indentation from */
XX    cptr = &curwp->w_dotp->l_text[0];
XX    tptr = curwp->w_doto - 1;
XX    gotleft = gotright = 0;
XX    for (i = 0; i<=tptr; i++) {
XX	if (*cptr == '{') ++gotleft;
XX	if (*cptr++ == '}') ++gotright;
XX	}
XX    if (gotright > gotleft) return(fixblockend(gotleft,gotright));
XX
XX
XX    /* save the indent of the previous line */
XX    i = getccol(TRUE); j = getccol(FALSE);
XX
XX    if (gotleft > gotright && i == j-1) {
XX	backdel(FALSE,1); /* get rid of curly on blank line */
XX	tab(FALSE,1);	   /* indent it correctly */
XX	linsert(1,'{');	 /* put it back in */
XX	}
XX    else if (i == j) {
XX	backdel(FALSE,tptr+1); /* get rid of spaces on blank lines */
XX	}
XX
XX    /* put in the newline */
XX    if (lnewline() == FALSE) return(FALSE);
XX
XX    /* and the saved indentation */
XX    while (getccol(TRUE) < i) tab(FALSE, 1);
XX
XX    /* add tabs for brace nesting on the previous line */
XX    while (gotleft-- > gotright) tab(FALSE,1);
XX
XX    return(TRUE);
XX    }
XX
XXfixblockend(gotleft,gotright)	/* fix up a close brace in CMODE/MMODE/LISP */
XX    {
XX    register int i;
XX    register int target;	/* column brace should go after */
XX
XX
XX    /* calc where we will go back to */
XX    target = getccol(TRUE);
XX    while (gotright-- > gotleft) {
XX	i = target % (tabsize == 0 ? 8 : tabsize);
XX	if (i == 0) i = (tabsize == 0 ? 8 : tabsize);
XX	target -= i;
XX	}
XX
XX    /* end the line and indent */
XX    if (lnewline() == FALSE) return(FALSE);
XX    if (target <= 0) return(TRUE);
XX
XX    while (getccol(TRUE) < target) tab(FALSE, 1);
XX
XX    return(TRUE);
XX
XX    }
XX
XXminsert() /* insert a newline and indentation for MODULA */
XX    {
XX    register char *cptr;    /* string pointer into text to copy */
XX    register int tptr;	    /* index to scan into line */
XX    register int i,j,doto;
XX    int gotleft,gotright;
XX    char scrbuf[20];	    /* scratch buffer for comparisons */
XX
XX    /* grab a pointer to text to copy indentation from */
XX    cptr = &curwp->w_dotp->l_text[0];
XX    tptr = curwp->w_doto - 1;
XX    gotleft = gotright = 0;
XX
XX    /* compress out leading white space */
XX    for (doto = 0; doto<=tptr && (*cptr == ' ' || *cptr == '\t'); doto++)
XX	cptr++;
XX
XX    /* upcase the test string */
XX    strncpy(scrbuf,cptr,6);
XX    for (i = 0; i<6 ; i++)
XX	if (scrbuf[i]>=0x61 && scrbuf[i]<=0x7A) scrbuf[i] -= 0x20;
XX
XX    if (strncmp(scrbuf,"IF",2) == 0 ||
XX	strncmp(scrbuf,"FOR",3) == 0 ||
XX	strncmp(scrbuf,"CASE",4) == 0 ||
XX	strncmp(scrbuf,"LOOP",4) == 0 ||
XX	strncmp(scrbuf,"WITH",4) == 0 ||
XX	strncmp(scrbuf,"WHILE",5) == 0 ||
XX	strncmp(scrbuf,"BEGIN",5) == 0 ||
XX	strncmp(scrbuf,"REPEAT",6) == 0 ||
XX	strncmp(scrbuf,"RECORD",6) == 0) ++gotleft;
XX    else if (strncmp(scrbuf,"ELSE",4) == 0 ||
XX	     strncmp(scrbuf,"ELSIF",5) == 0) {
XX	++gotleft;
XX	++gotright;
XX	}
XX    else if (strncmp(scrbuf,"END",3) == 0 ||
XX	     strncmp(scrbuf,"UNTIL",5) == 0) ++gotright;
XX
XX    /* just ended a block */
XX    if (gotright > gotleft) return(fixblockend(gotleft,gotright));
XX
XX	
XX    /* save the indent of the previous line */
XX    i = getccol(TRUE); j = getccol(FALSE);
XX
XX    /* get rid of spaces on blank lines */
XX    if (i == j) backdel(FALSE,tptr+1);
XX    
XX    /* adjust current line */
XX    else if (gotleft > 0 && gotleft == gotright) {
XX	curwp->w_doto = doto;
XX	while(getccol(TRUE) > i-4 && curwp->w_doto > 0) backdel(FALSE,1);
XX	while(getccol(TRUE) < i-4) tab(FALSE,1);
XX	curwp->w_doto = llength(curwp->w_dotp);
XX	}
XX
XX    /* put in the newline */
XX    if (lnewline() == FALSE) return(FALSE);
XX
XX    /* and the saved indentation */
XX    while (getccol(TRUE) < i) tab(FALSE, 1);
XX
XX    /* add tabs for block nesting on the previous line */
XX    while (gotleft-- > gotright) tab(FALSE,1);
XX
XX    return(TRUE);
XX    }
XX
XXlispinsert() /* insert a newline and indentation for LISP */
XX    {
XX    register char *cptr;    /* string pointer into text to copy */
XX    register int tptr;	/* index to scan into line */
XX    register int i,j;
XX    int gotleft,gotright;
XX
XX    /* grab a pointer to text to copy indentation from */
XX    cptr = &curwp->w_dotp->l_text[0];
XX    tptr = curwp->w_doto - 1;
XX    gotleft = gotright = 0;
XX    for (i = 0; i<=tptr; i++) {
XX	if (*cptr == '(') ++gotleft;
XX	if (*cptr++ == ')') ++gotright;
XX	}
XX    if (gotright > gotleft) return(fixblockend(gotleft,gotright));
XX
XX    /* save the indent of the previous line */
XX    i = getccol(TRUE); j = getccol(FALSE);
XX
XX    if (i == j) {
XX	backdel(FALSE,tptr+1); /* get rid of spaces on blank lines */
XX	}
XX
XX    /* put in the newline */
XX    if (lnewline() == FALSE) return(FALSE);
XX
XX    /* and the saved indentation */
XX    while (getccol(TRUE) < i) tab(FALSE, 1);
XX
XX    /* add tabs for paren nesting on the previous line */
XX    while (gotleft-- > gotright) tab(FALSE,1);
XX
XX    return(TRUE);
XX    }
XX
XX/*
XX* Delete blank lines around dot. What this command does depends if dot is
XX* sitting on a blank line. If dot is sitting on a blank line, this command
XX* deletes all the blank lines above and below the current line. If it is
XX* sitting on a non blank line then it deletes all of the blank lines after
XX* the line. Normally this command is bound to "C-X C-O". Any argument is
XX* ignored.
XX*/
XXdeblank(f, n)
XX    {
XX    register LINE   *lp1;
XX    register LINE   *lp2;
XX    register int    nld;
XX
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX    return(rdonly());    /* we are in read only mode */
XX    lp1 = curwp->w_dotp;
XX    while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep) lp1 = lp2;
XX    lp2 = lp1;
XX    nld = 0;
XX    while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0) ++nld;
XX    if (nld == 0) return (TRUE);
XX    curwp->w_dotp = lforw(lp1);
XX    curwp->w_doto = 0;
XX    return (ldelete(nld));
XX    }
XX
XX/*
XX* Insert a newline, then enough tabs and spaces to duplicate the indentation
XX* of the previous line. Assumes tabs are every eight characters. Quite simple.
XX* Figure out the indentation of the current line. Insert a newline by calling
XX* the standard routine. Insert the indentation by inserting the right number
XX* of tabs and spaces. Return TRUE if all ok. Return FALSE if one of the
XX* subcomands failed. Normally bound to "C-J".
XX*/
XXindent(f, n)
XX    {
XX    register int    nicol;
XX    register int    c;
XX    register int    i;
XX
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX    return(rdonly());    /* we are in read only mode */
XX    if (n < 0) return (FALSE);
XX    while (n--) {
XX	nicol = 0;
XX	for (i=0; i<llength(curwp->w_dotp); ++i) {
XX	    c = lgetc(curwp->w_dotp, i);
XX	    if (c!=' ' && c!='\t') break;
XX	    if (c == '\t') nicol |= 0x07;
XX	    ++nicol;
XX	    }
XX	if (lnewline() == FALSE || ((i=nicol/8)!=0 && linsert(i, '\t')==FALSE)
XX	|| ((i=nicol%8)!=0 && linsert(i,  ' ')==FALSE))
XX	return (FALSE);
XX	}
XX    return (TRUE);
XX    }
XX
XX/*
XX* Delete forward. This is real easy, because the basic delete routine does
XX* all of the work. Watches for negative arguments, and does the right thing.
XX* If any argument is present, it kills rather than deletes, to prevent loss
XX* of text if typed with a big argument. Normally bound to "C-D".
XX*/
XXforwdel(f, n)
XX    {
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX    return(rdonly());    /* we are in read only mode */
XX    if (n < 0) return (backdel(f, -n));
XX    if (f != FALSE) {	      /* Really a kill. */
XX	if ((lastflag&CFKILL) == 0)
XX	kdelete();
XX	thisflag |= CFKILL;
XX	}
XX    return (ldelete(n, f));
XX    }
XX
XX/*
XX* Delete backwards. This is quite easy too, because it's all done with other
XX* functions. Just move the cursor back, and delete forwards. Like delete
XX* forward, this actually does a kill if presented with an argument. Bound to
XX* both "RUBOUT" and "C-H".
XX*/
XXbackdel(f, n)
XX    {
XX    register int    s;
XX
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX    return(rdonly());    /* we are in read only mode */
XX    if (n < 0) return (forwdel(f, -n));
XX    if (f != FALSE) {	      /* Really a kill. */
XX	if ((lastflag&CFKILL) == 0)
XX	kdelete();
XX	thisflag |= CFKILL;
XX	}
XX    if ((s=backchar(f, n)) == TRUE) s = ldelete(n, f);
XX    return (s);
XX    }
XX
XX/*
XX* Kill text. If called without an argument, it kills from dot to the end of
XX* the line, unless it is at the end of the line, when it kills the newline.
XX* If called with an argument of 0, it kills from the start of the line to dot.
XX* If called with a positive argument, it kills from dot forward over that
XX* number of newlines. If called with a negative argument it kills backwards
XX* that number of newlines. Normally bound to "C-K".
XX*/
XXkilltext(f, n)
XX    {
XX    register int    chunk;
XX    register LINE   *nextp;
XX
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX
XX    return(rdonly());    /* we are in read only mode */
XX    if ((lastflag&CFKILL) == 0)      /* Clear kill buffer if */
XX    kdelete();	         /* last wasn't a kill. */
XX    thisflag |= CFKILL;
XX    if (f == FALSE) {
XX	chunk = llength(curwp->w_dotp)-curwp->w_doto;
XX	if (chunk == 0) chunk = 1;
XX	}
XX    else if (n == 0) {
XX	chunk = curwp->w_doto;
XX	curwp->w_doto = 0;
XX	}
XX    else if (n > 0) {
XX	chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
XX	nextp = lforw(curwp->w_dotp);
XX	while (--n) {
XX	    if (nextp == curbp->b_linep) return (FALSE);
XX	    chunk += llength(nextp)+1;
XX	    nextp = lforw(nextp);
XX	    }
XX	}
XX    else {
XX	mlwrite("neg kill");
XX	return (FALSE);
XX	}
XX    return (ldelete(chunk, TRUE));
XX    }
XX
XX/*
XX* Yank text back from the kill buffer. This is really easy. All of the work
XX* is done by the standard insert routines. All you do is run the loop, and
XX* check for errors. Bound to "C-Y".
XX*/
XXyank(f, n)
XX    {
XX    register int    c;
XX    register int    i;
XX    extern int    kused;
XX
XX    if (curbp->b_mode&MDVIEW)   /* don't allow this command if */
XX    return(rdonly());    /* we are in read only mode */
XX    if (n < 0) return (FALSE);
XX    while (n--) {
XX	i = 0;
XX	while ((c=kremove(i)) >= 0) {
XX	    if (c == '\n') {
XX		if (lnewline(FALSE, 1) == FALSE) return (FALSE);
XX		}
XX	    else {
XX		if (linsert(1, c) == FALSE) return (FALSE);
XX		}
XX	    ++i;
XX	    }
XX	}
XX    return (TRUE);
XX    }
XX
XX
XXadjustmode(f,n) /* change the editor mode status */
XX    {
XX    register char *scan;	/* scanning pointer to convert prompt */
XX    register int i;	    /* loop index */
XX    char cbuf[NPAT];    /* buffer to recieve mode name into */
XX    char prompt[80];    /* string to prompt user with */
XX
XX    strcpy(prompt,"Change mode (");
XX    strcat(prompt,modename[0]);
XX    for (i=1; i < NUMMODES; i++) {
XX	strcat(prompt,",");
XX	strcat(prompt,modename[i]);
XX	}
XX    strcat(prompt,"): ");
XX
XX    /* prompt the user and get an answer */
XX
XX    mlreply(prompt, cbuf, NPAT - 1);
XX
XX    /* make it uppercase */
XX
XX    scan = cbuf;
XX    while (*scan != 0) {
XX	if (*scan >= 'a' && *scan <= 'z') *scan = *scan - 32;
XX	scan++;
XX	}
XX
XX    /* test it against the modes we know (first letter only) */
XX
XX    for (i=0; i < NUMMODES; i++) {
XX	if (cbuf[0] == modename[i][0]) {
XX	    /* finding a match, we process it */
XX	    if ((curwp->w_bufp->b_mode & (1 << i)) == 0) {
XX		curwp->w_bufp->b_mode |= (1 << i);
XX		if ((1 << i) == MDCMOD) {
XX		    tab(FALSE,4);
XX		    curwp->w_bufp->b_mode &= ~(MDMMOD|MDLISP);
XX		    }
XX		if ((1 << i) == MDMMOD) {
XX		    tab(FALSE,4);
XX		    curwp->w_bufp->b_mode &= ~(MDCMOD|MDLISP);
XX		    }
XX		if ((1 << i) == MDLISP) {
XX		    tab(FALSE,2);
XX		    curwp->w_bufp->b_mode &= ~(MDCMOD|MDMMOD);
XX		    }
XX		}
XX	    else {
XX		curwp->w_bufp->b_mode &= ~(1 << i);
XX		if (((1 << i) == MDCMOD) ||
XX		    ((1 << i) == MDMMOD) ||
XX		    ((1 << i) == MDLISP)) tab(FALSE,0);
XX		}
XX	    /* display new mode line */
XX	    upmode();
XX	    mlerase(); /* erase the junk */
XX	    return(TRUE);
XX	    }
XX	}
XX
XX    mlwrite("No such mode!");
XX    return(FALSE);
XX    }
XX
SHAR_EOF
if test 18178 -ne "`wc -c random.c`"
then
echo shar: error transmitting random.c '(should have been 18178 characters)'
fi
#	End of shell archive
exit 0