Path: seismo!harvard!talcott!panda!decvax!minow (Martin Minow) From: sources-request@panda.UUCP Newsgroups: mod.sources Subject: MicroEmacs (Part 1 of 6) Message-ID: <1656@panda.UUCP> Date: 13 Apr 86 16:28:01 GMT Sender: jpn@panda.UUCP Lines: 2165 Approved: jpn@panda.UUCP Mod.sources: Volume 4, Issue 68 Submitted by: decvax!minow (Martin Minow) #! /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: # Readme.txt # basic.c # buffer.c # cinfo.c # def.h # display.c # This archive created: Sun Apr 13 11:15:10 1986 export PATH; PATH=/bin:$PATH echo shar: extracting "'Readme.txt'" '(4164 characters)' if test -f 'Readme.txt' then echo shar: will not over-write existing file "'Readme.txt'" else cat << \SHAR_EOF > 'Readme.txt' This is the only official distribution of MicroEmacs. Accept no substitutes. It is distributed on Usenet on 6 shar archives. Save them as uemacs1.shar ... uemacs6.shar. Move to .../uemacs and unshar all six source files: uemacs[1-3].shar Editor Mainline uemacs4.shar System-specific sources uemacs5.shar Terminal-specific sources uemacs6.shar Out of date TeX documentation The shar files will automatically create the following directory structure: .../uemacs Editor mainline sources .../uemacs/sys System specific sources .../uemacs/sys/atari Atari ST .../uemacs/sys/cpm86 .../uemacs/sys/msdos .../uemacs/sys/ultrix (and other 4.2 bsd Unix systems) .../uemacs/sys/vms .../uemacs/tty Terminal handler sources .../uemacs/tty/ansi VT100 and other Ansi-style terminals. .../uemacs/tty/atari .../uemacs/tty/heath To compile, choose one system, and one tty, and copy the files from the appropriate subdirectory into the mainline directory. Then compile all sources, and link. The ultrix version includes a Makefile. Unfortunately, the documentation is not yet ready. You will have to dig the keypad bindings out of the source code. Most are setup in symbol.c, a few might be set in the terminal or system specific modules. You can get a current keypad binding chart by entering the command X display-bindings is usually bound to or . Here are my possibly out-of-date bindings. Note the following abbreviations: C- Control- M- Meta -- generally the key. F10 (etc. -- a keypad function key). Up back-line Down forw-line Left back-char Right forw-char Find search-again Insert yank Remove kill-region Select set-mark Previous back-page Next forw-page Help help Do execute-macro F17 back-window F18 forw-window F19 enlarge-window F20 shrink-window Rubout back-del-char C-@ set-mark C-A goto-bol C-B back-char C-C spawn-cli C-D forw-del-char C-E goto-eol C-F forw-char C-G abort Backspace back-del-char C-J ins-nl-and-indent C-K kill-line C-L refresh Return ins-nl C-N forw-line C-O ins-nl-and-backup C-P back-line C-Q quote C-R back-i-search C-S forw-i-search C-T twiddle C-V forw-page C-W kill-region C-Y yank C-Z jeff-exit M-! reposition-window M-% query-replace M-. set-mark M-< goto-bob M-> goto-eob M-B back-word M-C cap-word M-D forw-del-word M-F forw-word M-L lower-word M-Q quote M-R back-search M-S forw-search M-U upper-word M-V back-page M-W copy-region M-X extended-command M-Rubout back-del-word C-M-G abort M-Backspace back-del-word C-M-R display-message C-M-V display-version C-X ( start-macro C-X ) end-macro C-X 1 only-window C-X 2 split-window C-X = display-position C-X B use-buffer C-X E execute-macro C-X G goto-line C-X K kill-buffer C-X N forw-window C-X P back-window C-X R back-i-search C-X S forw-i-search C-X Z enlarge-window C-X C-B display-buffers C-X C-C quit C-X C-D display-directory C-X C-F set-file-name C-X C-G abort C-X C-L lower-region C-X C-N down-window C-X C-O del-blank-lines C-X C-P up-window C-X C-R file-read C-X C-S file-save C-X C-U upper-region C-X C-V file-visit C-X C-W file-write C-X C-X swap-dot-and-mark C-X C-Z shrink-window SHAR_EOF if test 4164 -ne "`wc -c < 'Readme.txt'`" then echo shar: error transmitting "'Readme.txt'" '(should have been 4164 characters)' fi fi echo shar: extracting "'basic.c'" '(7726 characters)' if test -f 'basic.c' then echo shar: will not over-write existing file "'basic.c'" else cat << \SHAR_EOF > 'basic.c' /* * Name: MicroEMACS * Basic cursor motion commands. * Version: 29 * Last edit: 05-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * * The routines in this file are the basic * command functions for moving the cursor around on * the screen, setting mark, and swapping dot with * mark. Only moves between lines, which might make the * current buffer framing bad, are hard. */ #include "def.h" /* * Go to beginning of line. */ gotobol(f, n, k) { curwp->w_doto = 0; return (TRUE); } /* * Move cursor backwards. Do the * right thing if the count is less than * 0. Error if you try to move back from * the beginning of the buffer. */ backchar(f, n, k) register int n; { register LINE *lp; if (n < 0) return (forwchar(f, -n, KRANDOM)); while (n--) { if (curwp->w_doto == 0) { if ((lp=lback(curwp->w_dotp)) == curbp->b_linep) return (FALSE); curwp->w_dotp = lp; curwp->w_doto = llength(lp); curwp->w_flag |= WFMOVE; } else curwp->w_doto--; } return (TRUE); } /* * Go to end of line. */ gotoeol(f, n, k) { curwp->w_doto = llength(curwp->w_dotp); return (TRUE); } /* * Move cursor forwards. Do the * right thing if the count is less than * 0. Error if you try to move forward * from the end of the buffer. */ forwchar(f, n, k) register int n; { if (n < 0) return (backchar(f, -n, KRANDOM)); while (n--) { if (curwp->w_doto == llength(curwp->w_dotp)) { if (curwp->w_dotp == curbp->b_linep) return (FALSE); curwp->w_dotp = lforw(curwp->w_dotp); curwp->w_doto = 0; curwp->w_flag |= WFMOVE; } else curwp->w_doto++; } return (TRUE); } /* * Go to the beginning of the * buffer. Setting WFHARD is conservative, * but almost always the case. */ gotobob(f, n, k) { curwp->w_dotp = lforw(curbp->b_linep); curwp->w_doto = 0; curwp->w_flag |= WFHARD; return (TRUE); } /* * Go to the end of the buffer. * Setting WFHARD is conservative, but * almost always the case. */ gotoeob(f, n, k) { curwp->w_dotp = curbp->b_linep; curwp->w_doto = 0; curwp->w_flag |= WFHARD; return (TRUE); } /* * Move forward by full lines. * If the number of lines to move is less * than zero, call the backward line function to * actually do it. The last command controls how * the goal column is set. */ forwline(f, n, k) { register LINE *dlp; if (n < 0) return (backline(f, -n, KRANDOM)); if ((lastflag&CFCPCN) == 0) /* Fix goal. */ setgoal(); thisflag |= CFCPCN; dlp = curwp->w_dotp; while (n-- && dlp!=curbp->b_linep) dlp = lforw(dlp); curwp->w_dotp = dlp; curwp->w_doto = getgoal(dlp); curwp->w_flag |= WFMOVE; return (TRUE); } /* * This function is like "forwline", but * goes backwards. The scheme is exactly the same. * Check for arguments that are less than zero and * call your alternate. Figure out the new line and * call "movedot" to perform the motion. */ backline(f, n, k) { register LINE *dlp; if (n < 0) return (forwline(f, -n, KRANDOM)); if ((lastflag&CFCPCN) == 0) /* Fix goal. */ setgoal(); thisflag |= CFCPCN; dlp = curwp->w_dotp; while (n-- && lback(dlp)!=curbp->b_linep) dlp = lback(dlp); curwp->w_dotp = dlp; curwp->w_doto = getgoal(dlp); curwp->w_flag |= WFMOVE; return (TRUE); } /* * Set the current goal column, * which is saved in the external variable "curgoal", * to the current cursor column. The column is never off * the edge of the screen; it's more like display then * show position. */ setgoal() { register int c; register int i; curgoal = 0; /* Get the position. */ for (i=0; iw_doto; ++i) { c = lgetc(curwp->w_dotp, i); if (c == '\t') curgoal |= 0x07; else if (ISCTRL(c) != FALSE) ++curgoal; ++curgoal; } if (curgoal >= ncol) /* Chop to tty width. */ curgoal = ncol-1; } /* * This routine looks at a line (pointed * to by the LINE pointer "dlp") and the current * vertical motion goal column (set by the "setgoal" * routine above) and returns the best offset to use * when a vertical motion is made into the line. */ getgoal(dlp) register LINE *dlp; { register int c; register int col; register int newcol; register int dbo; col = 0; dbo = 0; while (dbo != llength(dlp)) { c = lgetc(dlp, dbo); newcol = col; if (c == '\t') newcol |= 0x07; else if (ISCTRL(c) != FALSE) ++newcol; ++newcol; if (newcol > curgoal) break; col = newcol; ++dbo; } return (dbo); } /* * Scroll forward by a specified number * of lines, or by a full page if no argument. * The "2" is the window overlap (this is the default * value from ITS EMACS). Because the top line in * the window is zapped, we have to do a hard * update and get it back. */ forwpage(f, n, k) register int n; { register LINE *lp; if (f == FALSE) { n = curwp->w_ntrows - 2; /* Default scroll. */ if (n <= 0) /* Forget the overlap */ n = 1; /* if tiny window. */ } else if (n < 0) return (backpage(f, -n, KRANDOM)); #if CVMVAS else /* Convert from pages */ n *= curwp->w_ntrows; /* to lines. */ #endif lp = curwp->w_linep; while (n-- && lp!=curbp->b_linep) lp = lforw(lp); curwp->w_linep = lp; curwp->w_dotp = lp; curwp->w_doto = 0; curwp->w_flag |= WFHARD; return (TRUE); } /* * This command is like "forwpage", * but it goes backwards. The "2", like above, * is the overlap between the two windows. The * value is from the ITS EMACS manual. The * hard update is done because the top line in * the window is zapped. */ backpage(f, n, k) register int n; { register LINE *lp; if (f == FALSE) { n = curwp->w_ntrows - 2; /* Default scroll. */ if (n <= 0) /* Don't blow up if the */ n = 1; /* window is tiny. */ } else if (n < 0) return (forwpage(f, -n, KRANDOM)); #if CVMVAS else /* Convert from pages */ n *= curwp->w_ntrows; /* to lines. */ #endif lp = curwp->w_linep; while (n-- && lback(lp)!=curbp->b_linep) lp = lback(lp); curwp->w_linep = lp; curwp->w_dotp = lp; curwp->w_doto = 0; curwp->w_flag |= WFHARD; return (TRUE); } /* * Set the mark in the current window * to the value of dot. A message is written to * the echo line unless we are running in a keyboard * macro, when it would be silly. */ setmark(f, n, k) { curwp->w_markp = curwp->w_dotp; curwp->w_marko = curwp->w_doto; if (kbdmop == NULL) eprintf("[Mark set]"); return (TRUE); } /* * Swap the values of "dot" and "mark" in * the current window. This is pretty easy, because * all of the hard work gets done by the standard routine * that moves the mark about. The only possible * error is "no mark". */ swapmark(f, n, k) { register LINE *odotp; register int odoto; if (curwp->w_markp == NULL) { eprintf("No mark in this window"); return (FALSE); } odotp = curwp->w_dotp; odoto = curwp->w_doto; curwp->w_dotp = curwp->w_markp; curwp->w_doto = curwp->w_marko; curwp->w_markp = odotp; curwp->w_marko = odoto; curwp->w_flag |= WFMOVE; return (TRUE); } /* * Go to a specific line, mostly for * looking up errors in C programs, which give the * error a line number. If an argument is present, then * it is the line number, else prompt for a line number * to use. */ gotoline(f, n, k) register int n; { register LINE *clp; register int s; char buf[32]; if (f == FALSE) { if ((s=ereply("Goto line: ", buf, sizeof(buf))) != TRUE) return (s); n = atoi(buf); } if (n <= 0) { eprintf("Bad line"); return (FALSE); } clp = lforw(curbp->b_linep); /* "clp" is first line */ while (n != 1) { if (clp == curbp->b_linep) { eprintf("Line number too large"); return (FALSE); } clp = lforw(clp); --n; } curwp->w_dotp = clp; curwp->w_doto = 0; curwp->w_flag |= WFMOVE; return (TRUE); } SHAR_EOF if test 7726 -ne "`wc -c < 'basic.c'`" then echo shar: error transmitting "'basic.c'" '(should have been 7726 characters)' fi fi echo shar: extracting "'buffer.c'" '(8922 characters)' if test -f 'buffer.c' then echo shar: will not over-write existing file "'buffer.c'" else cat << \SHAR_EOF > 'buffer.c' /* * Name: MicroEMACS * Buffer handling. * Version: 30 * Last edit: 17-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy */ #include "def.h" /* * Attach a buffer to a window. The * values of dot and mark come from the buffer * if the use count is 0. Otherwise, they come * from some other window. */ usebuffer(f, n, k) { register BUFFER *bp; register WINDOW *wp; register int s; char bufn[NBUFN]; if ((s=ereply("Use buffer: ", bufn, NBUFN)) != TRUE) return (s); if ((bp=bfind(bufn, TRUE)) == NULL) return (FALSE); if (--curbp->b_nwnd == 0) { /* Last use. */ curbp->b_dotp = curwp->w_dotp; curbp->b_doto = curwp->w_doto; curbp->b_markp = curwp->w_markp; curbp->b_marko = curwp->w_marko; } curbp = bp; /* Switch. */ curwp->w_bufp = bp; curwp->w_linep = bp->b_linep; /* For macros, ignored. */ curwp->w_flag |= WFMODE|WFFORCE|WFHARD; /* Quite nasty. */ if (bp->b_nwnd++ == 0) { /* First use. */ curwp->w_dotp = bp->b_dotp; curwp->w_doto = bp->b_doto; curwp->w_markp = bp->b_markp; curwp->w_marko = bp->b_marko; return (TRUE); } wp = wheadp; /* Look for old. */ while (wp != NULL) { if (wp!=curwp && wp->w_bufp==bp) { curwp->w_dotp = wp->w_dotp; curwp->w_doto = wp->w_doto; curwp->w_markp = wp->w_markp; curwp->w_marko = wp->w_marko; break; } wp = wp->w_wndp; } return (TRUE); } /* * Dispose of a buffer, by name. * Ask for the name. Look it up (don't get too * upset if it isn't there at all!). Get quite upset * if the buffer is being displayed. Clear the buffer (ask * if the buffer has been changed). Then free the header * line and the buffer header. Bound to "C-X K". */ killbuffer(f, n, k) { register BUFFER *bp; register BUFFER *bp1; register BUFFER *bp2; register int s; char bufn[NBUFN]; if ((s=ereply("Kill buffer: ", bufn, NBUFN)) != TRUE) return (s); if ((bp=bfind(bufn, FALSE)) == NULL) /* Easy if unknown. */ return (TRUE); if (bp->b_nwnd != 0) { /* Error if on screen. */ eprintf("Buffer is being displayed"); return (FALSE); } if ((s=bclear(bp)) != TRUE) /* Blow text away. */ return (s); free((char *) bp->b_linep); /* Release header line. */ bp1 = NULL; /* Find the header. */ bp2 = bheadp; while (bp2 != bp) { bp1 = bp2; bp2 = bp2->b_bufp; } bp2 = bp2->b_bufp; /* Next one in chain. */ if (bp1 == NULL) /* Unlink it. */ bheadp = bp2; else bp1->b_bufp = bp2; free((char *) bp); /* Release buffer block */ return (TRUE); } /* * Display the buffer list. This is done * in two parts. The "makelist" routine figures out * the text, and puts it in the buffer whoses header is * pointed to by the external "blistp". The "popblist" * then pops the data onto the screen. Bound to * "C-X C-B". */ listbuffers(f, n, k) { register int s; if ((s=makelist()) != TRUE) return (s); return (popblist()); } /* * Pop the special buffer whose * buffer header is pointed to by the external * variable "blistp" onto the screen. This is used * by the "listbuffers" routine (above) and by * some other packages. Returns a status. */ popblist() { register WINDOW *wp; register BUFFER *bp; if (blistp->b_nwnd == 0) { /* Not on screen yet. */ if ((wp=wpopup()) == NULL) return (FALSE); bp = wp->w_bufp; if (--bp->b_nwnd == 0) { bp->b_dotp = wp->w_dotp; bp->b_doto = wp->w_doto; bp->b_markp = wp->w_markp; bp->b_marko = wp->w_marko; } wp->w_bufp = blistp; ++blistp->b_nwnd; } wp = wheadp; while (wp != NULL) { if (wp->w_bufp == blistp) { wp->w_linep = lforw(blistp->b_linep); wp->w_dotp = lforw(blistp->b_linep); wp->w_doto = 0; wp->w_markp = NULL; wp->w_marko = 0; wp->w_flag |= WFMODE|WFHARD; } wp = wp->w_wndp; } return (TRUE); } /* * This routine rebuilds the * text in the special secret buffer * that holds the buffer list. It is called * by the list buffers command. Return TRUE * if everything works. Return FALSE if there * is an error (if there is no memory). */ makelist() { register char *cp1; register char *cp2; register int c; register BUFFER *bp; register LINE *lp; register int nbytes; register int s; char b[6+1]; char line[128]; blistp->b_flag &= ~BFCHG; /* Blow away old. */ if ((s=bclear(blistp)) != TRUE) return (s); strcpy(blistp->b_fname, ""); if (addline("C Size Buffer File") == FALSE || addline("- ---- ------ ----") == FALSE) return (FALSE); bp = bheadp; /* For all buffers */ while (bp != NULL) { cp1 = &line[0]; /* Start at left edge */ if ((bp->b_flag&BFCHG) != 0) /* "*" if changed */ *cp1++ = '*'; else *cp1++ = ' '; *cp1++ = ' '; /* Gap. */ nbytes = 0; /* Count bytes in buf. */ lp = lforw(bp->b_linep); while (lp != bp->b_linep) { nbytes += llength(lp)+1; lp = lforw(lp); } itoa(b, 6, nbytes); /* 6 digit buffer size. */ cp2 = &b[0]; while ((c = *cp2++) != 0) *cp1++ = c; *cp1++ = ' '; /* Gap. */ cp2 = &bp->b_bname[0]; /* Buffer name */ while ((c = *cp2++) != 0) *cp1++ = c; cp2 = &bp->b_fname[0]; /* File name */ if (*cp2 != 0) { while (cp1 < &line[1+1+6+1+NBUFN+1]) *cp1++ = ' '; while ((c = *cp2++) != 0) { if (cp1 < &line[128-1]) *cp1++ = c; } } *cp1 = 0; /* Add to the buffer. */ if (addline(line) == FALSE) return (FALSE); bp = bp->b_bufp; } return (TRUE); /* All done */ } /* * Used above. */ itoa(buf, width, num) register char buf[]; register int width; register int num; { buf[width] = 0; /* End of string. */ while (num >= 10) { /* Conditional digits. */ buf[--width] = (num%10) + '0'; num /= 10; } buf[--width] = num + '0'; /* Always 1 digit. */ while (width != 0) /* Pad with blanks. */ buf[--width] = ' '; } /* * The argument "text" points to * a string. Append this line to the * buffer list buffer. Handcraft the EOL * on the end. Return TRUE if it worked and * FALSE if you ran out of room. */ addline(text) char *text; { register LINE *lp; register int i; register int ntext; ntext = strlen(text); if ((lp=lalloc(ntext)) == NULL) return (FALSE); for (i=0; ib_linep->l_bp->l_fp = lp; /* Hook onto the end */ lp->l_bp = blistp->b_linep->l_bp; blistp->b_linep->l_bp = lp; lp->l_fp = blistp->b_linep; if (blistp->b_dotp == blistp->b_linep) /* If "." is at the end */ blistp->b_dotp = lp; /* move it to new line */ return (TRUE); } /* * Look through the list of * buffers. Return TRUE if there * are any changed buffers. Special buffers * like the buffer list buffer don't count, as * they are not in the list. Return FALSE if * there are no changed buffers. */ anycb() { register BUFFER *bp; bp = bheadp; while (bp != NULL) { if ((bp->b_flag&BFCHG) != 0) return (TRUE); bp = bp->b_bufp; } return (FALSE); } /* * Search for a buffer, by name. * If not found, and the "cflag" is TRUE, * create a buffer and put it in the list of * all buffers. Return pointer to the BUFFER * block for the buffer. */ BUFFER * bfind(bname, cflag) register char *bname; { register BUFFER *bp; bp = bheadp; while (bp != NULL) { if (strcmp(bname, bp->b_bname) == 0) return (bp); bp = bp->b_bufp; } if (cflag!=FALSE && (bp=bcreate(bname))!=NULL) { bp->b_bufp = bheadp; bheadp = bp; } return (bp); } /* * Create a buffer, by name. * Return a pointer to the BUFFER header * block, or NULL if the buffer cannot * be created. The BUFFER is not put in the * list of all buffers; this is called by * "edinit" to create the buffer list * buffer. */ BUFFER * bcreate(bname) register char *bname; { register BUFFER *bp; register LINE *lp; if ((bp=(BUFFER *)malloc(sizeof(BUFFER))) == NULL) return (NULL); if ((lp=lalloc(0)) == NULL) { free((char *) bp); return (NULL); } bp->b_bufp = NULL; bp->b_dotp = lp; bp->b_doto = 0; bp->b_markp = NULL; bp->b_marko = 0; bp->b_flag = 0; bp->b_nwnd = 0; bp->b_linep = lp; strcpy(bp->b_fname, ""); strcpy(bp->b_bname, bname); lp->l_fp = lp; lp->l_bp = lp; return (bp); } /* * This routine blows away all of the text * in a buffer. If the buffer is marked as changed * then we ask if it is ok to blow it away; this is * to save the user the grief of losing text. The * window chain is nearly always wrong if this gets * called; the caller must arrange for the updates * that are required. Return TRUE if everything * looks good. */ bclear(bp) register BUFFER *bp; { register LINE *lp; register int s; if ((bp->b_flag&BFCHG) != 0 /* Changed. */ && (s=eyesno("Discard changes")) != TRUE) return (s); bp->b_flag &= ~BFCHG; /* Not changed */ while ((lp=lforw(bp->b_linep)) != bp->b_linep) lfree(lp); bp->b_dotp = bp->b_linep; /* Fix "." */ bp->b_doto = 0; bp->b_markp = NULL; /* Invalidate "mark" */ bp->b_marko = 0; return (TRUE); } SHAR_EOF if test 8922 -ne "`wc -c < 'buffer.c'`" then echo shar: error transmitting "'buffer.c'" '(should have been 8922 characters)' fi fi echo shar: extracting "'cinfo.c'" '(2394 characters)' if test -f 'cinfo.c' then echo shar: will not over-write existing file "'cinfo.c'" else cat << \SHAR_EOF > 'cinfo.c' /* * Name: MicroEMACS * Character class tables. * Version: 29 * Last edit: 05-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * * Do it yourself character classification * macros, that understand the multinational character set, * and let me ask some questions the standard macros (in * ctype.h) don't let you ask. */ #include "def.h" /* * This table, indexed by a character drawn * from the 256 member character set, is used by my * own character type macros to answer questions about the * type of a character. It handles the full multinational * character set, and lets me ask some questions that the * standard "ctype" macros cannot ask. */ char cinfo[256] = { _C, _C, _C, _C, /* 0x0X */ _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, /* 0x1X */ _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, _C, 0, 0, 0, 0, /* 0x2X */ _W, 0, 0, _W, 0, 0, 0, 0, 0, 0, 0, 0, _W, _W, _W, _W, /* 0x3X */ _W, _W, _W, _W, _W, _W, 0, 0, 0, 0, 0, 0, 0, _U|_W, _U|_W, _U|_W, /* 0x4X */ _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, /* 0x5X */ _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, 0, 0, 0, 0, _W, 0, _L|_W, _L|_W, _L|_W, /* 0x6X */ _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, /* 0x7X */ _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, 0, 0, 0, 0, _C, 0, 0, 0, 0, /* 0x8X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x9X */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xAX */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xBX */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _U|_W, _U|_W, _U|_W, _U|_W, /* 0xCX */ _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, 0, _U|_W, _U|_W, _U|_W, /* 0xDX */ _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, _U|_W, 0, _W, _L|_W, _L|_W, _L|_W, _L|_W, /* 0xEX */ _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, 0, _L|_W, _L|_W, _L|_W, /* 0xFX */ _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, _L|_W, 0, 0 }; SHAR_EOF if test 2394 -ne "`wc -c < 'cinfo.c'`" then echo shar: error transmitting "'cinfo.c'" '(should have been 2394 characters)' fi fi echo shar: extracting "'def.h'" '(10999 characters)' if test -f 'def.h' then echo shar: will not over-write existing file "'def.h'" else cat << \SHAR_EOF > 'def.h' /* * Name: MicroEMACS * Common header file. * Version: 29 * Last edit: 14-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * * This file is the general header file for all parts * of the MicroEMACS display editor. It contains all of the * general definitions and macros. It also contains some * conditional compilation flags. All of the per-system and * per-terminal definitions are in special header files. * The most common reason to edit this file would be to zap * the definition of CVMVAS or BACKUP. */ #include "sysdef.h" /* Order is critical. */ #include "ttydef.h" #include #define CVMVAS 1 /* C-V, M-V work in pages. */ #define BACKUP 0 /* Make backup file. */ /* * Table sizes, etc. */ #define NSHASH 31 /* Symbol table hash size. */ #define NFILEN 80 /* Length, file name. */ #define NBUFN 16 /* Length, buffer name. */ #define NLINE 256 /* Length, line. */ #define NKBDM 256 /* Length, keyboard macro. */ #define NMSG 512 /* Length, message buffer. */ #define NPAT 80 /* Length, pattern. */ #define HUGE 1000 /* A rather large number. */ #define NSRCH 128 /* Undoable search commands. */ #define NXNAME 64 /* Length, extended command. */ /* * Universal. */ #define FALSE 0 /* False, no, bad, etc. */ #define TRUE 1 /* True, yes, good, etc. */ #define ABORT 2 /* Death, ^G, abort, etc. */ /* * These flag bits keep track of * some aspects of the last command. The CFCPCN * flag controls goal column setting. The CFKILL * flag controls the clearing versus appending * of data in the kill buffer. */ #define CFCPCN 0x0001 /* Last command was C-P, C-N */ #define CFKILL 0x0002 /* Last command was a kill */ /* * File I/O. */ #define FIOSUC 0 /* Success. */ #define FIOFNF 1 /* File not found. */ #define FIOEOF 2 /* End of file. */ #define FIOERR 3 /* Error. */ /* * Directory I/O. */ #define DIOSUC 0 /* Success. */ #define DIOEOF 1 /* End of file. */ #define DIOERR 2 /* Error. */ /* * Display colors. */ #define CNONE 0 /* Unknown color. */ #define CTEXT 1 /* Text color. */ #define CMODE 2 /* Mode line color. */ /* * Flags for "eread". */ #define EFNEW 0x0001 /* New prompt. */ #define EFAUTO 0x0002 /* Autocompletion enabled. */ #define EFCR 0x0004 /* Echo CR at end; last read. */ /* * Keys are represented inside using an 11 bit * keyboard code. The transformation between the keys on * the keyboard and 11 bit code is done by terminal specific * code in the "kbd.c" file. The actual character is stored * in 8 bits (DEC multinationals work); there is also a control * flag KCTRL, a meta flag KMETA, and a control-X flag KCTLX. * ASCII control characters are always represented using the * KCTRL form. Although the C0 control set is free, it is * reserved for C0 controls because it makes the communication * between "getkey" and "getkbd" easier. The funny keys get * mapped into the C1 control area. */ #define NKEYS 2048 /* 11 bit code. */ #define METACH 0x1B /* M- prefix, Control-[, ESC */ #define CTMECH 0x1C /* C-M- prefix, Control-\ */ #define EXITCH 0x1D /* Exit level, Control-] */ #define CTRLCH 0x1E /* C- prefix, Control-^ */ #define HELPCH 0x1F /* Help key, Control-_ */ #define KCHAR 0x00FF /* The basic character code. */ #define KCTRL 0x0100 /* Control flag. */ #define KMETA 0x0200 /* Meta flag. */ #define KCTLX 0x0400 /* Control-X flag. */ #define KFIRST 0x0080 /* First special. */ #define KLAST 0x009F /* Last special. */ #define KRANDOM 0x0080 /* A "no key" code. */ #define K01 0x0081 /* Use these names to define */ #define K02 0x0082 /* the special keys on your */ #define K03 0x0083 /* terminal. */ #define K04 0x0084 #define K05 0x0085 #define K06 0x0086 #define K07 0x0087 #define K08 0x0088 #define K09 0x0089 #define K0A 0x008A #define K0B 0x008B #define K0C 0x008C #define K0D 0x008D #define K0E 0x008E #define K0F 0x008F #define K10 0x0090 #define K11 0x0091 #define K12 0x0092 #define K13 0x0093 #define K14 0x0094 #define K15 0x0095 #define K16 0x0096 #define K17 0x0097 #define K18 0x0098 #define K19 0x0099 #define K1A 0x009A #define K1B 0x009B #define K1C 0x009C #define K1D 0x009D #define K1E 0x009E #define K1F 0x009F /* * These flags, and the macros below them, * make up a do-it-yourself set of "ctype" macros that * understand the DEC multinational set, and let me ask * a slightly different set of questions. */ #define _W 0x01 /* Word. */ #define _U 0x02 /* Upper case letter. */ #define _L 0x04 /* Lower case letter. */ #define _C 0x08 /* Control. */ #define ISWORD(c) ((cinfo[(c)]&_W)!=0) #define ISCTRL(c) ((cinfo[(c)]&_C)!=0) #define ISUPPER(c) ((cinfo[(c)]&_U)!=0) #define ISLOWER(c) ((cinfo[(c)]&_L)!=0) #define TOUPPER(c) ((c)-0x20) #define TOLOWER(c) ((c)+0x20) /* * The symbol table links editing functions * to names. Entries in the key map point at the symbol * table entry. A reference count is kept, but it is * probably next to useless right now. The old type code, * which was not being used and probably not right * anyway, is all gone. */ typedef struct SYMBOL { struct SYMBOL *s_symp; /* Hash chain. */ short s_nkey; /* Count of keys bound here. */ char *s_name; /* Name. */ int (*s_funcp)(); /* Function. */ } SYMBOL; /* * There is a window structure allocated for * every active display window. The windows are kept in a * big list, in top to bottom screen order, with the listhead at * "wheadp". Each window contains its own values of dot and mark. * The flag field contains some bits that are set by commands * to guide redisplay; although this is a bit of a compromise in * terms of decoupling, the full blown redisplay is just too * expensive to run for every input character. */ typedef struct WINDOW { struct WINDOW *w_wndp; /* Next window */ struct BUFFER *w_bufp; /* Buffer displayed in window */ struct LINE *w_linep; /* Top line in the window */ struct LINE *w_dotp; /* Line containing "." */ short w_doto; /* Byte offset for "." */ struct LINE *w_markp; /* Line containing "mark" */ short w_marko; /* Byte offset for "mark" */ char w_toprow; /* Origin 0 top row of window */ char w_ntrows; /* # of rows of text in window */ char w_force; /* If NZ, forcing row. */ char w_flag; /* Flags. */ } WINDOW; /* * Window flags are set by command processors to * tell the display system what has happened to the buffer * mapped by the window. Setting "WFHARD" is always a safe thing * to do, but it may do more work than is necessary. Always try * to set the simplest action that achieves the required update. * Because commands set bits in the "w_flag", update will see * all change flags, and do the most general one. */ #define WFFORCE 0x01 /* Force reframe. */ #define WFMOVE 0x02 /* Movement from line to line. */ #define WFEDIT 0x04 /* Editing within a line. */ #define WFHARD 0x08 /* Better to a full display. */ #define WFMODE 0x10 /* Update mode line. */ /* * Text is kept in buffers. A buffer header, described * below, exists for every buffer in the system. The buffers are * kept in a big list, so that commands that search for a buffer by * name can find the buffer header. There is a safe store for the * dot and mark in the header, but this is only valid if the buffer * is not being displayed (that is, if "b_nwnd" is 0). The text for * the buffer is kept in a circularly linked list of lines, with * a pointer to the header line in "b_linep". */ typedef struct BUFFER { struct BUFFER *b_bufp; /* Link to next BUFFER */ struct LINE *b_dotp; /* Link to "." LINE structure */ short b_doto; /* Offset of "." in above LINE */ struct LINE *b_markp; /* The same as the above two, */ short b_marko; /* but for the "mark" */ struct LINE *b_linep; /* Link to the header LINE */ char b_nwnd; /* Count of windows on buffer */ char b_flag; /* Flags */ char b_fname[NFILEN]; /* File name */ char b_bname[NBUFN]; /* Buffer name */ } BUFFER; #define BFCHG 0x01 /* Changed. */ #define BFBAK 0x02 /* Need to make a backup. */ /* * This structure holds the starting position * (as a line/offset pair) and the number of characters in a * region of a buffer. This makes passing the specification * of a region around a little bit easier. * There have been some complaints that the short in this * structure is wrong; that a long would be more appropriate. * I'll awat more comments from the folks with the little * machines; I have a VAX, and everything fits. */ typedef struct { struct LINE *r_linep; /* Origin LINE address. */ short r_offset; /* Origin LINE offset. */ short r_size; /* Length in characters. */ } REGION; /* * All text is kept in circularly linked * lists of "LINE" structures. These begin at the * header line (which is the blank line beyond the * end of the buffer). This line is pointed to by * the "BUFFER". Each line contains a the number of * bytes in the line (the "used" size), the size * of the text array, and the text. The end of line * is not stored as a byte; it's implied. Future * additions will include update hints, and a * list of marks into the line. */ typedef struct LINE { struct LINE *l_fp; /* Link to the next line */ struct LINE *l_bp; /* Link to the previous line */ short l_size; /* Allocated size */ short l_used; /* Used size */ #if PCC char l_text[1]; /* A bunch of characters. */ #else char l_text[]; /* A bunch of characters. */ #endif } LINE; /* * The rationale behind these macros is that you * could (with some editing, like changing the type of a line * link from a "LINE *" to a "REFLINE", and fixing the commands * like file reading that break the rules) change the actual * storage representation of lines to use something fancy on * machines with small address spaces. */ #define lforw(lp) ((lp)->l_fp) #define lback(lp) ((lp)->l_bp) #define lgetc(lp, n) ((lp)->l_text[(n)]&0xFF) #define lputc(lp, n, c) ((lp)->l_text[(n)]=(c)) #define llength(lp) ((lp)->l_used) /* * Externals. */ extern int thisflag; extern int lastflag; extern int curgoal; extern int epresf; extern int sgarbf; extern WINDOW *curwp; extern BUFFER *curbp; extern WINDOW *wheadp; extern BUFFER *bheadp; extern BUFFER *blistp; extern short kbdm[]; extern short *kbdmip; extern short *kbdmop; extern char pat[]; extern SYMBOL *symbol[]; extern SYMBOL *binding[]; extern BUFFER *bfind(); extern BUFFER *bcreate(); extern WINDOW *wpopup(); extern LINE *lalloc(); extern int nrow; extern int ncol; extern char *version[]; extern int ttrow; extern int ttcol; extern int tceeol; extern int tcinsl; extern int tcdell; extern char cinfo[]; extern char *keystrings[]; extern SYMBOL *symlookup(); extern int nmsg; extern int curmsgf; extern int newmsgf; extern char msg[]; /* * Standard I/O. */ extern char *malloc(); extern char *strcpy(); extern char *strcat(); SHAR_EOF if test 10999 -ne "`wc -c < 'def.h'`" then echo shar: error transmitting "'def.h'" '(should have been 10999 characters)' fi fi echo shar: extracting "'display.c'" '(19660 characters)' if test -f 'display.c' then echo shar: will not over-write existing file "'display.c'" else cat << \SHAR_EOF > 'display.c' /* * Name: MicroEMACS * Gosling style redisplay. * Version: 30 * Last edit: 10-Feb-86 * By: rex::conroy * decvax!decwrl!dec-rhea!dec-rex!conroy * * The functions in this file handle redisplay. The * redisplay system knows almost nothing about the editing * process; the editing functions do, however, set some * hints to eliminate a lot of the grinding. There is more * that can be done; the "vtputc" interface is a real * pig. Two conditional compilation flags; the GOSLING * flag enables dynamic programming redisplay, using the * algorithm published by Jim Gosling in SIGOA. The MEMMAP * changes things around for memory mapped video. With * both off, the terminal is a VT52. */ #include "def.h" /* * You can change these back to the types * implied by the name if you get tight for space. If you * make both of them "int" you get better code on the VAX. * They do nothing if this is not Gosling redisplay, except * for change the size of a structure that isn't used. * A bit of a cheat. */ #define XCHAR int #define XSHORT int /* * A video structure always holds * an array of characters whose length is equal to * the longest line possible. Only some of this is * used if "ncol" isn't the same as "NCOL". */ typedef struct { short v_hash; /* Hash code, for compares. */ short v_flag; /* Flag word. */ short v_color; /* Color of the line. */ XSHORT v_cost; /* Cost of display. */ char v_text[NCOL]; /* The actual characters. */ } VIDEO; #define VFCHG 0x0001 /* Changed. */ #define VFHBAD 0x0002 /* Hash and cost are bad. */ /* * SCORE structures hold the optimal * trace trajectory, and the cost of redisplay, when * the dynamic programming redisplay code is used. * If no fancy redisplay, this isn't used. The trace index * fields can be "char", and the score a "short", but * this makes the code worse on the VAX. */ typedef struct { XCHAR s_itrace; /* "i" index for track back. */ XCHAR s_jtrace; /* "j" index for trace back. */ XSHORT s_cost; /* Display cost. */ } SCORE; int sgarbf = TRUE; /* TRUE if screen is garbage. */ int vtrow = 0; /* Virtual cursor row. */ int vtcol = 0; /* Virtual cursor column. */ int tthue = CNONE; /* Current color. */ int ttrow = HUGE; /* Physical cursor row. */ int ttcol = HUGE; /* Physical cursor column. */ int tttop = HUGE; /* Top of scroll region. */ int ttbot = HUGE; /* Bottom of scroll region. */ VIDEO *vscreen[NROW-1]; /* Edge vector, virtual. */ VIDEO *pscreen[NROW-1]; /* Edge vector, physical. */ VIDEO video[2*(NROW-1)]; /* Actual screen data. */ VIDEO blanks; /* Blank line image. */ #if GOSLING /* * This matrix is written as an array because * we do funny things in the "setscores" routine, which * is very compute intensive, to make the subscripts go away. * It would be "SCORE score[NROW][NROW]" in old speak. * Look at "setscores" to understand what is up. */ SCORE score[NROW*NROW]; #endif /* * Initialize the data structures used * by the display code. The edge vectors used * to access the screens are set up. The operating * system's terminal I/O channel is set up. Fill the * "blanks" array with ASCII blanks. The rest is done * at compile time. The original window is marked * as needing full update, and the physical screen * is marked as garbage, so all the right stuff happens * on the first call to redisplay. */ vtinit() { register VIDEO *vp; register int i; ttopen(); ttinit(); vp = &video[0]; for (i=0; i= ncol) vp->v_text[ncol-1] = '$'; else if (c == '\t') { do { vtputc(' '); } while (vtcolv_text[vtcol++] = c; } /* * Erase from the end of the * software cursor to the end of the * line on which the software cursor is * located. The display routines will decide * if a hardware erase to end of line command * should be used to display this. */ vteeol() { register VIDEO *vp; vp = vscreen[vtrow]; while (vtcol < ncol) vp->v_text[vtcol++] = ' '; } /* * Make sure that the display is * right. This is a three part process. First, * scan through all of the windows looking for dirty * ones. Check the framing, and refresh the screen. * Second, make sure that "currow" and "curcol" are * correct for the current window. Third, make the * virtual and physical screens the same. */ update() { register LINE *lp; register WINDOW *wp; register VIDEO *vp1; register VIDEO *vp2; register int i; register int j; register int c; register int hflag; register int currow; register int curcol; register int offs; register int size; if (curmsgf!=FALSE || newmsgf!=FALSE) { wp = wheadp; while (wp != NULL) { wp->w_flag |= WFMODE; /* Must do mode lines. */ wp = wp->w_wndp; } } curmsgf = newmsgf; /* Sync. up right now. */ hflag = FALSE; /* Not hard. */ wp = wheadp; while (wp != NULL) { if (wp->w_flag != 0) { /* Need update. */ if ((wp->w_flag&WFFORCE) == 0) { lp = wp->w_linep; for (i=0; iw_ntrows; ++i) { if (lp == wp->w_dotp) goto out; if (lp == wp->w_bufp->b_linep) break; lp = lforw(lp); } } i = wp->w_force; /* Reframe this one. */ if (i > 0) { --i; if (i >= wp->w_ntrows) i = wp->w_ntrows-1; } else if (i < 0) { i += wp->w_ntrows; if (i < 0) i = 0; } else i = wp->w_ntrows/2; lp = wp->w_dotp; while (i!=0 && lback(lp)!=wp->w_bufp->b_linep) { --i; lp = lback(lp); } wp->w_linep = lp; wp->w_flag |= WFHARD; /* Force full. */ out: lp = wp->w_linep; /* Try reduced update. */ i = wp->w_toprow; if ((wp->w_flag&~WFMODE) == WFEDIT) { while (lp != wp->w_dotp) { ++i; lp = lforw(lp); } vscreen[i]->v_color = CTEXT; vscreen[i]->v_flag |= (VFCHG|VFHBAD); vtmove(i, 0); for (j=0; jw_flag&(WFEDIT|WFHARD)) != 0) { hflag = TRUE; while (i < wp->w_toprow+wp->w_ntrows) { vscreen[i]->v_color = CTEXT; vscreen[i]->v_flag |= (VFCHG|VFHBAD); vtmove(i, 0); if (lp != wp->w_bufp->b_linep) { for (j=0; jw_flag&WFMODE) != 0) modeline(wp); wp->w_flag = 0; wp->w_force = 0; } wp = wp->w_wndp; } lp = curwp->w_linep; /* Cursor location. */ currow = curwp->w_toprow; while (lp != curwp->w_dotp) { ++currow; lp = lforw(lp); } curcol = 0; i = 0; while (i < curwp->w_doto) { c = lgetc(lp, i++); if (c == '\t') curcol |= 0x07; else if (ISCTRL(c) != FALSE) ++curcol; ++curcol; } if (curcol >= ncol) /* Long line. */ curcol = ncol-1; if (sgarbf != FALSE) { /* Screen is garbage. */ sgarbf = FALSE; /* Erase-page clears */ epresf = FALSE; /* the message area. */ tttop = HUGE; /* Forget where you set */ ttbot = HUGE; /* scroll region. */ tthue = CNONE; /* Color unknown. */ ttmove(0, 0); tteeop(); for (i=0; iv_color != vp2->v_color || vp1->v_hash != vp2->v_hash) break; uline(offs, vp1, vp2); ucopy(vp1, vp2); ++offs; } if (offs == nrow-1) { /* Might get it all. */ ttmove(currow, curcol); ttflush(); return; } size = nrow-1; /* Get bottom match. */ while (size != offs) { vp1 = vscreen[size-1]; vp2 = pscreen[size-1]; if (vp1->v_color != vp2->v_color || vp1->v_hash != vp2->v_hash) break; uline(size-1, vp1, vp2); ucopy(vp1, vp2); --size; } if ((size -= offs) == 0) /* Get screen size. */ abort(); setscores(offs, size); /* Do hard update. */ traceback(offs, size, size, size); for (i=0; iv_flag&VFCHG) != 0) { uline(i, vp1, vp2); ucopy(vp1, vp2); } } ttmove(currow, curcol); ttflush(); } /* * Update a saved copy of a line, * kept in a VIDEO structure. The "vvp" is * the one in the "vscreen". The "pvp" is the one * in the "pscreen". This is called to make the * virtual and physical screens the same when * display has done an update. */ ucopy(vvp, pvp) register VIDEO *vvp; register VIDEO *pvp; { register int i; vvp->v_flag &= ~VFCHG; /* Changes done. */ pvp->v_flag = vvp->v_flag; /* Update model. */ pvp->v_hash = vvp->v_hash; pvp->v_cost = vvp->v_cost; pvp->v_color = vvp->v_color; for (i=0; iv_text[i] = vvp->v_text[i]; } /* * Update a single line. This routine only * uses basic functionality (no insert and delete character, * but erase to end of line). The "vvp" points at the VIDEO * structure for the line on the virtual screen, and the "pvp" * is the same for the physical screen. Avoid erase to end of * line when updating CMODE color lines, because of the way that * reverse video works on most terminals. */ uline(row, vvp, pvp) VIDEO *vvp; VIDEO *pvp; { #if MEMMAP putline(row+1, 1, &vvp->v_text[0]); #else register char *cp1; register char *cp2; register char *cp3; register char *cp4; register char *cp5; register int nbflag; if (vvp->v_color != pvp->v_color) { /* Wrong color, do a */ ttmove(row, 0); /* full redraw. */ ttcolor(vvp->v_color); cp1 = &vvp->v_text[0]; cp2 = &vvp->v_text[ncol]; while (cp1 != cp2) { ttputc(*cp1++); ++ttcol; } return; } cp1 = &vvp->v_text[0]; /* Compute left match. */ cp2 = &pvp->v_text[0]; while (cp1!=&vvp->v_text[ncol] && cp1[0]==cp2[0]) { ++cp1; ++cp2; } if (cp1 == &vvp->v_text[ncol]) /* All equal. */ return; nbflag = FALSE; cp3 = &vvp->v_text[ncol]; /* Compute right match. */ cp4 = &pvp->v_text[ncol]; while (cp3[-1] == cp4[-1]) { --cp3; --cp4; if (cp3[0] != ' ') /* Note non-blanks in */ nbflag = TRUE; /* the right match. */ } cp5 = cp3; /* Is erase good? */ if (nbflag==FALSE && vvp->v_color==CTEXT) { while (cp5!=cp1 && cp5[-1]==' ') --cp5; /* Alcyon hack */ if ((int)(cp3-cp5) <= tceeol) cp5 = cp3; } /* Alcyon hack */ ttmove(row, (int)(cp1-&vvp->v_text[0])); ttcolor(vvp->v_color); while (cp1 != cp5) { ttputc(*cp1++); ++ttcol; } if (cp5 != cp3) /* Do erase. */ tteeol(); #endif } /* * Redisplay the mode line for * the window pointed to by the "wp". * This is the only routine that has any idea * of how the modeline is formatted. You can * change the modeline format by hacking at * this routine. Called by "update" any time * there is a dirty window. */ modeline(wp) register WINDOW *wp; { register char *cp; register int c; register int n; register BUFFER *bp; n = wp->w_toprow+wp->w_ntrows; /* Location. */ vscreen[n]->v_color = CMODE; /* Mode line color. */ vscreen[n]->v_flag |= (VFCHG|VFHBAD); /* Recompute, display. */ vtmove(n, 0); /* Seek to right line. */ bp = wp->w_bufp; if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */ vtputc('*'); else vtputc(' '); n = 1; cp = "MicroEMACS"; /* Buffer name. */ while ((c = *cp++) != 0) { vtputc(c); ++n; } if (bp->b_bname[0] != 0) { vtputc(' '); ++n; cp = &bp->b_bname[0]; while ((c = *cp++) != 0) { vtputc(c); ++n; } } if (bp->b_fname[0] != 0) { /* File name. */ vtputc(' '); ++n; cp = "File:"; while ((c = *cp++) != 0) { vtputc(c); ++n; } cp = &bp->b_fname[0]; while ((c = *cp++) != 0) { vtputc(c); ++n; } } if (curmsgf != FALSE /* Message alert. */ && wp->w_wndp == NULL) { while (n < ncol-5-1) { vtputc(' '); ++n; } cp = "[Msg]"; /* Sizeof("[Msg]") = 5. */ while ((c = *cp++) != 0) { vtputc(c); ++n; } } while (n < ncol) { /* Pad out. */ vtputc(' '); ++n; } } #if GOSLING /* * Compute the hash code for * the line pointed to by the "vp". Recompute * it if necessary. Also set the approximate redisplay * cost. The validity of the hash code is marked by * a flag bit. The cost understand the advantages * of erase to end of line. Tuned for the VAX * by Bob McNamara; better than it used to be on * just about any machine. */ hash(vp) register VIDEO *vp; { register int i; register int n; register char *s; if ((vp->v_flag&VFHBAD) != 0) { /* Hash bad. */ s = &vp->v_text[ncol-1]; for (i=ncol; i!=0; --i, --s) if (*s != ' ') break; n = ncol-i; /* Erase cheaper? */ if (n > tceeol) n = tceeol; vp->v_cost = i+n; /* Bytes + blanks. */ for (n=0; i!=0; --i, --s) n = (n<<5) + n + *s; vp->v_hash = n; /* Hash code. */ vp->v_flag &= ~VFHBAD; /* Flag as all done. */ } } /* * Compute the Insert-Delete * cost matrix. The dynamic programming algorithm * described by James Gosling is used. This code assumes * that the line above the echo line is the last line involved * in the scroll region. This is easy to arrange on the VT100 * because of the scrolling region. The "offs" is the origin 0 * offset of the first row in the virtual/physical screen that * is being updated; the "size" is the length of the chunk of * screen being updated. For a full screen update, use offs=0 * and size=nrow-1. * * Older versions of this code implemented the score matrix by * a two dimensional array of SCORE nodes. This put all kinds of * multiply instructions in the code! This version is written to * use a linear array and pointers, and contains no multiplication * at all. The code has been carefully looked at on the VAX, with * only marginal checking on other machines for efficiency. In * fact, this has been tuned twice! Bob McNamara tuned it even * more for the VAX, which is a big issue for him because of * the 66 line X displays. * * On some machines, replacing the "for (i=1; i<=size; ++i)" with * i = 1; do { } while (++i <=size)" will make the code quite a * bit better; but it looks ugly. */ setscores(offs, size) { register SCORE *sp; register int tempcost; register int bestcost; register int j; register int i; register VIDEO **vp; register VIDEO **pp; register SCORE *sp1; register VIDEO **vbase; register VIDEO **pbase; vbase = &vscreen[offs-1]; /* By hand CSE's. */ pbase = &pscreen[offs-1]; score[0].s_itrace = 0; /* [0, 0] */ score[0].s_jtrace = 0; score[0].s_cost = 0; sp = &score[1]; /* Row 0, inserts. */ tempcost = 0; vp = &vbase[1]; for (j=1; j<=size; ++j) { sp->s_itrace = 0; sp->s_jtrace = j-1; tempcost += tcinsl; tempcost += (*vp)->v_cost; sp->s_cost = tempcost; ++vp; ++sp; } sp = &score[NROW]; /* Column 0, deletes. */ tempcost = 0; for (i=1; i<=size; ++i) { sp->s_itrace = i-1; sp->s_jtrace = 0; tempcost += tcdell; sp->s_cost = tempcost; sp += NROW; } sp1 = &score[NROW+1]; /* [1, 1]. */ pp = &pbase[1]; for (i=1; i<=size; ++i) { sp = sp1; vp = &vbase[1]; for (j=1; j<=size; ++j) { sp->s_itrace = i-1; sp->s_jtrace = j; bestcost = (sp-NROW)->s_cost; if (j != size) /* Cd(A[i])=0 @ Dis. */ bestcost += tcdell; tempcost = (sp-1)->s_cost; tempcost += (*vp)->v_cost; if (i != size) /* Ci(B[j])=0 @ Dsj. */ tempcost += tcinsl; if (tempcost < bestcost) { sp->s_itrace = i; sp->s_jtrace = j-1; bestcost = tempcost; } tempcost = (sp-NROW-1)->s_cost; if ((*pp)->v_color != (*vp)->v_color || (*pp)->v_hash != (*vp)->v_hash) tempcost += (*vp)->v_cost; if (tempcost < bestcost) { sp->s_itrace = i-1; sp->s_jtrace = j-1; bestcost = tempcost; } sp->s_cost = bestcost; ++sp; /* Next column. */ ++vp; } ++pp; sp1 += NROW; /* Next row. */ } } /* * Trace back through the dynamic programming cost * matrix, and update the screen using an optimal sequence * of redraws, insert lines, and delete lines. The "offs" is * the origin 0 offset of the chunk of the screen we are about to * update. The "i" and "j" are always started in the lower right * corner of the matrix, and imply the size of the screen. * A full screen traceback is called with offs=0 and i=j=nrow-1. * There is some do-it-yourself double subscripting here, * which is acceptable because this routine is much less compute * intensive then the code that builds the score matrix! */ traceback(offs, size, i, j) { register int itrace; register int jtrace; register int k; register int ninsl; register int ndraw; register int ndell; if (i==0 && j==0) /* End of update. */ return; itrace = score[(NROW*i) + j].s_itrace; jtrace = score[(NROW*i) + j].s_jtrace; if (itrace == i) { /* [i, j-1] */ ninsl = 0; /* Collect inserts. */ if (i != size) ninsl = 1; ndraw = 1; while (itrace!=0 || jtrace!=0) { if (score[(NROW*itrace) + jtrace].s_itrace != itrace) break; jtrace = score[(NROW*itrace) + jtrace].s_jtrace; if (i != size) ++ninsl; ++ndraw; } traceback(offs, size, itrace, jtrace); if (ninsl != 0) { ttcolor(CTEXT); ttinsl(offs+j-ninsl, offs+size-1, ninsl); } do { /* B[j], A[j] blank. */ k = offs+j-ndraw; uline(k, vscreen[k], &blanks); } while (--ndraw); return; } if (jtrace == j) { /* [i-1, j] */ ndell = 0; /* Collect deletes. */ if (j != size) ndell = 1; while (itrace!=0 || jtrace!=0) { if (score[(NROW*itrace) + jtrace].s_jtrace != jtrace) break; itrace = score[(NROW*itrace) + jtrace].s_itrace; if (j != size) ++ndell; } if (ndell != 0) { ttcolor(CTEXT); ttdell(offs+i-ndell, offs+size-1, ndell); } traceback(offs, size, itrace, jtrace); return; } traceback(offs, size, itrace, jtrace); k = offs+j-1; uline(k, vscreen[k], pscreen[offs+i-1]); } #endif SHAR_EOF if test 19660 -ne "`wc -c < 'display.c'`" then echo shar: error transmitting "'display.c'" '(should have been 19660 characters)' fi fi exit 0 # End of shell archive