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