v08i008: A Micro-Emacs variant that resembles GNU Emacs

sources-request at mirror.UUCP sources-request at mirror.UUCP
Wed Jan 28 04:13:31 AEST 1987


Submitted by: Bob Larson <seismo!usc-oberon!blarson>
Mod.sources: Volume 8, Issue 8
Archive-name: micrognu/Part01

[  It's editor week at mod.sources...  -r$ ]

#! /bin/sh
#
# distribution note: This distribution of mg 1a is 11 shar files:
#	mg_1.shar through mg_5.shar	system indepentend, termcap,
#					bsd, sysv, and osk files.
#	mg_amiga1.shar, mg_amiga2.shar	amiga specific files
#	mg_vms1.shar through mg_vms4.shar
#					vms and eunice specific files.
#
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	README
#	systty.mods
#	functions
#	def.h
#	display.c
#	kbd.c
export PATH; PATH=/bin:$PATH
if test -f 'README'
then
	echo shar: will not over-write existing file "'README'"
else
cat << \SHAR_EOF > 'README'
MG 1a README Nov 16, 1986

MicroGnuEmacs (mg) is a Public Domain EMACS style editor.  It is
"broadly" compatible with GNU Emacs, the latest creation of Richard M.
Stallman, Chief GNUisance and inventor of Emacs.  GNU Emacs (and other
portions of GNU as they are released) are essentially free, (there are
handling charges for obtaining it) and so is MicroGnuEmacs.  You may
never have to learn another editor.  (But probably will, at least long
enough to port MicroGnuEmacs...)

MicroGnuEmacs is not associated with the GNU project, and does not
have the copyright restrictions present in GNU Emacs.  (However, a few
of the system dependent modules do have copyright notices, specificly
the VMS termcap routines and the amiga specific routines.  Look at the
source code for exact copyright restrictions.)  The MicroGnuEmacs
authors individually may or may not agree with the opinions expressed
by Richard Stallman and the GNU project. 

This program is intended to be a small, fast, and portable editor for
people who can't run real Emacs thing for one reason or another.  It
is compatible with GNU because there shouldn't be any reason to learn
more than one Emacs flavor.  We have excised most MicroEMACS features
that were incompatible with the big brother, and added missing
features that seemed essential. 

There are at least two other major versions of MicroEMACS in
circulation.  One comes from Daniel Lawrence, (based on an old version
from Dave Conroy) and is available from mod.sources.  It uses a 3.x
version numbering scheme, and the latest I know about is 3.7i.  It has
some features not found in MicroGnuEmacs, is bigger, and is
incompatible with GNU Emacs.  It might be a better choice for you if
you *must* have something not present here and can't run GNU. 

Another variety uses a different numbering scheme, and is up to v30.
This also comes from mod.sources, and is the latest version from the
original MicroEMACS author Dave Conroy.  MicroGnuEmacs is derived from
this version, and we hope to replace it. 

Code will move fairly easily between MicroGnuEmacs and v30
derivatives.  It will not move easily to the 3.x strain because of
diverging ideas about how things should work internally.  Command
functions and keymapping, for instance, are completely different
between the two flavors. 

This is the first distribution release of MicroGnuEmacs.  (It went
through four beta releases to iron out the changes made by the various
autors.)  Beyond the work of Dave Conroy, author of the original
public domain v30, this contains the efforts of:

	mwm at ucbopal.berkeley.edu	Mike Meyer
	mic at ngp.utexas.edu		Mic Kaczmarczik
	blarson at usc-oberon.arpa		Bob Larson
	rtech!daveb at sun.com		Dave Brower

Special thanks are due the first three fellows, who did most of the
work. 

These systems are known to work in the current version:

	4.2 & 4.3 BSD Unix
	OS9/68k
	VMS
	Amiga
	System V
	Eunice

As far as MG is concerned, Ultrix-32 is equivalent to BSD unix.

It should support MSDOS, PCDOS, and the Rainbow if you swipe the sys
and tty files from the v30 distribution and modify them as specified
in the file systty.mods.  It obviously hasn't been tested. 

How to Make a MicroGnuEmacs
---------------------------

On UNIX at least, it's easy.  (Note that even on these systems you may
want to change a compile time option.)  If you have BSD UNIX, do:

	ln sys/bsd/Makefile .
	make

For System V, do:

	ln sys/sysv/Makefile .
	make

There are several other directories under sys: osk, vms, and eunice
and amiga.  You should follow the directions contained therein to make
one of those versions. 

For most systems (everyting except the amiga currently), the termcap
terminal definition is used.  There is a readme file in the termcap
subdirectory of the tty directory explaining what entries are used and
how.  (Termcap is a way to do display manipulation in a terminal
independent manner.)

----------------------------------------------------------------------

Known limitaions and minor bugs descovered immeditatly before release:

	A newline will be appended to the last line of a file if it does
	not have one.

	There is a fixed maximum line length on files read.  (Defaults
	to 256, but may be changed at compile time.)

	See functions for function by function differences from real
	GNU Emacs.

	DPROMPT code has not been added to ttyio.c for all systems
	where it could be supported.

	The Amiga code has not been extensivly tested with all options
	on all compilers.  A problem have been discovered but not
	duplicated, possibly a compiler problem.

	Multi-case buffer names can be created on case-insensitive systems
	(i.e. OSK) for files specified on the command line.

------------------------------------------------------------------------

If you have a change to make that you think should be incorporated
into the next version of MicroGnuEmacs, send it to the contact for
your system:

Amiga Lattice C:	Mike Meyer: 
	mwm at berkeley.edu
	ucbvax!mwm

Amiga Manx C & VMS:	Mic Kaczmarczik: 
	ut-sally!ut-ngp!mic
	mic at ngp.utexas.edu
	CCEP001 at UTADNX.BITNET

OSK & BSD:	Bob Larson: 
	blarson at usc-oberon.arpa
	sdcrdcf!usc-oberon!blarson

Support for additional systems and terminals should include being
available for beta testing as other changes are made.  (Send a short
note to all three contacts above.) If you can't reach one of us via a
computer network, I suppose you could send a change to my snail mail
address below on 5" os9 format disks or 9 track tape (ANSI variable
label or Prime magsav format), but this efectivly rules you out as a
potential beta tester.  (Don't expect the disk or tape back unless you
inculude a SASE with sufficent postage.) I will not be sending out
copies on magnetic media, so please don't ask.  If you somehow got an
incomplete or non-standard copy, (i.e. missing one of the sys
directories mentioned here as working) complain to who you got it from
not to me. 

	Robert Larson
	309 S. Alexandria Ave.
	Apt. 117
	Los Angeles, CA  90020
SHAR_EOF
fi # end of overwriting check
if test -f 'systty.mods'
then
	echo shar: will not over-write existing file "'systty.mods'"
else
cat << \SHAR_EOF > 'systty.mods'
1) All the function names have changed, so fix function bindings.
2) version has changed from char *[] to char *, fix all references.
3) if STARTUP is defined, startupfile (which returns a pointer to the
	name of the users startupfile) should be in fileio.c
4) The typedefs for KEY (the internal key type, an 11 bit value) and
	RSIZE (how big a region can be) need to be in sysdef.h
5) Either a function or a define for bcopy() needs to come in for the
	system. It looks like bcopy(b1, b2, length), and copies length
	bytes from b1 to b2. IT MUST DO A NON-DESTRUCTIVE COPY. Check for
	a routine that does this (by a different name, of course) in your
	system already, and make it a define.
6) Either a function or a define for typeahead() needs to exist. It returns
	true if there are input characters to be had. Easy case is to
	#define it as FALSE.
7) abort has turned into panic, with a string argument. Panic should
	spit out the string, and then leave a core image if possible.
8) All #if's were changed to #ifdef's.  Most configuration #define XXX 0 
	lines should be commented out.
9) Several optional defines have been added: VARARGS, SYSINIT, 
	STANDOUT_GLITCH, MOVE_STANDOUT, XCHAR + XSHORT, NLINE, DPROMPT,
	XKEYS. 
10) Define KEYDUP_ERROR for debugging symbol.c (and a (sometimes MUCH) 
	larger executable.)
11) User preference options have been moved to Makefile from def.h.
12) To use with DPROMPT, a ttwait function is needed in ttyio.c.  An
	example is in sys/osk.
SHAR_EOF
fi # end of overwriting check
if test -f 'functions'
then
	echo shar: will not over-write existing file "'functions'"
else
cat << \SHAR_EOF > 'functions'
Format:
#!function-name			[default binding]
	Description
!	How it differs from GNU.

The '!' in the function name is optional.  If present, it means that the
function does not exist in GNU.

To get a function list with bindings, do
	"grep ^# this_file | sed -e 's/^#//' -e 's/^#!//' > your_file"
Other interesting things can be extracted as you see fit.

-------------------------------------------------------------------------------

#auto-fill-mode
	Cause word-wrap at fill-column, after space is typed.
