home *** CD-ROM | disk | FTP | other *** search
- From: ustel@well.UUCP (Mark Hargrove)
- Newsgroups: comp.sources.misc
- Subject: v02i052: Unify TEXT fields from ACCELL Part 3/5
- Message-ID: <7220@ncoast.UUCP>
- Date: 11 Feb 88 00:49:28 GMT
- Approved: allbery@ncoast.UUCP
-
- Comp.sources.misc: Volume 2, Issue 52
- Submitted-By: "Mark Hargrove" <ustel@well.UUCP>
- Archive-Name: accell-text/Part3
-
- [Nice to know someone else posts Unify/Accell tools. ++bsa]
-
- #!/bin/sh
- # to extract, remove the header and type "sh filename"
- if `test ! -s ./cinfo.c`
- then
- echo "writing ./cinfo.c"
- cat > ./cinfo.c << '\Rogue\Monster\'
- /*
- * Character class tables.
- * 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, _P, 0, 0, /* 0x2X */
- _W, _W, 0, _W,
- 0, 0, 0, 0,
- 0, 0, _P, 0,
- _W, _W, _W, _W, /* 0x3X */
- _W, _W, _W, _W,
- _W, _W, 0, 0,
- 0, 0, 0, _P,
- 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, 0,
- 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
- };
-
- #ifdef __50SERIES
- /* Primos C blows up without this - wierd, really wierd... */
- static void dummy(){}
- #endif
- \Rogue\Monster\
- else
- echo "will not over write ./cinfo.c"
- fi
- if `test ! -s ./display.c`
- then
- echo "writing ./display.c"
- cat > ./display.c << '\Rogue\Monster\'
- /*
- * The functions in this file handle redisplay. The
- * redisplay system knows almost nothing about the editing
- * process; the editing functions do, however, set some
- * hints to eliminate a lot of the grinding. There is more
- * that can be done; the "vtputc" interface is a real
- * pig. Two conditional compilation flags; the GOSLING
- * flag enables dynamic programming redisplay, using the
- * algorithm published by Jim Gosling in SIGOA. The MEMMAP
- * changes things around for memory mapped video. With
- * both off, the terminal is a VT52.
- */
- #include "def.h"
-
- /*
- * You can change these back to the types
- * implied by the name if you get tight for space. If you
- * make both of them "int" you get better code on the VAX.
- * They do nothing if this is not Gosling redisplay, except
- * for change the size of a structure that isn't used.
- * A bit of a cheat.
- */
- /* These defines really belong in sysdef.h */
- #ifndef XCHAR
- # define XCHAR int
- # define XSHORT int
- #endif
-
- #ifdef STANDOUT_GLITCH
- extern int SG; /* number of standout glitches */
- #endif
-
- /*
- * A video structure always holds
- * an array of characters whose length is equal to
- * the longest line possible. Only some of this is
- * used if "ncol" isn't the same as "NCOL".
- */
- typedef struct {
- short v_hash; /* Hash code, for compares. */
- short v_flag; /* Flag word. */
- short v_color; /* Color of the line. */
- XSHORT v_cost; /* Cost of display. */
- char v_text[NCOL]; /* The actual characters. */
- } VIDEO;
-
- #define VFCHG 0x0001 /* Changed. */
- #define VFHBAD 0x0002 /* Hash and cost are bad. */
-
- /*
- * SCORE structures hold the optimal
- * trace trajectory, and the cost of redisplay, when
- * the dynamic programming redisplay code is used.
- * If no fancy redisplay, this isn't used. The trace index
- * fields can be "char", and the score a "short", but
- * this makes the code worse on the VAX.
- */
- typedef struct {
- XCHAR s_itrace; /* "i" index for track back. */
- XCHAR s_jtrace; /* "j" index for trace back. */
- XSHORT s_cost; /* Display cost. */
- } SCORE;
-
- int sgarbf = TRUE; /* TRUE if screen is garbage. */
- int vtrow = 0; /* Virtual cursor row. */
- int vtcol = 0; /* Virtual cursor column. */
- int tthue = CNONE; /* Current color. */
- int ttrow = HUGE; /* Physical cursor row. */
- int ttcol = HUGE; /* Physical cursor column. */
- int tttop = HUGE; /* Top of scroll region. */
- int ttbot = HUGE; /* Bottom of scroll region. */
-
- VIDEO *vscreen[NROW-1]; /* Edge vector, virtual. */
- VIDEO *pscreen[NROW-1]; /* Edge vector, physical. */
- VIDEO video[2*(NROW-1)]; /* Actual screen data. */
- VIDEO blanks; /* Blank line image. */
-
- /*
- * Some predeclerations to make ANSI compilers happy
- */
- VOID vtinit();
- VOID vttidy();
- VOID vtmove();
- VOID vtputc();
- VOID vteeol();
- VOID update();
- VOID ucopy();
- VOID uline();
- VOID modeline();
- VOID hash();
- VOID setscores();
- VOID traceback();
-
- #ifdef GOSLING
- /*
- * This matrix is written as an array because
- * we do funny things in the "setscores" routine, which
- * is very compute intensive, to make the subscripts go away.
- * It would be "SCORE score[NROW][NROW]" in old speak.
- * Look at "setscores" to understand what is up.
- */
- SCORE score[NROW*NROW];
- #endif
-
- /*
- * Initialize the data structures used
- * by the display code. The edge vectors used
- * to access the screens are set up. The operating
- * system's terminal I/O channel is set up. Fill the
- * "blanks" array with ASCII blanks. The rest is done
- * at compile time. The original window is marked
- * as needing full update, and the physical screen
- * is marked as garbage, so all the right stuff happens
- * on the first call to redisplay.
- */
- VOID
- vtinit()
- {
- register VIDEO *vp;
- register int i;
-
- ttopen();
- ttinit();
- vp = &video[0];
- for (i=0; i<NROW-1; ++i)
- {
- vscreen[i] = vp;
- ++vp;
- pscreen[i] = vp;
- ++vp;
- }
- blanks.v_color = CTEXT;
- for (i=0; i<NCOL; ++i)
- blanks.v_text[i] = ' ';
- }
-
- /*
- * Tidy up the virtual display system
- * in anticipation of a return back to the host
- * operating system. Right now all we do is position
- * the cursor to the last line, erase the line, and
- * close the terminal channel.
- */
- VOID
- vttidy()
- {
- ttcolor(CTEXT);
- ttnowindow(); /* No scroll window. */
- ttmove(nrow-1, 0); /* Echo line. */
- tteeol();
- tttidy();
- ttflush();
- ttclose();
- }
-
- /*
- * Move the virtual cursor to an origin
- * 0 spot on the virtual display screen. I could
- * store the column as a character pointer to the spot
- * on the line, which would make "vtputc" a little bit
- * more efficient. No checking for errors.
- */
- VOID
- vtmove(row, col)
- {
- vtrow = row;
- vtcol = col;
- }
-
- /*
- * Write a character to the virtual display,
- * dealing with long lines and the display of unprintable
- * things like control characters. Also expand tabs every 8
- * columns. This code only puts printing characters into
- * the virtual display image. Special care must be taken when
- * expanding tabs. On a screen whose width is not a multiple
- * of 8, it is possible for the virtual cursor to hit the
- * right margin before the next tab stop is reached. This
- * makes the tab code loop if you are not careful.
- * Three guesses how we found this.
- */
- VOID
- vtputc(c) register int c;
- {
- register VIDEO *vp;
-
- vp = vscreen[vtrow];
- if (vtcol >= ncol)
- vp->v_text[ncol-1] = '$';
- else if (
- #ifdef NOTAB
- !(mode&MNOTAB) &&
- #endif
- c == '\t')
- {
- do {
- vtputc(' ');
- } while (vtcol<ncol && (vtcol&0x07)!=0);
- }
- else if (ISCTRL(c) != FALSE)
- {
- vtputc('^');
- vtputc(c ^ 0x40);
- } else
- vp->v_text[vtcol++] = c;
- }
-
- /*
- * Erase from the end of the
- * software cursor to the end of the
- * line on which the software cursor is
- * located. The display routines will decide
- * if a hardware erase to end of line command
- * should be used to display this.
- */
- VOID
- vteeol()
- {
- register VIDEO *vp;
-
- vp = vscreen[vtrow];
- while (vtcol < ncol)
- vp->v_text[vtcol++] = ' ';
- }
-
- /*
- * Make sure that the display is
- * right. This is a three part process. First,
- * scan through all of the windows looking for dirty
- * ones. Check the framing, and refresh the screen.
- * Second, make sure that "currow" and "curcol" are
- * correct for the current window. Third, make the
- * virtual and physical screens the same.
- */
- VOID
- update()
- {
- register LINE *lp;
- register WINDOW *wp;
- register VIDEO *vp1;
- VIDEO *vp2;
- register int i;
- register int j;
- register int c;
- register int hflag;
- register int currow;
- register int curcol;
- register int offs;
- register int size;
- VOID traceback ();
- VOID uline ();
-
- if (typeahead()) return;
- if (sgarbf)
- { /* must update everything */
- wp = wheadp;
- while(wp != NULL)
- {
- wp->w_flag |= WFMODE | WFHARD;
- wp = wp->w_wndp;
- }
- }
- hflag = FALSE; /* Not hard. */
- wp = wheadp;
- while (wp != NULL)
- {
- if (wp->w_flag != 0)
- { /* Need update. */
- if ((wp->w_flag&WFFORCE) == 0)
- {
- lp = wp->w_linep;
- for (i=0; i<wp->w_ntrows; ++i)
- {
- if (lp == wp->w_dotp)
- goto out;
- if (lp == wp->w_bufp->b_linep)
- break;
- lp = lforw(lp);
- }
- }
- i = wp->w_force; /* Reframe this one. */
- if (i > 0)
- {
- --i;
- if (i >= wp->w_ntrows)
- i = wp->w_ntrows-1;
- } else if (i < 0)
- {
- i += wp->w_ntrows;
- if (i < 0)
- i = 0;
- } else
- i = wp->w_ntrows/2;
- lp = wp->w_dotp;
- while (i!=0 && lback(lp)!=wp->w_bufp->b_linep)
- {
- --i;
- lp = lback(lp);
- }
- wp->w_linep = lp;
- wp->w_flag |= WFHARD; /* Force full. */
- out:
- lp = wp->w_linep; /* Try reduced update. */
- i = wp->w_toprow;
- if ((wp->w_flag&~WFMODE) == WFEDIT)
- {
- while (lp != wp->w_dotp)
- {
- ++i;
- lp = lforw(lp);
- }
- vscreen[i]->v_color = CTEXT;
- vscreen[i]->v_flag |= (VFCHG|VFHBAD);
- vtmove(i, 0);
- for (j=0; j<llength(lp); ++j)
- vtputc(lgetc(lp, j));
- vteeol();
- }
- else if ((wp->w_flag&(WFEDIT|WFHARD)) != 0)
- {
- hflag = TRUE;
- while (i < wp->w_toprow+wp->w_ntrows)
- {
- vscreen[i]->v_color = CTEXT;
- vscreen[i]->v_flag |= (VFCHG|VFHBAD);
- vtmove(i, 0);
- if (lp != wp->w_bufp->b_linep)
- {
- for (j=0; j<llength(lp); ++j)
- vtputc(lgetc(lp, j));
- lp = lforw(lp);
- }
- vteeol();
- ++i;
- }
- }
- if ((wp->w_flag&WFMODE) != 0)
- modeline(wp);
- wp->w_flag = 0;
- wp->w_force = 0;
- }
- wp = wp->w_wndp;
- }
- lp = curwp->w_linep; /* Cursor location. */
- currow = curwp->w_toprow;
- while (lp != curwp->w_dotp)
- {
- ++currow;
- lp = lforw(lp);
- }
- curcol = 0;
- i = 0;
- while (i < curwp->w_doto)
- {
- c = lgetc(lp, i++);
- if (
- #ifdef NOTAB
- !(mode&MNOTAB) &&
- #endif
- c == '\t')
- curcol |= 0x07;
- else if (ISCTRL(c) != FALSE)
- ++curcol;
- ++curcol;
- }
- if (curcol >= ncol) /* Long line. */
- curcol = ncol-1;
- if (sgarbf != FALSE)
- { /* Screen is garbage. */
- sgarbf = FALSE; /* Erase-page clears */
- epresf = FALSE; /* the message area. */
- tttop = HUGE; /* Forget where you set */
- ttbot = HUGE; /* scroll region. */
- tthue = CNONE; /* Color unknown. */
- ttmove(0, 0);
- tteeop();
- for (i=0; i<nrow-1; ++i)
- {
- uline(i, vscreen[i], &blanks);
- ucopy(vscreen[i], pscreen[i]);
- }
- ttmove(currow, curcol);
- ttflush();
- return;
- }
- #ifdef GOSLING
- if (hflag != FALSE)
- { /* Hard update? */
- for (i=0; i<nrow-1; ++i)
- { /* Compute hash data. */
- hash(vscreen[i]);
- hash(pscreen[i]);
- }
- offs = 0; /* Get top match. */
- while (offs != nrow-1)
- {
- vp1 = vscreen[offs];
- vp2 = pscreen[offs];
- if (vp1->v_color != vp2->v_color
- || vp1->v_hash != vp2->v_hash)
- break;
- uline(offs, vp1, vp2);
- ucopy(vp1, vp2);
- ++offs;
- }
- if (offs == nrow-1)
- { /* Might get it all. */
- ttmove(currow, curcol);
- ttflush();
- return;
- }
- size = nrow-1; /* Get bottom match. */
- while (size != offs)
- {
- vp1 = vscreen[size-1];
- vp2 = pscreen[size-1];
- if (vp1->v_color != vp2->v_color
- || vp1->v_hash != vp2->v_hash)
- break;
- uline(size-1, vp1, vp2);
- ucopy(vp1, vp2);
- --size;
- }
- if ((size -= offs) == 0) /* Get screen size. */
- panic("Illegal screen size in update");
- setscores(offs, size); /* Do hard update. */
- traceback(offs, size, size, size);
- for (i=0; i<size; ++i)
- ucopy(vscreen[offs+i], pscreen[offs+i]);
- ttmove(currow, curcol);
- ttflush();
- return;
- }
- #endif
- for (i=0; i<nrow-1; ++i)
- { /* Easy update. */
- vp1 = vscreen[i];
- vp2 = pscreen[i];
- if ((vp1->v_flag&VFCHG) != 0)
- {
- uline(i, vp1, vp2);
- ucopy(vp1, vp2);
- }
- }
- ttmove(currow, curcol);
- ttflush();
- }
-
- /*
- * Update a saved copy of a line,
- * kept in a VIDEO structure. The "vvp" is
- * the one in the "vscreen". The "pvp" is the one
- * in the "pscreen". This is called to make the
- * virtual and physical screens the same when
- * display has done an update.
- */
- VOID
- ucopy(vvp, pvp) register VIDEO *vvp; register VIDEO *pvp;
- {
-
- vvp->v_flag &= ~VFCHG; /* Changes done. */
- pvp->v_flag = vvp->v_flag; /* Update model. */
- pvp->v_hash = vvp->v_hash;
- pvp->v_cost = vvp->v_cost;
- pvp->v_color = vvp->v_color;
- bcopy(vvp->v_text, pvp->v_text, ncol);
- }
-
- /*
- * Update a single line. This routine only
- * uses basic functionality (no insert and delete character,
- * but erase to end of line). The "vvp" points at the VIDEO
- * structure for the line on the virtual screen, and the "pvp"
- * is the same for the physical screen. Avoid erase to end of
- * line when updating CMODE color lines, because of the way that
- * reverse video works on most terminals.
- */
- VOID uline(row, vvp, pvp) VIDEO *vvp; VIDEO *pvp;
- {
- #ifdef MEMMAP
- putline(row+1, 1, &vvp->v_text[0]);
- #else
- register char *cp1;
- register char *cp2;
- register char *cp3;
- char *cp4;
- char *cp5;
- register int nbflag;
-
- if (vvp->v_color != pvp->v_color)
- { /* Wrong color, */
- ttmove(row, 0); /* do a full redraw. */
- #ifdef STANDOUT_GLITCH
- if (pvp->v_color != CTEXT && SG >= 0) tteeol();
- #endif
- ttcolor(vvp->v_color);
- #ifdef STANDOUT_GLITCH
- cp1 = &vvp->v_text[SG > 0 ? SG : 0];
- /* the odd code for SG==0 is to avoid putting the invisable
- * glitch character on the next line.
- * (Hazeltine executive 80 model 30)
- */
- cp2 = &vvp->v_text[ncol - (SG >= 0 ? (SG!=0 ? SG : 1) : 0)];
- #else
- cp1 = &vvp->v_text[0];
- cp2 = &vvp->v_text[ncol];
- #endif
- while (cp1 != cp2)
- {
- ttputc(*cp1++);
- ++ttcol;
- }
- #ifndef MOVE_STANDOUT
- ttcolor(CTEXT);
- #endif
- return;
- }
- cp1 = &vvp->v_text[0]; /* Compute left match. */
- cp2 = &pvp->v_text[0];
- while (cp1!=&vvp->v_text[ncol] && cp1[0]==cp2[0])
- {
- ++cp1;
- ++cp2;
- }
- if (cp1 == &vvp->v_text[ncol]) /* All equal. */
- return;
- nbflag = FALSE;
- cp3 = &vvp->v_text[ncol]; /* Compute right match. */
- cp4 = &pvp->v_text[ncol];
- while (cp3[-1] == cp4[-1])
- {
- --cp3;
- --cp4;
- if (cp3[0] != ' ') /* Note non-blanks in */
- nbflag = TRUE; /* the right match. */
- }
- cp5 = cp3; /* Is erase good? */
- if (nbflag==FALSE && vvp->v_color==CTEXT)
- {
- while (cp5!=cp1 && cp5[-1]==' ')
- --cp5;
- /* Alcyon hack */
- if ((int)(cp3-cp5) <= tceeol)
- cp5 = cp3;
- }
- /* Alcyon hack */
- ttmove(row, (int)(cp1-&vvp->v_text[0]));
- #ifdef STANDOUT_GLITCH
- if (vvp->v_color != CTEXT && SG > 0)
- {
- if(cp1 < &vvp->v_text[SG]) cp1 = &vvp->v_text[SG];
- if(cp5 > &vvp->v_text[ncol-SG]) cp5 = &vvp->v_text[ncol-SG];
- } else if (SG < 0)
- #endif
- ttcolor(vvp->v_color);
- while (cp1 != cp5)
- {
- ttputc(*cp1++);
- ++ttcol;
- }
- if (cp5 != cp3) /* Do erase. */
- tteeol();
- #endif
- }
-
- #define LAST_ROT 5
- static int rotat_pos = 1;
- /*
- * The mode line reflects the the Function-Key help
- * information, rather than the state of the current window/buffer
- * (since there is only one window in the TINY version).
- */
- VOID
- modeline(wp)
- register WINDOW *wp;
- {
- register int row, /* display row */
- col; /* current column */
- register BUFFER *bp;
-
- row = wp->w_toprow+wp->w_ntrows; /* Location. */
- vscreen[row]->v_color = CMODE; /* Mode line color. */
- vscreen[row]->v_flag |= (VFCHG|VFHBAD); /* Recompute, display. */
- vtmove(row, 0); /* Seek to right line. */
- bp = wp->w_bufp;
- if ((mode & MOVRSTK) == 0)
- col = vtputs(" Insert |");
- else
- col = vtputs(" Replace|");
-
- switch (rotat_pos)
- {
- case 1: /* Function Keys 1-4 */
- col += vtputs("F1 -Prv Form |");
- #ifdef MISLOG
- col += vtputs("F2 -Time Stmp|");
- #else
- col += vtputs(" |");
- #endif
- col += vtputs("F3 -Prv Line |");
- col += vtputs("F4 -Nxt Line |");
- break;
- case 2: /* Function Keys 5-8 */
- col += vtputs("F5 -Open Line|");
- col += vtputs("F6 -Fix Para |");
- #ifdef MENU_INSERT
- col += vtputs("F7 -Ins File |");
- #else
- col += vtputs(" |");
- #endif
- col += vtputs("F8 -Rep/Ins |");
- break;
- case 3: /* Function Keys 9,11-13 */
- col += vtputs("F9 -Save |");
- col += vtputs("F11-Restart |");
- col += vtputs("F12-Print |");
- col += vtputs("F13-Search |");
- break;
- case 4: /* Function Keys 14-17 */
- col += vtputs("F14-Prv Para |");
- col += vtputs("F15-Nxt Para |");
- col += vtputs("F16-Beg Line |");
- col += vtputs("F17-End Line |");
- break;
- case 5: /* Function Keys 18-19+ */
- col += vtputs("F18-Del Line |");
- col += vtputs("F19-Zoom Can |");
- col += vtputs(" |");
- col += vtputs(" |");
- break;
- default: /* shouldn't get here. set to known state */
- rotat_pos = 1;
- break;
- } /* end switch */
- while (col < 60)
- {
- vtputc(' ');
- ++col;
- }
- col += vtputs("F10- More Key");
- while (col < ncol)
- { /* Pad out. */
- vtputc(' ');
- ++col;
- }
- }
-
- /*
- * This routine does the actual rotating of the fields
- * of the mode-line help message.
- */
- /*ARGSUSED*/
- rotatmode( f, n, k)
- {
- rotat_pos += 1;
- if (rotat_pos > LAST_ROT)
- rotat_pos = 1;
- modeline(wheadp); /* NOTE: this only works because only */
- wheadp->w_flag &= WFHARD; /* one window allowed in TINY version */
- return TRUE;
- }
-
- /*
- * output a string to the mode line, report how long it was.
- */
- vtputs(s) register char *s;
- {
- register int n = 0;
-
- while (*s != '\0')
- {
- vtputc(*s++);
- ++n;
- }
- return n;
- }
- #ifdef GOSLING
- /*
- * Compute the hash code for
- * the line pointed to by the "vp". Recompute
- * it if necessary. Also set the approximate redisplay
- * cost. The validity of the hash code is marked by
- * a flag bit. The cost understand the advantages
- * of erase to end of line. Tuned for the VAX
- * by Bob McNamara; better than it used to be on
- * just about any machine.
- */
- VOID
- 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.
- */
- VOID
- setscores(offs, size)
- {
- register SCORE *sp;
- SCORE *sp1;
- register int tempcost;
- register int bestcost;
- register int j;
- register int i;
- register VIDEO **vp;
- VIDEO **pp, **vbase, **pbase;
-
- vbase = &vscreen[offs-1]; /* By hand CSE's. */
- pbase = &pscreen[offs-1];
- score[0].s_itrace = 0; /* [0, 0] */
- score[0].s_jtrace = 0;
- score[0].s_cost = 0;
- sp = &score[1]; /* Row 0, inserts. */
- tempcost = 0;
- vp = &vbase[1];
- for (j=1; j<=size; ++j)
- {
- sp->s_itrace = 0;
- sp->s_jtrace = j-1;
- tempcost += tcinsl;
- tempcost += (*vp)->v_cost;
- sp->s_cost = tempcost;
- ++vp;
- ++sp;
- }
- sp = &score[NROW]; /* Column 0, deletes. */
- tempcost = 0;
- for (i=1; i<=size; ++i)
- {
- sp->s_itrace = i-1;
- sp->s_jtrace = 0;
- tempcost += tcdell;
- sp->s_cost = tempcost;
- sp += NROW;
- }
- sp1 = &score[NROW+1]; /* [1, 1]. */
- pp = &pbase[1];
- for (i=1; i<=size; ++i)
- {
- sp = sp1;
- vp = &vbase[1];
- for (j=1; j<=size; ++j)
- {
- sp->s_itrace = i-1;
- sp->s_jtrace = j;
- bestcost = (sp-NROW)->s_cost;
- if (j != size) /* Cd(A[i])=0 @ Dis. */
- bestcost += tcdell;
- tempcost = (sp-1)->s_cost;
- tempcost += (*vp)->v_cost;
- if (i != size) /* Ci(B[j])=0 @ Dsj. */
- tempcost += tcinsl;
- if (tempcost < bestcost)
- {
- sp->s_itrace = i;
- sp->s_jtrace = j-1;
- bestcost = tempcost;
- }
- tempcost = (sp-NROW-1)->s_cost;
- if ((*pp)->v_color != (*vp)->v_color
- || (*pp)->v_hash != (*vp)->v_hash)
- tempcost += (*vp)->v_cost;
- if (tempcost < bestcost)
- {
- sp->s_itrace = i-1;
- sp->s_jtrace = j-1;
- bestcost = tempcost;
- }
- sp->s_cost = bestcost;
- ++sp; /* Next column. */
- ++vp;
- }
- ++pp;
- sp1 += NROW; /* Next row. */
- }
- }
-
- /*
- * Trace back through the dynamic programming cost
- * matrix, and update the screen using an optimal sequence
- * of redraws, insert lines, and delete lines. The "offs" is
- * the origin 0 offset of the chunk of the screen we are about to
- * update. The "i" and "j" are always started in the lower right
- * corner of the matrix, and imply the size of the screen.
- * A full screen traceback is called with offs=0 and i=j=nrow-1.
- * There is some do-it-yourself double subscripting here,
- * which is acceptable because this routine is much less compute
- * intensive then the code that builds the score matrix!
- */
- VOID traceback(offs, size, i, j)
- {
- register int itrace;
- register int jtrace;
- register int k;
- register int ninsl;
- register int ndraw;
- register int ndell;
-
- if (i==0 && j==0) /* End of update. */
- return;
- itrace = score[(NROW*i) + j].s_itrace;
- jtrace = score[(NROW*i) + j].s_jtrace;
- if (itrace == i)
- { /* [i, j-1] */
- ninsl = 0; /* Collect inserts. */
- if (i != size)
- ninsl = 1;
- ndraw = 1;
- while (itrace!=0 || jtrace!=0)
- {
- if (score[(NROW*itrace) + jtrace].s_itrace != itrace)
- break;
- jtrace = score[(NROW*itrace) + jtrace].s_jtrace;
- if (i != size)
- ++ninsl;
- ++ndraw;
- }
- traceback(offs, size, itrace, jtrace);
- if (ninsl != 0)
- {
- ttcolor(CTEXT);
- ttinsl(offs+j-ninsl, offs+size-1, ninsl);
- }
- do { /* B[j], A[j] blank. */
- k = offs+j-ndraw;
- uline(k, vscreen[k], &blanks);
- } while (--ndraw);
- return;
- }
- if (jtrace == j)
- { /* [i-1, j] */
- ndell = 0; /* Collect deletes. */
- if (j != size)
- ndell = 1;
- while (itrace!=0 || jtrace!=0)
- {
- if (score[(NROW*itrace) + jtrace].s_jtrace != jtrace)
- break;
- itrace = score[(NROW*itrace) + jtrace].s_itrace;
- if (j != size)
- ++ndell;
- }
- if (ndell != 0)
- {
- ttcolor(CTEXT);
- ttdell(offs+i-ndell, offs+size-1, ndell);
- }
- traceback(offs, size, itrace, jtrace);
- return;
- }
- traceback(offs, size, itrace, jtrace);
- k = offs+j-1;
- uline(k, vscreen[k], pscreen[offs+i-1]);
- }
- #endif
- \Rogue\Monster\
- else
- echo "will not over write ./display.c"
- fi
- if `test ! -s ./echo.c`
- then
- echo "writing ./echo.c"
- cat > ./echo.c << '\Rogue\Monster\'
- /*
- * Echo line reading and writing.
- *
- * Common routines for reading
- * and writing characters in the echo line area
- * of the display screen. Used by the entire
- * known universe.
- */
- #include "def.h"
- #ifdef VARARGS
- # include <varargs.h>
- static veread();
- VOID ewprintf();
- #endif
- static VOID eformat();
- static VOID eputi();
- static VOID eputl();
- static VOID eputs();
- static VOID eputc();
-
- int epresf = FALSE; /* Stuff in echo line flag. */
- /*
- * Erase the echo line.
- */
- VOID
- eerase()
- {
- ttcolor(CTEXT);
- ttmove(nrow-1, 0);
- tteeol();
- ttflush();
- epresf = FALSE;
- }
-
- /*
- * Ask "yes" or "no" question.
- * Return ABORT if the user answers the question
- * with the abort ("^G") character. Return FALSE
- * for "no" and TRUE for "yes". No formatting
- * services are available. No newline required.
- */
- eyorn(sp) char *sp;
- {
- register KEY s;
-
- if (kbdmop == NULL) ewprintf("%s? (y or n) ", sp);
- for (;;)
- {
- s = getkey(0);
- if (s == 'y' || s == 'Y') return (TRUE);
- if (s == 'n' || s == 'N') return (FALSE);
- if (s == (KCTRL|'G') || s == (KCTLX|KCTRL|'G')
- || s == (KMETA|KCTRL|'G'))
- {
- (VOID) ctrlg(FALSE, 1, KRANDOM);
- return ABORT;
- }
- if (kbdmop == NULL)
- ewprintf("Please answer y or n. %s? (y or n) ", sp);
- }
- /*NOTREACHED*/
- }
-
- /*
- * Like eyorn, but for more important question. User must type either all of
- * "yes" or "no", and the trainling newline.
- */
- eyesno(sp) char *sp;
- {
- register int s;
- char buf[64];
-
- s = ereply("%s? (yes or no) ", buf, sizeof(buf), sp);
- for (;;)
- {
- if (s == ABORT) return ABORT;
- if (s != FALSE)
- {
- if ((buf[0] == 'y' || buf[0] == 'Y')
- && (buf[1] == 'e' || buf[1] == 'E')
- && (buf[2] == 's' || buf[2] == 'S')) return TRUE;
- if ((buf[0] == 'n' || buf[0] == 'N')
- && (buf[1] == 'o' || buf[0] == 'O')) return FALSE;
- }
- s = ereply("Please answer yes or no. %s? (yes or no) ",
- buf, sizeof(buf), sp);
- }
- /*NOTREACHED*/
- }
- /*
- * Write out a prompt, and read back a
- * reply. The prompt is now written out with full "ewprintf"
- * formatting, although the arguments are in a rather strange
- * place. This is always a new message, there is no auto
- * completion, and the return is echoed as such.
- */
- #ifdef VARARGS
- ereply(va_alist)
- va_dcl
- {
- register int i;
- va_list pvar;
- register char *fp, *buf;
- register int nbuf;
-
- va_start(pvar);
- fp = va_arg(pvar, char *);
- buf = va_arg(pvar, char *);
- nbuf = va_arg(pvar, int);
- i = veread(fp, buf, nbuf, EFNEW|EFCR, &pvar);
- va_end(pvar);
- return i;
- }
- #else
- /* VARARGS3 */
- ereply(fp, buf, nbuf, arg) char *fp, *buf; int nbuf; long arg;
- {
- return (eread(fp, buf, nbuf, EFNEW|EFCR, (char *)&arg));
- }
- #endif
-
- /*
- * This is the general "read input from the
- * echo line" routine. The basic idea is that the prompt
- * string "prompt" is written to the echo line, and a one
- * line reply is read back into the supplied "buf" (with
- * maximum length "len"). The "flag" contains EFNEW (a
- * new prompt), an EFFUNC (autocomplete), or EFCR (echo
- * the carriage return as CR).
- */
- /* VARARGS4 */
- #ifdef VARARGS
- eread(va_alist)
- va_dcl
- {
- va_list pvar;
- char *fp, *buf;
- int nbuf, flag, i;
- va_start(pvar);
- fp = va_arg(pvar, char *);
- buf = va_arg(pvar, char *);
- nbuf = va_arg(pvar, int);
- flag = va_arg(pvar, int);
- i = veread(fp, buf, nbuf, flag, &pvar);
- va_end(pvar);
- return i;
- }
- #endif
-
- #ifdef VARARGS
- static veread(fp, buf, nbuf, flag, ap) char *fp; char *buf; va_list *ap;
- {
- #else
- eread(fp, buf, nbuf, flag, ap) char *fp; char *buf; char *ap;
- {
- #endif
- register int cpos;
- register int i;
- register KEY c;
-
- cpos = 0;
- if (kbdmop != NULL)
- { /* In a macro. */
- while ((c = *kbdmop++) != '\0')
- buf[cpos++] = (char) c;
- buf[cpos] = '\0';
- goto done;
- }
- if ((flag&EFNEW)!=0 || ttrow!=nrow-1)
- {
- ttcolor(CTEXT);
- ttmove(nrow-1, 0);
- epresf = TRUE;
- } else
- eputc(' ');
- eformat(fp, ap);
- tteeol();
- ttflush();
- for (;;)
- {
- c = getkey(KQUOTE|KNOMAC);
- if ((flag&EFAUTO) != 0 && (c == ' ' || c == CCHR('I')))
- {
- cpos += complete(flag, c, buf, cpos);
- continue;
- }
- switch (c)
- {
- case 0x0A:
- case 0x0D: /* Return, done. */
- if ((flag&EFFUNC) != 0)
- {
- if ((i = complete(flag, c, buf, cpos)) == 0)
- continue;
- if (i > 0) cpos += i;
- }
- buf[cpos] = '\0';
- if ((flag&EFCR) != 0)
- {
- ttputc(0x0D);
- ttflush();
- }
- if (kbdmip != NULL)
- {
- if (kbdmip+cpos+1 > &kbdm[NKBDM-3])
- {
- ewprintf("Keyboard macro overflow");
- ttflush();
- return FALSE;
- }
- for (i = 0; i <= cpos; ++i)
- *kbdmip++ = (KEY) buf[i];
- }
- goto done;
-
- case CCHR('G'): /* Bell, abort. */
- eputc(CCHR('G'));
- (VOID) ctrlg(FALSE, 0, KRANDOM);
- ttflush();
- return (ABORT);
-
- case 0x7F: /* Rubout, erase. */
- if (cpos != 0)
- {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- if (ISCTRL(buf[--cpos]) != FALSE)
- {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- }
- ttflush();
- }
- break;
-
- case CCHR('X'): /* C-X */
- case CCHR('U'): /* C-U, kill line. */
- while (cpos != 0)
- {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- if (ISCTRL(buf[--cpos]) != FALSE)
- {
- ttputc('\b');
- ttputc(' ');
- ttputc('\b');
- --ttcol;
- }
- }
- ttflush();
- break;
-
- case CCHR('Q'): /* C-Q, quote next */
- c = getkey(KQUOTE|KNOMAC) ;
- default: /* All the rest. */
- if (cpos < nbuf-1)
- {
- buf[cpos++] = (char) c;
- eputc((char) c);
- ttflush();
- }
- }
- }
- done:
- if (buf[0] == '\0')
- return (FALSE);
- return (TRUE);
- }
-
- /*
- * do completion on a list of objects.
- */
- complete(flags, c, buf, cpos) register char *buf; register int cpos;
- {
- register LIST *lh, *lh2;
- int i, nxtra;
- int nhits, bxtra;
- int wflag = FALSE;
- int msglen, nshown;
- char *msg;
-
- if ((flags&EFFUNC) != 0) lh = &(symbol[0]->s_list);
- else if ((flags&EFBUF) != 0) lh = &(bheadp->b_list);
- else panic("broken complete call: flags");
-
- if (c == ' ') wflag = TRUE;
- else if (c != '\t' && c != 0x0D && c != 0x0A)
- panic("broken complete call: c");
-
- nhits = 0;
- nxtra = HUGE;
-
- while (lh != NULL)
- {
- for (i=0; i<cpos; ++i)
- {
- if (buf[i] != lh->l_name[i])
- break;
- }
- if (i == cpos)
- {
- if (nhits == 0)
- lh2 = lh;
- ++nhits;
- if (lh->l_name[i] == '\0') nxtra = -1;
- else
- {
- bxtra = getxtra(lh, lh2, cpos, wflag);
- if (bxtra < nxtra) nxtra = bxtra;
- lh2 = lh;
- }
- }
- lh = lh->l_next;
- }
- if (nhits == 0)
- msg = " [No match]";
- else if (nhits > 1 && nxtra == 0)
- msg = " [Ambiguous]";
- else
- { /* Got a match, do it to it */
- /*
- * Being lazy - ought to check length, but all things
- * autocompleted have known types/lengths.
- */
- if (nxtra < 0 && nhits > 1 && c == ' ') nxtra = 1;
- for (i = 0; i < nxtra; ++i)
- {
- buf[cpos] = lh2->l_name[cpos];
- eputc(buf[cpos++]);
- }
- ttflush();
- if (nxtra < 0 && c != 0x0D && c != 0x0A) return 0;
- return nxtra;
- }
- /* Set up backspaces, etc., being mindful of echo line limit */
- msglen = strlen(msg);
- nshown = (ttcol + msglen + 2 > ncol) ?
- ncol - ttcol - 2 : msglen;
- eputs(msg);
- ttcol -= (i = nshown); /* update ttcol! */
- while (i--) /* move back before msg */
- ttputc('\b');
- ttflush(); /* display to user */
- i = nshown;
- while (i--) /* blank out on next flush */
- eputc(' ');
- ttcol -= (i = nshown); /* update ttcol on BS's */
- while (i--)
- ttputc('\b'); /* update ttcol again! */
- return 0;
-
- }
-
- /*
- * The "lp1" and "lp2" point to list structures. The
- * "cpos" is a horizontal position in the name.
- * Return the longest block of characters that can be
- * autocompleted at this point. Sometimes the two
- * symbols are the same, but this is normal.
- */
- getxtra(lp1, lp2, cpos, wflag) register LIST *lp1, *lp2; register int wflag;
- {
- register int i;
-
- i = cpos;
- for (;;)
- {
- if (lp1->l_name[i] != lp2->l_name[i]) break;
- if (lp1->l_name[i] == '\0') break;
- ++i;
- if (wflag && !ISWORD(lp1->l_name[i-1])) break;
- }
- return (i - cpos);
- }
-
- /*
- * Special "printf" for the echo line.
- * Each call to "ewprintf" starts a new line in the
- * echo area, and ends with an erase to end of the
- * echo line. The formatting is done by a call
- * to the standard formatting routine.
- */
- #ifdef VARARGS
- VOID
- ewprintf(va_alist)
- va_dcl
- {
- va_list pvar;
- register char *fp;
-
- va_start(pvar);
- fp = va_arg(pvar, char *);
- #else
- /* VARARGS1 */
- ewprintf(fp, arg) char *fp;
- {
- #endif
- ttcolor(CTEXT);
- ttmove(nrow-1, 0);
- #ifdef VARARGS
- eformat(fp, &pvar);
- va_end(pvar);
- #else
- eformat(fp, (char *)&arg);
- #endif
- tteeol();
- ttflush();
- epresf = TRUE;
- }
-
- /*
- * Printf style formatting. This is
- * called by both "ewprintf" and "ereply" to provide
- * formatting services to their clients. The move to the
- * start of the echo line, and the erase to the end of
- * the echo line, is done by the caller.
- * Note: %c works, and prints the "name" of the key. However
- * the key must be cast to an int to avoid tripping over
- * various oddities in C argument passing.
- */
- static VOID
- eformat(fp, ap) register char *fp;
- #ifdef VARARGS
- register va_list *ap;
- #else
- register char *ap;
- #endif
- {
- register int c;
- char kname[NKNAME];
-
- while ((c = *fp++) != '\0')
- {
- if (c != '%')
- eputc(c);
- else
- {
- c = *fp++;
- switch (c)
- {
- case 'c':
- #ifdef VARARGS
- keyname(kname, va_arg(*ap, int));
- #else
- /*NOSTRICT*/
- keyname(kname, *(int *)ap);
- ap += sizeof(int);
- #endif
- eputs(kname);
- break;
-
- case 'd':
- #ifdef VARARGS
- eputi(va_arg(*ap, int), 10);
- #else
- /*NOSTRICT*/
- eputi(*(int *)ap, 10);
- ap += sizeof(int);
- #endif
- break;
-
- case 'o':
- #ifdef VARARGS
- eputi(va_arg(*ap, int), 8);
- #else
- /*NOSTRICT*/
- eputi(*(int *)ap, 8);
- ap += sizeof(int);
- #endif
- break;
-
- case 's':
- #ifdef VARARGS
- eputs(va_arg(*ap, char *));
- #else
- /*NOSTRICT*/
- eputs(*(char **)ap);
- ap += sizeof(char *);
- #endif
- break;
- case 'l':/* explicit longword */
- c = *fp++;
- switch(c)
- {
- case 'd':
- #ifdef VARARGS
- eputl((long)va_arg(*ap, long), 10L);
- #else
- /*NOSTRICT*/
- eputl(*(long *)ap, 10L);
- ap += sizeof(long);
- #endif
- break;
- default:
- eputc(c);
- break;
- }
- break;
-
- default:
- eputc(c);
- }
- }
- }
- }
-
- /*
- * Put integer, in radix "r".
- */
- static VOID
- eputi(i, r) register int i; register int r;
- {
- register int q;
-
- if ((q=i/r) != 0)
- eputi(q, r);
- eputc(i%r+'0');
- }
-
- /*
- * Put long, in radix "r".
- */
- static VOID
- eputl(l, r) register long l; register long r;
- {
- register long q;
-
- if ((q=l/r) != 0)
- eputl(q, r);
- eputc((int)(l%r)+'0');
- }
-
- /*
- * Put string.
- */
- static VOID
- eputs(s) register char *s;
- {
- register int c;
-
- while ((c = *s++) != '\0')
- eputc(c);
- }
-
- /*
- * Put character. Watch for
- * control characters, and for the line
- * getting too long.
- */
- static VOID
- eputc(c) register char c;
- {
- if (ttcol+2 < ncol)
- {
- if (ISCTRL(c) != FALSE)
- {
- eputc('^');
- c ^= 0x40;
- }
- ttputc(c);
- ++ttcol;
- }
- }
-
- \Rogue\Monster\
- else
- echo "will not over write ./echo.c"
- fi
- if `test ! -s ./extend.c`
- then
- echo "writing ./extend.c"
- cat > ./extend.c << '\Rogue\Monster\'
- /*
- * Extended (M-X) commands.
- */
- #include "def.h"
-
-
- /*
- * Extended command. Call the message line
- * routine to read in the command name and apply autocompletion
- * to it. When it comes back, look the name up in the symbol table
- * and run the command if it is found and has the right type.
- * Print an error if there is anything wrong.
- */
- /*ARGSUSED*/
- extend(f, n, k)
- {
- register SYMBOL *sp;
- register int s;
- char xname[NXNAME];
-
- if (f == FALSE)
- s = eread("M-x ", xname, NXNAME, EFNEW|EFFUNC
- #ifndef VARARGS
- , (char *) NULL
- #endif
- ) ;
- else
- s = eread("%d M-x ", xname, NXNAME, EFNEW|EFFUNC,
- #ifdef VARARGS
- n
- #else
- (char *) &n, (char *) NULL
- #endif
- ) ;
- if (s != TRUE) return (s);
- if ((sp=symlookup(xname)) != NULL)
- return ((*sp->s_funcp)(f, n, KRANDOM));
- ewprintf("[No match]");
- return FALSE;
- }
-
- /*
- * This function will erase the current buffer, re-read the file, and
- * cancel the modification flag. It has to remember the file name.
- */
- /*ARGSUSED*/
- startover( f, n, k)
- {
- BUFFER *bp;
-
- bp = wheadp->w_bufp;
- if (bclear(bp) != FALSE) /* user did not abort it */
- {
- insertfile( bp->b_fname, (char *)NULL);
- notmodified( FALSE, 0, KRANDOM);
- sgarbf = TRUE;
- }
- }
-
- /*
- * This function will quit Emacs without saving any files,
- * or asking about saving them. Just call quit with an argument.
- */
- /*ARGSUSED*/
- reallyquit( f, n, k)
- {
- extern int quit();
-
- quit( TRUE, 1, KRANDOM);
- }
-
- /*
- * This function will delete the current line. It is easy because
- * all of the work is done in "killline". The cursor may be anywhere
- * on it, not just at the beginning.
- */
- /*ARGSUSED*/
- deleteline( f, n, k)
- {
- killline( TRUE, 0, KRANDOM); /* kill beginning of line */
- killline( TRUE, 1, KRANDOM); /* kill end including nl */
- }
-
- #ifdef STARTUP
- /*
- * Define the commands needed to do startup-file processing.
- * This code is mostly a kludge just so we can get startup-file processing.
- *
- * If you're serious about having this code, you should rewrite it.
- * To wit:
- * It has lots of funny things in it to make the startup-file look
- * like a GNU startup file; mostly dealing with parens and semicolons.
- * This should all vanish.
- *
- * It uses the same buffer as keyboard macros. The fix is easy (make
- * a new function "execmacro" that takes a pointer to char and
- * does what ctlxe does on it. Make ctlxe and excline both call it.)
- * but would slow down the non-micro version.
- *
- * We define eval-expression because it's easy. It's pretty useless,
- * since it duplicates the functionality of execute-extended-command.
- * All of this is just to support startup files, and should be turned
- * off for micros.
- */
-
- /*
- * evalexpr - get one line from the user, and run it. Identical in function
- * to extend, but easy.
- */
- /*ARGSUSED*/
- evalexpr(f, n, k)
- {
- register int s;
- char exbuf[NKBDM];
-
- if ((s = ereply("Eval: ", exbuf, NKBDM)) != TRUE)
- return s;
- return excline(exbuf);
- }
- /*
- * evalbuffer - evaluate the current buffer as line commands. Useful
- * for testing startup files.
- */
- /*ARGSUSED*/
- evalbuffer(f, n, k)
- {
- register LINE *lp;
- register BUFFER *bp = curbp;
- register int s;
- static char excbuf[NKBDM];
- char *strncpy();
-
- for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp))
- {
- if (llength(lp) >= NKBDM + 1) return FALSE ;
- (VOID) strncpy(excbuf, ltext(lp), NKBDM);
- if ((s = excline(excbuf)) != TRUE) return s;
- }
- return TRUE;
- }
- /*
- * evalfile - go get a file and evaluate it as line commands. You can
- * go get your own startup file if need be.
- */
- /*ARGSUSED*/
- evalfile(f, n, k)
- {
- register int s;
- char fname[NFILEN];
-
- if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
- return s;
- return load(fname);
- }
-
- /*
- * load - go load the file name we got passed.
- */
- load(fname) char *fname;
- {
- register int s;
- char excbuf[NKBDM];
-
- if (((s = ffropen(fname)) == FIOERR) || (s == FIOFNF))
- return FALSE;
- while ((s = ffgetline(excbuf, NKBDM)) == FIOSUC)
- if (excline(excbuf) != TRUE) break;
- (VOID) ffclose();
- return s == FIOEOF;
- }
-
- /*
- * excline - run a line from a load file or eval-expression.
- */
- excline(line) register char *line;
- {
- register char *funcp, *argp = NULL;
- char *skipwhite(), *parsetoken(), *backquote();
- int status;
-
- /* Don't know if it works; don't care - mwm */
- if (kbdmip != NULL || kbdmop != NULL)
- {
- ewprintf("Not now!") ;
- return FALSE;
- }
-
- funcp = skipwhite(line);
- if (*funcp == '\0') return TRUE; /* No error on blank lines */
- line = parsetoken(funcp);
- if (*line != '\0')
- {
- *line++ = '\0';
- line = skipwhite(line);
- if ((*line >= '0' && *line <= '9') || *line == '-')
- {
- argp = line;
- line = parsetoken(line);
- }
- }
-
- kbdmip = &kbdm[0];
- if (argp != NULL)
- {
- *kbdmip++ = (KEY) (KCTRL|'U');
- *kbdmip++ = (KEY) atoi(argp);
- }
- *kbdmip++ = (KEY) (KMETA|'X');
- /* Pack in function */
- while (*funcp != '\0')
- if (kbdmip+1 <= &kbdm[NKBDM-3])
- *kbdmip++ = (KEY) *funcp++;
- else
- {
- ewprintf("eval-expression macro overflow");
- ttflush();
- return FALSE;
- }
- *kbdmip++ = '\0'; /* done with function */
- /* Pack away all the args now... */
- while (*line != '\0')
- {
- argp = skipwhite(line);
- if (*argp == '\0') break ;
- line = parsetoken(argp) ;
- /* Slightly bogus for strings. But they should be SHORT! */
- if (kbdmip+(line-argp)+1 > &kbdm[NKBDM-3])
- {
- ewprintf("eval-expression macro overflow");
- ttflush();
- return FALSE;
- }
- if (*line != '\0') *line++ = '\0';
- if (*argp != '"')
- {
- if (*argp == '\'') ++argp;
- while (*argp != '\0')
- *kbdmip++ = (KEY) *argp++;
- *kbdmip++ = '\0';
- }
- else
- { /* Quoted strings special again */
- ++argp;
- while (*argp != '"' && *argp != '\0')
- if (*argp != '\\') *kbdmip++ = (KEY) *argp++;
- else argp = backquote(++argp, TRUE);
- /* Quotes strings are gotkey'ed, so no trailing null */
- }
- }
- *kbdmip++ = (KEY) (KCTLX|')');
- *kbdmip++ = '\0';
- kbdmip = NULL;
- status = ctlxe(FALSE, 1, KRANDOM);
- kbdm[0] = (KCTLX|')');
- return status;
- }
- /*
- * a pair of utility functions for the above
- */
- char *
- skipwhite(s) register char *s;
- {
-
- while ((*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
- && *s != '\0')
- if (*s == ';') *s = '\0' ;
- else s++;
- return s;
- }
-
- char *
- parsetoken(s) register char *s;
- {
-
- if (*s != '"')
- while (*s != ' ' && *s != '\t' && *s != '(' && *s != ')'
- && *s != '\0')
- {
- if (*s == ';')
- *s = '\0';
- else
- s++;
- }
- else /* Strings get special treatment */
- do {
- /* Beware: You can \ out the end of the string! */
- if (*s == '\\')
- ++s;
- if (ISLOWER(*s))
- *s = TOUPPER(*s);
- } while (*++s != '"' && *s != '\0');
- return s;
- }
- /*
- * Put a backquoted string element into the keyboard macro. Return pointer
- * to char following backquoted stuff.
- */
- /* Don't want to get the objects in isdigit.c just for this */
- #define isdigit(c) (((c) >= '0') && ((c) <= '9'))
-
- char *
- backquote(in, flag) char *in;
- {
- register KEY keycode;
-
- switch (*in++)
- {
- case 'T': *kbdmip++ = (KEY) (KCTRL|'I');
- break;
- case 'N': *kbdmip++ = (KEY) (KCTRL|'J');
- break;
- case 'R': *kbdmip++ = (KEY) (KCTRL|'M');
- break;
- case '^': *kbdmip = (KEY) (KCTRL|*in++);
- if (flag != FALSE && *kbdmip == (KEY) (KCTRL|'X'))
- {
- if (*in == '\\')
- in = backquote(++in, FALSE);
- else
- *kbdmip++ = (KEY) *in++;
- kbdmip[-1] |= (KEY) KCTLX;
- }
- else ++kbdmip;
- break;
- case 'E':
- if (flag != TRUE)
- *kbdmip++ = (KEY) (KCTRL|'[');
- else if (*in != '\\')
- *kbdmip++ = (KEY) (KMETA|*in++);
- else
- {
- in = backquote(++in, FALSE);
- kbdmip[-1] |= (KEY) KMETA;
- }
- break;
-
- /* (L. Frenkel) Convert "\Fd" and "\Fdd" to a function
- * key code between KFIRST and KLAST. "dd" should be
- * decimal; codes > KLAST are mapped to KLAST, for want
- * of a better idea of what to do with them.
- */
- case 'F':
- keycode = 0;
- if (isdigit(*in))
- keycode += *in++ - '0';
- if (isdigit(*in))
- keycode = (10 * keycode) + *in++ - '0';
- if ( (keycode += KFIRST) > KLAST)
- keycode = KLAST;
- *kbdmip++ = (KEY) keycode;
- break;
- }
- return in;
- }
- #endif STARTUP
- \Rogue\Monster\
- else
- echo "will not over write ./extend.c"
- fi
- if `test ! -s ./file.c`
- then
- echo "writing ./file.c"
- cat > ./file.c << '\Rogue\Monster\'
- /*
- * File commands.
- */
- #include "def.h"
-
- BUFFER *findbuffer();
- VOID makename();
- VOID upmodes();
-
- /*
- * insert a file into the current buffer. Real easy - just call the
- * insertfile routine with the file name.
- */
- /*ARGSUSED*/
- fileinsert(f, n, k)
- {
- register int s;
- char fname[NFILEN];
-
- if ((s=ereply("Insert file: ", fname, NFILEN)) != TRUE)
- return (s);
- adjustcase(fname);
- return (insertfile(fname, (char *) NULL)); /* don't set buffer name */
- }
-
- /*
- * Select a file for editing.
- * Look around to see if you can find the
- * fine in another buffer; if you can find it
- * just switch to the buffer. If you cannot find
- * the file, create a new buffer, read in the
- * text, and switch to the new buffer.
- */
- /*ARGSUSED*/
- filevisit(f, n, k)
- {
- register BUFFER *bp;
- int s;
- char fname[NFILEN];
-
- if ((s=ereply("Find file: ", fname, NFILEN)) != TRUE)
- return (s);
- if ((bp = findbuffer(fname, &s)) == NULL) return s;
- curbp = bp;
- if (showbuffer(bp, curwp, WFHARD) != TRUE) return FALSE;
- if (bp->b_fname[0] == 0)
- return (readin(fname)); /* Read it in. */
- return TRUE;
- }
-
-
- /*
- * given a file name, either find the buffer it uses, or create a new
- * empty buffer to put it in.
- */
- BUFFER *
- findbuffer(fname, s) char *fname; int *s;
- {
- register BUFFER *bp;
- char bname[NBUFN];
-
- adjustcase(fname);
- for (bp=bheadp; bp!=NULL; bp=bp->b_bufp)
- {
- if (strcmp(bp->b_fname, fname) == 0)
- {
- return bp;
- }
- }
- makename(bname, fname); /* New buffer name. */
- while ((bp=bfind(bname, FALSE)) != NULL)
- {
- *s = ereply("Buffer name: ", bname, NBUFN);
- if (*s == ABORT) /* ^G to just quit */
- return NULL;
- if (*s == FALSE)
- { /* CR to clobber it */
- bp->b_fname[0] = '\0';
- break;
- }
- }
- if (bp == NULL) bp = bfind(bname, TRUE);
- *s = FALSE;
- return bp;
- }
-
- /*
- * Read the file "fname" into the current buffer.
- * Make all of the text in the buffer go away, after checking
- * for unsaved changes. This is called by the "read" command, the
- * "visit" command, and the mainline (for "uemacs file").
- */
- readin(fname) char *fname;
- {
- register int status;
- register WINDOW *wp;
-
- if (bclear(curbp) != TRUE) /* Might be old. */
- return TRUE;
- status = insertfile(fname, fname) ;
- curbp->b_flag &= ~BFCHG; /* No change. */
- for (wp=wheadp; wp!=NULL; wp=wp->w_wndp)
- {
- if (wp->w_bufp == curbp)
- {
- wp->w_linep = lforw(curbp->b_linep);
- wp->w_dotp = lforw(curbp->b_linep);
- wp->w_doto = 0;
- wp->w_markp = NULL;
- wp->w_marko = 0;
- }
- }
- return status;
- }
- /*
- * insert a file in the current buffer, after dot. Set mark
- * at the end of the text inserted, point at the beginning.
- * Return a standard status. Print a summary (lines read,
- * error message) out as well. If the
- * BACKUP conditional is set, then this routine also does the read
- * end of backup processing. The BFBAK flag, if set in a buffer,
- * says that a backup should be taken. It is set when a file is
- * read in, but not on a new file (you don't need to make a backup
- * copy of nothing).
- *
- * Warning: Adds a trainling nl to files that don't end in one!
- * Need to fix, but later (I suspect that it will require a change
- * in the fileio files for all systems involved).
- */
- insertfile(fname, newname) char fname[], newname[];
- {
- register LINE *lp1;
- register LINE *lp2;
- LINE *olp; /* Line we started at */
- int opos; /* and offset into it */
- register WINDOW *wp;
- register int i;
- register int nbytes;
- int s, nline;
- BUFFER *bp;
- char line[NLINE];
-
- bp = curbp; /* Cheap. */
- if (newname != (char *) NULL)
- (VOID) strcpy(bp->b_fname, newname);
- if ((s=ffropen(fname)) == FIOERR) /* Hard file open. */
- goto out;
- if (s == FIOFNF)
- { /* File not found. */
- if (kbdmop == NULL)
- if (newname != NULL)
- ewprintf("(New file)");
- else
- ewprintf("(File not found)");
- goto out;
- }
- opos = curwp->w_doto;
- /* Open a new line, at point, and start inserting after it */
- (VOID) lnewline();
- olp = lback(curwp->w_dotp);
- nline = 0; /* Don't count fake line at end */
- while ((s=ffgetline(line, NLINE)) == FIOSUC)
- {
- nbytes = strlen(line);
- if ((lp1=lalloc((RSIZE) nbytes)) == NULL)
- {
- s = FIOERR; /* Keep message on the */
- break; /* display. */
- }
- lp2 = lback(curwp->w_dotp);
- lp2->l_fp = lp1;
- lp1->l_fp = curwp->w_dotp;
- lp1->l_bp = lp2;
- curwp->w_dotp->l_bp = lp1;
- for (i=0; i<nbytes; ++i)
- lputc(lp1, i, line[i]);
- ++nline;
- }
- (VOID) ffclose(); /* Ignore errors. */
- if (s==FIOEOF && kbdmop==NULL)
- { /* Don't zap an error. */
- if (nline == 1)
- ewprintf("(Read 1 line)");
- else
- ewprintf("(Read %d lines)", nline);
- }
- /* Set mark at the end of the text */
- curwp->w_markp = curwp->w_dotp;
- curwp->w_marko = curwp->w_doto;
- /* Now, delete the results of the lnewline we started with */
- curwp->w_dotp = olp;
- curwp->w_doto = opos;
- (VOID) ldelnewline();
- curwp->w_doto = opos; /* and dot is right */
- #ifdef BACKUP
- if (newname != NULL)
- bp->b_flag |= BFCHG | BFBAK; /* Need a backup. */
- else bp->b_flag |= BFCHG;
- #else
- bp->b_flag |= BFCHG;
- #endif
- /* if the insert was at the end of buffer, set lp1 to the end of
- * buffer line, and lp2 to the beginning of the newly inserted
- * text. (Otherwise lp2 is set to NULL.) This is
- * used below to set pointers in other windows correctly if they
- * are also at the end of buffer.
- */
- lp1 = bp->b_linep;
- if (curwp->w_markp == lp1)
- lp2 = curwp->w_dotp;
- else
- {
- out: lp2 = NULL;
- }
- for (wp=wheadp; wp!=NULL; wp=wp->w_wndp)
- {
- if (wp->w_bufp == curbp)
- {
- wp->w_flag |= WFMODE|WFEDIT;
- if (wp != curwp && lp2 != NULL)
- {
- if (wp->w_dotp == lp1)
- wp->w_dotp = lp2;
- if (wp->w_markp == lp1)
- wp->w_markp = lp2;
- if (wp->w_linep == lp1)
- wp->w_linep = lp2;
- }
- }
- }
- if (s == FIOERR) /* False if error. */
- return (FALSE);
- return (TRUE);
- }
-
- /*
- * Take a file name, and from it
- * fabricate a buffer name. This routine knows
- * about the syntax of file names on the target system.
- * BDC1 left scan delimiter.
- * BDC2 optional second left scan delimiter.
- * BDC3 optional right scan delimiter.
- */
- VOID
- makename(bname, fname) char bname[]; char fname[];
- {
- register char *cp1;
- register char *cp2;
-
- cp1 = &fname[0];
- while (*cp1 != 0)
- ++cp1;
- #ifdef BDC2
- while (cp1!=&fname[0] && cp1[-1]!=BDC1 && cp1[-1]!=BDC2)
- --cp1;
- #else
- while (cp1!=&fname[0] && cp1[-1]!=BDC1)
- --cp1;
- #endif
- cp2 = &bname[0];
- #ifdef BDC3
- while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=BDC3)
- *cp2++ = *cp1++;
- #else
- while (cp2!=&bname[NBUFN-1] && *cp1!=0)
- *cp2++ = *cp1++;
- #endif
- *cp2 = 0;
- }
-
- /*
- * Ask for a file name, and write the
- * contents of the current buffer to that file.
- * Update the remembered file name and clear the
- * buffer changed flag. This handling of file names
- * is different from the earlier versions, and
- * is more compatable with Gosling EMACS than
- * with ITS EMACS.
- */
- /*ARGSUSED*/
- filewrite(f, n, k)
- {
- register int s;
- char fname[NFILEN];
-
- if ((s=ereply("Write file: ", fname, NFILEN)) != TRUE)
- return (s);
- adjustcase(fname);
- if ((s=writeout(curbp, fname)) == TRUE)
- {
- #ifdef BACKUP
- curbp->b_flag &= ~(BFBAK | BFCHG);
- #else
- curbp->b_flag &= ~BFCHG;
- #endif
- upmodes(curbp);
- }
- return (s);
- }
-
- /*
- * Save the contents of the current buffer back into
- * its associated file. Do nothing if there have been no changes
- * (is this a bug, or a feature). Error if there is no remembered
- * file name. If this is the first write since the read or visit,
- * then a backup copy of the file is made.
- * Allow user to select whether or not to make backup files
- * by looking at the value of makebackup.
- */
- #ifdef BACKUP
- static int makebackup = 0;
- #endif
-
- /*ARGSUSED*/
- filesave(f, n, k)
- {
- register int s;
-
- if ((curbp->b_flag&BFCHG) == 0)
- { /* Return, no changes. */
- if (kbdmop == NULL) ewprintf("(No changes need to be saved)");
- return (TRUE);
- }
- if (curbp->b_fname[0] == 0)
- { /* Must have a name. */
- ewprintf("No file name");
- return (FALSE);
- }
- #ifdef BACKUP
- if (makebackup && ((curbp->b_flag&BFBAK) != 0))
- {
- s = fbackupfile(curbp->b_fname);
- if (s == ABORT) /* Hard error. */
- return FALSE;
- if (s == FALSE /* Softer error. */
- && (s=eyesno("Backup error, save anyway")) != TRUE)
- return (s);
- }
- #endif
- if ((s=writeout(curbp, curbp->b_fname)) == TRUE)
- {
- #ifdef BACKUP
- curbp->b_flag &= ~(BFCHG | BFBAK);
- #else
- curbp->b_flag &= ~BFCHG;
- #endif
- upmodes(curbp);
- }
- return (s);
- }
-
- #ifdef BACKUP
- /* Since we don't have variables (we probably should)
- * this is a command processor for changing the value of
- * the make backup flag. If no argument is given,
- * sets makebackup to true, so backups are made. If
- * an argument is given, no backup files are made when
- * saving a new version of a file. Only used when BACKUP
- * is #defined.
- */
- /*ARGSUSED*/
- makebkfile(f, n, k)
- {
- makebackup = !f; /* make backup if no argument given */
- ewprintf(makebackup ? "Backup files enabled" :
- "Disabling backup files");
- return (TRUE);
- }
- #endif
-
- /*
- * This function performs the details of file
- * writing; writing the file in buffer bp to
- * file fn. Uses the file management routines
- * in the "fileio.c" package. Most of the grief
- * is checking of some sort.
- */
- writeout(bp, fn) register BUFFER *bp; char *fn;
- {
- register int s;
- register LINE *lp;
-
- if ((s=ffwopen(fn)) != FIOSUC) /* Open writes message. */
- return (FALSE);
- lp = lforw(bp->b_linep); /* First line. */
- while (lp != bp->b_linep)
- {
- if ((s=ffputline(&(ltext(lp))[0], llength(lp))) != FIOSUC)
- break;
- lp = lforw(lp);
- }
- if (s == FIOSUC)
- { /* No write error. */
- s = ffclose();
- if (s==FIOSUC && kbdmop==NULL)
- ewprintf("Text Saved", fn);
- } else /* Ignore close error */
- (VOID) ffclose(); /* if a write error. */
- if (s != FIOSUC) /* Some sort of error. */
- return (FALSE);
- return (TRUE);
- }
-
- /*
- * Tag all windows for bp (all windows if bp NULL) as needing their
- * mode line updated.
- */
- VOID
- upmodes(bp) register BUFFER *bp;
- {
- register WINDOW *wp;
-
- for (wp = wheadp; wp != NULL; wp = wp->w_wndp)
- if (bp == NULL || curwp->w_bufp == bp) wp->w_flag |= WFMODE;
- }
- \Rogue\Monster\
- else
- echo "will not over write ./file.c"
- fi
- echo "Finished archive 3 of 5"
- exit
-
-
- --
- =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
- Mark A. Hargrove U.S. TeleCenters
- Voice: 408-496-1800 Santa Clara, CA
- uucp : {dual, hoptoad, hplabs, portal, ptsfa}!well!ustel
-