v08i011: A Micro-Emacs variant that resembles GNU Emacs
sources-request at mirror.UUCP
sources-request at mirror.UUCP
Wed Jan 28 04:18:48 AEST 1987
Submitted by: Bob Larson <seismo!usc-oberon!blarson>
Mod.sources: Volume 8, Issue 11
Archive-name: micrognu/Part04
#! /bin/sh
# 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:
# search.c
# symbol.c
# window.c
# tty/termcap/tty.c
# tty/termcap/readme
# tty/termcap/ttydef.h
# This archive created: Sat Nov 15 15:06:50 1986
export PATH; PATH=/bin:$PATH
if test ! -d sys
then
mkdir sys
fi
if test ! -d tty
then
mkdir tty
fi
if test ! -d tty/termcap
then
mkdir tty/termcap
fi
if test -f 'search.c'
then
echo shar: will not over-write existing file "'search.c'"
else
cat << \SHAR_EOF > 'search.c'
/*
* Search commands.
* The functions in this file implement the
* search commands (both plain and incremental searches
* are supported) and the query-replace command.
*
* The plain old search code is part of the original
* MicroEMACS "distribution". The incremental search code,
* and the query-replace code, is by Rich Ellison.
*/
#include "def.h"
#define SRCH_BEGIN (0) /* Search sub-codes. */
#define SRCH_FORW (-1)
#define SRCH_BACK (-2)
#define SRCH_NOPR (-3)
#define SRCH_ACCM (-4)
#define SRCH_MARK (-5)
typedef struct {
int s_code;
LINE *s_dotp;
int s_doto;
} SRCHCOM;
static SRCHCOM cmds[NSRCH];
static int cip;
int srch_lastdir = SRCH_NOPR; /* Last search flags. */
/*
* Search forward.
* Get a search string from the user, and search for it,
* starting at ".". If found, "." gets moved to just after the
* matched characters, and display does all the hard stuff.
* If not found, it just prints a message.
*/
/*ARGSUSED*/
forwsearch(f, n, k) {
register int s;
if ((s=readpattern("Search")) != TRUE)
return (s);
if (forwsrch() == FALSE) {
ewprintf("Search failed: \"%s\"", pat);
return (FALSE);
}
srch_lastdir = SRCH_FORW;
return (TRUE);
}
/*
* Reverse search.
* Get a search string from the user, and search, starting at "."
* and proceeding toward the front of the buffer. If found "." is left
* pointing at the first character of the pattern [the last character that
* was matched].
*/
/*ARGSUSED*/
backsearch(f, n, k) {
register int s;
if ((s=readpattern("Search backward")) != TRUE)
return (s);
if (backsrch() == FALSE) {
ewprintf("Search failed: \"%s\"", pat);
return (FALSE);
}
srch_lastdir = SRCH_BACK;
return (TRUE);
}
/*
* Search again, using the same search string
* and direction as the last search command. The direction
* has been saved in "srch_lastdir", so you know which way
* to go.
*/
/*ARGSUSED*/
searchagain(f, n, k) {
if (srch_lastdir == SRCH_FORW) {
if (forwsrch() == FALSE) {
ewprintf("Search failed: \"%s\"", pat);
return (FALSE);
}
return (TRUE);
}
if (srch_lastdir == SRCH_BACK) {
if (backsrch() == FALSE) {
ewprintf("Search failed: \"%s\"", pat);
return (FALSE);
}
return (TRUE);
}
ewprintf("No last search");
return (FALSE);
}
/*
* Use incremental searching, initially in the forward direction.
* isearch ignores any explicit arguments.
*/
/*ARGSUSED*/
forwisearch(f, n, k) {
return (isearch(SRCH_FORW));
}
/*
* Use incremental searching, initially in the reverse direction.
* isearch ignores any explicit arguments.
*/
/*ARGSUSED*/
backisearch(f, n, k) {
return (isearch(SRCH_BACK));
}
/*
* Incremental Search.
* dir is used as the initial direction to search.
* ^S switch direction to forward
* ^R switch direction to reverse
* ^Q quote next character (allows searching for ^N etc.)
* <ESC> exit from Isearch
* <DEL> undoes last character typed. (tricky job to do this correctly).
* other ^ exit search, don't set mark
* else accumulate into search string
*/
isearch(dir) {
register int c;
register LINE *clp;
register int cbo;
register int success;
int pptr;
char opat[NPAT];
for (cip=0; cip<NSRCH; cip++)
cmds[cip].s_code = SRCH_NOPR;
(VOID) strcpy(opat, pat);
cip = 0;
pptr = -1;
clp = curwp->w_dotp;
cbo = curwp->w_doto;
is_lpush();
is_cpush(SRCH_BEGIN);
success = TRUE;
is_prompt(dir, TRUE, success);
for (;;) {
update();
switch (c = (char) getkey(KQUOTE)) {
case METACH:
srch_lastdir = dir;
curwp->w_markp = clp;
curwp->w_marko = cbo;
if (kbdmop == NULL) ewprintf("Mark set");
return (TRUE);
case CCHR('G'):
if (success != TRUE) {
while (is_peek() == SRCH_ACCM)
if (is_undo(&pptr, &dir) == FALSE)
break;
success = TRUE;
is_prompt(dir, pptr < 0, success);
break;
}
curwp->w_dotp = clp;
curwp->w_doto = cbo;
curwp->w_flag |= WFMOVE;
srch_lastdir = dir;
(VOID) ctrlg(FALSE, 0, KRANDOM);
(VOID) strcpy(pat, opat);
return ABORT;
case CCHR('S'):
if (dir == SRCH_BACK) {
dir = SRCH_FORW;
is_lpush();
is_cpush(SRCH_FORW);
success = TRUE;
}
if (success==FALSE && dir==SRCH_FORW)
break;
is_lpush();
pptr = strlen(pat);
(VOID) forwchar(FALSE, 1, KRANDOM);
if (is_find(SRCH_FORW) != FALSE) is_cpush(SRCH_MARK);
else {
(VOID) backchar(FALSE, 1, KRANDOM);
ttbeep();
success = FALSE;
}
is_prompt(dir, pptr < 0, success);
break;
case CCHR('R'):
if (dir == SRCH_FORW) {
dir = SRCH_BACK;
is_lpush();
is_cpush(SRCH_BACK);
success = TRUE;
}
if (success==FALSE && dir==SRCH_BACK)
break;
is_lpush();
pptr = strlen(pat);
(VOID) backchar(FALSE, 1, KRANDOM);
if (is_find(SRCH_BACK) != FALSE) is_cpush(SRCH_MARK);
else {
(VOID) forwchar(FALSE, 1, KRANDOM);
ttbeep();
success = FALSE;
}
is_prompt(dir, pptr < 0, success);
break;
case 0x7F:
if (is_undo(&pptr, &dir) != TRUE) return FALSE;
if (is_peek() != SRCH_ACCM) success = TRUE;
is_prompt(dir, pptr < 0, success);
break;
case CCHR('Q'):
c = (char) getkey(KQUOTE);
goto addchar;
case CCHR('M'):
c = CCHR('J');
case CCHR('J'):
goto addchar;
default:
if (ISCTRL(c) != FALSE) {
c += '@';
c |= KCTRL;
success = execute((KEY) c, FALSE, 1);
curwp->w_markp = clp;
curwp->w_marko = cbo;
if (kbdmop == NULL) ewprintf("Mark set");
curwp->w_flag |= WFMOVE;
return (success);
}
addchar:
if (pptr == -1)
pptr = 0;
if (pptr == 0)
success = TRUE;
pat[pptr++] = c;
if (pptr == NPAT) {
ewprintf("Pattern too long");
return FALSE;
}
pat[pptr] = '\0';
is_lpush();
if (success != FALSE) {
if (is_find(dir) != FALSE)
is_cpush(c);
else {
success = FALSE;
ttbeep();
is_cpush(SRCH_ACCM);
}
} else
is_cpush(SRCH_ACCM);
is_prompt(dir, FALSE, success);
}
}
}
is_cpush(cmd) register int cmd; {
if (++cip >= NSRCH)
cip = 0;
cmds[cip].s_code = cmd;
}
is_lpush() {
register int ctp;
ctp = cip+1;
if (ctp >= NSRCH)
ctp = 0;
cmds[ctp].s_code = SRCH_NOPR;
cmds[ctp].s_doto = curwp->w_doto;
cmds[ctp].s_dotp = curwp->w_dotp;
}
is_pop() {
if (cmds[cip].s_code != SRCH_NOPR) {
curwp->w_doto = cmds[cip].s_doto;
curwp->w_dotp = cmds[cip].s_dotp;
curwp->w_flag |= WFMOVE;
cmds[cip].s_code = SRCH_NOPR;
}
if (--cip <= 0)
cip = NSRCH-1;
}
is_peek() {
return cmds[cip].s_code;
}
is_undo(pptr, dir) register int *pptr; register int *dir; {
register int redo = FALSE ;
switch (cmds[cip].s_code) {
case SRCH_BEGIN:
case SRCH_NOPR:
*pptr = -1;
case SRCH_MARK:
break;
case SRCH_FORW:
*dir = SRCH_BACK;
redo = TRUE;
break;
case SRCH_BACK:
*dir = SRCH_FORW;
redo = TRUE;
break;
case SRCH_ACCM:
default:
*pptr -= 1;
if (*pptr < 0)
*pptr = 0;
pat[*pptr] = '\0';
break;
}
is_pop();
if (redo) return is_undo(pptr, dir);
return (TRUE);
}
is_find(dir) register int dir; {
register int plen, odoto;
register LINE *odotp ;
odoto = curwp->w_doto;
odotp = curwp->w_dotp;
plen = strlen(pat);
if (plen != 0) {
if (dir==SRCH_FORW) {
(VOID) backchar(TRUE, plen, KRANDOM);
if (forwsrch() == FALSE) {
curwp->w_doto = odoto;
curwp->w_dotp = odotp;
return (FALSE);
}
return (TRUE);
}
if (dir==SRCH_BACK) {
(VOID) forwchar(TRUE, plen, KRANDOM);
if (backsrch() == FALSE) {
curwp->w_doto = odoto;
curwp->w_dotp = odotp;
return (FALSE);
}
return (TRUE);
}
ewprintf("bad call to is_find");
return FALSE;
}
return (FALSE);
}
/*
* If called with "dir" not one of SRCH_FORW
* or SRCH_BACK, this routine used to print an error
* message. It also used to return TRUE or FALSE,
* depending on if it liked the "dir". However, none
* of the callers looked at the status, so I just
* made the checking vanish.
*/
is_prompt(dir, flag, success) {
VOID is_dspl();
if (dir == SRCH_FORW) {
if (success != FALSE)
is_dspl("I-search", flag);
else
is_dspl("Failing I-search", flag);
} else if (dir == SRCH_BACK) {
if (success != FALSE)
is_dspl("I-search backward", flag);
else
is_dspl("Failing I-search backward", flag);
} else ewprintf("Broken call to is_prompt");
}
/*
* Prompt writing routine for the incremental search.
* The "prompt" is just a string. The "flag" determines
* whether pat should be printed.
*/
VOID
is_dspl(prompt, flag) char *prompt; {
if (kbdmop != NULL) return;
if (flag != FALSE)
ewprintf("%s: ", prompt);
else
ewprintf("%s: %s", prompt, pat);
}
/*
* Query Replace.
* Replace strings selectively. Does a search and replace operation.
*/
/*ARGSUSED*/
queryrepl(f, n, k) {
register int s;
register int rcnt = 0; /* Replacements made so far */
register int plen; /* length of found string */
char news[NPAT]; /* replacement string */
if ((s=readpattern("Query replace")) != TRUE)
return (s);
if ((s=ereply("Query replace %s with: ",news, NPAT, pat)) == ABORT)
return (s);
if (s == FALSE)
news[0] = '\0';
if (kbdmop == NULL) ewprintf("Query replacing %s with %s:", pat, news);
plen = strlen(pat);
/*
* Search forward repeatedly, checking each time whether to insert
* or not. The "!" case makes the check always true, so it gets put
* into a tighter loop for efficiency.
*/
while (forwsrch() == TRUE) {
retry:
update();
switch (getkey(KQUOTE)) {
case ' ':
if (lreplace((RSIZE) plen, news, f) == FALSE)
return (FALSE);
rcnt++;
break;
case '.':
if (lreplace((RSIZE) plen, news, f) == FALSE)
return (FALSE);
rcnt++;
goto stopsearch;
case CCHR('G'): /* ^G or ESC */
(VOID) ctrlg(FALSE, 0, KRANDOM);
case 033:
goto stopsearch;
case '!':
do {
if (lreplace((RSIZE) plen, news, f) == FALSE)
return (FALSE);
rcnt++;
} while (forwsrch() == TRUE);
goto stopsearch;
case 0x7F: /* To not replace */
break;
default:
ewprintf("<SP> replace, [.] rep-end, <DEL> don't, [!] repl rest <ESC> quit");
goto retry;
}
}
stopsearch:
curwp->w_flag |= WFHARD;
update();
if (kbdmop == NULL) {
if (rcnt == 0)
ewprintf("(No replacements done)");
else if (rcnt == 1)
ewprintf("(1 replacement done)");
else
ewprintf("(%d replacements done)", rcnt);
}
return TRUE;
}
/*
* This routine does the real work of a
* forward search. The pattern is sitting in the external
* variable "pat". If found, dot is updated, the window system
* is notified of the change, and TRUE is returned. If the
* string isn't found, FALSE is returned.
*/
forwsrch() {
register LINE *clp;
register int cbo;
register LINE *tlp;
register int tbo;
register char *pp;
register int c;
clp = curwp->w_dotp;
cbo = curwp->w_doto;
while (clp != curbp->b_linep) {
if (cbo == llength(clp)) {
clp = lforw(clp);
cbo = 0;
c = SEOL;
} else
c = lgetc(clp, cbo++);
if (eq(c, pat[0]) != FALSE) {
tlp = clp;
tbo = cbo;
pp = &pat[1];
while (*pp != 0) {
if (tlp == curbp->b_linep)
goto fail;
if (tbo == llength(tlp)) {
tlp = lforw(tlp);
if (tlp == curbp->b_linep)
goto fail;
tbo = 0;
c = SEOL;
} else
c = lgetc(tlp, tbo++);
if (eq(c, *pp++) == FALSE)
goto fail;
}
curwp->w_dotp = tlp;
curwp->w_doto = tbo;
curwp->w_flag |= WFMOVE;
return (TRUE);
}
fail: ;
}
return (FALSE);
}
/*
* This routine does the real work of a
* backward search. The pattern is sitting in the external
* variable "pat". If found, dot is updated, the window system
* is notified of the change, and TRUE is returned. If the
* string isn't found, FALSE is returned.
*/
backsrch() {
register LINE *clp;
register int cbo;
register LINE *tlp;
register int tbo;
register int c;
register char *epp;
register char *pp;
for (epp = &pat[0]; epp[1] != 0; ++epp)
;
clp = curwp->w_dotp;
cbo = curwp->w_doto;
for (;;) {
if (cbo == 0) {
clp = lback(clp);
if (clp == curbp->b_linep)
return (FALSE);
cbo = llength(clp)+1;
}
if (--cbo == llength(clp))
c = SEOL;
else
c = lgetc(clp,cbo);
if (eq(c, *epp) != FALSE) {
tlp = clp;
tbo = cbo;
pp = epp;
while (pp != &pat[0]) {
if (tbo == 0) {
tlp = lback(tlp);
if (tlp == curbp->b_linep)
goto fail;
tbo = llength(tlp)+1;
}
if (--tbo == llength(tlp))
c = SEOL;
else
c = lgetc(tlp,tbo);
if (eq(c, *--pp) == FALSE)
goto fail;
}
curwp->w_dotp = tlp;
curwp->w_doto = tbo;
curwp->w_flag |= WFMOVE;
return (TRUE);
}
fail: ;
}
}
/*
* Compare two characters.
* The "bc" comes from the buffer.
* It has its case folded out. The
* "pc" is from the pattern.
*/
eq(bc, pc) {
register int ibc;
register int ipc;
ibc = bc & 0xFF;
ipc = pc & 0xFF;
if (ISLOWER(ibc) != FALSE)
ibc = TOUPPER(ibc);
if (ISLOWER(ipc) != FALSE)
ipc = TOUPPER(ipc);
if (ibc == ipc)
return (TRUE);
return (FALSE);
}
/*
* Read a pattern.
* Stash it in the external variable "pat". The "pat" is
* not updated if the user types in an empty line. If the user typed
* an empty line, and there is no old pattern, it is an error.
* Display the old pattern, in the style of Jeff Lomicka. There is
* some do-it-yourself control expansion.
*/
readpattern(prompt) char *prompt; {
register int s;
char tpat[NPAT];
if (tpat[0] == '\0') s = ereply("%s: ", tpat, NPAT, prompt);
else s = ereply("%s: (default %s) ", tpat, NPAT, prompt, pat);
if (s == TRUE) /* Specified */
(VOID) strcpy(pat, tpat);
else if (s==FALSE && pat[0]!=0) /* CR, but old one */
s = TRUE;
return (s);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'symbol.c'
then
echo shar: will not over-write existing file "'symbol.c'"
else
cat << \SHAR_EOF > 'symbol.c'
/*
* Symbol tables, and keymap setup.
* The terminal specific parts of building the
* keymap has been moved to a better place.
*/
#include "def.h"
#ifdef HASH
Since you're seeing this, you must have defined HASH to try and get the
hashing code back. You're getting an error because I (mwm at ucbvax) want you
to read this.
With the change in function completion, there is at least one linear search
through the function list for every hash lookup (ignoring the startup code).
Given that there are probably actually MANY more linear searches for
completion than fullname lookups, some structure other than a hash table is
better suited to this purpose. I suggest trying sorting the lists for more
speed, then going to a binary search tree, and finally going to a trie.
#endif HASH
/*
* Defined here so to collect the #ifdef MEYN config stuff in one file
* If you set either MINDENT or MFILL, then you need to change the bindings
* in this file to match: KCTRL|'M' -> newline-and-indent and KCTRL|'J' ->
* insert-newline for MINDENT, and ' ' -> insert-with-wrap for MFILL.
* MEYN is used for compile-time customization of the system for micros.
*/
#ifndef MEYN
int mode = 0; /* All modes off */
#else
int mode = MBSMAP|MINDENT;
#endif
/*
* Defined by "main.c".
*/
extern int ctrlg(); /* Abort out of things */
extern int quit(); /* Quit */
extern int ctlxlp(); /* Begin macro */
extern int ctlxrp(); /* End macro */
extern int ctlxe(); /* Execute macro */
extern int showversion(); /* Show version numbers, etc. */
/*
* Defined by "search.c".
*/
extern int forwsearch(); /* Search forward */
extern int backsearch(); /* Search backwards */
extern int searchagain(); /* Repeat last search command */
extern int forwisearch(); /* Incremental search forward */
extern int backisearch(); /* Incremental search backwards */
extern int queryrepl(); /* Query replace */
/*
* Defined by "basic.c".
*/
extern int gotobol(); /* Move to start of line */
extern int backchar(); /* Move backward by characters */
extern int gotoeol(); /* Move to end of line */
extern int forwchar(); /* Move forward by characters */
extern int gotobob(); /* Move to start of buffer */
extern int gotoeob(); /* Move to end of buffer */
extern int forwline(); /* Move forward by lines */
extern int backline(); /* Move backward by lines */
extern int forwpage(); /* Move forward by pages */
extern int backpage(); /* Move backward by pages */
extern int pagenext(); /* Page forward next window */
extern int setmark(); /* Set mark */
extern int swapmark(); /* Swap "." and mark */
extern int gotoline(); /* Go to a specified line. */
/*
* Defined by "buffer.c".
*/
extern int listbuffers(); /* Display list of buffers */
extern int usebuffer(); /* Switch a window to a buffer */
extern int poptobuffer(); /* Other window to a buffer */
extern int killbuffer(); /* Make a buffer go away. */
extern int savebuffers(); /* Save unmodified buffers */
extern int bufferinsert(); /* Insert buffer into another */
extern int notmodified(); /* Reset modification flag */
#ifdef DIRLIST
/*
* Defined by "dirlist.c".
*/
extern int dirlist(); /* Directory list. */
#endif
/*
* Defined by "file.c".
*/
extern int filevisit(); /* Get a file, read write */
extern int poptofile(); /* Get a file, other window */
extern int filewrite(); /* Write a file */
extern int filesave(); /* Save current file */
extern int fileinsert(); /* Insert file into buffer */
/*
* Defined by "match.c"
*/
extern int blinkparen(); /* Fake blink-matching-paren var */
extern int showmatch(); /* Hack to show matching paren */
/*
* Defined by "random.c".
*/
extern int selfinsert(); /* Insert character */
extern int showcpos(); /* Show the cursor position */
extern int twiddle(); /* Twiddle characters */
extern int quote(); /* Insert literal */
extern int openline(); /* Open up a blank line */
extern int newline(); /* Insert CR-LF */
extern int deblank(); /* Delete blank lines */
extern int delwhite(); /* Delete extra whitespace */
extern int indent(); /* Insert CR-LF, then indent */
extern int forwdel(); /* Forward delete */
extern int backdel(); /* Backward delete in */
extern int killline(); /* Kill forward */
extern int yank(); /* Yank back from killbuffer. */
extern int bsmapmode(); /* set bsmap mode */
extern int flowmode(); /* set flow mode */
extern int indentmode(); /* set auto-indent mode */
extern int fillmode(); /* set word-wrap mode */
/*
* Defined by "region.c".
*/
extern int killregion(); /* Kill region. */
extern int copyregion(); /* Copy region to kill buffer. */
extern int lowerregion(); /* Lower case region. */
extern int upperregion(); /* Upper case region. */
#ifdef PREFIXREGION
extern int prefixregion(); /* Prefix all lines in region */
extern int setprefix(); /* Set line prefix string */
#endif
/*
* Defined by "spawn.c".
*/
extern int spawncli(); /* Run CLI in a subjob. */
#ifdef VMS
extern int attachtoparent(); /* Attach to parent process */
#endif
/*
* Defined by "window.c".
*/
extern int reposition(); /* Reposition window */
extern int refresh(); /* Refresh the screen */
extern int nextwind(); /* Move to the next window */
extern int prevwind(); /* Move to the previous window */
extern int onlywind(); /* Make current window only one */
extern int splitwind(); /* Split current window */
extern int delwind(); /* Delete current window */
extern int enlargewind(); /* Enlarge display window. */
extern int shrinkwind(); /* Shrink window. */
/*
* Defined by "word.c".
*/
extern int backword(); /* Backup by words */
extern int forwword(); /* Advance by words */
extern int upperword(); /* Upper case word. */
extern int lowerword(); /* Lower case word. */
extern int capword(); /* Initial capitalize word. */
extern int delfword(); /* Delete forward word. */
extern int delbword(); /* Delete backward word. */
/*
* Defined by "extend.c".
*/
extern int extend(); /* Extended commands. */
extern int desckey(); /* Help key. */
extern int bindtokey(); /* Modify key bindings. */
extern int unsetkey(); /* Unbind a key. */
extern int wallchart(); /* Make wall chart. */
#ifdef STARTUP
extern int evalexpr(); /* Extended commands (again) */
extern int evalbuffer(); /* Evaluate current buffer */
extern int evalfile(); /* Evaluate a file */
#endif
/*
* defined by "paragraph.c" - the paragraph justification code.
*/
extern int gotobop(); /* Move to start of paragraph. */
extern int gotoeop(); /* Move to end of paragraph. */
extern int fillpara(); /* Justify a paragraph. */
extern int killpara(); /* Delete a paragraph. */
extern int setfillcol(); /* Set fill column for justify. */
extern int fillword(); /* Insert char with word wrap. */
/*
* defined by prefix.c
*/
extern int help(); /* Parse help key. */
extern int ctlx4hack(); /* Parse a pop-to key. */
typedef struct {
KEY k_key; /* Key to bind. */
int (*k_funcp)(); /* Function. */
char *k_name; /* Function name string. */
} KEYTAB;
/*
* Default key binding table. This contains
* the function names, the symbol table name, and (possibly)
* a key binding for the builtin functions. There are no
* bindings for C-U or C-X. These are done with special
* code, but should be done normally.
*/
KEYTAB key[] = {
#ifdef MEYN /* Add meyer's peculiar bindings */
KCTRL|'J', newline, "insert-newline",
KCTRL|'M', indent, "newline-and-indent",
KCTLX|'N', nextwind, "next-window",
KCTLX|'P', prevwind, "previous-window",
KMETA|KCTRL|'C',quit, "save-buffers-kill-emacs",
KMETA|KCTRL|'L',refresh, "redraw-display",
KMETA|'G', gotoline, "goto-line",
KMETA|'J', fillpara, "fill-paragraph",
KMETA|'Q', queryrepl, "query-replace",
#endif
KCTRL|'@', setmark, "set-mark-command",
KCTRL|'A', gotobol, "beginning-of-line",
KCTRL|'B', backchar, "backward-char",
KCTRL|'D', forwdel, "delete-char",
KCTRL|'E', gotoeol, "end-of-line",
KCTRL|'F', forwchar, "forward-char",
KCTRL|'G', ctrlg, "keyboard-quit",
KCTRL|'H', help, "help",
KCTRL|'I', selfinsert, "self-insert-command",
#ifndef MEYN
KCTRL|'J', indent, "newline-and-indent",
#endif
KCTRL|'L', reposition, "recenter",
KCTRL|'K', killline, "kill-line",
#ifndef MEYN
KCTRL|'M', newline, "insert-newline",
#endif
KCTRL|'N', forwline, "next-line",
KCTRL|'O', openline, "open-line",
KCTRL|'P', backline, "previous-line",
KCTRL|'Q', quote, "quoted-insert",
KCTRL|'R', backisearch, "isearch-backward",
KCTRL|'S', forwisearch, "isearch-forward",
KCTRL|'T', twiddle, "transpose-chars",
KCTRL|'V', forwpage, "scroll-up",
KCTRL|'W', killregion, "kill-region",
KCTRL|'Y', yank, "yank",
#ifdef VMS
KCTRL|'Z', attachtoparent, "suspend-emacs",
#else
KCTRL|'Z', spawncli, "suspend-emacs",
#endif
KCTLX|KCTRL|'B',listbuffers, "list-buffers",
#ifndef MEYN
KCTLX|KCTRL|'C',quit, "save-buffers-kill-emacs",
#endif
#ifdef DIRLIST
KCTLX|KCTRL|'D',dirlist, "display-directory",
#endif
KCTLX|KCTRL|'F',filevisit, "find-file",
KCTLX|KCTRL|'L',lowerregion, "downcase-region",
KCTLX|KCTRL|'O',deblank, "delete-blank-lines",
KCTLX|KCTRL|'S',filesave, "save-buffer",
KCTLX|KCTRL|'U',upperregion, "upcase-region",
KCTLX|KCTRL|'W',filewrite, "write-file",
KCTLX|KCTRL|'X',swapmark, "exchange-point-and-mark",
KCTLX|'=', showcpos, "what-cursor-position",
KCTLX|'(', ctlxlp, "start-kbd-macro",
KCTLX|')', ctlxrp, "end-kbd-macro",
KCTLX|'^', enlargewind, "enlarge-window",
KCTLX|'0', delwind, "delete-window",
KCTLX|'1', onlywind, "delete-other-windows",
KCTLX|'2', splitwind, "split-window-vertically",
KCTLX|'4', ctlx4hack, "ctrlx-four-hack",
KCTLX|'B', usebuffer, "switch-to-buffer",
KCTLX|'E', ctlxe, "call-last-kbd-macro",
KCTLX|'F', setfillcol, "set-fill-column",
KCTLX|'I', fileinsert, "insert-file",
KCTLX|'K', killbuffer, "kill-buffer",
KCTLX|'S', savebuffers, "save-some-buffers",
#ifndef MEYN
KCTLX|'O', nextwind, "next-window",
KMETA|'%', queryrepl, "query-replace",
#endif
KMETA|KCTRL|'V',pagenext, "scroll-other-window",
KMETA|'>', gotoeob, "end-of-buffer",
KMETA|'<', gotobob, "beginning-of-buffer",
KMETA|'[', gotobop, "backward-paragraph",
KMETA|']', gotoeop, "forward-paragraph",
KMETA|' ', delwhite, "just-one-space",
KMETA|'B', backword, "backward-word",
KMETA|'C', capword, "capitalize-word",
KMETA|'D', delfword, "kill-word",
KMETA|'F', forwword, "forward-word",
KMETA|'L', lowerword, "downcase-word",
#ifndef MEYN
KMETA|'Q', fillpara, "fill-paragraph",
#endif
KMETA|'R', backsearch, "search-backward",
KMETA|'S', forwsearch, "search-forward",
KMETA|'U', upperword, "upcase-word",
KMETA|'V', backpage, "scroll-down",
KMETA|'W', copyregion, "copy-region-as-kill",
KMETA|'X', extend, "execute-extended-command",
KMETA|'~', notmodified, "not-modified",
#ifndef MEYN
-1, prevwind, "previous-window",
-1, refresh, "redraw-display",
-1, gotoline, "goto-line",
#endif
#ifdef STARTUP
-1, evalexpr, "eval-expression",
-1, evalbuffer, "eval-current-buffer",
-1, evalfile, "load",
#endif
-1, bsmapmode, "bsmap-mode",
-1, flowmode, "flow-mode",
-1, indentmode, "auto-indent-mode",
-1, fillmode, "auto-fill-mode",
-1, fillword, "insert-with-wrap",
-1, shrinkwind, "shrink-window",
-1, searchagain, "search-again",
-1, unsetkey, "global-unset-key",
-1, bindtokey, "global-set-key",
-1, killpara, "kill-paragraph",
-1, showversion, "emacs-version",
-1, blinkparen, "blink-matching-paren",
-1, showmatch, "blink-matching-paren-hack",
-1, bufferinsert, "insert-buffer",
#ifdef VMS
-1, spawncli, "push-to-dcl",
#endif
#ifdef PREFIXREGION
-1, prefixregion, "prefix-region",
-1, setprefix, "set-prefix-string",
#endif
/* You can actually get to these with keystrokes. See prefix.c */
-1, poptobuffer, "switch-to-buffer-other-window",
-1, poptofile, "find-file-other-window",
-1, desckey, "describe-key-briefly",
-1, wallchart, "describe-bindings",
};
#define NKEY (sizeof(key) / sizeof(key[0]))
/*
* Symbol table lookup.
* Return a pointer to the SYMBOL node, or NULL if
* the symbol is not found.
*/
SYMBOL *
symlookup(cp) register char *cp; {
register SYMBOL *sp;
#ifdef HASH
sp = symbol[symhash(cp)];
#else
sp = symbol[0];
#endif
while (sp != NULL) {
if (strcmp(cp, sp->s_name) == 0)
return (sp);
#ifdef HASH
if ((sp->s_flags&SFEND) != 0) break;
#endif
sp = sp->s_symp;
}
return (NULL);
}
#ifdef HASH
/*
* Take a string, and compute the symbol table
* bucket number. This is done by adding all of the characters
* together, and taking the sum mod NSHASH. The string probably
* should not contain any GR characters; if it does the "*cp"
* may get a nagative number on some machines, and the "%"
* will return a negative number!
*/
symhash(cp) register char *cp; {
register int c;
register int n;
n = 0;
while ((c = *cp++) != 0)
n += c;
return (n % NSHASH);
}
#endif
/*
* Build initial keymap. The funny keys
* (commands, odd control characters) are mapped using
* a big table and calls to "keyadd". The printing characters
* are done with some do-it-yourself handwaving. The terminal
* specific keymap initialization code is called at the
* very end to finish up. All errors are fatal.
*/
keymapinit() {
register SYMBOL *sp;
register KEYTAB *kp;
register int i;
for (i=0; i<NKEYS; ++i)
binding[i] = NULL;
for (kp = &key[0]; kp < &key[NKEY]; ++kp)
keyadd(kp->k_key, kp->k_funcp, kp->k_name);
keydup((KEY) (KCTLX|KCTRL|'G'), "keyboard-quit");
keydup((KEY) (KMETA|KCTRL|'G'), "keyboard-quit");
keyadd((KEY) (KMETA|0x7F), delbword,
"backward-kill-word");
keyadd((KEY) 0x7F, backdel, "backward-delete-char");
/*
* add duplicates (GNU-stuff)
*/
keydup((KEY) (KCTLX|KCTRL|'Z'), "suspend-emacs");
/*
* Should be bound by "tab" already.
*/
if ((sp=symlookup("self-insert-command")) == NULL)
panic("no self-insert-command in keymapinit");
for (i=0x20; i<0x7F; ++i) {
if (binding[i] != NULL)
panic("nonull binding in keymapinit");
binding[i] = sp;
}
ttykeymapinit();
#ifdef HASH
/* Link up the symbol table entries */
for (sp = symbol[i = 0]; i < NSHASH-1; sp = sp->s_symp)
if (sp->s_symp == NULL) sp->s_symp = symbol[++i];
#endif
}
/*
* Create a new builtin function "name"
* with function "funcp". If the "new" is a real
* key, bind it as a side effect. All errors
* are fatal.
*/
keyadd(new, funcp, name) register KEY new; int (*funcp)(); char *name; {
register SYMBOL *sp;
#ifdef HASH
register int hash;
#endif
if ((sp=(SYMBOL *)malloc(sizeof(SYMBOL))) == NULL)
panic("No memory");
#ifdef HASH
hash = symhash(name);
if (symbol[hash] == NULL) sp->s_flags |= SFEND;
sp->s_symp = symbol[hash];
symbol[hash] = sp;
#else
sp->s_symp = symbol[0];
symbol[0] = sp;
#endif
sp->s_name = name;
sp->s_funcp = funcp;
if (new >= 0) { /* Bind this key. */
if (binding[new] != NULL)
panic("rebinding old symbol");
binding[new] = sp;
}
}
/*
* Bind key "new" to the existing
* routine "name". If the name cannot be found,
* or the key is already bound, abort.
*/
keydup(new, name) register KEY new; char *name; {
register SYMBOL *sp;
if (binding[new]!=NULL || (sp=symlookup(name))==NULL) {
#ifdef KEYDUP_ERROR
fprintf (stderr, "keydup: binding[%d] = %x",
new, binding[new]);
fprintf (stderr, " and symlookup(%s) == %x\n", name, sp);
#endif
panic("keydup");
}
binding[new] = sp;
}
SHAR_EOF
fi # end of overwriting check
if test -f 'window.c'
then
echo shar: will not over-write existing file "'window.c'"
else
cat << \SHAR_EOF > 'window.c'
/*
* Window handling.
*/
#include "def.h"
/*
* Reposition dot in the current
* window to line "n". If the argument is
* positive, it is that line. If it is negative it
* is that line from the bottom. If it is 0 the window
* is centered (this is what the standard redisplay code
* does). If GOSREC is undefined, default is 0, so it acts like GNU.
* If GOSREC is defined, with no argument it defaults to 1
* and works like in Gosling.
*/
/*ARGSUSED*/
reposition(f, n, k) {
#ifndef GOSREC
curwp->w_force = ((f == FALSE) ? 0 : n) ;
#else
curwp->w_force = n;
#endif
curwp->w_flag |= WFFORCE;
sgarbf = TRUE;
return (TRUE);
}
/*
* Refresh the display. A call is made to the
* "ttresize" entry in the terminal handler, which tries
* to reset "nrow" and "ncol". They will, however, never
* be set outside of the NROW or NCOL range. If the display
* changed size, arrange that everything is redone, then
* call "update" to fix the display. We do this so the
* new size can be displayed. In the normal case the
* call to "update" in "main.c" refreshes the screen,
* and all of the windows need not be recomputed.
* Note that when you get to the "display unusable"
* message, the screen will be messed up. If you make
* the window bigger again, and send another command,
* everything will get fixed!
*/
/*ARGSUSED*/
refresh(f, n, k) {
register WINDOW *wp;
register int oldnrow;
register int oldncol;
oldnrow = nrow;
oldncol = ncol;
ttresize();
if (nrow!=oldnrow || ncol!=oldncol) {
wp = wheadp; /* Find last. */
while (wp->w_wndp != NULL)
wp = wp->w_wndp;
if (nrow < wp->w_toprow+3) { /* Check if too small. */
ewprintf("Display unusable");
return (FALSE);
}
wp->w_ntrows = nrow-wp->w_toprow-2;
sgarbf = TRUE;
update();
if (kbdmop == NULL) ewprintf("New size %d by %d", nrow, ncol);
} else
sgarbf = TRUE;
return (TRUE);
}
/*
* The command to make the next
* window (next => down the screen)
* the current window. There are no real
* errors, although the command does
* nothing if there is only 1 window on
* the screen.
*/
/*ARGSUSED*/
nextwind(f, n, k) {
register WINDOW *wp;
if ((wp=curwp->w_wndp) == NULL)
wp = wheadp;
curwp = wp;
curbp = wp->w_bufp;
return (TRUE);
}
/*
* This command makes the previous
* window (previous => up the screen) the
* current window. There arn't any errors,
* although the command does not do a lot
* if there is 1 window.
*/
/*ARGSUSED*/
prevwind(f, n, k) {
register WINDOW *wp1;
register WINDOW *wp2;
wp1 = wheadp;
wp2 = curwp;
if (wp1 == wp2)
wp2 = NULL;
while (wp1->w_wndp != wp2)
wp1 = wp1->w_wndp;
curwp = wp1;
curbp = wp1->w_bufp;
return (TRUE);
}
/*
* This command makes the current
* window the only window on the screen.
* Try to set the framing
* so that "." does not have to move on
* the display. Some care has to be taken
* to keep the values of dot and mark
* in the buffer structures right if the
* distruction of a window makes a buffer
* become undisplayed.
*/
/*ARGSUSED*/
onlywind(f, n, k) {
register WINDOW *wp;
register LINE *lp;
register int i;
while (wheadp != curwp) {
wp = wheadp;
wheadp = wp->w_wndp;
if (--wp->w_bufp->b_nwnd == 0) {
wp->w_bufp->b_dotp = wp->w_dotp;
wp->w_bufp->b_doto = wp->w_doto;
wp->w_bufp->b_markp = wp->w_markp;
wp->w_bufp->b_marko = wp->w_marko;
}
free((char *) wp);
}
while (curwp->w_wndp != NULL) {
wp = curwp->w_wndp;
curwp->w_wndp = wp->w_wndp;
if (--wp->w_bufp->b_nwnd == 0) {
wp->w_bufp->b_dotp = wp->w_dotp;
wp->w_bufp->b_doto = wp->w_doto;
wp->w_bufp->b_markp = wp->w_markp;
wp->w_bufp->b_marko = wp->w_marko;
}
free((char *) wp);
}
lp = curwp->w_linep;
i = curwp->w_toprow;
while (i!=0 && lback(lp)!=curbp->b_linep) {
--i;
lp = lback(lp);
}
curwp->w_toprow = 0;
curwp->w_ntrows = nrow-2; /* 2 = mode, echo. */
curwp->w_linep = lp;
curwp->w_flag |= WFMODE|WFHARD;
return (TRUE);
}
/*
* Split the current window. A window
* smaller than 3 lines cannot be split.
* The only other error that is possible is
* a "malloc" failure allocating the structure
* for the new window.
*/
/*ARGSUSED*/
splitwind(f, n, k) {
register WINDOW *wp;
register LINE *lp;
register int ntru;
register int ntrd;
int ntrl;
WINDOW *wp1, *wp2;
if (curwp->w_ntrows < 3) {
ewprintf("Cannot split a %d line window", curwp->w_ntrows);
return (FALSE);
}
if ((wp = (WINDOW *)malloc(sizeof(WINDOW))) == NULL) {
ewprintf("Can't get %d", sizeof(WINDOW));
return (FALSE);
}
++curbp->b_nwnd; /* Displayed twice. */
wp->w_bufp = curbp;
wp->w_dotp = curwp->w_dotp;
wp->w_doto = curwp->w_doto;
wp->w_markp = curwp->w_markp;
wp->w_marko = curwp->w_marko;
wp->w_flag = 0;
wp->w_force = 0;
ntru = (curwp->w_ntrows-1) / 2; /* Upper size */
ntrl = (curwp->w_ntrows-1) - ntru; /* Lower size */
lp = curwp->w_linep;
ntrd = 0;
while (lp != curwp->w_dotp) {
++ntrd;
lp = lforw(lp);
}
lp = curwp->w_linep;
if (ntrd <= ntru) { /* Old is upper window. */
if (ntrd == ntru) /* Hit mode line. */
lp = lforw(lp);
curwp->w_ntrows = ntru;
wp->w_wndp = curwp->w_wndp;
curwp->w_wndp = wp;
wp->w_toprow = curwp->w_toprow+ntru+1;
wp->w_ntrows = ntrl;
} else { /* Old is lower window */
wp1 = NULL;
wp2 = wheadp;
while (wp2 != curwp) {
wp1 = wp2;
wp2 = wp2->w_wndp;
}
if (wp1 == NULL)
wheadp = wp;
else
wp1->w_wndp = wp;
wp->w_wndp = curwp;
wp->w_toprow = curwp->w_toprow;
wp->w_ntrows = ntru;
++ntru; /* Mode line. */
curwp->w_toprow += ntru;
curwp->w_ntrows = ntrl;
while (ntru--)
lp = lforw(lp);
}
curwp->w_linep = lp; /* Adjust the top lines */
wp->w_linep = lp; /* if necessary. */
curwp->w_flag |= WFMODE|WFHARD;
wp->w_flag |= WFMODE|WFHARD;
return (TRUE);
}
/*
* Enlarge the current window.
* Find the window that loses space. Make
* sure it is big enough. If so, hack the window
* descriptions, and ask redisplay to do all the
* hard work. You don't just set "force reframe"
* because dot would move.
*/
/*ARGSUSED*/
enlargewind(f, n, k) {
register WINDOW *adjwp;
register LINE *lp;
register int i;
if (n < 0)
return (shrinkwind(f, -n, KRANDOM));
if (wheadp->w_wndp == NULL) {
ewprintf("Only one window");
return (FALSE);
}
if ((adjwp=curwp->w_wndp) == NULL) {
adjwp = wheadp;
while (adjwp->w_wndp != curwp)
adjwp = adjwp->w_wndp;
}
if (adjwp->w_ntrows <= n) {
ewprintf("Impossible change");
return (FALSE);
}
if (curwp->w_wndp == adjwp) { /* Shrink below. */
lp = adjwp->w_linep;
for (i=0; i<n && lp!=adjwp->w_bufp->b_linep; ++i)
lp = lforw(lp);
adjwp->w_linep = lp;
adjwp->w_toprow += n;
} else { /* Shrink above. */
lp = curwp->w_linep;
for (i=0; i<n && lback(lp)!=curbp->b_linep; ++i)
lp = lback(lp);
curwp->w_linep = lp;
curwp->w_toprow -= n;
}
curwp->w_ntrows += n;
adjwp->w_ntrows -= n;
curwp->w_flag |= WFMODE|WFHARD;
adjwp->w_flag |= WFMODE|WFHARD;
return (TRUE);
}
/*
* Shrink the current window.
* Find the window that gains space. Hack at
* the window descriptions. Ask the redisplay to
* do all the hard work.
*/
shrinkwind(f, n, k) {
register WINDOW *adjwp;
register LINE *lp;
register int i;
if (n < 0)
return (enlargewind(f, -n, KRANDOM));
if (wheadp->w_wndp == NULL) {
ewprintf("Only one window");
return (FALSE);
}
/*
* Bit of flakiness - KRANDOM means it was an internal call, and
* to be trusted implicitly about sizes.
*/
if (k != KRANDOM && curwp->w_ntrows <= n) {
ewprintf("Impossible change");
return (FALSE);
}
if ((adjwp=curwp->w_wndp) == NULL) {
adjwp = wheadp;
while (adjwp->w_wndp != curwp)
adjwp = adjwp->w_wndp;
}
if (curwp->w_wndp == adjwp) { /* Grow below. */
lp = adjwp->w_linep;
for (i=0; i<n && lback(lp)!=adjwp->w_bufp->b_linep; ++i)
lp = lback(lp);
adjwp->w_linep = lp;
adjwp->w_toprow -= n;
} else { /* Grow above. */
lp = curwp->w_linep;
for (i=0; i<n && lp!=curbp->b_linep; ++i)
lp = lforw(lp);
curwp->w_linep = lp;
curwp->w_toprow += n;
}
curwp->w_ntrows -= n;
adjwp->w_ntrows += n;
curwp->w_flag |= WFMODE|WFHARD;
adjwp->w_flag |= WFMODE|WFHARD;
return (TRUE);
}
/*
* Delete current window. Call shrink-window to do the screen
* updating, then throw away the window.
*/
/*ARGSUSED*/
delwind(f, n, k) {
register WINDOW *wp, *nwp;
wp = curwp; /* Cheap... */
/* shrinkwind returning false means only one window... */
if (shrinkwind(FALSE, wp->w_ntrows + 1, KRANDOM) == FALSE)
return FALSE;
if (--wp->w_bufp->b_nwnd == 0) {
wp->w_bufp->b_dotp = wp->w_dotp;
wp->w_bufp->b_doto = wp->w_doto;
wp->w_bufp->b_markp = wp->w_markp;
wp->w_bufp->b_marko = wp->w_marko;
}
/* since shrinkwind did't crap out, we know we have a second window */
if (wp == wheadp) wheadp = curwp = wp->w_wndp;
else if ((curwp = wp->w_wndp) == NULL) curwp = wheadp;
curbp = curwp->w_bufp;
for (nwp = wheadp; nwp != NULL; nwp = nwp->w_wndp)
if (nwp->w_wndp == wp) {
nwp->w_wndp = wp->w_wndp;
break ;
}
free((char *) wp);
return TRUE;
}
/*
* Pick a window for a pop-up.
* Split the screen if there is only
* one window. Pick the uppermost window that
* isn't the current window. An LRU algorithm
* might be better. Return a pointer, or
* NULL on error.
*/
WINDOW *
wpopup() {
register WINDOW *wp;
if (wheadp->w_wndp == NULL
&& splitwind(FALSE, 0, KRANDOM) == FALSE)
return (NULL);
wp = wheadp; /* Find window to use */
while (wp!=NULL && wp==curwp)
wp = wp->w_wndp;
return (wp);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'tty/termcap/tty.c'
then
echo shar: will not over-write existing file "'tty/termcap/tty.c'"
else
cat << \SHAR_EOF > 'tty/termcap/tty.c'
/*
* Termcap/terminfo display driver
*
* Termcap is a terminal information database and routines to describe
* terminals on most UNIX systems. Many other systems have adopted
* this as a reasonable way to allow for widly varying and ever changing
* varieties of terminal types. This should be used where practical.
*/
/* Known problems:
* tputs is always called with the number of lines affected set to
* one. Therefore, padding may be insufficient on some sequences
* dispite termcap being set up correctly.
*
* If you have a terminal with no clear to end of screen and
* memory of lines below the ones visible on the screen, display
* will be wrong in some cases. I doubt that any such terminal
* was ever made, but I thought everyone with delete line would
* have clear to end of screen too...
*
* Code for terminals without clear to end of screen and/or clear
* to end of line has not been extensivly tested.
*
* Cost calculations are very rough. Costs of insert/delete line
* may be far from the truth. This is accentuated by display.c
* not knowing about multi-line insert/delete.
*
* Using scrolling region vs insert/delete line should probably
* be based on cost rather than the assuption that scrolling
* region operations look better.
*/
#include "def.h"
#define BEL 0x07 /* BEL character. */
#define LF 0x0A /* Line feed. */
extern int ttrow;
extern int ttcol;
extern int tttop;
extern int ttbot;
extern int tthue;
int tceeol; /* Costs are set later */
int tcinsl;
int tcdell;
static int insdel; /* Do we have both insert & delete line? */
char *tgetstr();
char *tgoto();
int ttputc();
#define TCAPSLEN 1024
char tcapbuf[TCAPSLEN];
/* PC, UP, and BC are used by termlib, so must be extern and have these
* names unless you have a non-standard termlib.
*/
int LI; /* standard # lines */
char PC,
*CM,
*CE,
*UP,
*BC,
*IM, /* insert mode */
*IC, /* insert a single space */
*EI, /* end insert mode */
*DC,
*AL, /* add line */
*DL, /* del line */
*pAL, /* parameterized add line */
*pDL, /* parameterized delete line */
*TI, /* term init -- start using cursor motion */
*TE, /* term end --- end using cursor motion */
*SO,
*SE,
*CD,
*CS, /* set scroll region */
*SR; /* back index (used with scroll region */
#ifdef XKEYS
char *K[NFKEYS], /* other function key codes */
*L[NFKEYS], /* labels for other functions keys */
*KS, *KE, /* enter keypad mode, exit keypad mode */
*KH, *KU, *KD, *KL, *KR; /* home, arrow keys */
#endif
int SG; /* number of glitches, 0 for invisable, -1 for none */
/* (yes virginia, there are terminals with invisible glitches) */
/*
* Initialize the terminal when the editor
* gets started up.
*/
static char tcbuf[1024];
ttinit() {
char *getenv();
char *t, *p, *tgetstr();
char *tv_stype;
#ifdef XKEYS
char kname[3], lname[3];
int i;
#endif
#ifdef VAXC
if ((tv_stype = trnlnm("TERM")) == NULL)
#else
if ((tv_stype = getenv("TERM")) == NULL)/* Don't want VAX C getenv() */
#endif
panic("Environment variable TERM not defined!");
if((tgetent(tcbuf, tv_stype)) != 1)
{
(VOID) strcpy(tcbuf, "Unknown terminal type ");
(VOID) strcat(tcbuf, tv_stype);
panic(tcbuf);
}
p = tcapbuf;
t = tgetstr("pc", &p);
if(t) PC = *t;
LI = tgetnum("li");
CD = tgetstr("cd", &p);
CM = tgetstr("cm", &p);
CE = tgetstr("ce", &p);
UP = tgetstr("up", &p);
BC = tgetstr("bc", &p);
IM = tgetstr("im", &p);
IC = tgetstr("ic", &p);
EI = tgetstr("ei", &p);
DC = tgetstr("dc", &p);
AL = tgetstr("al", &p);
DL = tgetstr("dl", &p);
pAL= tgetstr("AL", &p); /* parameterized insert and del. line */
pDL= tgetstr("DL", &p);
TI = tgetstr("ti", &p);
TE = tgetstr("te", &p);
SO = tgetstr("so", &p);
SE = tgetstr("se", &p);
CS = tgetstr("cs", &p); /* set scrolling region */
SR = tgetstr("sr", &p);
SG = tgetnum("sg"); /* standout glitch */
#ifdef XKEYS
/* get the 10 standard termcap keys */
strcpy(kname,"kx");
strcpy(lname,"lx");
for (i = 0; i < 10; i++) {
kname[1] = i + '0';
K[i] = tgetstr(kname, &p);
lname[1] = i + '0';
L[i] = tgetstr(lname, &p);
}
/* Hack to get another bunch */
strcpy(kname,"Kx");
strcpy(lname,"Lx");
for (i = 0; i < 10; i++) {
kname[1] = i + '0';
K[10 + i] = tgetstr(kname, &p);
lname[1] = i + '0';
L[10 + i] = tgetstr(lname, &p);
}
/* Get the rest of the sequences */
KS = tgetstr("ks", &p);
KE = tgetstr("ke", &p);
KH = tgetstr("kh", &p);
KU = tgetstr("ku", &p);
KD = tgetstr("kd", &p);
KL = tgetstr("kl", &p);
KR = tgetstr("kr", &p);
#endif
if(CM == NULL || UP == NULL)
panic("This terminal is to stupid to run MicroGnuEmacs\n");
ttresize(); /* set nrow & ncol */
/* watch out for empty capabilities (sure to be wrong) */
if (CE && !*CE) CE = NULL;
if (CS && !*CS) CS = NULL;
if (SR && !*SR) SR = NULL;
if (AL && !*AL) AL = NULL;
if (DL && !*DL) DL = NULL;
if (pAL && !*pAL) pAL = NULL;
if (pDL && !*pDL) pDL = NULL;
if (CD && !*CD) CD = NULL;
if(!CE) tceeol = ncol;
else tceeol = charcost(CE);
/* Estimate cost of inserting a line */
if (CS && SR) tcinsl = charcost(CS)*2 + charcost(SR);
else if (pAL) tcinsl = charcost(pAL);
else if (AL) tcinsl = charcost(AL);
else tcinsl = NROW * NCOL; /* make this cost high enough */
/* Estimate cost of deleting a line */
if (CS) tcdell = charcost(CS)*2 + 1;
else if (pDL) tcdell = charcost(pDL);
else if (DL) tcdell = charcost(DL);
else tcdell = NROW * NCOL; /* make this cost high enough */
/* Flag to indicate that we can both insert and delete lines */
insdel = (AL || pAL) && (DL || pDL);
if (p >= &tcapbuf[TCAPSLEN])
panic("Terminal description too big!\n");
if (TI && *TI) putpad (TI); /* init the term */
}
/*
* Clean up the terminal, in anticipation of
* a return to the command interpreter. This is a no-op
* on the ANSI display. On the SCALD display, it sets the
* window back to half screen scrolling. Perhaps it should
* query the display for the increment, and put it
* back to what it was.
*/
tttidy() {
if (TE && *TE) putpad (TE); /* set the term back to normal mode */
#ifdef XKEYS
ttykeymaptidy();
#endif
}
/*
* Move the cursor to the specified
* origin 0 row and column position. Try to
* optimize out extra moves; redisplay may
* have left the cursor in the right
* location last time!
*/
ttmove(row, col) {
char *tgoto();
if (ttrow!=row || ttcol!=col) {
putpad(tgoto(CM, col, row));
ttrow = row;
ttcol = col;
}
}
/*
* Erase to end of line.
*/
tteeol() {
if(CE) putpad(CE);
else {
register int i=ncol-ttcol;
while(i--) ttputc(" ");
ttrow = ttcol = HUGE;
}
}
/*
* Erase to end of page.
*/
tteeop() {
if(CD) putpad(CD);
else {
putpad(CE);
if (insdel) ttdell(ttrow + 1, LI, LI - ttrow - 1);
else { /* do it by hand */
register int line;
for (line = ttrow + 1; line <= LI; ++line) {
ttmove(line, 0);
tteeol();
}
}
ttrow = ttcol = HUGE;
}
}
/*
* Make a noise.
*/
ttbeep() {
ttputc(BEL);
ttflush();
}
/*
* Insert nchunk blank line(s) onto the
* screen, scrolling the last line on the
* screen off the bottom. Use the scrolling
* region if possible for a smoother display.
* If no scrolling region, use a set
* of insert and delete line sequences
*/
ttinsl(row, bot, nchunk) {
register int i;
if (row == bot) { /* Case of one line insert is */
ttmove(row, 0); /* special */
tteeol();
return;
}
if (CS && SR) { /* Use scroll region and back index */
ttwindow(row,bot);
ttmove(row, 0);
while (nchunk--) putpad(SR);
ttnowindow();
return;
} else if (insdel) {
ttmove(1+bot-nchunk, 0);
if (pDL) putpad (tgoto(pDL, 0, nchunk));
else for (i=0; i<nchunk; i++) /* For all lines in the chunk */
putpad(DL);
ttmove(row, 0);
if (pAL) putpad (tgoto(pAL, 0, nchunk));
else for (i=0; i<nchunk; i++) /* For all lines in the chunk */
putpad(AL);
ttrow = HUGE;
ttcol = HUGE;
} else panic("ttinsl: Can't insert/delete line");
}
/*
* Delete nchunk line(s) from "row", replacing the
* bottom line on the screen with a blank line.
* Unless we're using the scrolling region, this is
* done with a crafty sequences of insert and delete
* lines. The presence of the echo area makes a
* boundry condition go away.
*/
ttdell(row, bot, nchunk)
{
register int i;
if (row == bot) { /* One line special case */
ttmove(row, 0);
tteeol();
return;
}
if (CS) { /* scrolling region */
ttwindow(row, bot);
ttmove(bot, 0);
while (nchunk--) ttputc(LF);
ttnowindow();
}
else if(insdel) {
ttmove(row, 0); /* Else use insert/delete line */
if (pDL) putpad (tgoto(pDL, 0, nchunk));
else for (i=0; i<nchunk; i++) /* For all lines in the chunk */
putpad(DL);
ttmove(1+bot-nchunk,0);
if (pAL) putpad (tgoto(pAL, 0, nchunk));
else for (i=0; i<nchunk; i++) /* For all lines in the chunk */
putpad(AL);
ttrow = HUGE;
ttcol = HUGE;
} else panic("ttdell: Can't insert/delete line");
}
/*
* This routine sets the scrolling window
* on the display to go from line "top" to line
* "bot" (origin 0, inclusive). The caller checks
* for the pathalogical 1 line scroll window that
* doesn't work right, and avoids it. The "ttrow"
* and "ttcol" variables are set to a crazy value
* to ensure that the next call to "ttmove" does
* not turn into a no-op (the window adjustment
* moves the cursor).
*
*/
ttwindow(top, bot)
{
if (CS && (tttop!=top || ttbot!=bot)) {
putpad(tgoto(CS, bot, top));
ttrow = HUGE; /* Unknown. */
ttcol = HUGE;
tttop = top; /* Remember region. */
ttbot = bot;
}
}
/*
* Switch to full screen scroll. This is
* used by "spawn.c" just before is suspends the
* editor, and by "display.c" when it is getting ready
* to exit. This function gets to full screen scroll
* by telling the terminal to set a scrolling regin
* that is LI or nrow rows high, whichever is larger.
* This behavior seems to work right on systems
* where you can set your terminal size.
*/
ttnowindow()
{
if (CS) {
putpad(tgoto(CS, (nrow > LI ? nrow : LI) - 1, 0));
ttrow = HUGE; /* Unknown. */
ttcol = HUGE;
tttop = HUGE; /* No scroll region. */
ttbot = HUGE;
}
}
/*
* Set the current writing color to the
* specified color. Watch for color changes that are
* not going to do anything (the color is already right)
* and don't send anything to the display.
* The rainbow version does this in putline.s on a
* line by line basis, so don't bother sending
* out the color shift.
*/
ttcolor(color) register int color; {
if (color != tthue) {
if (color == CTEXT) { /* Normal video. */
putpad(SE);
} else if (color == CMODE) { /* Reverse video. */
putpad(SO);
}
tthue = color; /* Save the color. */
}
}
/*
* This routine is called by the
* "refresh the screen" command to try and resize
* the display. The new size, which must be deadstopped
* to not exceed the NROW and NCOL limits, it stored
* back into "nrow" and "ncol". Display can always deal
* with a screen NROW by NCOL. Look in "window.c" to
* see how the caller deals with a change.
*/
ttresize() {
setttysize(); /* found in "ttyio.c", */
/* ask OS for tty size */
if (nrow < 1) /* Check limits. */
nrow = 1;
else if (nrow > NROW)
nrow = NROW;
if (ncol < 1)
ncol = 1;
else if (ncol > NCOL)
ncol = NCOL;
}
#ifdef NO_RESIZE
static setttysize() {
nrow = tgetnum("li");
ncol = tgetnum("co");
}
#endif
static int cci;
static /* fake char output for charcost() */
fakec(c) char c; {
#ifdef lint
c++;
#endif
cci++;
}
/* calculate the cost of doing string s */
charcost (s) char *s; {
cci = 0;
tputs(s, nrow, fakec);
return cci;
}
putpad(str) char *str; {
tputs(str, 1, ttputc);
}
SHAR_EOF
fi # end of overwriting check
if test -f 'tty/termcap/readme'
then
echo shar: will not over-write existing file "'tty/termcap/readme'"
else
cat << \SHAR_EOF > 'tty/termcap/readme'
MicroGnuEmacs Termcap Terminal Capabilities
The termcap library needs to know where to get the terminal type and
termcap capibilities file from. UNIX and Os9/68k users should "setenv
TERM" to their terminal type, and "setenv TERMCAP" if they are using a
non-standard termcap file. VMS users should see AAAREADME.1ST for
information on how to define the logical names TERM and ETC to point
to the termcap definition file. Users of other operating systems
should do the aproprate thing. For an example of a termcap file, UNIX
users may look in /etc/termcap, Os9/68k users may look at
/dd/sys/termcap (if present), and VMS users should see the file
[.SYS.VMS.TERMCAP]TERMCAP.
MicroGnuEmacs requires that certain terminal capabilities exist in the
specified termcap entry. The "cm" (cursor motion) capability *must*
be available to use MicroGnuEmacs. (Yes, it is possible to fake cm
with some other capibilities, but MicroGnuEmacs doesn't try.) If your
terminal is one that uses control characters in the paramater portion
of the "cm" string, the "up" and "bc" capabilites may also be needed.
(See your termlib documentation for when this is so.)
If the following capabilities are available, they are used. The AL
and DL sequences are not totally standard, but having them improves
the performance of the editor, since it doesn't have to redraw the
screen to delete a line. They should not be used if they need control
characters as paramaters.
cd -- clear display
ce -- clear to eol
al -- insert 1 line
dl -- delete 1 line
AL -- parametrized insert line (note capitalization)
DL -- parametrized delete line (note capitalization)
ti -- cursor movement initialization string
te -- cursor movement end string
The cs capability is not as standard as some of the other
capibilities, but is used by MicroGnuEmacs when available. It is used
to define a "scrolling region", which defines a window within the
screen where all the action takes place. A newline character at the
bottom of this area scrolls the rest of the text in the area up one
line, just like the normal screen; a reverse linefeed (sr) at the top
of the window moves all the text in the area down a line.
MicroGnuEmacs does not properly handle "cs" if your terminal needs
control characters as paramaters, and in this case "cs" should not be
defined.
If the cs and sr capabilities are available, the termcap driver uses
these to make the insert/delete line functions work more smoothly. If
only the cs capability is present, it is still used for the delete
line function, but not for inserting lines.
The definition of the cs capability is: the first parameter in the
sequence defines the first row (origin 0) that is in the scrolling
region, and the second argument defines the last row to include in the
scrolling region.
cs -- set scrolling region (arg1 = top, arg2 = bottom)
sr -- reverse index
The following capabilities provide for an enhanced (reverse-video
or otherwise rendered) mode line. The sg entry should not be present
on terminals that do this to characters as they are placed on the
screen. Terminals that put a region of the screen in the standout
mode should have sg defined as numeric: :sg#0: for terminals that do
this on regions but don't take any character positions to do this,
(this may be a non-standard interprition of the meaning of sg) and the
number of character positions taken by any other terminal.
so -- enter standout mode
se -- leave standout mode
sg -- number of character positions used by standout
Function Keys
If MicroGnuEmacs is compiled with XKEYS defined, a new feature of the
termcap driver is support for function keys, based on the termcap
entry that defines the terminal. This may not be be deisriable in all
cases, especially those in which the terminal in use does not use ESC
as the first character of all arrow and function keys. If you do
deside to use this feature, don't expect it to work with all terminal
types. Those termial types it doesn't work with will have to use
modified termcaps that do not include the termcap sequences described
below to be useful with MicroGnuEmacs compiled with the XKEYS option.
XKEYS also interferes with the proper operation of delayed prompts.
The termcap "standard" provides for a number of sequences that define
how to activate the function keys, what the function key sequences
are, and the names of the function keys. The termcap driver uses the
following capabilities to parse for function key sequences:
ks -- start using function keys
ke -- finish using the function keypad
kh -- home key
ku -- up arrow
kd -- down arrow
kl -- left arrow
kr -- right arrow
k0-k9 -- standard termcap function keys (1-10)
l0-l9 -- labels for same
The following key capabilities are not standard, but are used if
they are in the termcap:
K0-K9 -- function keys 10 through 19
L0-L9 -- labels for same
For example, the DEC LK201 (vt200-series, VAXstation) keyboard has an
editing keypad. A VT200 termcap entry could include the following
capabilities to go into application keypad mode, set up the arrow keys,
and map the editing keypad to internal function key codes KF0-KF7:
...the beginning of the termcap entry....
:ks=\E[?1h\E=:ke=\E[?1l\E>:\
:ku=\EOA:kd=\EOB:kr=\EOC:kl=\EOD:kh=\E[H:\
:k0=\E[28~:l0=Help:\
:k1=\E[29~:l1=Do:\
:k2=\E[1~:l2=Find:\
:k3=\E[2~:l3=Insert Here:\
:k4=\E[3~:l4=Remove:\
:k5=\E[4~:l5=Select:\
:k6=\E[5~:l6=Prev Screen:\
:k7=\E[6~:l7=Next Screen:\
There is one problem with supporting function keys: If the META
introducer key (usually ESC) is used as the initial character of a
function key sequence, how is the parser to know when the user intends
the introducer to be taken at face value? The parser doesn't have
enough information.
The approach the current code takes is that if the META introducer is
the first character in a function sequence, and the second character c
isn't part of a function key sequence, the parser returns (KMETA | c).
If it sees *two* META introducers in a row, it returns one instance of
METACH. This approach is subject to discussion and debate, but it
works right most of the time.
SHAR_EOF
fi # end of overwriting check
if test -f 'tty/termcap/ttydef.h'
then
echo shar: will not over-write existing file "'tty/termcap/ttydef.h'"
else
cat << \SHAR_EOF > 'tty/termcap/ttydef.h'
/*
* Termcap terminal file, nothing special, just make it big
* enough for windowing systems.
*/
#define GOSLING /* Compile in fancy display. */
/* #define MEMMAP */ /* Not memory mapped video. */
#define NROW 66 /* Rows. */
#define NCOL 132 /* Columns. */
/* #define MOVE_STANDOUT /* don't move in standout mode */
#define STANDOUT_GLITCH /* possible standout glitch */
#define TERMCAP /* for possible use in ttyio.c */
/*
* Termcap function keys. The last 10 keys correspond to the
* non-standard termcap entries K0-K9 (instead of k0-k9).
*/
#ifdef XKEYS
#define KFIRST K01
#define KLAST K1A
#define KHOME K01
#define KDOWN K02
#define KUP K03
#define KLEFT K04
#define KRIGHT K05
#define KF0 K06
#define KF1 K07
#define KF2 K08
#define KF3 K09
#define KF4 K0A
#define KF5 K0B
#define KF6 K0C
#define KF7 K0D
#define KF8 K0E
#define KF9 K0F
#define KF10 K10
#define KF11 K11
#define KF12 K12
#define KF13 K13
#define KF14 K14
#define KF15 K15
#define KF16 K16
#define KF17 K17
#define KF18 K18
#define KF19 K19
#define KF20 K1A
#define NFKEYS 20 /* # of function keys (k0-k9, K0-K9) */
#endif
SHAR_EOF
fi # end of overwriting check
# End of shell archive
exit 0
More information about the Mod.sources
mailing list