[comp.emacs] Key bindings for MicroEMACS

glf@mundoe.mu.oz (Giuseppe Fiusco) (09/09/87)

These are the files and diffs required to implement the programmable key
bindings that I advertised a couple of weeks. They come in three files. The
first (this one) contains various bits and pieces required ie. the Makefile,
a binding description file and some general information. The second contains
complete copies of the files bind.c and isearch.c that should replace the
originals while the third contains standard diffs for the other files (use
patch).

To anyone prepared to risk implementing these changes -

Good Luck :-)

Giuseppe Fiusco

ACSnet: glf@mundoe.mu
UUCP:	{uunet,mcvax,ukc,ubc-vision}!munnari!mundoe.mu.oz!glf
ARPA:	munnari!mundoe.mu.oz!glf@uunet.css.gov
CSNET:	glf%mundoe.mu.oz@csnet-relay
: ---------------------------------------- cut here

echo x - "Readme" 2>&1
sed "s/^X//" >"Readme" <<'!The!End!'
XThis is a description of how to use the changes made to MicroEMACS(3.8i)
Xto allow the key bindings for functions to be loaded in from a startup 
Xdescription file. It describes the various changes to some of the syntax
Xin the functions that have been effected by the changes, this is mainly
Xthose routines contained in the file bind.c.
X
XThe binding file.
X
XThe binding file contains a description of what series of key-strokes are
Xbound to what functions within the editor. The binding file (whose name 
Xis defined in the file epath.h) contains various commands for the setting
Xup the key bindings and for obtaining a preloaded binding format.
X
XThe binding file is treated as a macro-file so you must follow the rules for
Xmacros when defining your file ie you may use all of the clauses and
Xdefinitions that are allowed in macros. As the binding file is the first
Xthing that is read in from a file there is no display window so the display
Xcommand ($discmd) has been turned off. It is turned back on after the
Xbinding file has been read in.
X
XThe commands that have been added to allow for the bindings to be used
Xand installed are :
X
Xcore           This command causes the preloaded emacs to dump core.
X	       This core file can then be used to create a preloaded
X	       editor where the standard key bindings are set.
X
Xdigit          A dummy routine that is used to tell whether the user 
X	       wishes to type a number argument before the command.
X	       ie To allow the old sequences M-0...M-9,M-- to be 
X	       replaced by any set of key-strokes.
X
Xdummy          A dummy routine that can be used for adding bindings to
X	       greater depths if the user is adding them directly from
X	       the keyboard.
X
Xspecial-char   Allows the definition of special character codes so that
X	       terminals that emit a strange character in its function
X	       keys can be bound (up to eight).
X
Xuniversal-argument   Although this already existed it is now used to
X		     define key-bindings that will invoke the universal
X		     argument handling routines.
X
XSpecial characters (special-char)
X
XThere are eight special character code values that may be defined by using
Xthis command. The command has the format
X
Xspecial-char	code-number	code-value
X
XNote that the code-number is modulo 8 (0 - 7) and that the code-value is
Xmodulo 256 (0 - 255). Eg to define define the amiga special character you
Xwould use 
X
Xspecial-char	0	155
X
XTo obtain access to these values in the key bindings you use the definition
X\0 - \7 to describe the particular special key.
X
XThis command may be placed anywhere in the bindings file.
X
XDumping core (core)
X
XThis causes a core dump of a preloaded MicroEMACS file. This core file can
Xthen be turned into an executable file. This allows the system administrator
Xto set up a default preloaded version of the editor (perhaps with all of the
Xstandard key definitions for MicroEMACS) and then for each individual user to
Xhave a small definitions file that may add bindings particular to their
Xtastes and terminal ie direction and function keys.
X
XAt the moment this can only be achieved on BSD systems as it requires the
Xpreviously distributed undump program.
X
XBinding Keys (bind-to-key)
X
XThis command allows a function as described in the function binding table to
Xbe mapped onto any particular series of key-strokes. The overall advantage of
Xthis is that allows the editor to be totally customizable by the end user so
Xlong as he is using an pure version of the editor ie not preloaded. If the
Xeditor is a preloaded version then there are a few small restrictions. The
Xcommand has the following format
X
Xbind-to-key	function-name		key-strokes
X
XThe function-name is that which is defined in the binding table while the
Xkey-strokes consists of a description of the keys that are bound to the
Xfunction. The following is allowed when describing a key.
X
X\e - escape
X\n - linefeed
X\r - carriage return
X\0 - \7 - special characters
X\\ - the character '\'
X\^ - the character '^'
X^? - control character (where ? is in the range [A - Z])
X
XSome examples of valid keystroke definitions.
X
X\e[C      escape [ C        The key sequence generated by the right arrow key
X			    on a VT100 keyboard.
X\e^X      escape control-X
X^X1       control-X 1       Single window (EMACS command)
X^Y        control-Y         Yank (EMACS command)
X
XThis allows the user to place all of his standard bindings in the binding
Xfile and terminal specific keys in the startup file with perhaps a method 
Xof query for the different terminals. eg.
X
X	set %term "Terminal : "
X	!if &sequal @%term "vt100"
X		bind-to-key	forward-character	\e[C
X		     .                   .                .
X	!endif
X	!if &sequal %term "vt52"
X		bind-to-key	forward-character	\eC
X		     .                   .               .
X	!endif
X
XBecause the method used in the key bindings is dual linked list structure it
Xis far better to place all of the heavily used bindings at the front of the
Xbindings file eg in standard MicroEMACS you would have at least one Meta
X(escape) and one control-X at the beginning of the file.
X
XDon't forget that in the macro description language that the character '~'
Xhas special significance and must be used with caution. This is not
Ximportant when just using the command from the keyboard.
X
XSome important changes
X
XWith this new method MicroEMACS no longer understands things such as
XSPEC & META as far as describing keys (although a meta key does still
Xexist).
X
XThe command META-n where is a digit no longer forces emacs into
Xargument mode. This is achieved by binding a particular set of keys to
Xthe dummy routine "digit". Thus to get MicroEMACS to behave as it did 
Xbefore, you bind the keys to the appropriate digit. eg
X
Xbind-to-key	digit		\e0
Xbind-to-key	digit		\e1
X     .            .              .
Xbind-to-key	digit		\e9
Xbind-to-key	digit		\e-
X
Xbut this selection is up to the user and they are not forced into any 
Xparticular selection. Similarly with the universal argument which may be
Xbound using the dummy function "universal". eg.
X
Xbind-to-key	universal-argument	^U
X
XBUGS
X====
X
XProbably lots - mail when you find them please.
X
XThe syntax of certain commands, especially when defining key bindings has
Xchanged to a large amount.
X
XAt the moment the binding increase the size of the file by a large amount
X(much more than expected due to the stdio library mallocs for buffer space).
XThis only increases the size of the binary (slow startup time) but means
Xthat most of the internal buffers have already been allocated. If this
Xcauses a problem then it should be pretty easy to rectify.
X
XSome of the patches sent out do not seem relevant but are in fact some small
Xchanges I made to help with implementing some EDT like functions. I will
Xprobably post these out once I feel they are working properly. They in no
Xway effect the current usage of MicroEMACS.
X
X
XGood luck to those of you prepared to risk using these hacks. Please let me
Xknow of any improvements or other suggestions you have.
X
XWhat you get.
X-------------
X
XYou recieve complete copies of the files bind.c and isearch.c that will
Xreplace your current copies. You will also recieve diffs of all the other
Xfiles that have been changed. These files are edef.d, efunc.d, estruct.d,
Xeval.d, exec.d, input.d, main.d and random.d. You can remove the file
Xebind.h as that is no longer necessary. You will also recieve copies of the
Xadditional files that are now required and a new version of the Makefile.
!The!End!

echo x - "makefile" 2>&1
sed "s/^X//" >"makefile" <<'!The!End!'
XCFLAGS=		-O
X
XOFILES=		ansi.o basic.o bind.o buffer.o crypt.o dg10.o \
X		display.o edtem.o eval.o exec.o file.o fileio.o \
X		hp110.o hp150.o ibmpc.o input.o isearch.o line.o \
X		lock.o main.o random.o region.o search.o spawn.o \
X		st520.o tcap.o termio.o tipc.o vmsvt.o vt52.o \
X		window.o word.o z309.o
X
XCFILES=		ansi.c basic.c bind.c buffer.c crypt.c dg10.c \
X		display.c edtem.c eval.c exec.c file.c fileio.c \
X		hp110.c hp150.c ibmpc.c input.c isearch.c line.c \
X		lock.c main.c random.c region.c search.c spawn.c \
X		st520.c tcap.c termio.c tipc.c vmsvt.c vt52.c \
X		window.c word.c z309.c
X
XHFILES=		estruct.h edef.h efunc.h epath.h evar.h
X
Xemacs:		$(OFILES)
X		$(CC) $(CFLAGS) $(OFILES) -ltermcap -lc -o emacs
X
X$(OFILES):	$(HFILES)
!The!End!

echo x - "emacs.bind" 2>&1
sed "s/^X//" >"emacs.bind" <<'!The!End!'
Xbind-to-key	abort-command			^G
Xbind-to-key	add-mode			^XM
Xbind-to-key	add-global-mode			\eM
Xbind-to-key	apropos				\eA
Xbind-to-key	backward-character		^B
Xbind-to-key	begin-macro			^X(
Xbind-to-key	beginning-of-file		\e<
Xbind-to-key	beginning-of-line		^A
Xbind-to-key	bind-to-key			\eK
Xbind-to-key	buffer-position			\e=
Xbind-to-key	case-region-lower		^X^L
Xbind-to-key	case-region-upper		^X^U
Xbind-to-key	case-word-capitalize		\eC
Xbind-to-key	case-word-lower			\eL
Xbind-to-key	case-word-upper			\eU
Xbind-to-key	change-file-name		^XN
Xbind-to-key	change-screen-size		\e^S
Xbind-to-key	change-screen-width		\e^T
Xbind-to-key	clear-and-redraw		^L
X; bind-to-key	clear-message-line
Xbind-to-key	copy-region			\eW
Xbind-to-key	count-words			\e^C
Xbind-to-key	delete-blank-lines		^X^O
Xbind-to-key	delete-buffer			^XK
Xbind-to-key	delete-mode			^X\r
Xbind-to-key	delete-global-mode		\e\r
Xbind-to-key	delete-next-character		^D
Xbind-to-key	delete-next-word		\eD
Xbind-to-key	delete-other-windows		^X1
Xbind-to-key	delete-previous-character	^H
Xbind-to-key	delete-previous-word		\e^H
Xbind-to-key	delete-window			^X0
X; bind-to-key	describe-bindings
Xbind-to-key	describe-key			^X?
Xbind-to-key	detab-line			^X^D
Xbind-to-key	end-macro			^X)
Xbind-to-key	end-of-file			\e>
Xbind-to-key	end-of-line			^E
Xbind-to-key	entab-line			^X^E
Xbind-to-key	exchange-point-and-mark		^X^X
X; bind-to-key	execute-buffer
X; bind-to-key	execute-command-line
X; bind-to-key	execute-file
Xbind-to-key	execute-macro			^XE
X; bind-to-key	execute-macro-1
X; bind-to-key	execute-macro-2
X; bind-to-key	execute-macro-3
X; bind-to-key	execute-macro-4
X; bind-to-key	execute-macro-5
X; bind-to-key	execute-macro-6
X; bind-to-key	execute-macro-7
X; bind-to-key	execute-macro-8
X; bind-to-key	execute-macro-9
X; bind-to-key	execute-macro-10
X; bind-to-key	execute-macro-11
X; bind-to-key	execute-macro-12
X; bind-to-key	execute-macro-13
X; bind-to-key	execute-macro-14
X; bind-to-key	execute-macro-15
X; bind-to-key	execute-macro-16
X; bind-to-key	execute-macro-17
X; bind-to-key	execute-macro-18
X; bind-to-key	execute-macro-19
X; bind-to-key	execute-macro-20
X; bind-to-key	execute-macro-21
X; bind-to-key	execute-macro-22
X; bind-to-key	execute-macro-23
X; bind-to-key	execute-macro-24
X; bind-to-key	execute-macro-25
X; bind-to-key	execute-macro-26
X; bind-to-key	execute-macro-27
X; bind-to-key	execute-macro-28
X; bind-to-key	execute-macro-29
X; bind-to-key	execute-macro-30
X; bind-to-key	execute-macro-31
X; bind-to-key	execute-macro-32
X; bind-to-key	execute-macro-33
X; bind-to-key	execute-macro-34
X; bind-to-key	execute-macro-35
X; bind-to-key	execute-macro-36
X; bind-to-key	execute-macro-37
X; bind-to-key	execute-macro-38
X; bind-to-key	execute-macro-39
X; bind-to-key	execute-macro-40
Xbind-to-key	execute-named-command		\eX
Xbind-to-key	execute-procedure		\e^E
Xbind-to-key	exit-emacs			^X^C
Xbind-to-key	fill-paragraph			\eQ
Xbind-to-key	filter-buffer			^X#
Xbind-to-key	find-file			^X^F
Xbind-to-key	forward-character		^F
Xbind-to-key	goto-line			\eG
Xbind-to-key	goto-matching-fence		\e^F
Xbind-to-key	grow-window			^X\^
Xbind-to-key	handle-tab			^I
X; bind-to-key	hunt-forward
X; bind-to-key	hunt-backward
Xbind-to-key	help				\e?
Xbind-to-key	i-shell				^XC
Xbind-to-key	incremental-search		^XS
Xbind-to-key	insert-file			^X^I
Xbind-to-key	insert-space			^C
X; bind-to-key	insert-string
Xbind-to-key	kill-paragraph			\e^W
Xbind-to-key	kill-region			^W
Xbind-to-key	kill-to-end-of-line		^K
Xbind-to-key	list-buffers			^X^B
Xbind-to-key	move-window-down		^X^N
Xbind-to-key	move-window-up			^X^P
Xbind-to-key	name-buffer			\e^N
Xbind-to-key	newline				\r
Xbind-to-key	newline-and-indent		\n
Xbind-to-key	next-buffer			^XX
Xbind-to-key	next-line			^N
Xbind-to-key	next-page			^V
Xbind-to-key	next-paragraph			\eN
Xbind-to-key	next-window			^XO
Xbind-to-key	next-word			\eF
Xbind-to-key	open-line			^O
Xbind-to-key	pipe-command			^X@
Xbind-to-key	previous-line			^P
Xbind-to-key	previous-page			^Z
Xbind-to-key	previous-paragraph		\eP
Xbind-to-key	previous-window			^XP
Xbind-to-key	previous-word			\eB
Xbind-to-key	query-replace-string		\e^R
Xbind-to-key	quick-exit			\eZ
Xbind-to-key	quote-character			^Q
Xbind-to-key	read-file			^X^R
Xbind-to-key	redraw-display			\e^L
Xbind-to-key	resize-window			^XW
X; bind-to-key	restore-window
Xbind-to-key	replace-string			\eR
Xbind-to-key	reverse-incremental-search	^XR
Xbind-to-key	run				\e^E
Xbind-to-key	save-file			^X^S
X; bind-to-key	save-window
Xbind-to-key	scroll-next-up			\e^Z
Xbind-to-key	scroll-next-down		\e^V
Xbind-to-key	search-forward			^S
Xbind-to-key	search-reverse			^R
Xbind-to-key	select-buffer			^XB
Xbind-to-key	set				^XA
Xbind-to-key	set-encryption-key		\eE
Xbind-to-key	set-fill-column			^XF
X; bind-to-key	set-mark
Xbind-to-key	shell-command			^X!
Xbind-to-key	shrink-window			^X^Z
Xbind-to-key	split-current-window		^X2
X; bind-to-key	store-macro
X; bind-to-key	store-procedure
Xbind-to-key	transpose-characters		^T
Xbind-to-key	trim-line			^X^T
Xbind-to-key	unbind-key			\e^K
Xbind-to-key	unmark-buffer			\e~~
X; bind-to-key	update-screen
Xbind-to-key	view-file			^X^V
X; bind-to-key	wrap-word
Xbind-to-key	write-file			^X^W
X; bind-to-key	write-message
Xbind-to-key	yank				^Y
!The!End!
exit

glf@mundoe.mu.oz (Giuseppe Fiusco) (09/09/87)

: ---------------------------------------- cut here

echo x - "bind.c" 2>&1
sed "s/^X//" >"bind.c" <<'!The!End!'
X/*	This file is for functions having to do with key bindings,
X	descriptions, help commands and startup file.
X
X	written 11-feb-86 by Daniel Lawrence
X
X	Rewritten to use programmable key bindings
X	 - Tue Aug 18 1987 by G.Fiusco
X								*/
X
X#include	<stdio.h>
X#include	<pwd.h>
X#include	<ctype.h>
X#include	"estruct.h"
X#include	"edef.h"
X#include	"epath.h"
X
X
Xextern int ctrlg(); /* dummy prefix binding functions */
Xchar *getenv() ;
Xint (*fncmatch())() ;
Xextern struct spec_chars *bindh ;
Xextern NBIND cbind[] ;
Xstatic char spec_c[8] ;
X
X
X/* 
X * A dummy routine for adding bindings deeper into the list.
X */
X
Xdummy()
X{
X}
X
X
X/* 
X * A dummy routine for handling integers for function calls.
X */
X
Xdigit()
X{
X}
X
X
X/* 
X * A dummy routine for handling the universal routine.
X */
X
Xunarg()
X{
X}
X
X
Xdeskey(f, n)	/* describe the command for a certain key */
X
X{
X	register unsigned char *c;
X				/* command character to describe */
X	register char *ptr;	/* string pointer to scan output strings */
X	struct spec_chars *c_bind, *p_bind ;
X				/* pointers into key bind list */
X	register NBIND *nptr;	/* pointer into the name binding table */
X	char outseq[80];	/* output buffer for command sequence */
X
X	/* prompt the user to type us a key to describe */
X	mlwrite(": describe-key ");
X
X	/* get the command sequence to describe */
X	c = getckey();			/* get a command sequence */
X
X	/* change it to something we can print as well */
X	cmdstr(c, &outseq[0]);
X
X	/* and dump it out */
X	if (discmd) {
X		ptr = &outseq[0];
X		while (*ptr)
X			TTputc(*ptr++);
X		TTputc(' ');		/* space it out */
X	}
X
X	/* find the right ->function */
X	if (keymatch(bindh,&c_bind,&p_bind,c)) {
X	    nptr = names ;
X	    strcpy(outseq,"[Bad Binding]") ;
X	    /* search for described function */
X	    while (nptr->n_func) {
X		if (nptr->n_func == c_bind->com.command) {
X		    strcpy(outseq,nptr->n_name) ;
X		    break ;
X		}
X		nptr++ ;
X	    }
X	}
X	else
X	    strcpy(outseq,"Not bound") ;
X
X	/* output the command sequence */
X	ptr = &outseq[0];
X	while (*ptr)
X		TTputc(*ptr++);
X}
X
Xcmdstr(k, seq)	/* change a key command to a string we can print out */
X
Xchar *k, *seq;	/* destination string for sequence */
X
X{
X	register unsigned char c ;
X	int i, set_spec = 0 ;
X
X	while (c = *(k++)) {
X	    for (i=0 ; i<8 ; i++) {
X		if (c == spec_c[i]) {
X		    *seq++ = '\\' ;
X		    *seq++ = (char)i|0x30 ;
X		    set_spec = 1 ;
X		    break ;
X		}
X	    }
X	    if (!set_spec)
X	        switch (c) {
X	            case 033   : *seq++ = '\\' ;   /* ESC */
X			         *seq++ = 'e' ;
X			         break ;
X	            case '\n'  : *seq++ = '\\' ;
X			         *seq++ = 'n' ;
X			         break ;
X	            case '\r'  : *seq++ = '\\' ;
X			         *seq++ = 'r' ;
X			         break ;
X	            case '\\'  : *seq++ = '\\' ;
X			         *seq++ = '\\' ;
X			         break ;
X	            case '^'   : *seq++ = '\\' ;
X			         *seq++ = '^' ;
X			         break ;
X	            default   : if (c <= 037) {    /* control character */
X				    *seq++ = '^' ;
X				    c += 0100 ;
X			        }
X			        *seq++ = c ;
X	        }
X	    set_spec = 0 ;
X	}
X	*seq = 0;	/* terminate the string */
X}
X
Xhelp(f, n)	/* give me some help!!!!
X		   bring up a fake buffer and read the help file
X		   into it with view mode			*/
X{
X	register WINDOW *wp;	/* scaning pointer to windows */
X	register BUFFER *bp;	/* buffer pointer to help */
X	char *fname;		/* ptr to file returned by flook() */
X
X	/* first check if we are already here */
X	bp = bfind("emacs.hlp", FALSE, BFINVS);
X
X	if (bp == NULL) {
X		fname = flook(pathname[1], FALSE);
X		if (fname == NULL) {
X			mlwrite("[Help file is not online]");
X			return(FALSE);
X		}
X	}
X
X	/* split the current window to make room for the help stuff */
X	if (splitwind(FALSE, 1) == FALSE)
X			return(FALSE);
X
X	if (bp == NULL) {
X		/* and read the stuff in */
X		if (getfile(fname, FALSE) == FALSE)
X			return(FALSE);
X	} else
X		swbuffer(bp);
X
X	/* make this window in VIEW mode, update all mode lines */
X	curwp->w_bufp->b_mode |= MDVIEW;
X	curwp->w_bufp->b_flag |= BFINVS;
X	wp = wheadp;
X	while (wp != NULL) {
X		wp->w_flag |= WFMODE;
X		wp = wp->w_wndp;
X	}
X	return(TRUE);
X}
X
X/*
X * This values are required by for the new key binding method
X */
X
X#define VALID   1
X#define E_FUNC  -1
X#define E_KCODE	-2
X#define DEFAULT 1
X#define CCTRL   -1
X#define CSPEC   -2
X
Xunsigned char 
X*getbindkey(bkeys)  /* change key descriptions into actual characters */
X
Xchar *bkeys ;
X
X{
X	static unsigned char buf[20] ;
X	unsigned char *bufp = buf, c ;
X	int mode = DEFAULT, i ;
X
X	while (c = *bkeys++) {
X	    switch (mode) {
X		case CCTRL : c &= 037 ;
X			     mode = DEFAULT ;
X			     break ;
X		case CSPEC : if (isdigit(c))
X				c = spec_c[c&007] ;
X			     else
X			         switch (c) {
X				     case '\\' : c = '\\' ;
X					        break ;
X				     case 'e'  : c = 033 ;   /* ESC */
X					        break ;
X				     case 'n'  : c = '\n' ;
X					        break ;
X				     case 'r'  : c = '\r' ;
X					        break ;
X				     case '^'  : c = '^' ;
X					        break ;
X				     default   : return((unsigned char *)0) ;
X			         }
X			     mode = DEFAULT ;
X			     break ;
X		case DEFAULT : switch (c) {
X				   case '\\' : mode = CSPEC ;
X					      continue ;
X				   case '^' : mode = CCTRL ;
X					      continue ;
X			       }
X			       break ;
X	    }
X	    *bufp++ = c ;
X	}
X	*bufp = '\0' ;
X	return(buf) ;
X}
X
X
Xsetspecial(f,n)
X
X{
X	char specialchar[40], value[40], c, *valuep=value ;
X
X	if (clexec) {
X	    macarg(specialchar) ;
X	    macarg(value) ;
X	}
X	else {
X	    mlwrite(": special-char ") ;
X	    while (1) {
X		if ((c = tgetc()) == abortc || c == '\r')
X		    return(FALSE) ;
X		if (c >= '0' && c<= '7')
X		    break ;
X		putchar(007) ;
X	    }
X	    TTputc(c) ;
X	    TTputc(' ') ;
X	    *specialchar = c ;
X	    *(specialchar+1) = '\0' ;
X	    while (1) {
X		if ((c = tgetc()) == abortc)
X		    return(FALSE) ;
X		if (c == '\r')
X		    break ;
X		if (c >= '0' && c<= '7') {
X		    TTputc(c) ;
X		    *valuep++ = c ;
X		}
X		else
X		    putchar(007) ;
X	    }
X	    *valuep = '\0' ;
X	}
X	spec_c[atoi(specialchar)&0x07] = atoi(value)&0xff ;
X}
X
X
Xint
X(*fncmatch(fname))()	    /* match fname to a function in the names table
X			    and return any match or NULL if none	*/
X
Xchar *fname;	/* name to attempt to match */
X
X{
X	register NBIND *ffp = names ;
X
X	/* scan through the table, returning any match */
X	while (ffp->n_func != NULL) {
X		if (strcmp(fname, ffp->n_name) == 0)
X			return(ffp->n_func);
X		++ffp;
X	}
X	return(NULL);
X}
X
X
Xkeymatch(head,curr,prev,c)    /* match keys to command they invoke and return
X			         function or NULL */
X
Xunsigned char *c ;
Xstruct spec_chars *head ;
Xstruct spec_chars **curr, **prev ;
X
X{
X	struct spec_chars *c_bind = head, *p_bind = NULL ;
X
X	/* scan through the lists matching a key path */
X	while(*c) {
X	    scanlist(c_bind,&c_bind,&p_bind,*c) ;
X	    if (c_bind == NULL)
X		return(NULL) ;
X	    c++ ;
X	    if (c_bind->research)
X		c_bind = c_bind->com.k_codelist ;
X	    else
X		if (*c)
X		    return(NULL) ;
X		else {
X		    *curr = c_bind ;
X		    *prev = p_bind ;
X		    return(1) ;
X		}
X	}
X	return(NULL) ;
X}
X
X
Xaddbinding(c,func,prev)  /* add binding to list */
X
Xunsigned char *c ;
Xint (*func)() ;
Xstruct spec_chars *prev ;
X
X{
X	struct spec_chars *new ;
X	int c_pos = 1 ;
X	extern int quit(), quickexit();
X	int bindtokey() ;
X	extern int exit_def ;
X
X	/* make sure it will be possible to exit emacs after keys loaded */
X	if (func == quit || func == quickexit || func == bindtokey)
X	    exit_def = 1 ;
X	/* bind the key code to the function */
X	while (*c) {
X	    new = (struct spec_chars *)malloc(sizeof(struct spec_chars)) ;
X	    new->k_code = *c ;
X	    new->research = 0 ;
X	    new->com.command = func ;
X	    new->next = NULL ;
X	    if (bindh == NULL)
X	        /* No keys yet bound */
X		bindh = new ;
X	    else
X		if (c_pos == 1)
X		    /* add to current key code list */
X		    prev->next = new ;
X		else {
X		    /* add key code to the next level */
X		    prev->research = 1 ;
X		    prev->com.k_codelist = new ;
X		}
X	    c++ ;
X	    c_pos++ ;
X	    prev = new ;
X	}
X}
X
X
Xscanlist(head,curr,prev,data)
X
Xstruct spec_chars *head ;
Xstruct spec_chars **curr, **prev ;
Xunsigned char data ;
X
X{
X	struct spec_chars *t_curr = head, *t_prev = NULL ;
X
X	while (t_curr != NULL) {
X	    if (t_curr->k_code == data)
X		break ;
X	    t_prev = t_curr ;
X	    t_curr = t_curr->next ;
X	}
X	*prev = t_prev ;
X	*curr = t_curr ;
X}
X
X
Xbindkeytofunc(kfunc,keys)
X
Xunsigned char *keys ;
Xint (*kfunc)() ;
X
X{
X	char c ;
X	struct spec_chars *c_bind = bindh, *p_bind = NULL ;
X
X	if (!*keys)
X	    return(E_KCODE) ;
X	if (kfunc) {
X	    while (*keys) {
X		scanlist(c_bind,&c_bind,&p_bind,*keys) ;
X		if (c_bind == NULL) {
X		    /* keys not yet bound */
X		    addbinding(keys,kfunc,p_bind) ;
X		    return(VALID) ;
X		}
X		if (c_bind->com.command == dummy) {
X		    p_bind->next = c_bind->next ;
X		    free(c_bind) ;
X		    addbinding(keys,kfunc,p_bind) ;
X		    return(VALID) ;
X		}
X		keys++ ;
X		if (c_bind->research)
X		    c_bind = c_bind->com.k_codelist ;
X		else
X		    if (*keys)
X			return(E_KCODE) ;
X		    else {
X			c_bind->com.command = kfunc ;
X			return(VALID) ;
X		    }
X	    }
X	    return(E_KCODE) ;
X	}
X	else
X	    return(E_FUNC) ;
X}
X
X
X/* bindtokey:	add a new key to the key binding table		*/
X
Xbindtokey(f, n)
X
Xint f, n;	/* command arguments [IGNORED] */
X
X{
X	register unsigned char *c;
X				/* command key to bind */
X	register (*kfunc)();	/* ptr to the requexted function to bind to */
X	register char *ptr;	/* ptr to dump out input key string */
X	char outseq[80];	/* output buffer for keystroke sequence */
X	int (*getname())();
X
X	/* prompt the user to type in a key to bind */
X	mlwrite(": bind-to-key ");
X
X	/* get the function name to bind it to */
X	kfunc = getname();
X	if (kfunc == NULL) {
X		mlwrite("[No such function]");
X		return(FALSE);
X	}
X	if (discmd) {
X		TTputc(' ');		/* space it out */
X		TTflush();
X	}
X
X	/* get the command sequence to bind */
X	c = getckey() ;
X
X	/* change it to something we can print as well */
X	cmdstr(c, &outseq[0]);
X
X	/* and dump it out */
X	if (discmd) {
X	    ptr = &outseq[0];
X	    while (*ptr)
X		TTputc(*ptr++);
X	}
X	return(bindkeytofunc(kfunc,c)) ;
X
X}
X
X/* unbindkey:	delete a key from the key binding table	*/
X
Xunbindkey(f, n)
X
Xint f, n;	/* command arguments [IGNORED] */
X
X{
X	register unsigned char *c;
X				/* command key to unbind */
X	register char *ptr;	/* ptr to dump out input key string */
X	char outseq[80];	/* output buffer for keystroke sequence */
X	struct spec_chars *c_bind, *p_bind ;
X				/* pointers in key bind list */
X
X	/* prompt the user to type in a key to unbind */
X	mlwrite(": unbind-key ");
X
X	/* get the command sequence to unbind */
X	c = getckey();		/* get a command sequence */
X
X	/* change it to something we can print as well */
X	cmdstr(c, &outseq[0]);
X
X	/* and dump it out */
X	if (discmd) {
X		ptr = &outseq[0];
X		while (*ptr)
X			TTputc(*ptr++);
X	}
X
X	/* if it isn't bound, bitch */
X	if (keymatch(bindh,&c_bind,&p_bind,c)) {
X	    p_bind->next = c_bind->next ;
X	    free(c_bind) ;
X	    return(TRUE) ;
X	}
X	else {
X	    mlwrite("[Key not bound]") ;
X	    return(FALSE) ;
X	}
X}
X
X
Xlistscan(bind,nptr,keys)
X
Xstruct spec_chars *bind ;
XNBIND *nptr ;
Xunsigned char *keys ;
X
X{
X	char *fname = nptr->n_name, outc ;
X	unsigned char *c ;
X	char *alloca() ;
X	int keylen = strlen(keys), outlen ;
X	char outseq[80];	/* output buffer for keystroke sequence */
X
X	c = (unsigned char *)alloca(keylen+2) ;  /* temp storage for keys */
X	strcpy(c,keys) ;
X	*(c+keylen) = bind->k_code ;
X	*(c+keylen+1) = '\0' ;
X	if (bind->research) {
X	    listscan(bind->com.k_codelist,nptr,c) ;
X	}
X	if (nptr->n_func == bind->com.command) {
X	    cmdstr(c,outseq) ;
X	    *(c+keylen) = '\0' ;
X	    for (outlen=0 ; outlen<30 ; outlen++) {
X	        if (*fname)
X		   outc = *fname++ ;
X		else
X		   outc = ' ' ;
X	        linsert(1,outc) ;
X	    }
X	    fname = outseq ;
X	    while (*fname) 
X	       linsert(1,*fname++) ;
X	    lnewline() ;
X	}
X	if (bind->next) {
X	    *(c+keylen) = '\0' ;
X	    listscan(bind->next,nptr,c) ;
X	}
X}
X
X
Xdesbind(f, n)	/* describe bindings
X		   bring up a fake buffer and list the key bindings
X		   into it with view mode			*/
X
X#if	APROP
X{
X	buildlist(TRUE, "");
X}
X
Xapro(f, n)	/* Apropos (List functions that match a substring) */
X
X{
X	char mstring[NSTRING];	/* string to match cmd names to */
X	int status;		/* status return */
X
X	status = mlreply("Apropos string: ", mstring, NSTRING - 1);
X	if (status != TRUE)
X		return(status);
X
X	return(buildlist(FALSE, mstring));
X}
X
Xbuildlist(type, mstring)  /* build a binding list (limited or full) */
X
Xint type;	/* true = full list,   false = partial list */
Xchar *mstring;	/* match string if a partial list */
X
X#endif
X{
X#if	ST520 & LATTICE
X#define	register		
X#endif
X	register WINDOW *wp;	/* scanning pointer to windows */
X	register NBIND *nptr;	/* pointer into the name binding table */
X	register BUFFER *bp;	/* buffer to put binding list into */
X
X	/* split the current window to make room for the binding list */
X	if (splitwind(FALSE, 1) == FALSE)
X			return(FALSE);
X
X	/* and get a buffer for it */
X	bp = bfind("Binding list", TRUE, 0);
X	if (bp == NULL || bclear(bp) == FALSE) {
X		mlwrite("Can not display binding list");
X		return(FALSE);
X	}
X
X	/* let us know this is in progress */
X	mlwrite("[Building binding list]");
X
X	/* disconect the current buffer */
X        if (--curbp->b_nwnd == 0) {             /* Last use.            */
X                curbp->b_dotp  = curwp->w_dotp;
X                curbp->b_doto  = curwp->w_doto;
X                curbp->b_markp = curwp->w_markp;
X                curbp->b_marko = curwp->w_marko;
X        }
X
X	/* connect the current window to this buffer */
X	curbp = bp;	/* make this buffer current in current window */
X	bp->b_mode = 0;		/* no modes active in binding list */
X	bp->b_nwnd++;		/* mark us as more in use */
X	wp = curwp;
X	wp->w_bufp = bp;
X	wp->w_linep = bp->b_linep;
X	wp->w_flag = WFHARD|WFFORCE;
X	wp->w_dotp = bp->b_dotp;
X	wp->w_doto = bp->b_doto;
X	wp->w_markp = NULL;
X	wp->w_marko = 0;
X
X	/* build the contents of this window, inserting it line by line */
X	nptr = &names[0];
X	while (nptr->n_func != NULL) {
X
X#if	APROP
X		if (type == FALSE &&
X		    /* and current string doesn't include the search string */
X		    strinc(nptr->n_name, mstring) == FALSE)
X			goto fail;
X#endif
X		/* search down any keys bound to this */
X
X		listscan(bindh,nptr,0) ;
X
Xfail:		/* and on to the next name */
X		++nptr;
X	}
X
X	curwp->w_bufp->b_mode |= MDVIEW;/* put this buffer view mode */
X	curbp->b_flag &= ~BFCHG;	/* don't flag this as a change */
X	wp->w_dotp = lforw(bp->b_linep);/* back to the beginning */
X	wp->w_doto = 0;
X	wp = wheadp;			/* and update ALL mode lines */
X	while (wp != NULL) {
X		wp->w_flag |= WFMODE;
X		wp = wp->w_wndp;
X	}
X	mlwrite("");	/* clear the mode line */
X	return(TRUE);
X}
X
X#if	APROP
Xstrinc(source, sub)	/* does source include sub? */
X
Xchar *source;	/* string to search in */
Xchar *sub;	/* substring to look for */
X
X{
X	char *sp;	/* ptr into source */
X	char *nxtsp;	/* next ptr into source */
X	char *tp;	/* ptr into substring */
X
X	/* for each character in the source string */
X	sp = source;
X	while (*sp) {
X		tp = sub;
X		nxtsp = sp;
X
X		/* is the substring here? */
X		while (*tp) {
X			if (*nxtsp++ != *tp)
X				break;
X			else
X				tp++;
X		}
X
X		/* yes, return a success */
X		if (*tp == 0)
X			return(TRUE);
X
X		/* no, onward */
X		sp++;
X	}
X	return(FALSE);
X}
X#endif
X
X/* get a command key sequence from the keyboard	*/
X
Xunsigned char *
Xgetckey()
X
X{
X	int c;		/* fetched keystroke */
X	unsigned static char tok[20] ;
X	unsigned char *tokp = tok ;		/* command incoming */
X	struct spec_chars *binding = bindh ;
X
X	/* check to see if we are executing a command line */
X	if (clexec) {
X		macarg(tok);	/* get the next token */
X		return(getbindkey(tok));
X	}
X
X	/* or the normal way ie. from the keyboard */
X
Xcharreq:
X	c = tgetc();
X	*tokp++ = (char)c ;
X	/* check if key is bound */
X	while (binding) {
X	    if (binding->k_code == c) {
X		if (binding->research) {
X		    binding = binding->com.k_codelist ;
X		    goto charreq ; /* wops */
X		}
X		if (binding->com.command == dummy)
X		    *tokp++ = tgetc() ;
X		*tokp = '\0' ;
X		return(tok) ;
X	    }
X	    binding = binding->next ;
X	}
X	*tokp = '\0' ;
X	return(tok);
X}
X
X/* execute the startup file */
X
Xstartup(sfname)
X
Xchar *sfname;	/* name of startup file (null if default) */
X
X{
X	char *fname;	/* resulting file name to execute */
X
X	/* look up the startup file */
X	if (*sfname != 0)
X		fname = flook(sfname, TRUE);
X	else
X		fname = flook(pathname[0], TRUE);
X
X	/* if it isn't around, don't sweat it */
X	if (fname == NULL)
X		return(TRUE);
X
X	/* otherwise, execute the sucker */
X	return(dofile(fname));
X}
X
X/*	Look up the existance of a file along the normal or PATH
X	environment variable. Look first in the HOME directory if
X	asked and possible
X*/
X
Xchar *flook(fname, hflag)
X
Xchar *fname;	/* base file name to search for */
Xint hflag;	/* Look in the HOME environment variable first? */
X
X{
X	register char *home;	/* path to home directory */
X	register char *path;	/* environmental PATH variable */
X	register char *sp;	/* pointer into path spec */
X	register int i;		/* index */
X	register int status;	/* return status */
X	static char fspec[NSTRING];	/* full path spec to search */
X
X#if	((MSDOS) & (LATTICE | AZTEC | MSC)) | V7 | USG | BSD
X
X	if (hflag) {
X		home = getenv("HOME");
X		if (home != NULL) {
X			/* build home dir file spec */
X			strcpy(fspec, home);
X			strcat(fspec, "/");
X			strcat(fspec, fname);
X
X			/* and try it out */
X			status = ffropen(fspec);
X			if (status == FIOSUC) {
X				ffclose();
X				return(fspec);
X			}
X		}
X	}
X
X	/* get the PATH variable */
X	path = getenv("PATH");
X	if (path != NULL)
X		while (*path) {
X
X			/* build next possible file spec */
X			sp = fspec;
X			while (*path && (*path != PATHCHR))
X				*sp++ = *path++;
X			*sp++ = '/';
X			*sp = 0;
X			strcat(fspec, fname);
X
X			/* and try it out */
X			status = ffropen(fspec);
X			if (status == FIOSUC) {
X				ffclose();
X				return(fspec);
X			}
X
X			if (*path == PATHCHR)
X				++path;
X		}
X#endif
X
X	/* look it up via the old table method */
X	for (i=2; i < NPNAMES; i++) {
X		strcpy(fspec, pathname[i]);
X		strcat(fspec, fname);
X
X		/* and try it out */
X		status = ffropen(fspec);
X		if (status == FIOSUC) {
X			ffclose();
X			return(fspec);
X		}
X	}
X
X	return(NULL);	/* no such luck */
X}
X
!The!End!

echo x - "isearch.c" 2>&1
sed "s/^X//" >"isearch.c" <<'!The!End!'
X/*
X * The functions in this file implement commands that perform incremental
X * searches in the forward and backward directions.  This "ISearch" command
X * is intended to emulate the same command from the original EMACS 
X * implementation (ITS).  Contains references to routines internal to
X * SEARCH.C.
X *
X * REVISION HISTORY:
X *
X *	D. R. Banks 9-May-86
X *	- added ITS EMACSlike ISearch
X *
X *	John M. Gamble 5-Oct-86
X *	- Made iterative search use search.c's scanner() routine.
X *	  This allowed the elimination of bakscan().
X *	- Put isearch constants into estruct.h
X *	- Eliminated the passing of 'status' to scanmore() and
X *	  checknext(), since there were no circumstances where
X *	  it ever equalled FALSE.
X */
X
X#include        <stdio.h>
X#include	"estruct.h"
X#include        "edef.h"
X
X#if	ISRCH
X
Xextern int scanner();			/* Handy search routine */
Xextern int eq();			/* Compare chars, match case */
X
X/* A couple of "own" variables for re-eat */
X
Xint	(*saved_get_char)();		/* Get character routine */
Xint	eaten_char = -1;		/* Re-eaten char */
X
X/* A couple more "own" variables for the command string */
X
Xint	cmd_buff[CMDBUFLEN];		/* Save the command args here */
Xint	cmd_offset;			/* Current offset into command buff */
Xint	cmd_reexecute = -1;		/* > 0 if re-executing command */
X
X
X/*
X * Subroutine to do incremental reverse search.  It actually uses the
X * same code as the normal incremental search, as both can go both ways.
X */
X 
Xint risearch(f, n)
X{
X    LINE *curline;			/* Current line on entry	     */
X    int  curoff;			/* Current offset on entry	     */
X
X    /* remember the initial . on entry: */
X
X    curline = curwp->w_dotp;		/* Save the current line pointer     */
X    curoff  = curwp->w_doto;		/* Save the current offset	     */
X
X    /* Make sure the search doesn't match where we already are:		     */
X
X    backchar(TRUE, 1);			/* Back up a character		     */
X
X    if (!(isearch(f, -n)))		/* Call ISearch backwards	     */
X    {					/* If error in search:		     */
X	curwp->w_dotp = curline;	/* Reset the line pointer	     */
X	curwp->w_doto = curoff;		/*  and the offset to original value */
X	curwp->w_flag |= WFMOVE;	/* Say we've moved		     */
X	update(FALSE);			/* And force an update		     */
X	mlwrite ("[search failed]");	/* Say we died			     */
X    } else mlerase ();			/* If happy, just erase the cmd line */
X}
X
X/* Again, but for the forward direction */
X
Xint fisearch(f, n)
X{
X    LINE *curline;			/* Current line on entry	     */
X    int  curoff;			/* Current offset on entry	     */
X
X    /* remember the initial . on entry: */
X
X    curline = curwp->w_dotp;		/* Save the current line pointer     */
X    curoff  = curwp->w_doto;		/* Save the current offset	     */
X
X    /* do the search */
X
X    if (!(isearch(f, n)))		/* Call ISearch forwards	     */
X    {					/* If error in search:		     */
X	curwp->w_dotp = curline;	/* Reset the line pointer	     */
X	curwp->w_doto = curoff;		/*  and the offset to original value */
X	curwp->w_flag |= WFMOVE;	/* Say we've moved		     */
X	update(FALSE);			/* And force an update		     */
X	mlwrite ("[search failed]");	/* Say we died			     */
X    } else mlerase ();			/* If happy, just erase the cmd line */
X}
X
X/*
X * Subroutine to do an incremental search.  In general, this works similarly
X * to the older micro-emacs search function, except that the search happens
X * as each character is typed, with the screen and cursor updated with each
X * new search character.
X *
X * While searching forward, each successive character will leave the cursor
X * at the end of the entire matched string.  Typing a Control-S or Control-X
X * will cause the next occurrence of the string to be searched for (where the
X * next occurrence does NOT overlap the current occurrence).  A Control-R will
X * change to a backwards search, META will terminate the search and Control-G
X * will abort the search.  Rubout will back up to the previous match of the
X * string, or if the starting point is reached first, it will delete the
X * last character from the search string.
X *
X * While searching backward, each successive character will leave the cursor
X * at the beginning of the matched string.  Typing a Control-R will search
X * backward for the next occurrence of the string.  Control-S or Control-X
X * will revert the search to the forward direction.  In general, the reverse
X * incremental search is just like the forward incremental search inverted.
X *
X * In all cases, if the search fails, the user will be feeped, and the search
X * will stall until the pattern string is edited back into something that
X * exists (or until the search is aborted).
X */
X 
Xisearch(f, n)
X{
X    int			status;		/* Search status */
X    int			col;		/* prompt column */
X    register int	cpos;		/* character number in search string */
X    register int	c;		/* current input character */
X    char		pat_save[NPAT];	/* Saved copy of the old pattern str */
X    LINE		*curline;	/* Current line on entry	     */
X    int			curoff;		/* Current offset on entry	     */
X    int			init_direction;	/* The initial search direction	     */
X
X    /* Initialize starting conditions */
X
X    cmd_reexecute = -1;		/* We're not re-executing (yet?)      */
X    cmd_offset = 0;			/* Start at the beginning of the buff*/
X    cmd_buff[0] = '\0';		/* Init the command buffer	      */
X    strncpy (pat_save, pat, NPAT);	/* Save the old pattern string	     */
X    curline = curwp->w_dotp;		/* Save the current line pointer     */
X    curoff  = curwp->w_doto;		/* Save the current offset	     */
X    init_direction = n;			/* Save the initial search direction */
X
X    /* This is a good place to start a re-execution: */
X
Xstart_over:
X
X    /* ask the user for the text of a pattern */
X    col = promptpattern("ISearch: ");		/* Prompt, remember the col  */
X
X    cpos = 0;					/* Start afresh		     */
X    status = TRUE;				/* Assume everything's cool  */
X
X    /*
X       Get the first character in the pattern.  If we get an initial Control-S
X       or Control-R, re-use the old search string and find the first occurrence
X     */
X
X    c = get_char();				/* Get the first character   */
X    if ((c == IS_FORWARD) ||
X        (c == IS_REVERSE) ||
X        (c == IS_VMSFORW))			/* Reuse old search string?  */
X    {
X    	for (cpos = 0; pat[cpos] != 0; cpos++)	/* Yup, find the length	     */
X    	    col = echochar(pat[cpos],col);	/*  and re-echo the string   */
X	if (c == IS_REVERSE) {			/* forward search?	     */
X	    n = -1;				/* No, search in reverse     */
X	    backchar (TRUE, 1);			/* Be defensive about EOB    */
X	} else
X	    n = 1;				/* Yes, search forward	     */
X	status = scanmore(pat, n);		/* Do the search	     */
X	c = get_char();				/* Get another character     */
X    }
X
X    /* Top of the per character loop */
X        	
X    for (;;)					/* ISearch per character loop*/
X    {
X	/* Check for special characters first: */
X	/* Most cases here change the search */
X
X	if (c == metac)				/* Want to quit searching?   */
X	    return (TRUE);			/* Quit searching now	     */
X
X	switch (c)				/* dispatch on the input char*/
X	{
X	  case IS_ABORT:			/* If abort search request   */
X	    return(FALSE);			/* Quit searching again	     */
X
X	  case IS_REVERSE:			/* If backward search	     */
X	  case IS_FORWARD:			/* If forward search	     */
X	  case IS_VMSFORW:			/*  of either flavor	     */
X	    if (c == IS_REVERSE)		/* If reverse search	     */
X		n = -1;				/* Set the reverse direction */
X	    else				/* Otherwise, 		     */
X		n = 1;				/*  go forward		     */
X	    status = scanmore(pat, n);		/* Start the search again    */
X	    c = get_char();			/* Get the next char	     */
X	    continue;				/* Go continue with the search*/
X
X	  case IS_NEWLINE:			/* Carriage return	     */
X	    c = '\n';				/* Make it a new line	     */
X	    break;				/* Make sure we use it	     */
X
X	  case IS_QUOTE:			/* Quote character	     */
X	  case IS_VMSQUOTE:			/*  of either variety	     */
X	    c = get_char();			/* Get the next char	     */
X
X	  case IS_TAB:				/* Generically allowed	     */
X	  case '\n':				/*  controlled characters    */
X	    break;				/* Make sure we use it	     */
X
X	  case IS_BACKSP:			/* If a backspace:           */
X	  case IS_RUBOUT:			/*  or if a Rubout:	     */
X	    if (cmd_offset <= 1)		/* Anything to delete?	     */
X		return (TRUE);			/* No, just exit	     */
X	    --cmd_offset;			/* Back up over the Rubout   */
X	    cmd_buff[--cmd_offset] = '\0';	/* Yes, delete last char   */
X	    curwp->w_dotp = curline;		/* Reset the line pointer    */
X	    curwp->w_doto = curoff;		/*  and the offset	     */
X	    n = init_direction;			/* Reset the search direction*/
X	    strncpy (pat, pat_save, NPAT);	/* Restore the old search str*/
X	    cmd_reexecute = 0;			/* Start the whole mess over */
X	    goto start_over;			/* Let it take care of itself*/
X
X	  /* Presumably a quasi-normal character comes here */
X
X	  default:				/* All other chars    	     */
X	    if (c < ' ')			/* Is it printable?	     */
X	    {					/* Nope.		     */
X		reeat (c);			/* Re-eat the char	     */
X		return (TRUE);			/* And return the last status*/
X	    }
X	}  /* Switch */
X
X	/* I guess we got something to search for, so search for it	     */
X
X	pat[cpos++] = c;			/* put the char in the buffer*/
X	if (cpos >= NPAT)			/* too many chars in string? */
X	{					/* Yup.  Complain about it   */
X	    mlwrite("? Search string too long");
X	    return(TRUE);			/* Return an error	     */
X	}
X	pat[cpos] = 0;				/* null terminate the buffer */
X	col = echochar(c,col);			/* Echo the character	     */
X	if (!status) {				/* If we lost last time	     */
X	    TTputc(BELL);		/* Feep again		      */
X	    TTflush();			/* see that the feep feeps    */
X	} else					/* Otherwise, we must have won*/
X	    if (!(status = checknext(c, pat, n))) /* See if match	     */
X		status = scanmore(pat, n);	/*  or find the next match   */
X	c = get_char();				/* Get the next char	     */
X    } /* for {;;} */
X}
X
X/*
X * Trivial routine to insure that the next character in the search string is
X * still true to whatever we're pointing to in the buffer.  This routine will
X * not attempt to move the "point" if the match fails, although it will 
X * implicitly move the "point" if we're forward searching, and find a match,
X * since that's the way forward isearch works.
X *
X * If the compare fails, we return FALSE and assume the caller will call
X * scanmore or something.
X */
X
Xint checknext (chr, patrn, dir)	/* Check next character in search string */
Xchar	chr;			/* Next char to look for		 */
Xchar	*patrn;			/* The entire search string (incl chr)   */
Xint	dir;			/* Search direction			 */
X{
X    register LINE *curline;		/* current line during scan	     */
X    register int curoff;		/* position within current line	     */
X    register int buffchar;		/* character at current position     */
X    int status;				/* how well things go		     */
X
X
X    /* setup the local scan pointer to current "." */
X
X    curline = curwp->w_dotp;		/* Get the current line structure    */
X    curoff  = curwp->w_doto;		/* Get the offset within that line   */
X
X    if (dir > 0)			/* If searching forward		     */
X    {
X    	if (curoff == llength(curline)) /* If at end of line		     */
X    	{
X	    curline = lforw(curline);	/* Skip to the next line	     */
X	    if (curline == curbp->b_linep)
X		return (FALSE);		/* Abort if at end of buffer	     */
X	    curoff = 0;			/* Start at the beginning of the line*/
X	    buffchar = '\n';		/* And say the next char is NL	     */
X	} else
X	    buffchar = lgetc(curline, curoff++); /* Get the next char	     */
X	if (status = eq(buffchar, chr))	/* Is it what we're looking for?     */
X	{
X	    curwp->w_dotp = curline;	/* Yes, set the buffer's point	     */
X	    curwp->w_doto = curoff;	/*  to the matched character	     */
X	    curwp->w_flag |= WFMOVE;	/* Say that we've moved		     */
X	}
X	return (status);		/* And return the status	     */
X    } else				/* Else, if reverse search:	     */
X	return (match_pat (patrn));	/* See if we're in the right place   */
X}
X
X/*
X * This hack will search for the next occurrence of <pat> in the buffer, either
X * forward or backward.  It is called with the status of the prior search
X * attempt, so that it knows not to bother if it didn't work last time.  If
X * we can't find any more matches, "point" is left where it was before.  If
X * we do find a match, "point" will be at the end of the matched string for
X * forward searches and at the beginning of the matched string for reverse
X * searches.
X */
X 
Xint scanmore(patrn, dir)	/* search forward or back for a pattern	     */
Xchar	*patrn;			/* string to scan for			     */
Xint	dir;			/* direction to search			     */
X{
X	int	sts;			/* search status		     */
X
X    	if (dir < 0)				/* reverse search?	     */
X    	{
X		rvstrcpy(tap, patrn);		/* Put reversed string in tap*/
X		sts = scanner(tap, REVERSE, PTBEG);
X	}
X	else
X		sts = scanner(patrn, FORWARD, PTEND);	/* Nope. Go forward  */
X
X	if (!sts)
X	{
X		TTputc(BELL);	/* Feep if search fails       */
X		TTflush();		/* see that the feep feeps    */
X	}
X
X	return(sts);				/* else, don't even try	     */
X}
X
X/*
X * The following is a worker subroutine used by the reverse search.  It
X * compares the pattern string with the characters at "." for equality. If
X * any characters mismatch, it will return FALSE.
X *
X * This isn't used for forward searches, because forward searches leave "."
X * at the end of the search string (instead of in front), so all that needs to
X * be done is match the last char input.
X */
X
Xint match_pat (patrn)	/* See if the pattern string matches string at "."   */
Xchar	*patrn;		/* String to match to buffer			     */
X{
X    register int  i;			/* Generic loop index/offset	     */
X    register int buffchar;		/* character at current position     */
X    register LINE *curline;		/* current line during scan	     */
X    register int curoff;		/* position within current line	     */
X
X    /* setup the local scan pointer to current "." */
X
X    curline = curwp->w_dotp;		/* Get the current line structure    */
X    curoff  = curwp->w_doto;		/* Get the offset within that line   */
X
X    /* top of per character compare loop: */
X
X    for (i = 0; i < strlen(patrn); i++)	/* Loop for all characters in patrn  */
X    {
X    	if (curoff == llength(curline)) /* If at end of line		     */
X    	{
X	    curline = lforw(curline);	/* Skip to the next line	     */
X	    curoff = 0;			/* Start at the beginning of the line*/
X	    if (curline == curbp->b_linep)
X		return (FALSE);		/* Abort if at end of buffer	     */
X	    buffchar = '\n';		/* And say the next char is NL	     */
X	} else
X	    buffchar = lgetc(curline, curoff++); /* Get the next char	     */
X	if (!eq(buffchar, patrn[i]))	/* Is it what we're looking for?     */
X	    return (FALSE);		/* Nope, just punt it then	     */
X    }
X    return (TRUE);			/* Everything matched? Let's celebrate*/
X}
X
X/* Routine to prompt for I-Search string. */
X
Xint promptpattern(prompt)
Xchar *prompt;
X{
X    char tpat[NPAT+20];
X
X    strcpy(tpat, prompt);		/* copy prompt to output string */
X    strcat(tpat, " [");			/* build new prompt string */
X    expandp(pat, &tpat[strlen(tpat)], NPAT/2);	/* add old pattern */
X    strcat(tpat, "]<META>: ");
X
X    /* check to see if we are executing a command line */
X    if (!clexec) {
X	mlwrite(tpat);
X    }
X    return(strlen(tpat));
X}
X
X/* routine to echo i-search characters */
X
Xint echochar(c,col)
Xint	c;	/* character to be echoed */
Xint	col;	/* column to be echoed in */
X{
X    movecursor(term.t_nrow,col);		/* Position the cursor	     */
X    if ((c < ' ') || (c == 0x7F))		/* Control character?	     */
X    {
X	switch (c)				/* Yes, dispatch special cases*/
X	{
X	  case '\n':				/* Newline		     */
X	    TTputc('<');
X	    TTputc('N');
X	    TTputc('L');
X	    TTputc('>');
X	    col += 3;
X	    break;
X
X	  case '\t':				/* Tab			     */
X	    TTputc('<');
X	    TTputc('T');
X	    TTputc('A');
X	    TTputc('B');
X	    TTputc('>');
X	    col += 4;
X	    break;
X
X	  case 0x7F:				/* Rubout:		     */
X	    TTputc('^');		/* Output a funny looking     */
X	    TTputc('?');		/*  indication of Rubout      */
X	    col++;				/* Count the extra char      */
X	    break;
X
X	  default:				/* Vanilla control char      */
X	    TTputc('^');		/* Yes, output prefix	      */
X    	    TTputc(c+0x40);		/* Make it "^X"		      */
X	    col++;				/* Count this char	     */
X	}
X    } else
X	TTputc(c);			/* Otherwise, output raw char */
X    TTflush();				/* Flush the output	      */
X    return(++col);				/* return the new column no  */
X}
X
X/*
X * Routine to get the next character from the input stream.  If we're reading
X * from the real terminal, force a screen update before we get the char. 
X * Otherwise, we must be re-executing the command string, so just return the
X * next character.
X */
X
Xint get_char ()
X{
X    int	c;				/* A place to get a character	    */
X
X    /* See if we're re-executing: */
X
X    if (cmd_reexecute >= 0)		/* Is there an offset?		    */
X	if ((c = cmd_buff[cmd_reexecute++]) != 0)
X	    return (c);			/* Yes, return any character	    */
X
X    /* We're not re-executing (or aren't any more).  Try for a real char    */
X
X    cmd_reexecute = -1;		/* Say we're in real mode again	      */
X    update(FALSE);			/* Pretty up the screen		    */
X    if (cmd_offset >= CMDBUFLEN-1)	/* If we're getting too big ...	    */
X    {
X	mlwrite ("? command too long");	/* Complain loudly and bitterly	    */
X	return (metac);			/* And force a quit		    */
X    }
X    c = tgetc();			/* Get the next character	    */
X    cmd_buff[cmd_offset++] = c; 	/* Save the char for next time      */
X    cmd_buff[cmd_offset] = '\0';	/* And terminate the buffer	    */
X    return (c);				/* Return the character		    */
X}
X
X/*
X * Hacky routine to re-eat a character.  This will save the character to be
X * re-eaten by redirecting the input call to a routine here.  Hack, etc.
X */
X
X/* Come here on the next term.t_getchar call: */
X
Xint uneat()
X{
X    int c;
X
X    term.t_getchar = saved_get_char;	/* restore the routine address	     */
X    c = eaten_char;			/* Get the re-eaten char	     */
X    eaten_char = -1;			/* Clear the old char		     */
X    return(c);				/* and return the last char	     */
X}
X
Xint reeat(c)
Xint	c;
X{
X    if (eaten_char != -1)		/* If we've already been here	     */
X	return/*(NULL)*/;		/* Don't do it again		     */
X    eaten_char = c;			/* Else, save the char for later     */
X    saved_get_char = term.t_getchar;	/* Save the char get routine	     */
X    term.t_getchar = uneat;		/* Replace it with ours		     */
X}
X#else
Xisearch()
X{
X}
X#endif
!The!End!
exit

glf@mundoe.mu.oz (Giuseppe Fiusco) (09/09/87)

: ---------------------------------------- cut here

echo x - "edef.d" 2>&1
sed "s/^X//" >"edef.d" <<'!The!End!'
X25c25
X< unsigned int getckey();
X---
X> unsigned char *getckey();
X54c54
X< int	discmd	= TRUE;			/* display command flag		*/
X---
X> int	discmd	= FALSE;		/* display command flag		*/
X64,67c64,66
X< int	metac = CTRL | '[';		/* current meta character */
X< int	ctlxc = CTRL | 'X';		/* current control X prefix char */
X< int	reptc = CTRL | 'U';		/* current universal repeat char */
X< int	abortc = CTRL | 'G';		/* current abort command char	*/
X---
X> int	metac = CTRL & '[';		/* current meta character */
X> int	ctlxc = CTRL & 'X';		/* current control X prefix char */
X> int	abortc = CTRL & 'G';		/* current abort command char	*/
X91a91,93
X> struct 	spec_chars *bindh=NULL; /* pointer to head of key bindings */
X> int	(*command)(); 		/* command that must be executed */
X> int	exit_def = 0 ;		/* is it possible to exit 	*/
X92a95
X> 
X158,159c161
X< extern	KEYTAB keytab[];		/* key bind to functions table	*/
X< extern	NBIND names[];			/* name to function table	*/
X---
X> extern	NBIND    names[];		/* name to function table	*/
X181d182
X< extern	int	reptc;			/* current universal repeat char */
X186,190c187,191
X< extern KILL *kbufp;			/* current kill buffer chunk pointer */
X< extern KILL *kbufh;			/* kill buffer header pointer	*/
X< extern int kused;			/* # of bytes used in KB        */
X< extern WINDOW *swindow;			/* saved window pointer		*/
X< extern int cryptflag;			/* currently encrypting?	*/
X---
X> extern	KILL *kbufp;			/* current kill buffer chunk pointer */
X> extern	KILL *kbufh;			/* kill buffer header pointer	*/
X> extern	int kused;			/* # of bytes used in KB        */
X> extern	WINDOW *swindow;		/* saved window pointer		*/
X> extern	int cryptflag;			/* currently encrypting?	*/
!The!End!

echo x - "efunc.d" 2>&1
sed "s/^X//" >"efunc.d" <<'!The!End!'
X11a12,16
X> extern	int	dummy();		/* Dummy binding routine	*/
X> extern	int	digit();		/* Dummy meta-integer handler   */
X> extern	int	unarg();		/* Dummy universal-arg handler  */
X> extern	int	dumpcore();		/* Leathal, causes a core dump -
X> 					   Only available in macros     */
X97a103
X> extern	int	setspecial();		/* define special charater code */
X160,162d165
X< extern	int	meta();			/* meta prefix dummy function	*/
X< extern	int	cex();			/* ^X prefix dummy function	*/
X< extern	int	unarg();		/* ^U repeat arg dummy function	*/
X232a236
X> 	{"core",			dumpcore},
X236d239
X< 	{"ctlx-prefix",			cex},
X251a255,256
X> 	{"digit",			digit},
X> 	{"dummy",			dummy},
X339d343
X< 	{"meta-prefix",			meta},
X391a396
X> 	{"special-char",		setspecial},
!The!End!

echo x - "epath.d" 2>&1
sed "s/^X//" >"epath.d" <<'!The!End!'
X13a14
X> 	".emacskb",
X23a25
X> 	"emacs.kb",
X34a37
X> 	"emacs.kb",
X44a48
X> 	"emacs.kb",
X56a61
X> 	".emacskb",
X66a72
X> 	"emacs.kb",
!The!End!

echo x - "estruct.d" 2>&1
sed "s/^X//" >"estruct.d" <<'!The!End!'
X6a7,9
X> 
X> 			A few more changes relating to the key bindings
X> 			implemented by G.Fiusco
X207,210c210
X< #define CTRL    0x0100                  /* Control flag, or'ed in       */
X< #define META    0x0200                  /* Meta flag, or'ed in          */
X< #define CTLX    0x0400                  /* ^X flag, or'ed in            */
X< #define	SPEC	0x0800			/* special key (function keys)	*/
X---
X> #define CTRL    037                     /* Control flag, or'ed in       */
X243a244,245
X> #define BSP	0x10			/* backspace character 		*/
X> #define DEL	0x7f			/* delete character 		*/
X475,478c477,485
X< typedef struct  {
X<         short   k_code;                 /* Key code                     */
X<         int     (*k_fp)();              /* Routine to handle it         */
X< }       KEYTAB;
X---
X> struct spec_chars {
X>         int     k_code;                 /* Key code changed from short  */
X> 	int     research ;
X> 	union {
X> 	    int (*command)() ;
X> 	    struct spec_chars *k_codelist ;
X> 	} com ;
X> 	struct spec_chars *next ;
X> } ;
!The!End!

echo x - "eval.d" 2>&1
sed "s/^X//" >"eval.d" <<'!The!End!'
X170c170,173
X< int setvar(f, n)		/* set a variable */
X---
X> /*
X>  * returns the type of variable passed. Also retruns in paramters
X>  * the reference location for the varaible.
X>  */
X172,173c175,176
X< int f;		/* default flag */
X< int n;		/* numeric arg (can overide prompted value) */
X---
X> int
X> checkvar(var,varref)
X174a178,180
X> char *var ;
X> int *varref ;
X> 
X176,182c182,183
X< 	register int vnum;	/* ordinal number of var refrenced */
X< 	register int status;	/* status return */
X< 	register int vtype;	/* type of variable to set */
X< 	register int c;		/* translated character */
X< 	register char * sp;	/* scratch string pointer */
X< 	char var[NVSIZE+1];	/* name of variable to fetch */
X< 	char value[NSTRING];	/* value to set variable to */
X---
X> 	register	int	vtype ;
X> 	register	int	vnum ;
X184,194d184
X< 	/* first get the variable to set.. */
X< 	if (clexec == FALSE) {
X< 		status = mlreply("Variable to set: ", &var[0], NVSIZE);
X< 		if (status != TRUE)
X< 			return(status);
X< 	} else {	/* macro line argument */
X< 		/* grab token and skip it */
X< 		execstr = token(execstr, var);
X< 	}
X< 
X< 	/* check the legality and find the var */
X196,197c186
X< 	switch (var[0]) {
X< 
X---
X> 	switch (*var) {
X232a222,224
X> 	*varref = vnum ;
X> 	return(vtype) ;
X> }
X234,238d225
X< 	/* if its not legal....bitch */
X< 	if (vtype == -1) {
X< 		mlwrite("%%No such variable");
X< 		return(FALSE);
X< 	}
X240,247c227,228
X< 	/* get the value for that variable */
X< 	if (f == TRUE)
X< 		strcpy(value, itoa(n));
X< 	else {
X< 		status = mlreply("Value: ", &value[0], NSTRING);
X< 		if (status != TRUE)
X< 			return(status);
X< 	}
X---
X> int
X> varset(vtype,vnum,value)
X249c230,237
X< 	/* and set the appropriate value */
X---
X> register int vtype, vnum ;
X> register char *value ;
X> 
X> {
X> 	register int status;	/* status return */
X> 	register int c;		/* translated character */
X> 	register char * sp;	/* scratch string pointer */
X> 
X319a308,352
X> 
X> int setvar(f, n)		/* set a variable */
X> 
X> int f;		/* default flag */
X> int n;		/* numeric arg (can overide prompted value) */
X> 
X> {
X> 	int vnum;		/* ordinal number of var refrenced */
X> 	register int status;	/* status return */
X> 	register int vtype;	/* type of variable to set */
X> 	char var[NVSIZE+1];	/* name of variable to fetch */
X> 	char value[NSTRING];	/* value to set variable to */
X> 
X> 	/* first get the variable to set.. */
X> 	if (clexec == FALSE) {
X> 		status = mlreply("Variable to set: ", &var[0], NVSIZE);
X> 		if (status != TRUE)
X> 			return(status);
X> 	} else {	/* macro line argument */
X> 		/* grab token and skip it */
X> 		execstr = token(execstr, var);
X> 	}
X> 
X> 	/* check the legality and find the var */
X> 	vtype = checkvar(var,&vnum) ;
X> 
X> 	/* if its not legal....bitch */
X> 	if (vtype == -1) {
X> 		mlwrite("%%No such variable");
X> 		return(FALSE);
X> 	}
X> 
X> 	/* get the value for that variable */
X> 	if (f == TRUE)
X> 		strcpy(value, itoa(n));
X> 	else {
X> 		status = mlreply("Value: ", &value[0], NSTRING);
X> 		if (status != TRUE)
X> 			return(status);
X> 	}
X> 
X> 	/* and set the appropriate value */
X> 	return(varset(vtype,vnum,value));
X> }
X> 
X448c481
X< 					   buf, NSTRING, ctoec('\n'));
X---
X> 					   buf, NSTRING, '\n');
!The!End!

echo x - "exec.d" 2>&1
sed "s/^X//" >"exec.d" <<'!The!End!'
X378c378
X< 	status = nextarg("", tok, NSTRING, ctoec('\n'));
X---
X> 	status = nextarg("", tok, NSTRING, '\n');
!The!End!

echo x - "input.d" 2>&1
sed "s/^X//" >"input.d" <<'!The!End!'
X8a9,10
X> extern struct spec_chars *bindh ;
X> 
X32c34
X< 		if (c == ectoc(abortc))		/* Bail out! */
X---
X> 		if (c == abortc)		/* Bail out! */
X55c57
X< 	return(nextarg(prompt, buf, nbuf, ctoec('\n')));
X---
X> 	return(nextarg(prompt, buf, nbuf, '\n'));
X68,95d69
X< /*	ectoc:	expanded character to character
X< 		colapse the CTRL and SPEC flags back into an ascii code   */
X< 
X< ectoc(c)
X< 
X< int c;
X< 
X< {
X< 	if (c & CTRL)
X< 		c = c & ~(CTRL | 0x40);
X< 	if (c & SPEC)
X< 		c= c & 255;
X< 	return(c);
X< }
X< 
X< /*	ctoec:	character to extended character
X< 		pull out the CTRL and SPEC prefixes (if possible)	*/
X< 
X< ctoec(c)
X< 
X< int c;
X< 
X< {
X<         if (c>=0x00 && c<=0x1F)
X<                 c = CTRL | (c+'@');
X<         return (c);
X< }
X<  
X111c85
X< 	register NBIND *cffp;	/* current ptr to entry in name binding table */
X---
X> 	register NBIND *cffp;	/* ptr to entry in name binding table */
X131c105
X< 		if (c == 0x0d) {
X---
X> 		if (c == '\r') {
X137c111
X< 		} else if (c == ectoc(abortc)) {	/* Bell, abort */
X---
X> 		} else if (c == abortc) {	/* Bell, abort */
X142c116
X< 		} else if (c == 0x7F || c == 0x08) {	/* rubout/erase */
X---
X> 		} else if (c == DEL || c == BSP) {	/* rubout/erase */
X152c126
X< 		} else if (c == 0x15) {	/* C-U, kill */
X---
X> 		} else if (c == (CTRL&'U')) {	/* C-U, kill */
X282,342c256,258
X< /*	GET1KEY:	Get one keystroke. The only prefixs legal here
X< 			are the SPEC and CTRL prefixes.
X< 								*/
X< 
X< get1key()
X< 
X< {
X< 	int    c;
X< #if	AMIGA
X< 	int	d;
X< #endif
X< 
X< 	/* get a keystroke */
X<         c = tgetc();
X< 
X< #if	MSDOS | ST520
X< 	if (c == 0) {				/* Apply SPEC prefix	*/
X< 	        c = tgetc();
X< 	        if (c>=0x00 && c<=0x1F)		/* control key? */
X<         	        c = CTRL | (c+'@');
X< 		return(SPEC | c);
X< 	}
X< #endif
X< 
X< #if	AMIGA
X< 	/* apply SPEC prefix */
X< 	if ((unsigned)c == 155) {
X< 		c = tgetc();
X< 
X< 		/* first try to see if it is a cursor key */
X< 		if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T')
X< 			return(SPEC | c);
X< 
X< 		/* next, a 2 char sequence */
X< 		d = tgetc();
X< 		if (d == '~')
X< 			return(SPEC | c);
X< 
X< 		/* decode a 3 char sequence */
X< 		c = d + 32;
X< 		/* if a shifted function key, eat the tilde */
X< 		if (d >= '0' && d <= '9')
X< 			d = tgetc();
X< 		return(SPEC | c);
X< 	}
X< #endif
X< 
X< #if  WANGPC
X< 	if (c == 0x1F) {			/* Apply SPEC prefix    */
X< 	        c = tgetc();
X< 		return(SPEC | c);
X< 	}
X< #endif
X< 
X<         if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
X<                 c = CTRL | (c+'@');
X<         return (c);
X< }
X< 
X< /*	GETCMD:	Get a command from the keyboard. Process all applicable
X< 		prefix keys
X---
X> /*	GETCMD:	Get a command from the keyboard. Process keys and return
X> 		either the key stroke or if the key is bound to a funtion
X> 		then load command with the function and return NULL
X347a264,265
X> 	struct spec_chars *binding = bindh ;
X> 	extern int (*command)() ;
X349,359c267,279
X< 	/* get initial character */
X< 	c = get1key();
X< 
X< 	/* process META prefix */
X< 	if (c == metac) {
X< 		c = get1key();
X< 	        if (islower(c))		/* Force to upper */
X<         	        c ^= DIFCASE;
X< 	        if (c>=0x00 && c<=0x1F)		/* control key */
X< 	        	c = CTRL | (c+'@');
X< 		return(META | c);
X---
X> charreq:
X> 	c = tgetc();
X> 	/* check if key is bound */
X> 	while (binding) {
X> 	    if (binding->k_code == c) {
X> 		if (binding->research) {
X> 		    binding = binding->com.k_codelist ;
X> 		    goto charreq ; /* wops */
X> 		}
X> 		command = binding->com.command ;
X> 		return(NULL) ;
X> 	    }
X> 	    binding = binding->next ;
X361,372d280
X< 
X< 	/* process CTLX prefix */
X< 	if (c == ctlxc) {
X< 		c = get1key();
X< 	        if (c>='a' && c<='z')		/* Force to upper */
X<         	        c -= 0x20;
X< 	        if (c>=0x00 && c<=0x1F)		/* control key */
X< 	        	c = CTRL | (c+'@');
X< 		return(CTLX | c);
X< 	}
X< 
X< 	/* otherwise, just return it */
X399c307
X< 		c = get1key();
X---
X> 		c = tgetc();
X402,403c310,311
X< 		if (c == (CTRL | 0x4d))
X< 			c = CTRL | 0x40 | '\n';
X---
X> 		if (c == '\r')
X> 			c = '\n';
X420,423c328
X< 		/* change from command form back to character form */
X< 		c = ectoc(c);
X< 
X< 		if (c == ectoc(abortc) && quotef == FALSE) {
X---
X> 		if (c == abortc && quotef == FALSE) {
X428c333
X< 		} else if ((c==0x7F || c==0x08) && quotef==FALSE) {
X---
X> 		} else if ((c==DEL || c==BSP) && quotef==FALSE) {
X446c351
X< 		} else if (c == 0x15 && quotef == FALSE) {
X---
X> 		} else if (c == (CTRL&'U') && quotef == FALSE) {
!The!End!

echo x - "main.d" 2>&1
sed "s/^X//" >"main.d" <<'!The!End!'
X681d680
X< #include	"ebind.h"	/* default key bindings */
X691a691
X> 
X703d702
X< 	int basec;			/* c stripped of meta character */
X713a713
X> 	extern char *pathname[] ;       /* seach paths and fnames */
X715a716,721
X> 	startup(pathname[2]) ;		/* read in the bindings */
X> 	if (!exit_def) {
X> 	    fprintf(stderr,"You must make it possible to exit.\n") ;
X> 	    exit(10) ;
X> 	}
X> 	discmd = TRUE ;
X859,862c865,868
X< loop:
X<         update(FALSE);                          /* Fix up the screen    */
X<         c = getcmd();
X<         if (mpresf != FALSE) {
X---
X> 	while(1) {
X>             update(FALSE);                      /* Fix up the screen    */
X>             c = getcmd();
X>             if (mpresf != FALSE) {
X867c873
X<                         goto loop;
X---
X>                     continue ;
X870,871c876,877
X<         f = FALSE;
X<         n = 1;
X---
X>             f = FALSE;
X>             n = 1;
X873c879
X< 	/* do META-# processing if needed */
X---
X> 	    /* do META-# processing if needed */
X875,876c881
X< 	basec = c & ~META;		/* strip meta char off if there */
X< 	if ((c & META) && ((basec >= '0' && basec <= '9') || basec == '-')) {
X---
X> 	    if (command == digit && !c) {
X880c885
X< 		c = basec;		/* strip the META */
X---
X> 		c = lastkey ;
X898c903
X< 	}
X---
X> 	    }
X900c905
X< 	/* do ^U repeat argument processing */
X---
X> 	    /* do ^U repeat argument processing */
X902c907,908
X<         if (c == reptc) {                  /* ^U, start argument   */
X---
X>             if (command == unarg && !c) {   /* ^U, start argument   */
X> 		command = 0 ;
X907,908c913,915
X<                 while ((c=getcmd()) >='0' && c<='9' || c==reptc || c=='-'){
X<                         if (c == reptc)
X---
X>                 while ((c=getcmd()) >='0' && c<='9' ||
X> 			command == unarg || c=='-'){
X>                         if (command == unarg)
X945c952,955
X<         }
X---
X>             }
X> 	    execute(c,f,n) ;
X> 	}
X> }
X947,949c957,967
X< 	/* and execute the command */
X<         execute(c, f, n);
X<         goto loop;
X---
X> /* Causes the program to dump core */
X> 
X> dumpcore(f,n)
X> 
X> {
X> 	if (clexec) {
X> 	    clexec = FALSE ;
X> 	    abort() ;
X> 	}
X> 	else
X> 	    mlwrite("[Sorry, you can't do that from here]") ;
X999d1016
X<         register KEYTAB *ktp;
X1002,1010c1019,1023
X<         ktp = &keytab[0];                       /* Look in key table.   */
X<         while (ktp->k_fp != NULL) {
X<                 if (ktp->k_code == c) {
X<                         thisflag = 0;
X<                         status   = (*ktp->k_fp)(f, n);
X<                         lastflag = thisflag;
X<                         return (status);
X<                 }
X<                 ++ktp;
X---
X>         if (c == NULL) {
X>             thisflag = 0;
X>             status   = (*command)(f, n);
X>             lastflag = thisflag;
X>             return (status);
X1021c1034
X< 		execute(META|SPEC|'W', FALSE, 1);
X---
X> 		wrapword(FALSE, 1);
X1213,1224d1225
X< }
X< 
X< meta()	/* dummy function for binding to meta prefix */
X< {
X< }
X< 
X< cex()	/* dummy function for binding to control-x prefix */
X< {
X< }
X< 
X< unarg()	/* dummy function for binding to universal-argument */
X< {
!The!End!

echo x - "random.d" 2>&1
sed "s/^X//" >"random.d" <<'!The!End!'
X450c450
X< 		execute(META|SPEC|'W', FALSE, 1);
X---
X> 		wrapword(FALSE, 1);
!The!End!
exit