sources-request@mirror.UUCP (01/27/87)
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@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