Subject: v09i047: Repost of display.c from MicroEmacs, Patch1 Newsgroups: mod.sources Approved: rs@mirror.TMC.COM Submitted by: pur-ee!pur-phy!duncan!lawrence Mod.sources: Volume 9, Issue 47 Archive-name: uemacs3.8b/Patch1 [ When last we heard from this group, articles had been leaving site "mirror" with 512 bytes elided from them... This is the first of a couple of re-posts. --r$ ] Daniel Lawrence can be reached at: UUCP: ihnp4!pur-ee!pur-phy!duncan!lawrence ARPA: nwd@j.cc.purdue.edu FIDO: The Programmer's Room 201/2 (317) 742-5533 300/1200 baud 24 hours USmail: 617 New York St Lafayette, IN 47901 ATT: (317) 742-5153 -----CUT-----HERE----- #! /bin/sh # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # If this archive is complete, you will see the message: # "End of shell archive." # Contents: display.c # Wrapped by rs@mirror on Tue Apr 14 16:52:46 1987 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo shar: Extracting \"display.c\" \(23829 characters\) if test -f display.c ; then echo shar: Will not over-write existing file \"display.c\" else sed "s/^X//" >display.c <<'END_OF_display.c' X/* X * The functions in this file handle redisplay. There are two halves, the X * ones that update the virtual display screen, and the ones that make the X * physical display screen the same as the virtual display screen. These X * functions use hints that are left in the windows by the commands. X * X */ X X#include X#include "estruct.h" X#include "edef.h" X X#if MEGAMAX & ST520 Xoverlay "display" X#endif X Xtypedef struct VIDEO { X int v_flag; /* Flags */ X#if COLOR X int v_fcolor; /* current forground color */ X int v_bcolor; /* current background color */ X int v_rfcolor; /* requested forground color */ X int v_rbcolor; /* requested background color */ X#endif X char v_text[1]; /* Screen data. */ X} VIDEO; X X#define VFCHG 0x0001 /* Changed flag */ X#define VFEXT 0x0002 /* extended (beyond column 80) */ X#define VFREV 0x0004 /* reverse video status */ X#define VFREQ 0x0008 /* reverse video request */ X#define VFCOL 0x0010 /* color change requested */ X XVIDEO **vscreen; /* Virtual screen. */ X#if MEMMAP == 0 XVIDEO **pscreen; /* Physical screen. */ X#endif X X/* X * Initialize the data structures used by the display code. The edge vectors X * used to access the screens are set up. The operating system's terminal I/O X * channel is set up. All the other things get initialized at compile time. X * The original window has "WFCHG" set, so that it will get completely X * redrawn on the first call to "update". X */ Xvtinit() X{ X register int i; X register VIDEO *vp; X char *malloc(); X X TTopen(); /* open the screen */ X TTkopen(); /* open the keyboard */ X TTrev(FALSE); X vscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *)); X X if (vscreen == NULL) X exit(1); X X#if MEMMAP == 0 X pscreen = (VIDEO **) malloc(term.t_nrow*sizeof(VIDEO *)); X X if (pscreen == NULL) X exit(1); X#endif X X for (i = 0; i < term.t_nrow; ++i) X { X vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_mcol); X X if (vp == NULL) X exit(1); X X vp->v_flag = 0; X#if COLOR X vp->v_rfcolor = 7; X vp->v_rbcolor = 0; X#endif X vscreen[i] = vp; X#if MEMMAP == 0 X vp = (VIDEO *) malloc(sizeof(VIDEO)+term.t_mcol); X X if (vp == NULL) X exit(1); X X vp->v_flag = 0; X pscreen[i] = vp; X#endif X } X} X X/* X * Clean up the virtual terminal system, in anticipation for a return to the X * operating system. Move down to the last line and clear it out (the next X * system prompt will be written in the line). Shut down the channel to the X * terminal. X */ Xvttidy() X{ X mlerase(); X movecursor(term.t_nrow, 0); X TTflush(); X TTclose(); X TTkclose(); X} X X/* X * Set the virtual cursor to the specified row and column on the virtual X * screen. There is no checking for nonsense values; this might be a good X * idea during the early stages. X */ Xvtmove(row, col) X{ X vtrow = row; X vtcol = col; X} X X/* Write a character to the virtual screen. The virtual row and X column are updated. If we are not yet on left edge, don't print X it yet. If the line is too long put a "$" in the last column. X This routine only puts printing characters into the virtual X terminal buffers. Only column overflow is checked. X*/ X Xvtputc(c) X Xint c; X X{ X register VIDEO *vp; /* ptr to line being updated */ X X vp = vscreen[vtrow]; X X if (c == '\t') { X do { X vtputc(' '); X } while (((vtcol + taboff)&0x07) != 0); X } else if (vtcol >= term.t_ncol) { X ++vtcol; X vp->v_text[term.t_ncol - 1] = '$'; X } else if (c < 0x20 || c == 0x7F) { X vtputc('^'); X vtputc(c ^ 0x40); X } else { X if (vtcol >= 0) X vp->v_text[vtcol] = c; X ++vtcol; X } X} X X/* X * Erase from the end of the software cursor to the end of the line on which X * the software cursor is located. X */ Xvteeol() X{ X register VIDEO *vp; X X vp = vscreen[vtrow]; X while (vtcol < term.t_ncol) X vp->v_text[vtcol++] = ' '; X} X X/* upscreen: user routine to force a screen update X always finishes complete update */ X Xupscreen(f, n) X X{ X update(TRUE); X return(TRUE); X} X X/* X * Make sure that the display is right. This is a three part process. First, X * scan through all of the windows looking for dirty ones. Check the framing, X * and refresh the screen. Second, make sure that "currow" and "curcol" are X * correct for the current window. Third, make the virtual and physical X * screens the same. X */ Xupdate(force) X Xint force; /* force update past type ahead? */ X X{ X register WINDOW *wp; X X#if TYPEAH X if (force == FALSE && typahead()) X return(TRUE); X#endif X#if VISMAC == 0 X if (force == FALSE && kbdmode == PLAY) X return(TRUE); X#endif X X /* update any windows that need refreshing */ X wp = wheadp; X while (wp != NULL) { X if (wp->w_flag) { X /* if the window has changed, service it */ X reframe(wp); /* check the framing */ X if ((wp->w_flag & ~WFMODE) == WFEDIT) X updone(wp); /* update EDITed line */ X else if (wp->w_flag & ~WFMOVE) X updall(wp); /* update all lines */ X if (wp->w_flag & WFMODE) X modeline(wp); /* update modeline */ X wp->w_flag = 0; X wp->w_force = 0; X } X /* on to the next window */ X wp = wp->w_wndp; X } X X /* recalc the current hardware cursor location */ X updpos(); X X#if MEMMAP X /* update the cursor and flush the buffers */ X movecursor(currow, curcol - lbound); X#endif X X /* check for lines to de-extend */ X upddex(); X X /* if screen is garbage, re-plot it */ X if (sgarbf != FALSE) X updgar(); X X /* update the virtual screen to the physical screen */ X updupd(force); X X /* update the cursor and flush the buffers */ X movecursor(currow, curcol - lbound); X TTflush(); X return(TRUE); X} X X/* reframe: check to see if the cursor is on in the window X and re-frame it if needed or wanted */ X Xreframe(wp) X XWINDOW *wp; X X{ X register LINE *lp; X register int i; X X /* if not a requested reframe, check for a needed one */ X if ((wp->w_flag & WFFORCE) == 0) { X lp = wp->w_linep; X for (i = 0; i < wp->w_ntrows; i++) { X X /* if the line is in the window, no reframe */ X if (lp == wp->w_dotp) X return(TRUE); X X /* if we are at the end of the file, reframe */ X if (lp == wp->w_bufp->b_linep) X break; X X /* on to the next line */ X lp = lforw(lp); X } X } X X /* reaching here, we need a window refresh */ X i = wp->w_force; X X /* how far back to reframe? */ X if (i > 0) { /* only one screen worth of lines max */ X if (--i >= wp->w_ntrows) X i = wp->w_ntrows - 1; X } else if (i < 0) { /* negative update???? */ X i += wp->w_ntrows; X if (i < 0) X i = 0; X } else X i = wp->w_ntrows / 2; X X /* backup to new line at top of window */ X lp = wp->w_dotp; X while (i != 0 && lback(lp) != wp->w_bufp->b_linep) { X --i; X lp = lback(lp); X } X X /* and reset the current line at top of window */ X wp->w_linep = lp; X wp->w_flag |= WFHARD; X wp->w_flag &= ~WFFORCE; X return(TRUE); X} X X/* updone: update the current line to the virtual screen */ X Xupdone(wp) X XWINDOW *wp; /* window to update current line in */ X X{ X register LINE *lp; /* line to update */ X register int sline; /* physical screen line to update */ X register int i; X X /* search down the line we want */ X lp = wp->w_linep; X sline = wp->w_toprow; X while (lp != wp->w_dotp) { X ++sline; X lp = lforw(lp); X } X X /* and update the virtual line */ X vscreen[sline]->v_flag |= VFCHG; X vscreen[sline]->v_flag &= ~VFREQ; X vtmove(sline, 0); X for (i=0; i < llength(lp); ++i) X vtputc(lgetc(lp, i)); X#if COLOR X vscreen[sline]->v_rfcolor = wp->w_fcolor; X vscreen[sline]->v_rbcolor = wp->w_bcolor; X#endif X vteeol(); X} X X/* updall: update all the lines in a window on the virtual screen */ X Xupdall(wp) X XWINDOW *wp; /* window to update lines in */ X X{ X register LINE *lp; /* line to update */ X register int sline; /* physical screen line to update */ X register int i; X X /* search down the lines, updating them */ X lp = wp->w_linep; X sline = wp->w_toprow; X while (sline < wp->w_toprow + wp->w_ntrows) { X X /* and update the virtual line */ X vscreen[sline]->v_flag |= VFCHG; X vscreen[sline]->v_flag &= ~VFREQ; X vtmove(sline, 0); X if (lp != wp->w_bufp->b_linep) { X /* if we are not at the end */ X for (i=0; i < llength(lp); ++i) X vtputc(lgetc(lp, i)); X lp = lforw(lp); X } X X /* on to the next one */ X#if COLOR X vscreen[sline]->v_rfcolor = wp->w_fcolor; X vscreen[sline]->v_rbcolor = wp->w_bcolor; X#endif X vteeol(); X ++sline; X } X X} X X/* updpos: update the position of the hardware cursor and handle extended X lines. This is the only update for simple moves. */ X Xupdpos() X X{ X register LINE *lp; X register int c; X register int i; X X /* find the current row */ X lp = curwp->w_linep; X currow = curwp->w_toprow; X while (lp != curwp->w_dotp) { X ++currow; X lp = lforw(lp); X } X X /* find the current column */ X curcol = 0; X i = 0; X while (i < curwp->w_doto) { X c = lgetc(lp, i++); X if (c == '\t') X curcol |= 0x07; X else X if (c < 0x20 || c == 0x7f) X ++curcol; X X ++curcol; X } X X /* if extended, flag so and update the virtual line image */ X if (curcol >= term.t_ncol - 1) { X vscreen[currow]->v_flag |= (VFEXT | VFCHG); X updext(); X } else X lbound = 0; X} X X/* upddex: de-extend any line that derserves it */ X Xupddex() X X{ X register WINDOW *wp; X register LINE *lp; X register int i,j; X X wp = wheadp; X X while (wp != NULL) { X lp = wp->w_linep; X i = wp->w_toprow; X X while (i < wp->w_toprow + wp->w_ntrows) { X if (vscreen[i]->v_flag & VFEXT) { X if ((wp != curwp) || (lp != wp->w_dotp) || X (curcol < term.t_ncol - 1)) { X vtmove(i, 0); X for (j = 0; j < llength(lp); ++j) X vtputc(lgetc(lp, j)); X vteeol(); X X /* this line no longer is extended */ X vscreen[i]->v_flag &= ~VFEXT; X vscreen[i]->v_flag |= VFCHG; X } X } X lp = lforw(lp); X ++i; X } X /* and onward to the next window */ X wp = wp->w_wndp; X } X} X X/* updgar: if the screen is garbage, clear the physical screen and X the virtual screen and force a full update */ X Xupdgar() X X{ X register char *txt; X register int i,j; X X for (i = 0; i < term.t_nrow; ++i) { X vscreen[i]->v_flag |= VFCHG; X#if REVSTA X vscreen[i]->v_flag &= ~VFREV; X#endif X#if COLOR X vscreen[i]->v_fcolor = gfcolor; X vscreen[i]->v_bcolor = gbcolor; X#endif X#if MEMMAP == 0 X txt = pscreen[i]->v_text; X for (j = 0; j < term.t_ncol; ++j) X txt[j] = ' '; X#endif X } X X movecursor(0, 0); /* Erase the screen. */ X (*term.t_eeop)(); X sgarbf = FALSE; /* Erase-page clears */ X mpresf = FALSE; /* the message area. */ X#if COLOR X mlerase(); /* needs to be cleared if colored */ X#endif X} X X/* updupd: update the physical screen from the virtual screen */ X Xupdupd(force) X Xint force; /* forced update flag */ X X{ X register VIDEO *vp1; X register int i; X X for (i = 0; i < term.t_nrow; ++i) { X vp1 = vscreen[i]; X X /* for each line that needs to be updated*/ X if ((vp1->v_flag & VFCHG) != 0) { X#if TYPEAH X if (force == FALSE && typahead()) X return(TRUE); X#endif X#if MEMMAP X updateline(i, vp1); X#else X updateline(i, vp1, pscreen[i]); X#endif X } X } X return(TRUE); X} X X/* updext: update the extended line which the cursor is currently X on at a column greater than the terminal width. The line X will be scrolled right or left to let the user see where X the cursor is X */ X Xupdext() X X{ X register int rcursor; /* real cursor location */ X register LINE *lp; /* pointer to current line */ X register int j; /* index into line */ X X /* calculate what column the real cursor will end up in */ X rcursor = ((curcol - term.t_ncol) % term.t_scrsiz) + term.t_margin; X taboff = lbound = curcol - rcursor + 1; X X /* scan through the line outputing characters to the virtual screen */ X /* once we reach the left edge */ X vtmove(currow, -lbound); /* start scanning offscreen */ X lp = curwp->w_dotp; /* line to output */ X for (j=0; jv_text[0] = '$'; X} X X/* X * Update a single line. This does not know how to use insert or delete X * character sequences; we are using VT52 functionality. Update the physical X * row and column variables. It does try an exploit erase to end of line. The X * RAINBOW version of this routine uses fast video. X */ X#if MEMMAP X/* UPDATELINE specific code for the IBM-PC and other compatables */ X Xupdateline(row, vp1) X Xint row; /* row of screen to update */ Xstruct VIDEO *vp1; /* virtual screen image */ X X{ X#if COLOR X scwrite(row, vp1->v_text, vp1->v_rfcolor, vp1->v_rbcolor); X vp1->v_fcolor = vp1->v_rfcolor; X vp1->v_bcolor = vp1->v_rbcolor; X#else X if (vp1->v_flag & VFREQ) X scwrite(row, vp1->v_text, 0, 7); X else X scwrite(row, vp1->v_text, 7, 0); X#endif X vp1->v_flag &= ~(VFCHG | VFCOL); /* flag this line as changed */ X X} X X#else X Xupdateline(row, vp1, vp2) X Xint row; /* row of screen to update */ Xstruct VIDEO *vp1; /* virtual screen image */ Xstruct VIDEO *vp2; /* physical screen image */ X X{ X#if RAINBOW X/* UPDATELINE specific code for the DEC rainbow 100 micro */ X X register char *cp1; X register char *cp2; X register int nch; X X /* since we don't know how to make the rainbow do this, turn it off */ X flags &= (~VFREV & ~VFREQ); X X cp1 = &vp1->v_text[0]; /* Use fast video. */ X cp2 = &vp2->v_text[0]; X putline(row+1, 1, cp1); X nch = term.t_ncol; X X do X { X *cp2 = *cp1; X ++cp2; X ++cp1; X } X while (--nch); X *flags &= ~VFCHG; X#else X/* UPDATELINE code for all other versions */ X X register char *cp1; X register char *cp2; X register char *cp3; X register char *cp4; X register char *cp5; X register int nbflag; /* non-blanks to the right flag? */ X int rev; /* reverse video flag */ X int req; /* reverse video request flag */ X X X /* set up pointers to virtual and physical lines */ X cp1 = &vp1->v_text[0]; X cp2 = &vp2->v_text[0]; X X#if COLOR X TTforg(vp1->v_rfcolor); X TTbacg(vp1->v_rbcolor); X#endif X X#if REVSTA | COLOR X /* if we need to change the reverse video status of the X current line, we need to re-write the entire line */ X rev = (vp1->v_flag & VFREV) == VFREV; X req = (vp1->v_flag & VFREQ) == VFREQ; X if ((rev != req) X#if COLOR X || (vp1->v_fcolor != vp1->v_rfcolor) || (vp1->v_bcolor != vp1->v_rbcolor) X#endif X#if HP150 X /* the HP150 has some reverse video problems */ X || req || rev X#endif X ) { X movecursor(row, 0); /* Go to start of line. */ X /* set rev video if needed */ X if (rev != req) X (*term.t_rev)(req); X X /* scan through the line and dump it to the screen and X the virtual screen array */ X cp3 = &vp1->v_text[term.t_ncol]; X while (cp1 < cp3) { X TTputc(*cp1); X ++ttcol; X *cp2++ = *cp1++; X } X /* turn rev video off */ X if (rev != req) X (*term.t_rev)(FALSE); X X /* update the needed flags */ X vp1->v_flag &= ~VFCHG; X if (req) X vp1->v_flag |= VFREV; X else X vp1->v_flag &= ~VFREV; X#if COLOR X vp1->v_fcolor = vp1->v_rfcolor; X vp1->v_bcolor = vp1->v_rbcolor; X#endif X return(TRUE); X } X#endif X X /* advance past any common chars at the left */ X while (cp1 != &vp1->v_text[term.t_ncol] && cp1[0] == cp2[0]) { X ++cp1; X ++cp2; X } X X/* This can still happen, even though we only call this routine on changed X * lines. A hard update is always done when a line splits, a massive X * change is done, or a buffer is displayed twice. This optimizes out most X * of the excess updating. A lot of computes are used, but these tend to X * be hard operations that do a lot of update, so I don't really care. X */ X /* if both lines are the same, no update needs to be done */ X if (cp1 == &vp1->v_text[term.t_ncol]) { X vp1->v_flag &= ~VFCHG; /* flag this line is changed */ X return(TRUE); X } X X /* find out if there is a match on the right */ X nbflag = FALSE; X cp3 = &vp1->v_text[term.t_ncol]; X cp4 = &vp2->v_text[term.t_ncol]; X X while (cp3[-1] == cp4[-1]) { X --cp3; X --cp4; X if (cp3[0] != ' ') /* Note if any nonblank */ X nbflag = TRUE; /* in right match. */ X } X X cp5 = cp3; X X /* Erase to EOL ? */ X if (nbflag == FALSE && eolexist == TRUE && (req != TRUE)) { X while (cp5!=cp1 && cp5[-1]==' ') X --cp5; X X if (cp3-cp5 <= 3) /* Use only if erase is */ X cp5 = cp3; /* fewer characters. */ X } X X movecursor(row, cp1 - &vp1->v_text[0]); /* Go to start of line. */ X#if REVSTA X TTrev(rev); X#endif X X while (cp1 != cp5) { /* Ordinary. */ X TTputc(*cp1); X ++ttcol; X *cp2++ = *cp1++; X } X X if (cp5 != cp3) { /* Erase. */ X TTeeol(); X while (cp1 != cp3) X *cp2++ = *cp1++; X } X#if REVSTA X TTrev(FALSE); X#endif X vp1->v_flag &= ~VFCHG; /* flag this line as updated */ X return(TRUE); X#endif X} X#endif X X/* X * Redisplay the mode line for the window pointed to by the "wp". This is the X * only routine that has any idea of how the modeline is formatted. You can X * change the modeline format by hacking at this routine. Called by "update" X * any time there is a dirty window. X */ Xmodeline(wp) X WINDOW *wp; X{ X register char *cp; X register int c; X register int n; /* cursor position count */ X register BUFFER *bp; X register i; /* loop index */ X register lchar; /* character to draw line in buffer with */ X register firstm; /* is this the first mode? */ X char tline[NLINE]; /* buffer for part of mode line */ X X n = wp->w_toprow+wp->w_ntrows; /* Location. */ X vscreen[n]->v_flag |= VFCHG | VFREQ | VFCOL;/* Redraw next time. */ X#if COLOR X vscreen[n]->v_rfcolor = 0; /* black on */ X vscreen[n]->v_rbcolor = 7; /* white.....*/ X#endif X vtmove(n, 0); /* Seek to right line. */ X if (wp == curwp) /* mark the current buffer */ X lchar = '='; X else X#if REVSTA X if (revexist) X lchar = ' '; X else X#endif X lchar = '-'; X X vtputc(lchar); X bp = wp->w_bufp; X X if ((bp->b_flag&BFCHG) != 0) /* "*" if changed. */ X vtputc('*'); X else X vtputc(lchar); X X n = 2; X strcpy(tline, " MicroEMACS "); /* Buffer name. */ X strcat(tline, VERSION); X strcat(tline, " ("); X X /* display the modes */ X X firstm = TRUE; X for (i = 0; i < NUMMODES; i++) /* add in the mode flags */ X if (wp->w_bufp->b_mode & (1 << i)) { X if (firstm != TRUE) X strcat(tline, " "); X firstm = FALSE; X strcat(tline, modename[i]); X } X strcat(tline,") "); X X cp = &tline[0]; X while ((c = *cp++) != 0) X { X vtputc(c); X ++n; X } X X#if 0 X vtputc(lchar); X vtputc((wp->w_flag&WFCOLR) != 0 ? 'C' : lchar); X vtputc((wp->w_flag&WFMODE) != 0 ? 'M' : lchar); X vtputc((wp->w_flag&WFHARD) != 0 ? 'H' : lchar); X vtputc((wp->w_flag&WFEDIT) != 0 ? 'E' : lchar); X vtputc((wp->w_flag&WFMOVE) != 0 ? 'V' : lchar); X vtputc((wp->w_flag&WFFORCE) != 0 ? 'F' : lchar); X vtputc(lchar); X n += 8; X#endif X X vtputc(lchar); X vtputc(lchar); X vtputc(' '); X n += 3; X cp = &bp->b_bname[0]; X X while ((c = *cp++) != 0) X { X vtputc(c); X ++n; X } X X vtputc(' '); X vtputc(lchar); X vtputc(lchar); X n += 3; X X if (bp->b_fname[0] != 0) /* File name. */ X { X vtputc(' '); X ++n; X cp = "File: "; X X while ((c = *cp++) != 0) X { X vtputc(c); X ++n; X } X X cp = &bp->b_fname[0]; X X while ((c = *cp++) != 0) X { X vtputc(c); X ++n; X } X X vtputc(' '); X ++n; X } X X while (n < term.t_ncol) /* Pad to full width. */ X { X vtputc(lchar); X ++n; X } X} X Xupmode() /* update all the mode lines */ X X{ X register WINDOW *wp; X X wp = wheadp; X while (wp != NULL) { X wp->w_flag |= WFMODE; X wp = wp->w_wndp; X } X} X X/* X * Send a command to the terminal to move the hardware cursor to row "row" X * and column "col". The row and column arguments are origin 0. Optimize out X * random calls. Update "ttrow" and "ttcol". X */ Xmovecursor(row, col) X { X if (row!=ttrow || col!=ttcol) X { X ttrow = row; X ttcol = col; X TTmove(row, col); X } X } X X/* X * Erase the message line. This is a special routine because the message line X * is not considered to be part of the virtual screen. It always works X * immediately; the terminal buffer is flushed via a call to the flusher. X */ Xmlerase() X { X int i; X X movecursor(term.t_nrow, 0); X#if COLOR X TTforg(7); X TTbacg(0); X#endif X if (eolexist == TRUE) X TTeeol(); X else { X for (i = 0; i < term.t_ncol - 1; i++) X TTputc(' '); X movecursor(term.t_nrow, 1); /* force the move! */ X movecursor(term.t_nrow, 0); X } X TTflush(); X mpresf = FALSE; X } X X/* X * Write a message into the message line. Keep track of the physical cursor X * position. A small class of printf like format items is handled. Assumes the X * stack grows down; this assumption is made by the "++" in the argument scan X * loop. Set the "message line" flag TRUE. X */ X Xmlwrite(fmt, arg) X char *fmt; X { X register int c; X register char *ap; X X#if COLOR X TTforg(7); X TTbacg(0); X#endif X if (eolexist == FALSE) { X mlerase(); X TTflush(); X } X X movecursor(term.t_nrow, 0); X ap = (char *) &arg; X while ((c = *fmt++) != 0) { X if (c != '%') { X TTputc(c); X ++ttcol; X } X else X { X c = *fmt++; X switch (c) { X case 'd': X mlputi(*(int *)ap, 10); X ap += sizeof(int); X break; X X case 'o': X mlputi(*(int *)ap, 8); X ap += sizeof(int); X break; X X case 'x': X mlputi(*(int *)ap, 16); X ap += sizeof(int); X break; X X case 'D': X mlputli(*(long *)ap, 10); X ap += sizeof(long); X break; X X case 's': X mlputs(*(char **)ap); X ap += sizeof(char *); X break; X X case 'f': X mlputf(*(int *)ap); X ap += sizeof(int); X break; X X default: X TTputc(c); X ++ttcol; X } X } X } X if (eolexist == TRUE) X TTeeol(); X TTflush(); X mpresf = TRUE; X } X X/* X * Write out a string. Update the physical cursor position. This assumes that X * the characters in the string all have width "1"; if this is not the case X * things will get screwed up a little. X */ Xmlputs(s) X char *s; X { X register int c; X X while ((c = *s++) != 0) X { X TTputc(c); X ++ttcol; X } X } X X/* X * Write out an integer, in the specified radix. Update the physical cursor X * position. X */ Xmlputi(i, r) X { X register int q; X static char hexdigits[] = "0123456789ABCDEF"; X X if (i < 0) X { X i = -i; X TTputc('-'); X } X X q = i/r; X X if (q != 0) X mlputi(q, r); X X TTputc(hexdigits[i%r]); X ++ttcol; X } X X/* X * do the same except as a long integer. X */ Xmlputli(l, r) X long l; X { X register long q; X X if (l < 0) X { X l = -l; X TTputc('-'); X } X X q = l/r; X X if (q != 0) X mlputli(q, r); X X TTputc((int)(l%r)+'0'); X ++ttcol; X } X X/* X * write out a scaled integer with two decimal places X */ X Xmlputf(s) X Xint s; /* scaled integer to output */ X X{ X int i; /* integer portion of number */ X int f; /* fractional portion of number */ X X /* break it up */ X i = s / 100; X f = s % 100; X X /* send out the integer portion */ X mlputi(i, 10); X TTputc('.'); X TTputc((f / 10) + '0'); X TTputc((f % 10) + '0'); X ttcol += 3; X} X X#if RAINBOW X Xputline(row, col, buf) X int row, col; X char buf[]; X { X int n; X X n = strlen(buf); X if (col + n - 1 > term.t_ncol) X n = term.t_ncol - col + 1; X Put_Data(row, col, n, buf); X } X#endif X END_OF_display.c if test 23829 -ne `wc -c