v02i052: Unify TEXT fields from ACCELL Part 3/5
Mark Hargrove
ustel at well.UUCP
Thu Feb 11 10:49:28 AEST 1988
Comp.sources.misc: Volume 2, Issue 52
Submitted-By: "Mark Hargrove" <ustel at 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
More information about the Comp.sources.misc
mailing list