!	Modes are global across all buffers.
#!auto-indent-mode
	Cause indent to first whitespace after a newline.
#backward-char			[C-b]
	Move point left ARG characters (right if ARG negative).
	On reaching end of buffer, stop and signal error.
#backward-delete-char		[DEL]
	Delete characters backwards. Delete ARG chars, and save in
	kill buffer if ARG was specified
#backward-kill-word		[ESC DEL]
	Kill characters backward until encountering the end of a word.
	With argument, do this that many times.
!	When deleting backwards across line boundaries onto non-null
!	kill buffers, things get put in the kill buffer in the wrong
!	order.
#backward-paragraph		[ESC [ ]
	Move backward to start of paragraph.  With arg, do it arg times.
!	Definition of paragraph isn't quite the same as with GNU, need
!	to fill it in.
#backward-word			[ESC b]
	Move backward until encountering the end of a word.
	With argument, do this that many times.
#beginning-of-buffer		[ESC < ]
	Move point to the beginning of the buffer; leave mark at
	previous position.
!	Doesn't understand arguments.
#beginning-of-line		[C-a]
	Move point to beginning of current line.
#!bsmap-mode
	If no argument, turns on a mode that maps ^H to del and del
	to ^H, where the editor can't see it. If there is an argument,
	turns that mode off.
