home *** CD-ROM | disk | FTP | other *** search
- /*
- * The functions in this file handle redisplay. There are two halves, the
- * ones that update the virtual display screen, and the ones that make the
- * physical display screen the same as the virtual display screen. These
- * functions use hints that are left in the windows by the commands.
- *
- */
-
- #include <stdio.h>
- #include "estruct.h"
- #include "edef.h"
-
- #define WFDEBUG 0 /* Window flag debug. */
-
- typedef struct VIDEO {
- short v_flag; /* Flags */
- char v_text[1]; /* Screen data. */
- } VIDEO;
-
- #define VFCHG 0x0001 /* Changed flag */
- #define VFEXT 0x0002 /* extended (beyond column 80) */
- #define VFREV 0x0004 /* reverse video status */
- #define VFREQ 0x0008 /* reverse video request */
-
- int vtrow = 0; /* Row location of SW cursor */
- int vtcol = 0; /* Column location of SW cursor */
- int ttrow = HUGE; /* Row location of HW cursor */
- int ttcol = HUGE; /* Column location of HW cursor */
- int lbound = 0; /* leftmost column of current line
- being displayed */
-
- VIDEO **vscreen; /* Virtual screen. */
- VIDEO **pscreen; /* Physical screen. */
-
- /*
- * 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. All the other things get initialized at compile time.
- * The original window has "WFCHG" set, so that it will get completely
- * redrawn on the first call to "update".
- */
- vtinit()
- {
- register int i;
- register VIDEO *vp;
- char *malloc();
-
- (*term.t_open)();
- (*term.t_rev)(FALSE);
- vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
-
- if (vscreen == NULL)
- exit(1);
-
- pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *));
-
- if (pscreen == NULL)
- exit(1);
-
- for (i = 0; i < term.t_nrow; ++i)
- {
- vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
-
- if (vp == NULL)
- exit(1);
-
- vp->v_flag = 0;
- vscreen[i] = vp;
- vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_ncol);
-
- if (vp == NULL)
- exit(1);
-
- vp->v_flag = 0;
- pscreen[i] = vp;
- }
- }
-
- /*
- * Clean up the virtual terminal system, in anticipation for a return to the
- * operating system. Move down to the last line and clear it out (the next
- * system prompt will be written in the line). Shut down the channel to the
- * terminal.
- */
- vttidy()
- {
- mlerase();
- movecursor(term.t_nrow, 0);
- (*term.t_close)();
- }
-
- /*
- * Set the virtual cursor to the specified row and column on the virtual
- * screen. There is no checking for nonsense values; this might be a good
- * idea during the early stages.
- */
- vtmove(row, col)
- {
- vtrow = row;
- vtcol = col;
- }
-
- /*
- * Write a character to the virtual screen. The virtual row and column are
- * updated. If the line is too long put a "$" in the last column. This routine
- * only puts printing characters into the virtual terminal buffers. Only
- * column overflow is checked.
- */
- vtputc(c)
- int c;
- {
- register VIDEO *vp;
-
- vp = vscreen[vtrow];
-
- if (vtcol >= term.t_ncol) {
- vtcol = (vtcol + 0x07) & ~0x07;
- vp->v_text[term.t_ncol - 1] = '$';
- } else if (c == '\t')
- {
- do
- {
- vtputc(' ');
- }
- while ((vtcol&0x07) != 0);
- }
- else if (c < 0x20 || c == 0x7F)
- {
- vtputc('^');
- vtputc(c ^ 0x40);
- }
- else
- vp->v_text[vtcol++] = c;
- }
-
- /* put a character to the virtual screen in an extended line. If we are
- not yet on left edge, don't print it yet. check for overflow on
- the right margin */
-
- vtpute(c)
-
- int c;
-
- {
- register VIDEO *vp;
-
- vp = vscreen[vtrow];
-
- if (vtcol >= term.t_ncol) {
- vtcol = (vtcol + 0x07) & ~0x07;
- vp->v_text[term.t_ncol - 1] = '$';
- } else if (c == '\t')
- {
- do
- {
- vtpute(' ');
- }
- while (((vtcol + lbound)&0x07) != 0);
- }
- else if (c < 0x20 || c == 0x7F)
- {
- vtpute('^');
- vtpute(c ^ 0x40);
- }
- else {
- if (vtcol >= 0)
- vp->v_text[vtcol] = c;
- ++vtcol;
- }
- }
-
- /*
- * Erase from the end of the software cursor to the end of the line on which
- * the software cursor is located.
- */
- vteeol()
- {
- register VIDEO *vp;
-
- vp = vscreen[vtrow];
- while (vtcol < term.t_ncol)
- vp->v_text[vtcol++] = ' ';
- }
-
- /*
- * Make sure that the display is right. This is a three part process. First,
- * scan through all of the windows looking for dirty ones. Check the framing,
- * and refresh the screen. Second, make sure that "currow" and "curcol" are
- * correct for the current window. Third, make the virtual and physical
- * screens the same.
- */
- update()
- {
- register LINE *lp;
- register WINDOW *wp;
- register VIDEO *vp1;
- register VIDEO *vp2;
- register int i;
- register int j;
- register int c;
-
- #if TYPEAH
- if (typahead())
- return(TRUE);
- #endif
-
- /* update the reverse video flags for any mode lines out there */
- for (i = 0; i < term.t_nrow; ++i)
- vscreen[i]->v_flag &= ~VFREQ;
-
- #if REVSTA
- wp = wheadp;
- while (wp != NULL) {
- vscreen[wp->w_toprow+wp->w_ntrows]->v_flag |= VFREQ;
- wp = wp->w_wndp;
- }
- #endif
-
- wp = wheadp;
-
- while (wp != NULL)
- {
- /* Look at any window with update flags set on. */
-
- if (wp->w_flag != 0)
- {
- /* If not force reframe, check the framing. */
-
- 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);
- }
- }
-
- /* Not acceptable, better compute a new value for the line at the
- * top of the window. Then set the "WFHARD" flag to force full
- * redraw.
- */
- i = wp->w_force;
-
- 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:
- /* Try to use reduced update. Mode line update has its own special
- * flag. The fast update is used if the only thing to do is within
- * the line editing.
- */
- lp = wp->w_linep;
- i = wp->w_toprow;
-
- if ((wp->w_flag & ~WFMODE) == WFEDIT)
- {
- while (lp != wp->w_dotp)
- {
- ++i;
- lp = lforw(lp);
- }
-
- vscreen[i]->v_flag |= VFCHG;
- vtmove(i, 0);
-
- for (j = 0; j < llength(lp); ++j)
- vtputc(lgetc(lp, j));
-
- vteeol();
- }
- else if ((wp->w_flag & (WFEDIT | WFHARD)) != 0)
- {
- while (i < wp->w_toprow+wp->w_ntrows)
- {
- vscreen[i]->v_flag |= VFCHG;
- vtmove(i, 0);
-
- /* if line has been changed */
- if (lp != wp->w_bufp->b_linep)
- {
- for (j = 0; j < llength(lp); ++j)
- vtputc(lgetc(lp, j));
-
- lp = lforw(lp);
- }
-
- vteeol();
- ++i;
- }
- }
- #if ~WFDEBUG
- if ((wp->w_flag&WFMODE) != 0)
- modeline(wp);
-
- wp->w_flag = 0;
- wp->w_force = 0;
- #endif
- }
- #if WFDEBUG
- modeline(wp);
- wp->w_flag = 0;
- wp->w_force = 0;
- #endif
-
- /* and onward to the next window */
- wp = wp->w_wndp;
- }
-
- /* Always recompute the row and column number of the hardware cursor. This
- * is the only update for simple moves.
- */
- lp = curwp->w_linep;
- currow = curwp->w_toprow;
-
- while (lp != curwp->w_dotp)
- {
- ++currow;
- lp = lforw(lp);
- }
-
- curcol = 0;
- i = 0;
-
- while (i < curwp->w_doto)
- {
- c = lgetc(lp, i++);
-
- if (c == '\t')
- curcol |= 0x07;
- else if (c < 0x20 || c == 0x7F)
- ++curcol;
-
- ++curcol;
- }
-
- if (curcol >= term.t_ncol - 1) { /* extended line. */
- /* flag we are extended and changed */
- vscreen[currow]->v_flag |= VFEXT | VFCHG;
- updext(); /* and output extended line */
- } else
- lbound = 0; /* not extended line */
-
- /* make sure no lines need to be de-extended because the cursor is
- no longer on them */
-
- wp = wheadp;
-
- while (wp != NULL) {
- lp = wp->w_linep;
- i = wp->w_toprow;
-
- while (i < wp->w_toprow + wp->w_ntrows) {
- if (vscreen[i]->v_flag & VFEXT) {
- /* always flag extended lines as changed */
- vscreen[i]->v_flag |= VFCHG;
- if ((wp != curwp) || (lp != wp->w_dotp) ||
- (curcol < term.t_ncol - 1)) {
- vtmove(i, 0);
- for (j = 0; j < llength(lp); ++j)
- vtputc(lgetc(lp, j));
- vteeol();
-
- /* this line no longer is extended */
- vscreen[i]->v_flag &= ~VFEXT;
- }
- }
- lp = lforw(lp);
- ++i;
- }
- /* and onward to the next window */
- wp = wp->w_wndp;
- }
-
- /* Special hacking if the screen is garbage. Clear the hardware screen,
- * and update your copy to agree with it. Set all the virtual screen
- * change bits, to force a full update.
- */
- if (sgarbf != FALSE)
- {
- for (i = 0; i < term.t_nrow; ++i)
- {
- vscreen[i]->v_flag |= VFCHG;
- vp1 = pscreen[i];
- for (j = 0; j < term.t_ncol; ++j)
- vp1->v_text[j] = ' ';
- }
-
- movecursor(0, 0); /* Erase the screen. */
- (*term.t_eeop)();
- sgarbf = FALSE; /* Erase-page clears */
- mpresf = FALSE; /* the message area. */
- }
-
- /* Make sure that the physical and virtual displays agree. Unlike before,
- * the "updateline" code is only called with a line that has been updated
- * for sure.
- */
- for (i = 0; i < term.t_nrow; ++i)
- {
- vp1 = vscreen[i];
-
- /* for each line that needs to be updated, or that needs its
- reverse video status changed, call the line updater */
- j = vp1->v_flag;
- if (((j & VFCHG) != 0) || (((j & VFREV) == 0) != ((j & VFREQ) == 0)))
- {
- #if TYPEAH
- if (typahead())
- return(TRUE);
- #endif
- vp2 = pscreen[i];
- updateline(i, &vp1->v_text[0], &vp2->v_text[0], &vp1->v_flag);
- }
- }
-
- /* Finally, update the hardware cursor and flush out buffers. */
-
- movecursor(currow, curcol - lbound);
- (*term.t_flush)();
- }
-
- /* updext: update the extended line which the cursor is currently
- on at a column greater than the terminal width. The line
- will be scrolled right or left to let the user see where
- the cursor is
- */
-
- updext()
-
- {
- register int rcursor; /* real cursor location */
- register LINE *lp; /* pointer to current line */
- register int j; /* index into line */
-
- /* calculate what column the real cursor will end up in */
- rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin;
- lbound = curcol - rcursor + 1;
-
- /* scan through the line outputing characters to the virtual screen */
- /* once we reach the left edge */
- vtmove(currow, -lbound); /* start scanning offscreen */
- lp = curwp->w_dotp; /* line to output */
- for (j=0; j<llength(lp); ++j) /* until the end-of-line */
- vtpute(lgetc(lp, j));
-
- /* truncate the virtual line */
- vteeol();
-
- /* and put a '$' in column 1 */
- vscreen[currow]->v_text[0] = '$';
- }
-
- /*
- * Update a single line. This does not know how to use insert or delete
- * character sequences; we are using VT52 functionality. Update the physical
- * row and column variables. It does try an exploit erase to end of line. The
- * RAINBOW version of this routine uses fast video.
- */
- updateline(row, vline, pline, flags)
- char vline[]; /* what we want it to end up as */
- char pline[]; /* what it looks like now */
- short *flags; /* and how we want it that way */
- {
- #if RAINBOW
- register char *cp1;
- register char *cp2;
- register int nch;
-
- /* since we don't know how to make the rainbow do this, turn it off */
- flags &= (~VFREV & ~VFREQ);
-
- cp1 = &vline[0]; /* Use fast video. */
- cp2 = &pline[0];
- putline(row+1, 1, cp1);
- nch = term.t_ncol;
-
- do
- {
- *cp2 = *cp1;
- ++cp2;
- ++cp1;
- }
- while (--nch);
- *flags &= ~VFCHG;
- #else
- register char *cp1;
- register char *cp2;
- register char *cp3;
- register char *cp4;
- register char *cp5;
- register int nbflag; /* non-blanks to the right flag? */
- int rev; /* reverse video flag */
- int req; /* reverse video request flag */
-
-
- /* set up pointers to virtual and physical lines */
- cp1 = &vline[0];
- cp2 = &pline[0];
-
- #if REVSTA
- /* if we need to change the reverse video status of the
- current line, we need to re-write the entire line */
- rev = *flags & VFREV;
- req = *flags & VFREQ;
- if (rev != req) {
- movecursor(row, 0); /* Go to start of line. */
- (*term.t_rev)(req != FALSE); /* set rev video if needed */
-
- /* scan through the line and dump it to the screen and
- the virtual screen array */
- cp3 = &vline[term.t_ncol];
- while (cp1 < cp3) {
- (*term.t_putchar)(*cp1);
- ++ttcol;
- *cp2++ = *cp1++;
- }
- (*term.t_rev)(FALSE); /* turn rev video off */
-
- /* update the needed flags */
- *flags &= ~VFCHG;
- if (req)
- *flags |= VFREV;
- else
- *flags &= ~VFREV;
- return(TRUE);
- }
- #endif
-
- /* advance past any common chars at the left */
- while (cp1 != &vline[term.t_ncol] && cp1[0] == cp2[0]) {
- ++cp1;
- ++cp2;
- }
-
- /* This can still happen, even though we only call this routine on changed
- * lines. A hard update is always done when a line splits, a massive
- * change is done, or a buffer is displayed twice. This optimizes out most
- * of the excess updating. A lot of computes are used, but these tend to
- * be hard operations that do a lot of update, so I don't really care.
- */
- /* if both lines are the same, no update needs to be done */
- if (cp1 == &vline[term.t_ncol])
- return(TRUE);
-
- /* find out if there is a match on the right */
- nbflag = FALSE;
- cp3 = &vline[term.t_ncol];
- cp4 = &pline[term.t_ncol];
-
- while (cp3[-1] == cp4[-1]) {
- --cp3;
- --cp4;
- if (cp3[0] != ' ') /* Note if any nonblank */
- nbflag = TRUE; /* in right match. */
- }
-
- cp5 = cp3;
-
- if (nbflag == FALSE && eolexist == TRUE) { /* Erase to EOL ? */
- while (cp5!=cp1 && cp5[-1]==' ')
- --cp5;
-
- if (cp3-cp5 <= 3) /* Use only if erase is */
- cp5 = cp3; /* fewer characters. */
- }
-
- movecursor(row, cp1-&vline[0]); /* Go to start of line. */
-
- while (cp1 != cp5) { /* Ordinary. */
- (*term.t_putchar)(*cp1);
- ++ttcol;
- *cp2++ = *cp1++;
- }
-
- if (cp5 != cp3) { /* Erase. */
- (*term.t_eeol)();
- while (cp1 != cp3)
- *cp2++ = *cp1++;
- }
- *flags &= ~VFCHG; /* flag this line is changed */
- #endif
- }
-
- /*
- * Redisplay the mode line for the window pointed to by the "wp". This is the
- * only routine that has any idea of how the modeline is formatted. You can
- * change the modeline format by hacking at this routine. Called by "update"
- * any time there is a dirty window.
- */
- modeline(wp)
- WINDOW *wp;
- {
- register char *cp;
- register int c;
- register int n; /* cursor position count */
- register BUFFER *bp;
- register i; /* loop index */
- register lchar; /* character to draw line in buffer with */
- register firstm; /* is this the first mode? */
- char tline[NLINE]; /* buffer for part of mode line */
-
- n = wp->w_toprow+wp->w_ntrows; /* Location. */
- vscreen[n]->v_flag |= VFCHG; /* Redraw next time. */
- vtmove(n, 0); /* Seek to right line. */
- if (wp == curwp) /* mark the current buffer */
- lchar = '=';
- else
- #if REVSTA
- if (revexist)
- lchar = ' ';
- else
- #endif
- lchar = '-';
-
- vtputc(lchar);
- bp = wp->w_bufp;
-
- if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */
- vtputc('*');
- else
- vtputc(lchar);
-
- n = 2;
- strcpy(tline, " MicroEMACS 3.6 ("); /* Buffer name. */
-
- /* display the modes */
-
- firstm = TRUE;
- for (i = 0; i < NUMMODES; i++) /* add in the mode flags */
- if (wp->w_bufp->b_mode & (1 << i)) {
- if (firstm != TRUE)
- strcat(tline, " ");
- firstm = FALSE;
- strcat(tline, modename[i]);
- }
- strcat(tline,") ");
-
- cp = &tline[0];
- while ((c = *cp++) != 0)
- {
- vtputc(c);
- ++n;
- }
-
- vtputc(lchar);
- vtputc(lchar);
- vtputc(' ');
- n += 3;
- cp = &bp->b_bname[0];
-
- while ((c = *cp++) != 0)
- {
- vtputc(c);
- ++n;
- }
-
- vtputc(' ');
- vtputc(lchar);
- vtputc(lchar);
- n += 3;
-
- if (bp->b_fname[0] != 0) /* File name. */
- {
- vtputc(' ');
- ++n;
- cp = "File: ";
-
- while ((c = *cp++) != 0)
- {
- vtputc(c);
- ++n;
- }
-
- cp = &bp->b_fname[0];
-
- while ((c = *cp++) != 0)
- {
- vtputc(c);
- ++n;
- }
-
- vtputc(' ');
- ++n;
- }
-
- #if WFDEBUG
- vtputc(lchar);
- vtputc((wp->w_flag&WFMODE)!=0 ? 'M' : lchar);
- vtputc((wp->w_flag&WFHARD)!=0 ? 'H' : lchar);
- vtputc((wp->w_flag&WFEDIT)!=0 ? 'E' : lchar);
- vtputc((wp->w_flag&WFMOVE)!=0 ? 'V' : lchar);
- vtputc((wp->w_flag&WFFORCE)!=0 ? 'F' : lchar);
- n += 6;
- #endif
-
- while (n < term.t_ncol) /* Pad to full width. */
- {
- vtputc(lchar);
- ++n;
- }
- }
-
- upmode() /* update all the mode lines */
-
- {
- register WINDOW *wp;
-
- wp = wheadp;
- while (wp != NULL) {
- wp->w_flag |= WFMODE;
- wp = wp->w_wndp;
- }
- }
-
- /*
- * Send a command to the terminal to move the hardware cursor to row "row"
- * and column "col". The row and column arguments are origin 0. Optimize out
- * random calls. Update "ttrow" and "ttcol".
- */
- movecursor(row, col)
- {
- if (row!=ttrow || col!=ttcol)
- {
- ttrow = row;
- ttcol = col;
- (*term.t_move)(row, col);
- }
- }
-
- /*
- * Erase the message line. This is a special routine because the message line
- * is not considered to be part of the virtual screen. It always works
- * immediately; the terminal buffer is flushed via a call to the flusher.
- */
- mlerase()
- {
- int i;
-
- movecursor(term.t_nrow, 0);
- if (eolexist == TRUE)
- (*term.t_eeol)();
- else {
- for (i = 0; i < term.t_ncol - 1; i++)
- (*term.t_putchar)(' ');
- movecursor(term.t_nrow, 1); /* force the move! */
- movecursor(term.t_nrow, 0);
- }
- (*term.t_flush)();
- mpresf = FALSE;
- }
-
- /*
- * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
- * ABORT. The ABORT status is returned if the user bumps out of the question
- * with a ^G. Used any time a confirmation is required.
- */
-
- mlyesno(prompt)
-
- char *prompt;
-
- {
- char c; /* input character */
- char buf[NPAT]; /* prompt to user */
-
- for (;;) {
- /* build and prompt the user */
- strcpy(buf, prompt);
- strcat(buf, " [y/n]? ");
- mlwrite(buf);
-
- /* get the responce */
- c = (*term.t_getchar)();
-
- if (c == BELL) /* Bail out! */
- return(ABORT);
-
- if (c=='y' || c=='Y')
- return(TRUE);
-
- if (c=='n' || c=='N')
- return(FALSE);
- }
- }
-
- /*
- * Write a prompt into the message line, then read back a response. Keep
- * track of the physical position of the cursor. If we are in a keyboard
- * macro throw the prompt away, and return the remembered response. This
- * lets macros run at full speed. The reply is always terminated by a carriage
- * return. Handle erase, kill, and abort keys.
- */
-
- mlreply(prompt, buf, nbuf)
- char *prompt;
- char *buf;
- {
- return(mlreplyt(prompt,buf,nbuf,'\n'));
- }
-
- /* A more generalized prompt/reply function allowing the caller
- to specify the proper terminator. If the terminator is not
- a return ('\n') it will echo as "<NL>"
- */
- mlreplyt(prompt, buf, nbuf, eolchar)
-
- char *prompt;
- char *buf;
- char eolchar;
-
- {
- register int cpos;
- register int i;
- register int c;
-
- cpos = 0;
-
- if (kbdmop != NULL) {
- while ((c = *kbdmop++) != '\0')
- buf[cpos++] = c;
-
- buf[cpos] = 0;
-
- if (buf[0] == 0)
- return(FALSE);
-
- return(TRUE);
- }
-
- /* check to see if we are executing a command line */
- if (clexec) {
- nxtarg(buf);
- return(TRUE);
- }
-
- mlwrite(prompt);
-
- for (;;) {
- /* get a character from the user. if it is a <ret>, change it
- to a <NL> */
- c = (*term.t_getchar)();
- if (c == 0x0d)
- c = '\n';
-
- if (c == eolchar) {
- buf[cpos++] = 0;
-
- if (kbdmip != NULL) {
- if (kbdmip+cpos > &kbdm[NKBDM-3]) {
- ctrlg(FALSE, 0);
- (*term.t_flush)();
- return(ABORT);
- }
-
- for (i=0; i<cpos; ++i)
- *kbdmip++ = buf[i];
- }
-
- (*term.t_putchar)('\r');
- ttcol = 0;
- (*term.t_flush)();
-
- if (buf[0] == 0)
- return(FALSE);
-
- return(TRUE);
-
- } else if (c == 0x07) { /* Bell, abort */
- (*term.t_putchar)('^');
- (*term.t_putchar)('G');
- ttcol += 2;
- ctrlg(FALSE, 0);
- (*term.t_flush)();
- return(ABORT);
-
- } else if (c == 0x7F || c == 0x08) { /* rubout/erase */
- if (cpos != 0) {
- (*term.t_putchar)('\b');
- (*term.t_putchar)(' ');
- (*term.t_putchar)('\b');
- --ttcol;
-
- if (buf[--cpos] < 0x20) {
- (*term.t_putchar)('\b');
- (*term.t_putchar)(' ');
- (*term.t_putchar)('\b');
- --ttcol;
- }
-
- if (buf[cpos] == '\n') {
- (*term.t_putchar)('\b');
- (*term.t_putchar)('\b');
- (*term.t_putchar)(' ');
- (*term.t_putchar)(' ');
- (*term.t_putchar)('\b');
- (*term.t_putchar)('\b');
- --ttcol;
- --ttcol;
- }
-
- (*term.t_flush)();
- }
-
- } else if (c == 0x15) { /* C-U, kill */
- while (cpos != 0) {
- (*term.t_putchar)('\b');
- (*term.t_putchar)(' ');
- (*term.t_putchar)('\b');
- --ttcol;
-
- if (buf[--cpos] < 0x20) {
- (*term.t_putchar)('\b');
- (*term.t_putchar)(' ');
- (*term.t_putchar)('\b');
- --ttcol;
- }
- }
-
- (*term.t_flush)();
-
- } else {
- if (cpos < nbuf-1) {
- buf[cpos++] = c;
-
- if ((c < ' ') && (c != '\n')) {
- (*term.t_putchar)('^');
- ++ttcol;
- c ^= 0x40;
- }
-
- if (c != '\n')
- (*term.t_putchar)(c);
- else { /* put out <NL> for <ret> */
- (*term.t_putchar)('<');
- (*term.t_putchar)('N');
- (*term.t_putchar)('L');
- (*term.t_putchar)('>');
- ttcol += 3;
- }
- ++ttcol;
- (*term.t_flush)();
- }
- }
- }
- }
-
- /*
- * Write a message into the message line. Keep track of the physical cursor
- * position. A small class of printf like format items is handled. Assumes the
- * stack grows down; this assumption is made by the "++" in the argument scan
- * loop. Set the "message line" flag TRUE.
- */
-
- mlwrite(fmt, arg)
- char *fmt;
- {
- register int c;
- register char *ap;
-
- if (eolexist == FALSE) {
- mlerase();
- (*term.t_flush)();
- }
-
- movecursor(term.t_nrow, 0);
- ap = (char *) &arg;
- while ((c = *fmt++) != 0) {
- if (c != '%') {
- (*term.t_putchar)(c);
- ++ttcol;
- }
- else
- {
- c = *fmt++;
- switch (c) {
- case 'd':
- mlputi(*(int *)ap, 10);
- ap += sizeof(int);
- break;
-
- case 'o':
- mlputi(*(int *)ap, 8);
- ap += sizeof(int);
- break;
-
- case 'x':
- mlputi(*(int *)ap, 16);
- ap += sizeof(int);
- break;
-
- case 'D':
- mlputli(*(long *)ap, 10);
- ap += sizeof(long);
- break;
-
- case 's':
- mlputs(*(char **)ap);
- ap += sizeof(char *);
- break;
-
- default:
- (*term.t_putchar)(c);
- ++ttcol;
- }
- }
- }
- if (eolexist == TRUE)
- (*term.t_eeol)();
- (*term.t_flush)();
- mpresf = TRUE;
- }
-
- /*
- * Write out a string. Update the physical cursor position. This assumes that
- * the characters in the string all have width "1"; if this is not the case
- * things will get screwed up a little.
- */
- mlputs(s)
- char *s;
- {
- register int c;
-
- while ((c = *s++) != 0)
- {
- (*term.t_putchar)(c);
- ++ttcol;
- }
- }
-
- /*
- * Write out an integer, in the specified radix. Update the physical cursor
- * position. This will not handle any negative numbers; maybe it should.
- */
- mlputi(i, r)
- {
- register int q;
- static char hexdigits[] = "0123456789ABCDEF";
-
- if (i < 0)
- {
- i = -i;
- (*term.t_putchar)('-');
- }
-
- q = i/r;
-
- if (q != 0)
- mlputi(q, r);
-
- (*term.t_putchar)(hexdigits[i%r]);
- ++ttcol;
- }
-
- /*
- * do the same except as a long integer.
- */
- mlputli(l, r)
- long l;
- {
- register long q;
-
- if (l < 0)
- {
- l = -l;
- (*term.t_putchar)('-');
- }
-
- q = l/r;
-
- if (q != 0)
- mlputli(q, r);
-
- (*term.t_putchar)((int)(l%r)+'0');
- ++ttcol;
- }
-
- #if RAINBOW
-
- putline(row, col, buf)
- int row, col;
- char buf[];
- {
- int n;
-
- n = strlen(buf);
- if (col + n - 1 > term.t_ncol)
- n = term.t_ncol - col + 1;
- Put_Data(row, col, n, buf);
- }
- #endif
-
- /* get a command name from the command line. Command completion means
- that pressing a <SPACE> will attempt to complete an unfinished command
- name if it is unique.
- */
-
- int (*getname())()
-
- {
- register int cpos; /* current column on screen output */
- register int c;
- register char *sp; /* pointer to string for output */
- register NBIND *ffp; /* first ptr to entry in name binding table */
- register NBIND *cffp; /* current ptr to entry in name binding table */
- register NBIND *lffp; /* last ptr to entry in name binding table */
- char buf[NSTRING]; /* buffer to hold tentative command name */
- int (*fncmatch())();
-
- /* starting at the begining of the string buffer */
- cpos = 0;
-
- /* if we are executing a keyboard macro, fill our buffer from there,
- and attempt a straight match */
- if (kbdmop != NULL) {
- while ((c = *kbdmop++) != '\0')
- buf[cpos++] = c;
-
- buf[cpos] = 0;
-
- /* return the result of a match */
- return(fncmatch(&buf[0]));
- }
-
- /* if we are executing a command line get the next arg and match it */
- if (clexec) {
- nxtarg(buf);
- return(fncmatch(&buf[0]));
- }
-
- /* build a name string from the keyboard */
- while (TRUE) {
- c = (*term.t_getchar)();
-
- /* if we are at the end, just match it */
- if (c == 0x0d) {
- buf[cpos] = 0;
-
- /* save keyboard macro string if needed */
- if (kbdtext(&buf[0]) == ABORT)
- return( (int (*)()) NULL);
-
- /* and match it off */
- return(fncmatch(&buf[0]));
-
- } else if (c == 0x07) { /* Bell, abort */
- (*term.t_putchar)('^');
- (*term.t_putchar)('G');
- ttcol += 2;
- ctrlg(FALSE, 0);
- (*term.t_flush)();
- return( (int (*)()) NULL);
-
- } else if (c == 0x7F || c == 0x08) { /* rubout/erase */
- if (cpos != 0) {
- (*term.t_putchar)('\b');
- (*term.t_putchar)(' ');
- (*term.t_putchar)('\b');
- --ttcol;
- --cpos;
- (*term.t_flush)();
- }
-
- } else if (c == 0x15) { /* C-U, kill */
- while (cpos != 0) {
- (*term.t_putchar)('\b');
- (*term.t_putchar)(' ');
- (*term.t_putchar)('\b');
- --cpos;
- --ttcol;
- }
-
- (*term.t_flush)();
-
- } else if (c == ' ') {
- /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
- /* attempt a completion */
- buf[cpos] = 0; /* terminate it for us */
- ffp = &names[0]; /* scan for matches */
- while (ffp->n_func != NULL) {
- if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
- /* a possible match! More than one? */
- if ((ffp + 1)->n_func == NULL ||
- (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
- /* no...we match, print it */
- sp = ffp->n_name + cpos;
- while (*sp)
- (*term.t_putchar)(*sp++);
- (*term.t_flush)();
- return(ffp->n_func);
- } else {
- /* << << << << << << << << << << << << << << << << << */
- /* try for a partial match against the list */
-
- /* first scan down until we no longer match the current input */
- lffp = (ffp + 1);
- while ((lffp+1)->n_func != NULL) {
- if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0)
- break;
- ++lffp;
- }
-
- /* and now, attempt to partial complete the string, char at a time */
- while (TRUE) {
- /* add the next char in */
- buf[cpos] = ffp->n_name[cpos];
-
- /* scan through the candidates */
- cffp = ffp + 1;
- while (cffp <= lffp) {
- if (cffp->n_name[cpos] != buf[cpos])
- goto onward;
- ++cffp;
- }
-
- /* add the character */
- (*term.t_putchar)(buf[cpos++]);
- }
- /* << << << << << << << << << << << << << << << << << */
- }
- }
- ++ffp;
- }
-
- /* no match.....beep and onward */
- (*term.t_beep)();
- onward:;
- (*term.t_flush)();
- /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
- } else {
- if (cpos < NSTRING-1 && c > ' ') {
- buf[cpos++] = c;
- (*term.t_putchar)(c);
- }
-
- ++ttcol;
- (*term.t_flush)();
- }
- }
- }
-
- kbdtext(buf) /* add this text string to the current keyboard macro
- definition */
-
- char *buf; /* text to add to keyboard macro */
-
- {
- /* if we are defining a keyboard macro, save it */
- if (kbdmip != NULL) {
- if (kbdmip+strlen(buf) > &kbdm[NKBDM-4]) {
- ctrlg(FALSE, 0);
- (*term.t_flush)();
- return(ABORT);
- }
-
- /* copy string in and null terminate it */
- while (*buf)
- *kbdmip++ = *buf++;
- *kbdmip++ = 0;
- }
- return(TRUE);
- }
-