#call-last-kbd-macro		[C-x e]
	Call the last keyboard macro that you defined with C-x (.
!	Not as fancy as GNU version.
#capitalize-word		[ESC c]
	Convert following word (or ARG words) to upper case, moving over.
!	Doesn't handle negative arguments.
#copy-region-as-kill		[ESC w]
	Save the region as if killed, but don't kill it.
#!ctrlx-four-hack
	Exists to support the Ctl-x 4 <things> code.
#delete-blank-lines		[C-x C-o]
	On blank line, delete all surrounding blank lines, leaving just one.
!	Always behaves that way, doesn't do the isolated blank and non-blank
!	lines as does GNU.
#delete-char			[C-d]
	Delete the following ARG characters (previous, with negative arg).
	If ARG is specified, appends deleted characters to the kill buffer.
#delete-other-windows		[C-x 1]
	Make current window fill the screen.
#delete-window			[C-x 0]
	Remove current window from the display.
#describe-bindings		[C-h b]
	Show a list of all defined keys, and their definitions.
	The list is put in a buffer, which is displayed.
!	No heading on columns in output buffer
#describe-key-briefly		[C-h c]
	Print the name of the function KEY invokes.
#downcase-region		[C-x C-l]
	Convert the region to lower case.
#downcase-word			[ESC l]
	Convert following word (or ARG words) to lower case, moving over.
!	Doesn't handle negative arguments.
#emacs-version
	Print string describing the version of Emacs that is running.
#end-kbd-macro			[C-x ) ]
	Finish defining a keyboard macro.
	The definition was started by C-x (.
	The macro is now available for use via C-x e,
!	Can't use end-kbd-macro to execute macro.
#end-of-buffer			[ESC > ]
	Move point to the end of the buffer; leave mark at previous position.
!	Doesn't understand arguments
#end-of-line			[C-e]
	Move point to end of current line.
!	Doesn't understand arguments.
#enlarge-window			[C-x ^]
	Make current window ARG lines bigger.
!	Won't make other windows vanish to make room for enlarging window.
#eval-current-buffer
	Execute the current buffer as an Emacs command file.
!	Doesn't exist in the MICRO version.
#eval-expression
	Get Emacs command and evaluate.
!	Doesn't exist in MICRO version. No autocompletion.
#exchange-point-and-mark	[C-x C-x]
	Put the mark where point is now, and point where the mark is now.
#execute-extended-command
	Read function name, then read its arguments and call it.
#fill-paragraph			[ESC q]
	Fill paragraph at or after point.
!	Leaves point at end of paragraph, instead of where it started.
!	Other differences, such as paragraph definition and what
!	characters to doublespace after also exist.
#find-file			[C-x C-f]
	Edit file FILENAME.
	Switch to a buffer visiting file FILENAME,
	creating one if none already exists.
!	MicroGnuEmacs will put a newline at the end of the last line
!	if there is not one there already.
#find-file-other-window		[C-x 4 f] [C-x 4 C-f]
	Edit file FILENAME, in another window.
	May create a new window, or reuse an existing one;
!	See find-file.
#!flow-mode
	Without an argument, sets a mode that maps ^\ to ^S and ^^ to ^Q,
	and silently eats ^S and ^Q at a level where the editor can't see
	it. With an argument, turns that mode off.
#forward-char			[C-f]
	Move point right ARG characters (left if ARG negative).
	On reaching end of buffer, stop and signal error.
#forward-paragraph		[ESC ] ]
	Move forward to end of paragraph.  With arg, do it arg times.
!	See backward-paragraph
#forward-word			[ESC f]
	Move point forward ARG words (backward if ARG is negative).
#global-set-key
	Give KEY a definition of COMMAND.
#global-unset-key
	Remove global definition of KEY.
#goto-line
	goto LINE in the current buffer.
!	Want to leave mark at old position, but....
#help				[C-h]
	Prompt user to find out what kind of help to supply
!	Only b (describe-bindings), c (describe-key-briefly) and ^H
!	(help) work.
#insert-file			[C-x i]
	Insert contents of file FILENAME into buffer after point.
	Set mark after the inserted text.
!	File not found handling differs from GNU Emacs.
!	see find-file.
#!insert-newline		[RET]
	Bound to newline so that it does the right things.  Usually
	ignorable.
#!insert-with-wrap
	Bound to space in auto-fill-mode. Check current column, and adds
	a newline if past it.
#isearch-backward		[C-r]
	Do incremental search backward.
	See isearch-forward for more information.
!	Not as fancy as the GNU version.
#isearch-forward		[C-s]
	Do incremental search forward.
	As you type characters, they add to the search string and are found.
	Type Delete to cancel characters from end of search string.
	Type ESC to exit, leaving point at location found.
	Type C-S to search again forward, C-R to search again backward.
	Type C-Q to quote control character to search for it.
	C-G while searching or when search has failed
	cancels input back to what has been found successfully.
	C-G when search is successful aborts and moves point to starting point.
	Other control and meta characters terminate the search
	 and are then executed normally.
!	See isearch-backward.
#just-one-space			[ESC SPC]
#keyboard-quit			[C-g]
	Terminate the current function with an quit condition.
#kill-buffer			[C-x k]
	Get rid of the specified buffer.
!	Has minor problems: if buffer being killed is open in any windows,
!	those windows must have valid alternate buffers.  Leaves point and 
!	mark at end of buffer if alternate buffer is open on another window.
#kill-line			[C-k]
	Kill the rest of the current line; before a newline, kill the newline.
	With prefix argument, kill that many lines from point.
	Negative arguments kill lines backward.
!	When killing backwards across line boundaries (args of < 0) onto a
!	non-empty kill buffer, it appends things in the wrong order.
#kill-paragraph
	Kill current paragraph.
!	NEEDS TO BE CHANGED TO KILL TO END OF CURRENT PARAGRAPH!!!
#kill-region			[C-w]
	Kill between point and mark.
	The text is deleted but saved in the kill buffer.
	The command C-y can retrieve it from there.
#kill-word			[ESC d]
	Kill characters forward until encountering the end of a word.
	With argument, do this that many times.
#list-buffers
	Display a list of names of existing buffers.
	Inserts it in buffer *Buffer List* and displays that.
!	Note that buffers with names starting with spaces are listed, where
!	GNU omits them. Less information listed.
#load
	Execute a file of Emacs commands.
!	Mucho different; any of '();' comments outside of strings; only
!	one-line "S-expressions" work; only present if compilation option 
!	specified.
#newline-and-indent		[C-j]
	Insert a newline, then indent.
#next-line			[C-n]
	Move cursor vertically down ARG lines.
!	Not like GNU, not sure of the differences.
#!next-window
	Move to the next window down the screen.
!	Named other-window in GNU. Done this way for GOSLING freaks
!	who want next and previous window.
#not-modified			[ESC ~]
	Clear buffer modified flag.
#open-line			[C-o]
	Insert a newline and leave point before it.
	With arg, inserts that many newlines.
#!prefix-region
	Prepend a string (set by set-prefix-string) to each line
	in the curernt region.  If given an argument, prompts
	you for the string to use.
!	Probably available in GNU under a different name or through a
!	different functionality.  Intended purpose is mail quoting and
!	bar comments in C code.  Compilation option.
previous-line			[C-p]
	Move cursor vertically up ARG lines.
!	See next-line.
#!previous-window
	Move to the next window up the screen.
!	previous-window is there for GOSLING freaks (like me).
#query-replace			[ESC % ]
	Replace some occurrences of FROM-STRING with TO-STRING.
	As each match is found, the user must type a character saying
	what to do with it.
	Type Help char within query-replace for directions.
!	Not quite as sharp as GNU version
#quoted-insert			[C-q]
	Read next input character and insert it.
	Useful for inserting control characters.
!	Doesn't handle the 3 octal digits case.
#recenter			[C-l]
	Center point in window and redisplay screen.  With ARG, put point
	on line ARG.  The desired position of point is always relative
	to the current window.  Also forces full screen refresh.
#save-buffer			[C-x C-s]
	Save current buffer in visited file.
!	Always saves buffer, even if it isn't modified.
#save-buffers-kill-emacs	[C-x C-c]
	Offer to save each buffer, then kill this Emacs.
#save-some-buffers		[C-x s]
	Save some modified file-visiting buffers.  Asks user about each one.
	With argument, saves all with no questions.
#scroll-down			[ESC v]
	Scroll text of current window downward ARG lines; or near full
	screen if no ARG.
#scroll-other-window		[ESC C-v]
	Scroll text of next window upward ARG lines; or near full screen
	if no ARG. The next window is the one below the current one; or
	the one at the top if the current one is at the bottom.
#scroll-up			[C-v]
	Scroll text of current window upward ARG lines; or near full
	screen if no ARG.
#!search-again
	Handy to have around for function keys/menus, etc.
#search-backward		[ESC r]
	Search backward from point for STRING.
!	Last search pattern is remembered, including isearches
!	Bound to C-s in uemacs, not bound in GNU
#search-forward			[ESC s]
	Search forward from point for STRING.
	see search-backward
#self-insert-command		[All printing characters]
	Insert this character.
#set-fill-column		[C-x f]
	Set fill-column to current column, or to argument if given.
!	Global, not buffer-local (no buffer-local stuff in uemacs)
#set-mark-command		[C-@]
	Set mark to where point is.
!	No mark ring, so args don't make sense.
#!set-prefix-string
!	Set string used by prefix-region to put in front of each line text.
!	Probably available in GNU in some other form, but this specific
!	form suits a number of situations.  Compilation option.
#shrink-window
	Make the current window ARG lines smaller.
!	Will not make the current window vanish if you try and make it
!	to small; won't shrink window if you only have one window.
#split-window-vertically	[C-x 2]
	Split current window into two windows, one above the other.
!	Behaves differently about which is going to be current window,
!	Doesn't use ARG to decide how many lines to use.
#start-kbd-macro		[C-x ( ]
	Record subsequent keyboard input, defining a keyboard macro.
	The commands are recorded even as they are executed.
#suspend-emacs			[C-z] [C-x C-z]
	Get a shell.  Exactly what shell depends on the system you
	are on.
#switch-to-buffer		[C-x b]
	Select the specified buffer in the current window.
!	Memory of old buffer names doesn't work quite as well.
#switch-to-buffer-other-window	[C-x 4 b]
	Switch to specified buffer in another window.
!	See switch-to-buffer
#transpose-chars		[C-t]
	Interchange characters around point, moving forward one character.
!	Doesn't work across newlines, ignores args
#upcase-region			[C-x C-u]
	Convert the region to upper case.
#upcase-word			[ESC u]
	Convert the following word (or ARG words) to upper case, moving over.
!	Doesn't handle negative arguments.
#what-cursor-position		[C-x =]
	Print info on cursor position.
!	slightly more information in output.
#write-file			[C-x C-w]
	Write current buffer into file FILENAME. Makes FILENAME the file for
	the current buffer.
#yank
	Reinsert the last stretch of killed text.
!	Doesn't keep a kill ring, so no yanks of stuff older than
!	last delete, and arg-yank does yank arg times, instead of
!	getting the arg'th thing off the kill ring.




SHAR_EOF
fi # end of overwriting check
if test -f 'def.h'
then
	echo shar: will not over-write existing file "'def.h'"
else
cat << \SHAR_EOF > 'def.h'
/*
 * This file is the general header file for all parts
 * of the MicroEMACS display editor. It contains all of the
 * general definitions and macros. It also contains some
 * conditional compilation flags. All of the per-system and
 * per-terminal definitions are in special header files.
 * The most common reason to edit this file would be to zap
 * the definition of CVMVAS or BACKUP.
 */
#include	"sysdef.h"		/* Order is critical.		*/
#include	"ttydef.h"
#include	<stdio.h>

/*
 * If your system and/or compiler does not support the "void" type
 * then define NO_VOID_TYPE in sysdef.h.  In the absence of some
 * other definition for VOID, the default in that case will be to
 * turn it into an int, which works with most compilers that don't
 * support void.  In the absence of any definition of VOID or
 * NO_VOID_TYPE, the default is to assume void is supported, which
 * should be the case for most modern C compilers.
 */

#ifndef VOID
#ifdef NO_VOID_TYPE
#  define VOID int			/* Default for no void is int */
#else
#  define VOID void			/* Just use normal void */
#endif /* NO_VOID_TYPE */
#endif /* VOID */

/*
 * Table sizes, etc.
 */
#ifdef	HASH
#define	NSHASH	31			/* Symbol table hash size.	*/
#endif
#define	NFILEN	80			/* Length, file name.		*/
#define	NBUFN	24			/* Length, buffer name.		*/
#ifndef NLINE			/* allow it to be defined in makefile */
#define	NLINE	256			/* Length, line.		*/
#endif
#define	NKBDM	256			/* Length, keyboard macro.	*/
#define	NPAT	80			/* Length, pattern.		*/
#define	HUGE	1000			/* A rather large number.	*/
#define NSRCH	128			/* Undoable search commands.	*/
#define	NXNAME	64			/* Length, extended command.	*/
#define	NKNAME	20			/* Length, key names		*/
/*
 * Universal.
 */
#define	FALSE	0			/* False, no, bad, etc.		*/
#define	TRUE	1			/* True, yes, good, etc.	*/
#define	ABORT	2			/* Death, ^G, abort, etc.	*/

/*
 * These flag bits keep track of
 * some aspects of the last command. The CFCPCN
 * flag controls goal column setting. The CFKILL
 * flag controls the clearing versus appending
 * of data in the kill buffer.
 */
#define	CFCPCN	0x0001			/* Last command was C-P, C-N	*/
#define	CFKILL	0x0002			/* Last command was a kill	*/

/*
 * File I/O.
 */
#define	FIOSUC	0			/* Success.			*/
#define	FIOFNF	1			/* File not found.		*/
#define	FIOEOF	2			/* End of file.			*/
#define	FIOERR	3			/* Error.			*/

/*
 * Directory I/O.
 */
#define	DIOSUC	0			/* Success.			*/
#define	DIOEOF	1			/* End of file.			*/
#define	DIOERR	2			/* Error.			*/

/*
 * Display colors.
 */
#define	CNONE	0			/* Unknown color.		*/
#define	CTEXT	1			/* Text color.			*/
#define	CMODE	2			/* Mode line color.		*/

/*
 * global mode
 */
#define	MBSMAP	0x0001			/* Map bs<->del			*/
#define MFLOW	0x0002			/* Use ^^ for ^Q and ^/ for ^S	*/
#define	MINDENT	0x0004			/* autoindent			*/
#define	MFILL	0x0008			/* fill mode			*/

/*
 * Flags for "eread".
 */
#define	EFFUNC	0x0001			/* Autocomplete functions.	*/
#define EFBUF	0x0002			/* Autocomplete buffers.	*/
#define EFFILE	0x0004			/* " files (maybe someday)	*/
#define	EFAUTO	0x0007			/* Some autocompleteion on	*/
#define	EFNEW	0x0008			/* New prompt.			*/
#define	EFCR	0x0010			/* Echo CR at end; last read.	*/

/*
 * Flags for "getkey".
 */
#define KQUOTE	0x0001			/* Get raw character		*/
#define	KNOMAC	0x0002			/* Don't record for macros	*/
#define	KPROMPT 0x0004			/* do delayed prompting		*/

/*
 * Flags for "ldelete"/"kinsert"
 */

#define KNONE	0
#define KFORW	1
#define KBACK	2

/*
 * Keys are represented inside using an 11 bit
 * keyboard code. The transformation between the keys on
 * the keyboard and 11 bit code is done by terminal specific
 * code in the "kbd.c" file. The actual character is stored
 * in 8 bits (DEC multinationals work); there is also a control
 * flag KCTRL, a meta flag KMETA, and a control-X flag KCTLX.
 * ASCII control characters are always represented using the
 * KCTRL form. Although the C0 control set is free, it is
 * reserved for C0 controls because it makes the communication
 * between "getkey" and "getkbd" easier. The funny keys get
 * mapped into the C1 control area. The KEY type is typedefed in
 * sysdef.h, as it may depeond on compiler/machine.
 */
#define	NKEYS	2048			/* 11 bit code.			*/

#define	METACH	0x1B			/* M- prefix,   Control-[, ESC	*/
#define	CTMECH	0x1C			/* C-M- prefix, Control-\	*/
#define	EXITCH	0x1D			/* Exit level,  Control-]	*/
#define	CTRLCH	0x1E			/* C- prefix,	Control-^	*/
#define	HELPCH	0x1F			/* Help key,    Control-_	*/

#define	KCHAR	0x00FF			/* The basic character code.	*/
#define	KCTRL	0x0100			/* Control flag.		*/
#define	KMETA	0x0200			/* Meta flag.			*/
#define	KCTLX	0x0400			/* Control-X flag.		*/

#define	KFIRST	0x0080			/* First special.		*/
#define	KLAST	0x009F			/* Last special.		*/

#define	KRANDOM	0x0080			/* A "no key" code.		*/
#define	K01	0x0081			/* Use these names to define	*/
#define	K02	0x0082			/* the special keys on your	*/
#define	K03	0x0083			/* terminal.			*/
#define	K04	0x0084
#define	K05	0x0085
#define	K06	0x0086
#define	K07	0x0087
#define	K08	0x0088
#define	K09	0x0089
#define	K0A	0x008A
#define	K0B	0x008B
#define	K0C	0x008C
#define	K0D	0x008D
#define	K0E	0x008E
#define	K0F	0x008F
#define	K10	0x0090
#define	K11	0x0091
#define	K12	0x0092
#define	K13	0x0093
#define	K14	0x0094
#define	K15	0x0095
#define	K16	0x0096
#define	K17	0x0097
#define	K18	0x0098
#define	K19	0x0099
#define	K1A	0x009A
#define	K1B	0x009B
#define	K1C	0x009C
#define	K1D	0x009D
#define	K1E	0x009E
#define	K1F	0x009F

#ifndef SEOL		/* needed for OSK, where '\r' == '\n' */
#  define SEOL '\n'
#endif

/*
 * These flags, and the macros below them,
 * make up a do-it-yourself set of "ctype" macros that
 * understand the DEC multinational set, and let me ask
 * a slightly different set of questions.
 */
#define	_W	0x01			/* Word.			*/
#define	_U	0x02			/* Upper case letter.		*/
#define	_L	0x04			/* Lower case letter.		*/
#define	_C	0x08			/* Control.			*/
#define _P	0x10			/* end of sentence punctuation	*/

#define	ISWORD(c)	((cinfo[(c)]&_W)!=0)
#define	ISCTRL(c)	((cinfo[(c)]&_C)!=0)
#define	ISUPPER(c)	((cinfo[(c)]&_U)!=0)
#define	ISLOWER(c)	((cinfo[(c)]&_L)!=0)
#define	ISEOSP(c)	((cinfo[(c)]&_P)!=0)
#define	TOUPPER(c)	((c)-0x20)
#define	TOLOWER(c)	((c)+0x20)

/*
 * generally useful thing for chars
 */
#define CCHR(x)		((x)-'@')

/*
 * All repeated structures are kept as linked lists of structures.
 * All of these start with a LIST structure (except lines, which
 * have their own abstraction). This will allow for
 * later conversion to generic list manipulation routines should
 * I decide to do that. it does mean that there are four extra
 * bytes per window. I feel that this is an acceptable price,
 * considering that there are usually only one or two windows.
 */
typedef struct LIST {
	union {
		struct SYMBOL	*l_sp;
		struct WINDOW	*l_wp;
		struct BUFFER	*l_bp;
		struct LIST	*l_nxt;
	} l_p;
	char	*l_name;
} LIST;
/*
 * Usual hack - to keep from uglifying the code with lotsa
 * references through the union, we #define something for it.
 */
#define	l_next	l_p.l_nxt

/*
 * The symbol table links editing functions
 * to names. Entries in the key map point at the symbol
 * table entry.
 */
typedef	struct	SYMBOL {
	LIST	s_list;			/* List chain.			*/
	int	(*s_funcp)();		/* Function.			*/
#ifdef	HASH
	short	s_flags;		/* Flags for this symbol	*/
#endif
}	SYMBOL;
#define	s_symp	s_list.l_p.l_sp
#define s_name	s_list.l_name
#ifdef	HASH
#define SFEND	0x001			/* End of has list		*/
#endif

/*
 * There is a window structure allocated for
 * every active display window. The windows are kept in a
 * big list, in top to bottom screen order, with the listhead at
 * "wheadp". Each window contains its own values of dot and mark.
 * The flag field contains some bits that are set by commands
 * to guide redisplay; although this is a bit of a compromise in
 * terms of decoupling, the full blown redisplay is just too
 * expensive to run for every input character. 
 */
typedef	struct	WINDOW {
	LIST	w_list;			/* List header		       */
	struct	BUFFER *w_bufp;		/* Buffer displayed in window	*/
	struct	LINE *w_linep;		/* Top line in the window	*/
	struct	LINE *w_dotp;		/* Line containing "."		*/
	struct	LINE *w_markp;		/* Line containing "mark"	*/
	short	w_doto;			/* Byte offset for "."		*/
	short	w_marko;		/* Byte offset for "mark"	*/
	char	w_toprow;		/* Origin 0 top row of window	*/
	char	w_ntrows;		/* # of rows of text in window	*/
	char	w_force;		/* If NZ, forcing row.		*/
	char	w_flag;			/* Flags.			*/
}	WINDOW;
#define	w_wndp	w_list.l_p.l_wp
#define w_name	w_list.l_name

/*
 * Window flags are set by command processors to
 * tell the display system what has happened to the buffer
 * mapped by the window. Setting "WFHARD" is always a safe thing
 * to do, but it may do more work than is necessary. Always try
 * to set the simplest action that achieves the required update.
 * Because commands set bits in the "w_flag", update will see
 * all change flags, and do the most general one.
 */
#define	WFFORCE	0x01			/* Force reframe.		*/
#define	WFMOVE	0x02			/* Movement from line to line.	*/
#define	WFEDIT	0x04			/* Editing within a line.	*/
#define	WFHARD	0x08			/* Better to a full display.	*/
#define	WFMODE	0x10			/* Update mode line.		*/

/*
 * Text is kept in buffers. A buffer header, described
 * below, exists for every buffer in the system. The buffers are
 * kept in a big list, so that commands that search for a buffer by
 * name can find the buffer header. There is a safe store for the
 * dot and mark in the header, but this is only valid if the buffer
 * is not being displayed (that is, if "b_nwnd" is 0). The text for
 * the buffer is kept in a circularly linked list of lines, with
 * a pointer to the header line in "b_linep".
 */
typedef	struct	BUFFER {
	LIST	b_list;			/* buffer list pointer		*/
	struct	BUFFER *b_altb;		/* Link to alternate buffer	*/
	struct	LINE *b_dotp;		/* Link to "." LINE structure	*/
	struct	LINE *b_markp;		/* The same as the above two,	*/
	struct	LINE *b_linep;		/* Link to the header LINE	*/
	short	b_doto;			/* Offset of "." in above LINE	*/
	short	b_marko;		/* but for the "mark"		*/
	char	b_nwnd;			/* Count of windows on buffer	*/
	char	b_flag;			/* Flags			*/
	char	b_fname[NFILEN];	/* File name			*/
}	BUFFER;
#define	b_bufp	b_list.l_p.l_bp
#define b_bname	b_list.l_name

#define	BFCHG	0x01			/* Changed.			*/
#define	BFBAK	0x02			/* Need to make a backup.	*/

/*
 * This structure holds the starting position
 * (as a line/offset pair) and the number of characters in a
 * region of a buffer. This makes passing the specification
 * of a region around a little bit easier.
 */
typedef	struct	{
	struct	LINE *r_linep;		/* Origin LINE address.		*/
	short	r_offset;		/* Origin LINE offset.		*/
	RSIZE	r_size;			/* Length in characters.	*/
}	REGION;

/*
 * All text is kept in circularly linked
 * lists of "LINE" structures. These begin at the
 * header line (which is the blank line beyond the
 * end of the buffer). This line is pointed to by
 * the "BUFFER". Each line contains a the number of
 * bytes in the line (the "used" size), the size
 * of the text array, and the text. The end of line
 * is not stored as a byte; it's implied. Future
 * additions will include update hints, and a
 * list of marks into the line.
 */
typedef	struct	LINE {
	struct	LINE *l_fp;		/* Link to the next line	*/
	struct	LINE *l_bp;		/* Link to the previous line	*/
	short	l_size;			/* Allocated size		*/
	short	l_used;			/* Used size			*/
#ifdef	PCC
	char	l_text[1];		/* A bunch of characters.	*/
#else
	char	l_text[];		/* A bunch of characters.	*/
#endif
}	LINE;

/*
 * The rationale behind these macros is that you
 * could (with some editing, like changing the type of a line
 * link from a "LINE *" to a "REFLINE", and fixing the commands
 * like file reading that break the rules) change the actual
 * storage representation of lines to use something fancy on
 * machines with small address spaces.
 */
#define	lforw(lp)	((lp)->l_fp)
#define	lback(lp)	((lp)->l_bp)
#define	lgetc(lp, n)	((lp)->l_text[(n)]&0xFF)
#define	lputc(lp, n, c)	((lp)->l_text[(n)]=(c))
#define	llength(lp)	((lp)->l_used)
#define	ltext(lp)	((lp)->l_text)

/*
 * Externals.
 */
extern	int	thisflag;
extern	int	lastflag;
extern	int	curgoal;
extern	int	epresf;
extern	int	sgarbf;
extern	int	mode;
extern	WINDOW	*curwp;
extern	BUFFER	*curbp;
extern	WINDOW	*wheadp;
extern	BUFFER	*bheadp;
extern	KEY	kbdm[];
extern	KEY	*kbdmip;
extern	KEY	*kbdmop;
extern	KEY	getkey();
extern	char	pat[];
extern	SYMBOL	*symbol[];
extern	SYMBOL	*binding[];
extern	BUFFER	*bfind();
extern	WINDOW	*popbuf();
extern	WINDOW	*wpopup();
extern	LINE	*lalloc();
extern  int	nrow;
extern  int	ncol;
extern	char	*version;
extern	int	ttrow;
extern	int	ttcol;
extern	int	tceeol;
extern	int	tcinsl;
extern	int	tcdell;
extern	char	cinfo[];
extern	char	*keystrings[];
extern	SYMBOL	*symlookup();
VOID		update();
VOID		keyname();
/*
 * Standard I/O.
 */
extern	char	*strcpy();
extern	char	*strcat();
extern	char	*malloc();
SHAR_EOF
fi # end of overwriting check
if test -f 'display.c'
then
	echo shar: will not over-write existing file "'display.c'"
else
cat << \SHAR_EOF > 'display.c'
/*
 * The functions in this file handle redisplay. The
 * redisplay system knows almost nothing about the editing
 * process; the editing functions do, however, set some
 * hints to eliminate a lot of the grinding. There is more
 * that can be done; the "vtputc" interface is a real
 * pig. Two conditional compilation flags; the GOSLING
 * flag enables dynamic programming redisplay, using the
 * algorithm published by Jim Gosling in SIGOA. The MEMMAP
 * changes things around for memory mapped video. With
 * both off, the terminal is a VT52.
 */
#include	"def.h"

/*
 * You can change these back to the types
 * implied by the name if you get tight for space. If you
 * make both of them "int" you get better code on the VAX.
 * They do nothing if this is not Gosling redisplay, except
 * for change the size of a structure that isn't used.
 * A bit of a cheat.
 */
/* These defines really belong in sysdef.h */
#ifndef XCHAR
#  define	XCHAR	int
#  define	XSHORT	int
#endif

#ifdef	STANDOUT_GLITCH
extern int SG;				/* number of standout glitches	*/
#endif

/*
 * A video structure always holds
 * an array of characters whose length is equal to
 * the longest line possible. Only some of this is
 * used if "ncol" isn't the same as "NCOL".
 */
typedef	struct	{
	short	v_hash;			/* Hash code, for compares.	*/
	short	v_flag;			/* Flag word.			*/
	short	v_color;		/* Color of the line.		*/
	XSHORT	v_cost;			/* Cost of display.		*/
	char	v_text[NCOL];		/* The actual characters.	*/
}	VIDEO;

#define	VFCHG	0x0001			/* Changed.			*/
#define	VFHBAD	0x0002			/* Hash and cost are bad.	*/

/*
 * SCORE structures hold the optimal
 * trace trajectory, and the cost of redisplay, when
 * the dynamic programming redisplay code is used.
 * If no fancy redisplay, this isn't used. The trace index
 * fields can be "char", and the score a "short", but
 * this makes the code worse on the VAX.
 */
typedef	struct	{
	XCHAR	s_itrace;		/* "i" index for track back.	*/
	XCHAR	s_jtrace;		/* "j" index for trace back.	*/
	XSHORT	s_cost;			/* Display cost.		*/
}	SCORE;

int	sgarbf	= TRUE;			/* TRUE if screen is garbage.	*/
int	vtrow	= 0;			/* Virtual cursor row.		*/
int	vtcol	= 0;			/* Virtual cursor column.	*/
int	tthue	= CNONE;		/* Current color.		*/
int	ttrow	= HUGE;			/* Physical cursor row.		*/
int	ttcol	= HUGE;			/* Physical cursor column.	*/
int	tttop	= HUGE;			/* Top of scroll region.	*/
int	ttbot	= HUGE;			/* Bottom of scroll region.	*/

VIDEO	*vscreen[NROW-1];		/* Edge vector, virtual.	*/
VIDEO	*pscreen[NROW-1];		/* Edge vector, physical.	*/
VIDEO	video[2*(NROW-1)];		/* Actual screen data.		*/
VIDEO	blanks;				/* Blank line image.		*/

#ifdef	GOSLING
/*
 * This matrix is written as an array because
 * we do funny things in the "setscores" routine, which
 * is very compute intensive, to make the subscripts go away.
 * It would be "SCORE	score[NROW][NROW]" in old speak.
 * Look at "setscores" to understand what is up.
 */
SCORE	score[NROW*NROW];
#endif

/*
 * Initialize the data structures used
 * by the display code. The edge vectors used
 * to access the screens are set up. The operating
 * system's terminal I/O channel is set up. Fill the
 * "blanks" array with ASCII blanks. The rest is done
 * at compile time. The original window is marked
 * as needing full update, and the physical screen
 * is marked as garbage, so all the right stuff happens
 * on the first call to redisplay.
 */
vtinit() {
	register VIDEO	*vp;
	register int	i;

	ttopen();
	ttinit();
	vp = &video[0];
	for (i=0; i<NROW-1; ++i) {
		vscreen[i] = vp;
		++vp;
		pscreen[i] = vp;
		++vp;
	}
	blanks.v_color = CTEXT;
	for (i=0; i<NCOL; ++i)
		blanks.v_text[i] = ' ';
}

/*
 * Tidy up the virtual display system
 * in anticipation of a return back to the host
 * operating system. Right now all we do is position
 * the cursor to the last line, erase the line, and
 * close the terminal channel.
 */
vttidy() {
	ttcolor(CTEXT);
	ttnowindow();				/* No scroll window.	*/
	ttmove(nrow-1, 0);			/* Echo line.		*/
	tteeol();
	tttidy();
	ttflush();
	ttclose();
}

/*
 * Move the virtual cursor to an origin
 * 0 spot on the virtual display screen. I could
 * store the column as a character pointer to the spot
 * on the line, which would make "vtputc" a little bit
 * more efficient. No checking for errors.
 */
vtmove(row, col) {
	vtrow = row;
	vtcol = col;
}

/*
 * Write a character to the virtual display,
 * dealing with long lines and the display of unprintable
 * things like control characters. Also expand tabs every 8
 * columns. This code only puts printing characters into 
 * the virtual display image. Special care must be taken when
 * expanding tabs. On a screen whose width is not a multiple
 * of 8, it is possible for the virtual cursor to hit the
 * right margin before the next tab stop is reached. This
 * makes the tab code loop if you are not careful.
 * Three guesses how we found this.
 */
vtputc(c) register int c; {
	register VIDEO	*vp;

	vp = vscreen[vtrow];
	if (vtcol >= ncol)
		vp->v_text[ncol-1] = '$';
	else if (c == '\t') {
		do {
			vtputc(' ');
		} while (vtcol<ncol && (vtcol&0x07)!=0);
	} else if (ISCTRL(c) != FALSE) {
		vtputc('^');
		vtputc(c ^ 0x40);
	} else
		vp->v_text[vtcol++] = c;		
}

/*
 * Erase from the end of the
 * software cursor to the end of the
 * line on which the software cursor is
 * located. The display routines will decide
 * if a hardware erase to end of line command
 * should be used to display this.
 */
vteeol() {
	register VIDEO	*vp;

	vp = vscreen[vtrow];
	while (vtcol < ncol)
		vp->v_text[vtcol++] = ' ';
}

/*
 * Make sure that the display is
 * right. This is a three part process. First,
 * scan through all of the windows looking for dirty
 * ones. Check the framing, and refresh the screen.
 * Second, make sure that "currow" and "curcol" are
 * correct for the current window. Third, make the
 * virtual and physical screens the same.
 */
VOID
update() {
	register LINE	*lp;
	register WINDOW	*wp;
	register VIDEO	*vp1;
	register VIDEO	*vp2;
	register int	i;
	register int	j;
	register int	c;
	register int	hflag;
	register int	currow;
	register int	curcol;
	register int	offs;
	register int	size;
	VOID traceback ();
	VOID uline ();

	if (typeahead()) return;
	if (sgarbf) {				/* must update everything */
		wp = wheadp; 
		while(wp != NULL) {
			wp->w_flag |= WFMODE | WFHARD;
			wp = wp->w_wndp;
		}
	}
	hflag = FALSE;				/* Not hard.		*/
	wp = wheadp;
	while (wp != NULL) {
		if (wp->w_flag != 0) {		/* Need update.		*/
			if ((wp->w_flag&WFFORCE) == 0) {
				lp = wp->w_linep;
				for (i=0; i<wp->w_ntrows; ++i) {
					if (lp == wp->w_dotp)
						goto out;
					if (lp == wp->w_bufp->b_linep)
						break;
					lp = lforw(lp);
				}
			}
			i = wp->w_force;	/* Reframe this one.	*/
			if (i > 0) {
				--i;
				if (i >= wp->w_ntrows)
					i = wp->w_ntrows-1;
			} else if (i < 0) {
				i += wp->w_ntrows;
				if (i < 0)
					i = 0;
			} else
				i = wp->w_ntrows/2;
			lp = wp->w_dotp;
			while (i!=0 && lback(lp)!=wp->w_bufp->b_linep) {
				--i;
				lp = lback(lp);
			}
			wp->w_linep = lp;
			wp->w_flag |= WFHARD;	/* Force full.		*/
		out:
			lp = wp->w_linep;	/* Try reduced update.	*/
			i  = wp->w_toprow;
			if ((wp->w_flag&~WFMODE) == WFEDIT) {
				while (lp != wp->w_dotp) {
					++i;
					lp = lforw(lp);
				}
				vscreen[i]->v_color = CTEXT;
				vscreen[i]->v_flag |= (VFCHG|VFHBAD);
				vtmove(i, 0);
				for (j=0; j<llength(lp); ++j)
					vtputc(lgetc(lp, j));
				vteeol();
			} else if ((wp->w_flag&(WFEDIT|WFHARD)) != 0) {
				hflag = TRUE;
				while (i < wp->w_toprow+wp->w_ntrows) {
					vscreen[i]->v_color = CTEXT;
					vscreen[i]->v_flag |= (VFCHG|VFHBAD);
					vtmove(i, 0);
					if (lp != wp->w_bufp->b_linep) {
						for (j=0; j<llength(lp); ++j)
							vtputc(lgetc(lp, j));
						lp = lforw(lp);
					}
					vteeol();
					++i;
				}
			}
			if ((wp->w_flag&WFMODE) != 0)
				modeline(wp);
			wp->w_flag  = 0;
			wp->w_force = 0;
		}		
		wp = wp->w_wndp;
	}
	lp = curwp->w_linep;			/* Cursor location.	*/
	currow = curwp->w_toprow;
	while (lp != curwp->w_dotp) {
		++currow;
		lp = lforw(lp);
	}
	curcol = 0;
	i = 0;
	while (i < curwp->w_doto) {
		c = lgetc(lp, i++);
		if (c == '\t')
			curcol |= 0x07;
		else if (ISCTRL(c) != FALSE)
			++curcol;
		++curcol;
	}
	if (curcol >= ncol)			/* Long line.		*/
		curcol = ncol-1;
	if (sgarbf != FALSE) {			/* Screen is garbage.	*/
		sgarbf = FALSE;			/* Erase-page clears	*/
		epresf = FALSE;			/* the message area.	*/
		tttop  = HUGE;			/* Forget where you set	*/
		ttbot  = HUGE;			/* scroll region.	*/
		tthue  = CNONE;			/* Color unknown.	*/
		ttmove(0, 0);
		tteeop();
		for (i=0; i<nrow-1; ++i) {
			uline(i, vscreen[i], &blanks);
			ucopy(vscreen[i], pscreen[i]);
		}
		ttmove(currow, curcol);
		ttflush();
		return;
	}
#ifdef	GOSLING
	if (hflag != FALSE) {			/* Hard update?		*/
		for (i=0; i<nrow-1; ++i) {	/* Compute hash data.	*/
			hash(vscreen[i]);
			hash(pscreen[i]);
		}
		offs = 0;			/* Get top match.	*/
		while (offs != nrow-1) {
			vp1 = vscreen[offs];
			vp2 = pscreen[offs];
			if (vp1->v_color != vp2->v_color
			||  vp1->v_hash  != vp2->v_hash)
				break;
			uline(offs, vp1, vp2);
			ucopy(vp1, vp2);
			++offs;
		}
		if (offs == nrow-1) {		/* Might get it all.	*/
			ttmove(currow, curcol);
			ttflush();
			return;
		}
		size = nrow-1;			/* Get bottom match.	*/
		while (size != offs) {
			vp1 = vscreen[size-1];
			vp2 = pscreen[size-1];
			if (vp1->v_color != vp2->v_color
			||  vp1->v_hash  != vp2->v_hash)
				break;
			uline(size-1, vp1, vp2);
			ucopy(vp1, vp2);
			--size;
		}
		if ((size -= offs) == 0)	/* Get screen size.	*/
			panic("Illegal screen size in update");
		setscores(offs, size);		/* Do hard update.	*/
		traceback(offs, size, size, size);
		for (i=0; i<size; ++i)
			ucopy(vscreen[offs+i], pscreen[offs+i]);
		ttmove(currow, curcol);
		ttflush();
		return;			
	}
#endif
	for (i=0; i<nrow-1; ++i) {		/* Easy update.		*/
		vp1 = vscreen[i];
		vp2 = pscreen[i];
		if ((vp1->v_flag&VFCHG) != 0) {
			uline(i, vp1, vp2);
			ucopy(vp1, vp2);
		}
	}
	ttmove(currow, curcol);
	ttflush();
}

/*
 * Update a saved copy of a line,
 * kept in a VIDEO structure. The "vvp" is
 * the one in the "vscreen". The "pvp" is the one
 * in the "pscreen". This is called to make the
 * virtual and physical screens the same when
 * display has done an update.
 */
ucopy(vvp, pvp) register VIDEO *vvp; register VIDEO *pvp; {

	vvp->v_flag &= ~VFCHG;			/* Changes done.	*/
	pvp->v_flag  = vvp->v_flag;		/* Update model.	*/
	pvp->v_hash  = vvp->v_hash;
	pvp->v_cost  = vvp->v_cost;
	pvp->v_color = vvp->v_color;
	bcopy(vvp->v_text, pvp->v_text, ncol);
}

/*
 * Update a single line. This routine only
 * uses basic functionality (no insert and delete character,
 * but erase to end of line). The "vvp" points at the VIDEO
 * structure for the line on the virtual screen, and the "pvp"
 * is the same for the physical screen. Avoid erase to end of
 * line when updating CMODE color lines, because of the way that
 * reverse video works on most terminals.
 */
VOID uline(row, vvp, pvp) VIDEO *vvp; VIDEO *pvp; {
#ifdef	MEMMAP
	putline(row+1, 1, &vvp->v_text[0]);
#else
	register char	*cp1;
	register char	*cp2;
	register char	*cp3;
	register char	*cp4;
	register char	*cp5;
	register int	nbflag;

	if (vvp->v_color != pvp->v_color) {	/* Wrong color, do a	*/
		ttmove(row, 0);			/* full redraw.		*/
#ifdef	STANDOUT_GLITCH
		if (pvp->v_color != CTEXT && SG >= 0) tteeol();
#endif
		ttcolor(vvp->v_color);
#ifdef	STANDOUT_GLITCH
		cp1 = &vvp->v_text[SG > 0 ? SG : 0];
		/* the odd code for SG==0 is to avoid putting the invisable
		 * glitch character on the next line.  
		 * (Hazeltine executive 80 model 30)
		 */
		cp2 = &vvp->v_text[ncol - (SG >= 0 ? (SG!=0 ? SG : 1) : 0)];
#else
		cp1 = &vvp->v_text[0];
		cp2 = &vvp->v_text[ncol];
#endif
		while (cp1 != cp2) {
			ttputc(*cp1++);
			++ttcol;
		}
#ifndef	MOVE_STANDOUT
		ttcolor(CTEXT);
#endif
		return;
	}
	cp1 = &vvp->v_text[0];			/* Compute left match.	*/
	cp2 = &pvp->v_text[0];
	while (cp1!=&vvp->v_text[ncol] && cp1[0]==cp2[0]) {
		++cp1;
		++cp2;
	}
	if (cp1 == &vvp->v_text[ncol])		/* All equal.		*/
		return;
	nbflag = FALSE;
	cp3 = &vvp->v_text[ncol];		/* Compute right match.	*/
	cp4 = &pvp->v_text[ncol];
	while (cp3[-1] == cp4[-1]) {
		--cp3;
		--cp4;
		if (cp3[0] != ' ')		/* Note non-blanks in	*/
			nbflag = TRUE;		/* the right match.	*/
	}
	cp5 = cp3;				/* Is erase good?	*/
	if (nbflag==FALSE && vvp->v_color==CTEXT) {
		while (cp5!=cp1 && cp5[-1]==' ')
			--cp5;
		/* Alcyon hack */
		if ((int)(cp3-cp5) <= tceeol)
			cp5 = cp3;
	}
	/* Alcyon hack */
	ttmove(row, (int)(cp1-&vvp->v_text[0]));
#ifdef	STANDOUT_GLITCH
	if (vvp->v_color != CTEXT && SG > 0) {
		if(cp1 < &vvp->v_text[SG]) cp1 = &vvp->v_text[SG];
		if(cp5 > &vvp->v_text[ncol-SG]) cp5 = &vvp->v_text[ncol-SG];
	} else if (SG < 0)
#endif
	ttcolor(vvp->v_color);
	while (cp1 != cp5) {
		ttputc(*cp1++);
		++ttcol;
	}
	if (cp5 != cp3)				/* Do erase.		*/
		tteeol();
#endif
}

/*
 * Redisplay the mode line for
 * the window pointed to by the "wp".
 * This is the only routine that has any idea
 * of how the modeline is formatted. You can
 * change the modeline format by hacking at
 * this routine. Called by "update" any time
 * there is a dirty window.
 * Note that if STANDOUT_GLITCH is defined, first and last SG characters
 * may never be seen.
 */
modeline(wp) register WINDOW *wp; {
	register int	n;
	register BUFFER	*bp;

	n = wp->w_toprow+wp->w_ntrows;		/* Location.		*/
	vscreen[n]->v_color = CMODE;		/* Mode line color.	*/
	vscreen[n]->v_flag |= (VFCHG|VFHBAD);	/* Recompute, display.	*/
	vtmove(n, 0);				/* Seek to right line.	*/
	bp = wp->w_bufp;
	vtputc('-'); vtputc('-');
	if ((bp->b_flag&BFCHG) != 0) {		/* "*" if changed.	*/
		vtputc('*'); vtputc('*');
	} else {
		vtputc('-'); vtputc('-');
	}
	vtputc('-');
	n  = 5;
	n += vtputs("MicroGnuEmacs:");
	if (bp->b_bname[0] != 0) {
		vtputc(' ');
		++n;
		n += vtputs(&(bp->b_bname[0]));
	}
	while (n < 42) {			/* Pad out with blanks	*/
		vtputc(' ');
		++n;
	}
	vtputc('(');
	++n;
	if (mode == 0) n += vtputs("Fundamental");
	else {
		if ((mode&MBSMAP) != 0) {
			n += vtputs("bsmap");
			if ((mode&~MBSMAP) != 0) {
				vtputc('-');
				++n;
			}
		}
		if ((mode&MFLOW) != 0) {
			n += vtputs("flow");
			if ((mode&~(MFLOW|MBSMAP)) != 0) {
				vtputc('-');
				++n;
			}
		}
		if ((mode&MINDENT) != 0) {
			n += vtputs("indent");
			if ((mode&~(MINDENT|MFLOW|MBSMAP)) != 0) {
				vtputc('-');
				++n;
			}
		}
		if ((mode&MFILL) != 0)
			n += vtputs("fill");
	}
	vtputc(')');
	++n;
	while (n < ncol) {			/* Pad out.		*/
		vtputc('-');
		++n;
	}
}
/*
 * output a string to the mode line, report how long it was.
 */
vtputs(s) register char *s; {
	register int n = 0;

	while (*s != '\0') {
		vtputc(*s++);
		++n;
	}
	return n;
}
#ifdef	GOSLING
/*
 * Compute the hash code for
 * the line pointed to by the "vp". Recompute
 * it if necessary. Also set the approximate redisplay
 * cost. The validity of the hash code is marked by
 * a flag bit. The cost understand the advantages
 * of erase to end of line. Tuned for the VAX
 * by Bob McNamara; better than it used to be on
 * just about any machine.
 */
hash(vp) register VIDEO *vp; {
	register int	i;
	register int	n;
	register char	*s;
 
	if ((vp->v_flag&VFHBAD) != 0) {		/* Hash bad.		*/
		s = &vp->v_text[ncol-1];
		for (i=ncol; i!=0; --i, --s)
			if (*s != ' ')
				break;
		n = ncol-i;			/* Erase cheaper?	*/
		if (n > tceeol)
			n = tceeol;
		vp->v_cost = i+n;		/* Bytes + blanks.	*/
		for (n=0; i!=0; --i, --s)
			n = (n<<5) + n + *s;
		vp->v_hash = n;			/* Hash code.		*/
		vp->v_flag &= ~VFHBAD;		/* Flag as all done.	*/
	}
}

/*
 * Compute the Insert-Delete
 * cost matrix. The dynamic programming algorithm
 * described by James Gosling is used. This code assumes
 * that the line above the echo line is the last line involved
 * in the scroll region. This is easy to arrange on the VT100
 * because of the scrolling region. The "offs" is the origin 0
 * offset of the first row in the virtual/physical screen that
 * is being updated; the "size" is the length of the chunk of
 * screen being updated. For a full screen update, use offs=0
 * and size=nrow-1.
 *
 * Older versions of this code implemented the score matrix by
 * a two dimensional array of SCORE nodes. This put all kinds of
 * multiply instructions in the code! This version is written to
 * use a linear array and pointers, and contains no multiplication
 * at all. The code has been carefully looked at on the VAX, with
 * only marginal checking on other machines for efficiency. In
 * fact, this has been tuned twice! Bob McNamara tuned it even
 * more for the VAX, which is a big issue for him because of
 * the 66 line X displays.
 *
 * On some machines, replacing the "for (i=1; i<=size; ++i)" with
 * i = 1; do { } while (++i <=size)" will make the code quite a
 * bit better; but it looks ugly.
 */
setscores(offs, size) {
	register SCORE	*sp;
	SCORE		*sp1;
	register int	tempcost;
	register int	bestcost;
	register int	j;
	register int	i;
	register VIDEO	**vp;
	VIDEO		**pp, **vbase, **pbase;
 
	vbase = &vscreen[offs-1];		/* By hand CSE's.	*/
	pbase = &pscreen[offs-1];
	score[0].s_itrace = 0;			/* [0, 0]		*/
	score[0].s_jtrace = 0;
	score[0].s_cost   = 0;
	sp = &score[1];				/* Row 0, inserts.	*/
	tempcost = 0;
	vp = &vbase[1];
	for (j=1; j<=size; ++j) {
		sp->s_itrace = 0;
		sp->s_jtrace = j-1;
		tempcost += tcinsl;
		tempcost += (*vp)->v_cost;
		sp->s_cost = tempcost;
		++vp;
		++sp;
	}
	sp = &score[NROW];			/* Column 0, deletes.	*/
	tempcost = 0;
	for (i=1; i<=size; ++i) {
		sp->s_itrace = i-1;
		sp->s_jtrace = 0;
		tempcost  += tcdell;
		sp->s_cost = tempcost;
		sp += NROW;
	}
	sp1 = &score[NROW+1];			/* [1, 1].		*/
	pp = &pbase[1];
	for (i=1; i<=size; ++i) {
		sp = sp1;
		vp = &vbase[1];
		for (j=1; j<=size; ++j) {
			sp->s_itrace = i-1;
			sp->s_jtrace = j;
			bestcost = (sp-NROW)->s_cost;
			if (j != size)		/* Cd(A[i])=0 @ Dis.	*/
				bestcost += tcdell;
			tempcost = (sp-1)->s_cost;
			tempcost += (*vp)->v_cost;
			if (i != size)		/* Ci(B[j])=0 @ Dsj.	*/
				tempcost += tcinsl;
			if (tempcost < bestcost) {
				sp->s_itrace = i;
				sp->s_jtrace = j-1;
				bestcost = tempcost;
			}
			tempcost = (sp-NROW-1)->s_cost;
			if ((*pp)->v_color != (*vp)->v_color
			||  (*pp)->v_hash  != (*vp)->v_hash)
				tempcost += (*vp)->v_cost;
			if (tempcost < bestcost) {
				sp->s_itrace = i-1;
				sp->s_jtrace = j-1;
				bestcost = tempcost;
			}
			sp->s_cost = bestcost;
			++sp;			/* Next column.		*/
			++vp;
		}
		++pp;
		sp1 += NROW;			/* Next row.		*/
	}
}

/*
 * Trace back through the dynamic programming cost
 * matrix, and update the screen using an optimal sequence
 * of redraws, insert lines, and delete lines. The "offs" is
 * the origin 0 offset of the chunk of the screen we are about to
 * update. The "i" and "j" are always started in the lower right
 * corner of the matrix, and imply the size of the screen.
 * A full screen traceback is called with offs=0 and i=j=nrow-1.
 * There is some do-it-yourself double subscripting here,
 * which is acceptable because this routine is much less compute
 * intensive then the code that builds the score matrix!
 */
VOID traceback(offs, size, i, j) {
	register int	itrace;
	register int	jtrace;
	register int	k;
	register int	ninsl;
	register int	ndraw;
	register int	ndell;

	if (i==0 && j==0)			/* End of update.	*/
		return;
	itrace = score[(NROW*i) + j].s_itrace;
	jtrace = score[(NROW*i) + j].s_jtrace;
	if (itrace == i) {			/* [i, j-1]		*/
		ninsl = 0;			/* Collect inserts.	*/
		if (i != size)
			ninsl = 1;
		ndraw = 1;
		while (itrace!=0 || jtrace!=0) {
			if (score[(NROW*itrace) + jtrace].s_itrace != itrace)
				break;
			jtrace = score[(NROW*itrace) + jtrace].s_jtrace;
			if (i != size)
				++ninsl;
			++ndraw;
		}
		traceback(offs, size, itrace, jtrace);
		if (ninsl != 0) {
			ttcolor(CTEXT);
			ttinsl(offs+j-ninsl, offs+size-1, ninsl);
		}
		do {				/* B[j], A[j] blank.	*/
			k = offs+j-ndraw;
			uline(k, vscreen[k], &blanks);
		} while (--ndraw);
		return;
	}
	if (jtrace == j) {			/* [i-1, j]		*/
		ndell = 0;			/* Collect deletes.	*/
		if (j != size)
			ndell = 1;
		while (itrace!=0 || jtrace!=0) {
			if (score[(NROW*itrace) + jtrace].s_jtrace != jtrace)
				break;
			itrace = score[(NROW*itrace) + jtrace].s_itrace;
			if (j != size)
				++ndell;
		}
		if (ndell != 0) {
			ttcolor(CTEXT);
			ttdell(offs+i-ndell, offs+size-1, ndell);
		}
		traceback(offs, size, itrace, jtrace);
		return;
	}
	traceback(offs, size, itrace, jtrace);
	k = offs+j-1;
	uline(k, vscreen[k], pscreen[offs+i-1]);
}
#endif
SHAR_EOF
fi # end of overwriting check
if test -f 'kbd.c'
then
	echo shar: will not over-write existing file "'kbd.c'"
else
cat << \SHAR_EOF > 'kbd.c'
/*
 *		Terminal independent keyboard handling.
 */
#include	"def.h"

#ifdef	DPROMPT
#define	PROMPTL	80
  char	prompt[PROMPTL], *promptp;
#endif

/*
 * All input from the user (should!) go through
 * getkey. Quotep is true to get raw keys, false to
 * get 11-bit code keys.
 * Getkey is responsible for putting keystrokes away
 * for macros. It also takes keystrokes out of the macro,
 * though other input routines will can also do this.
 * Read in a key, doing the terminal
 * independent prefix handling. The terminal specific
 * "getkbd" routine gets the first swing, and may return
 * one of the special codes used by the special keys
 * on the keyboard. The "getkbd" routine returns the
 * C0 controls as received; this routine moves them to
 * the right spot in 11 bit code.
 * If the KPROMPT bit in the flags is set and DPROMPT is
 * defined, do delayed prompting.  (dprompt routine is 
 * in sys/???/ttyio.c)
 */
KEY
getkey(f) register int f; {
	register KEY	c;
	KEY		keychar();
	int		getkbd(), ttgetc();

	if (kbdmop != NULL) return *kbdmop++;
#ifdef	DPROMPT
	if(!(f&KPROMPT)) prompt[0] = '\0';
#endif
	c = (KEY) mapin(getkbd);
#ifdef	DPROMPT
	if(f&KPROMPT) {
		if(promptp > prompt) *(promptp-1) = ' ';
		if(promptp >= &prompt[PROMPTL-8]) f &= ~KPROMPT;
				/* must have a lot of prefixes.... */
	}
#endif
	if ((f&KQUOTE) == 0) {
#ifdef	DO_METAKEY
		if ((c & ~KCHAR) == KCTRL)	/* Function key		*/
			c &= KCHAR;		/* remove wrapping	*/
		else if ((c >= 0x80) && (c <= 0xFF)) /* real meta key	*/
			c = KMETA | keychar(c & ~0x80, TRUE);
#endif
#ifdef	DPROMPT
		if(f&KPROMPT) {
			keyname(promptp, (c<=0x1F && c>=0x00)?KCTRL|(c+'@'):c);
			strcat(promptp, "-");
		}
#endif
		if (c == METACH)		/* M-			*/
			c = KMETA | keychar(mapin(ttgetc), TRUE);
		else if (c == CTRLCH)		/* C-			*/
			c = KCTRL | keychar(mapin(ttgetc), TRUE);
		else if (c == CTMECH)		/* C-M-			*/
			c = KCTRL | KMETA | keychar(mapin(ttgetc), TRUE);
		else if (c<=0x1F && c>=0x00)	/* Relocate control.	*/
			c = KCTRL | (c+'@');
		if (c == (KCTRL|'X'))		/* C-X			*/
			c = KCTLX | keychar(mapin(ttgetc), TRUE);
	}

	if ((f&KNOMAC) == 0 && kbdmip != NULL) {
		if (kbdmip+1 > &kbdm[NKBDM-3]) {	/* macro overflow */
			(VOID) ctrlg(FALSE, 0, KRANDOM);
			ewprintf("Keyboard macro overflow");
			ttflush();
			return (KCTRL|'G');		/* ^G it for us	*/
		}
		*kbdmip++ = c;
	}
#ifdef	DPROMPT
	if(f&KPROMPT) {
		keyname(promptp, c);
		promptp += strlen(promptp);
		*promptp++ = '-';
		*promptp = '\0';
	}
#endif
	return (c);
}

/*
 * go get a key, and run it through whatever mapping the modes
 * specify.
 */
static mapin(get) int (*get)(); {
	register int	c;

#ifdef	DPROMPT
	if(prompt[0]!='\0' && ttwait()) {
		ewprintf("%s", prompt);		/* avoid problems with % */
		update();			/* put the cursor back	 */
		epresf = KPROMPT;
	}
#endif
	c = (*get)();
	if ((mode&MFLOW) != 0) {
		while (c == CCHR('S') || c == CCHR('Q'))
			c = (*get)();
		if (c == CCHR('^')) c = CCHR('Q');
		else if (c == CCHR('\\')) c = CCHR('S');
	}
	if ((mode&MBSMAP) != 0)
		if (c == CCHR('H')) c = 0x7f;
		else if (c == 0x7f) c = CCHR('H');
	return c;
}
/*
 * Transform a key code into a name,
 * using a table for the special keys and combination
 * of some hard code and some general processing for
 * the rest. None of this code is terminal specific any
 * more. This makes adding keys easier.
 */
VOID
keyname(cp, k) register char *cp; register int k; {
	register char	*np;
	register int	c;
	char		nbuf[3];

	static	char	hex[] = {
		'0',	'1',	'2',	'3',
		'4',	'5',	'6',	'7',
		'8',	'9',	'A',	'B',
		'C',	'D',	'E',	'F'
	};

	if ((k&KCTLX) != 0) {			/* C-X prefix.		*/
		*cp++ = 'C';
		*cp++ = '-';
		*cp++ = 'x';
		*cp++ = ' ';
	}
	if ((k&KMETA) != 0) {			/* Add M- mark.		*/
		*cp++ = 'E';
		*cp++ = 'S';
		*cp++ = 'C';
		*cp++ = ' ';
	}
	if ((k&KCHAR)>=KFIRST && (k&KCHAR)<=KLAST) {
		if ((np=keystrings[(k&KCHAR)-KFIRST]) != NULL) {
			if ((k&KCTRL) != 0) {
				*cp++ = 'C';
				*cp++ = '-';
			}
			(VOID) strcpy(cp, np);
			return;
		}
	}
	c = k & ~(KMETA|KCTLX);
	if (c == (KCTRL|'I'))	/* Some specials.	*/
		np = "TAB";
	else if (c == (KCTRL|'M'))
		np = "RET";
	else if (c == (KCTRL|'J'))
		np = "LFD";
	else if (c == ' ')
		np = "SPC";
	else if (c == 0x7F)
		np = "DEL";
	else if (c == (KCTRL|'['))
		np = "ESC";
	else {
		if ((k&KCTRL) != 0) {		/* Add C- mark.		*/
			*cp++ = 'C';
			*cp++ = '-';
		}
		if ((k&(KCTRL|KMETA|KCTLX)) != 0 && ISUPPER(k&KCHAR) != FALSE)
			k = TOLOWER(k&KCHAR);
		np = &nbuf[0];
		if (((k&KCHAR)>=0x20 && (k&KCHAR)<=0x7E)
		||  ((k&KCHAR)>=0xA0 && (k&KCHAR)<=0xFE)) {
			nbuf[0] = k&KCHAR;	/* Graphic.		*/
			nbuf[1] = 0;
		} else {			/* Non graphic.		*/
			nbuf[0] = hex[(k>>4)&0x0F];
			nbuf[1] = hex[k&0x0F];
			nbuf[2] = 0;
		}
	}
	(VOID) strcpy(cp, np);
}

/*
 * turn a key into an internal char.
 */
KEY
keychar(c, f) register int c, f; {

	if (f == TRUE && ISLOWER(c) != FALSE)
		c = TOUPPER(c);
	else if (c>=0x00 && c<=0x1F)		/* Relocate control.	*/
		c = (KCTRL|(c+'@'));
	return (KEY) c;
}
SHAR_EOF
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Mod.sources mailing list