pvr@wang.com (Peter Reilley) (02/28/91)
#! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 11 (of 11)." # Contents: display.c # Wrapped by pvr@elf on Wed Feb 27 14:16:51 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'display.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'display.c'\" else echo shar: Extracting \"'display.c'\" \(49127 characters\) sed "s/^X//" >'display.c' <<'END_OF_FILE' X/* X* The functions in this file handle redisplay. The X* redisplay system knows almost nothing about the editing X* process; the editing functions do, however, set some X* hints to eliminate a lot of the grinding. There is more X* that can be done; the "vtputc" interface is a real X* pig. Two conditional compilation flags; the GOSLING X* flag enables dynamic programming redisplay, using the X* algorithm published by Jim Gosling in SIGOA. The MEMMAP X* changes things around for memory mapped video. With X* both off, the terminal is a VT52. X*/ X X#define LINT_ARGS 1 /* enable lint type checking */ X#include "def.h" X XD32 get_long (); XD16 get_int (); Xvoid writ_echo (); Xvoid uline (); Xvoid ucopy (); Xvoid modeline (); Xvoid bin_to_text (); Xuint fill_buf (); Xuint get_currow (); Xuint get_curcol (); X#if MSDOS Xvoid mem_line (); X#endif X X extern char MSG_prn_to[]; X extern char MSG_disp_r_n[]; X extern char MSG_11lX[]; X extern char MSG_11lo[]; X extern char MSG_11ld[]; X extern char MSG_03o[]; X extern char MSG_06o[]; X extern char MSG_011lo[]; X extern char MSG_03u[]; X extern char MSG_05u[]; X extern char MSG_010lu[]; X extern char MSG_02X[]; X extern char MSG_04X[]; X extern char MSG_08lX[]; X extern char MSG_prog_name[]; X extern char MSG_disp_b_lst[]; X extern char MSG_file[]; X extern char MSG_RO[]; X extern char MSG_WL[]; X extern char MSG_RW[]; X extern char MSG_AU[]; X extern char MSG_NOT_AU[]; X extern char MSG_curs_asc[]; X extern char MSG_curs_ebc[]; X extern char MSG_curs_hex[]; X extern char MSG_curs_bin[]; X extern char MSG_curs_dec[]; X extern char MSG_curs_oct[]; X extern char MSG_siz_8[]; X extern char MSG_siz_16[]; X extern char MSG_siz_32[]; X extern char MSG_siz_null[]; X extern char MSG_int_shift[]; X extern char MSG_mot_shift[]; X extern char MSG_print1[]; X extern char MSG_print2[]; X#if RUNCHK X extern char ERR_disp_1[]; X extern char ERR_disp_2[]; X extern char ERR_disp_3[]; X extern char ERR_disp_4[]; X extern char ERR_disp_5[]; X extern char ERR_disp_6[]; X#endif X X#include "lintfunc.dec" Xextern char ebcdic_table[]; X Xextern bool mem_map; X X/* X* You can change these back to the types X* implied by the name if you get tight for space. If you X* make both of them "int" you get better code on the VAX. X* They do nothing if this is not Gosling redisplay, except X* for change the size of a structure that isn't used. X* A bit of a cheat. X*/ X#define XCHAR int X#define XSHORT int X X/* X* A video structure always holds X* an array of characters whose length is equal to X* the longest line possible. Only some of this is X* used if "ncol" isn't the same as "NCOL". X*/ Xtypedef struct vid X{ X short v_hash; /* Hash code, for compares. */ X short v_flag; /* Flag word. */ X short v_color; /* Color of the line. */ X XSHORT v_cost; /* Cost of display. */ X char v_text[NCOL]; /* The actual characters. */ X} VIDEO; X X#define VFCHG 0x0001 /* Changed. */ X#define VFHBAD 0x0002 /* Hash and cost are bad. */ X X/* X* SCORE structures hold the optimal X* trace trajectory, and the cost of redisplay, when X* the dynamic programming redisplay code is used. X* If no fancy redisplay, this isn't used. The trace index X* fields can be "char", and the score a "short", but X* this makes the code worse on the VAX. X*/ Xtypedef struct X{ X XCHAR s_itrace; /* "i" index for track back. */ X XCHAR s_jtrace; /* "j" index for trace back. */ X XSHORT s_cost; /* Display cost. */ X} SCORE; X Xint sgarbf = TRUE; /* TRUE if screen is garbage. */ Xint vtrow = 0; /* Virtual cursor row. */ Xint vtcol = 0; /* Virtual cursor column. */ Xint tthue = CNONE; /* Current color. */ Xint ttrow = HUGE; /* Physical cursor row. */ Xint ttcol = HUGE; /* Physical cursor column. */ Xint tttop = HUGE; /* Top of scroll region. */ Xint ttbot = HUGE; /* Bottom of scroll region. */ Xchar file_off_bad = FALSE; /* Have file offsets been changed */ X XVIDEO * vscreen[NROW]; /* Edge vector, virtual. */ XVIDEO * pscreen[NROW]; /* Edge vector, physical. */ XVIDEO video[2 * (NROW)]; /* Actual screen data. */ XVIDEO blanks; /* Blank line image. */ X X#if GOSLING X/* X* This matrix is written as an array because X* we do funny things in the "setscores" routine, which X* is very compute intensive, to make the subscripts go away. X* It would be "SCORE score[NROW][NROW]" in old speak. X* Look at "setscores" to understand what is up. X*/ XSCORE score[NROW * NROW]; X#endif X X/* X* Initialize the data structures used X* by the display code. The edge vectors used X* to access the screens are set up. The operating X* system's terminal I/O channel is set up. Fill the X* "blanks" array with ASCII blanks. The rest is done X* at compile time. The original window is marked X* as needing full update, and the physical screen X* is marked as garbage, so all the right stuff happens X* on the first call to redisplay. X*/ Xvoid vtinit () X{ X register VIDEO * vp; X register int i; X X ttopen (); X ttinit (); X vp = &video[0]; X for (i = 0; i < NROW; ++i) X { X vscreen[i] = vp; X ++vp; X pscreen[i] = vp; X ++vp; X } X blanks.v_color = CTEXT; X for (i = 0; i < NCOL; ++i) X blanks.v_text[i] = ' '; X} X X/* X* Tidy up the virtual display system X* in anticipation of a return back to the host X* operating system. Right now all we do is position X* the cursor to the last line, erase the line, and X* close the terminal channel. X*/ Xvoid vttidy () X{ X ttcolor (CTEXT); X ttnowindow (); /* No scroll window. */ X ttmove (nrow - 1, 0); /* Echo line. */ X tteeol (); X tttidy (); X ttflush (); X ttclose (); X} X X/* X* Move the virtual cursor to an origin X* 0 spot on the virtual display screen. I could X* store the column as a character pointer to the spot X* on the line, which would make "vtputc" a little bit X* more efficient. No checking for errors. X*/ Xvoid vtmove (row, col) X{ X vtrow = row; X vtcol = col; X} X X/* X* Write a character to the virtual display, X* dealing with long lines and the display of unprintable X* things like control characters. Also expand tabs every 8 X* columns. This code only puts printing characters into X* the virtual display image. Special care must be taken when X* expanding tabs. On a screen whose width is not a multiple X* of 8, it is possible for the virtual cursor to hit the X* right margin before the next tab stop is reached. This X* makes the tab code loop if you are not careful. X* Three guesses how we found this. X*/ Xvoid vtputc (c) Xregister int c; X{ X register VIDEO * vp; X X vp = vscreen[vtrow]; X if (vtcol >= ncol) X vp -> v_text[ncol - 1] = '$'; X else X if (ISCTRL (c) != FALSE) X { X vtputc ('^'); X vtputc (c ^ 0x40); X } X else X { X vp -> v_text[vtcol] = c; X vtcol++; X } X X} X/* X* Write an entire screen line in the correct format. pvr X* X* This code only puts printing characters into X* the virtual display image. X* Return TRUE if something was printed to the line. X*/ X#define REGI register Xbool vtputd (wp, row) XWINDOW * wp; Xint row; /* line # to print to v screen */ X X{ X REGI VIDEO * vp; X REGI char *lin_ptr, X ch, X mode; X REGI A32 row_offst; X REGI uint chrs_per_row, X lin_offset, X crs, X i, X j, X k, X chrs_in_lin; X LINE * cur_line; X REGI uchar tempc; X REGI D32 temp_long; X REGI D16 temp_int; X static char w_buf[128]; /* temp buffer for data */ X REGI char *fmnt_ptr; /* pointer to format structure */ X X vp = vscreen[vtrow]; /* point to VIDEO structure to print into */ X mode = R_TYPE(wp); /* get type of format structure */ X X /* get number of bytes per row */ X chrs_per_row = R_BYTES(wp); X X /* determine the offset from begining of the buffer for this line */ X row_offst = WIND_POS(wp) + (row * chrs_per_row); X X /* search for and point to first character in buffer to be printed */ X cur_line = wp -> w_linep; /* start with current first window line */ X while (TRUE) X { /* find line with desired character */ X if (cur_line == wp -> w_bufp -> b_linep) X { /* at end of buffer? */ X return (FALSE); X } X if (cur_line -> l_file_offset > row_offst) X { X /* if less than current line */ X cur_line = cur_line -> l_bp;/* step back */ X } X else X if ((cur_line -> l_file_offset + cur_line -> l_used) <= row_offst) X { X cur_line = cur_line -> l_fp;/* step ahead */ X } X else X break; X } X X lin_offset = row_offst - cur_line -> l_file_offset;/* offset into line */ X X /* get index into the current line to start reading the current row's data */ X /* copy line text into buffer */ X chrs_in_lin = fill_buf (wp, cur_line, lin_offset, w_buf, chrs_per_row); X X /* limit line length to screen width, used in TEXT mode only */ X if (chrs_in_lin > NCOL) X chrs_in_lin = NCOL; X X /* Clear the line to spaces */ X for (i = 0; i < NCOL; i++) X { X vp -> v_text[i] = ' '; X } X switch (mode) X { X case TEXT: X break; X case ASCII: X case EBCDIC: X case BINARY: X case HEX: X /* print the row offset from the start of the file in HEX */ X sprintf (vp -> v_text, MSG_11lX, row_offst);/* to vid buf */ X break; X case OCTAL: X /* print the row offset from the start of the file */ X sprintf (vp -> v_text, MSG_11lo, row_offst);/* to vid buf */ X break; X case DECIMAL: X /* print the row offset from the start of the file */ X sprintf (vp -> v_text, MSG_11ld, row_offst);/* to vid buf */ X break; X#if RUNCHK X default: X writ_echo (ERR_disp_1); X break; X#endif X } X X /* print the binary data to the text line */ X bin_to_text (w_buf, vp -> v_text, chrs_in_lin, X wp -> w_fmt_ptr); X X vtcol = NCOL; X return (TRUE); X} X X/* X* Print the contents of then binary data buffer bin_buf X* into the proper mode of text into txt_buf. X* Process 'len' bytes. X* X* input: X* bin_buf pointer to buffer of binary data to process. X* txt_buf pointer to output buffer to print text result into. X* len length in bytes of data in bin_buf to process. X* fmt_ptr pointer to a ROW_FMT to use to format the data X* conversion and printing process. X* output: X* none. X*/ X Xvoid bin_to_text (bin_buf, txt_buf, len, fmt_ptr) X Xchar *bin_buf, X *txt_buf; Xuint len; XROW_FMT *fmt_ptr; X X{ X uchar i, X ch, X k, X j, X mode, X size, X *posn; X uint temp_int; X ulong temp_long; X X mode = fmt_ptr -> r_type; /* get type of format structure */ X size = fmt_ptr -> r_size; /* get size of format structure */ X posn = fmt_ptr -> r_positions;/* pointer to array of display positions */ X X switch (mode) X { X case TEXT: X case ASCII: X for (i = 0; i < len; i++) X { X ch = bin_buf[i]; X if ((ch >= ' ') && (ch < 0x7f)) X txt_buf[posn[0] + i] = ch; X else X txt_buf[posn[0] + i] = '.'; X } X break; X X case EBCDIC: X for (i = 0; i < len; i++) X { X txt_buf[posn[0] + i] = X 0xff & ebcdic_table[0xff & bin_buf[i]]; X } X break; X X case OCTAL: X switch (size) X { X case BYTES: /* print octal bytes */ X for (i = 0; i < len; i++) X { X sprintf (&txt_buf[ X posn[i]], MSG_03o, 0xff & bin_buf[i]); X } X break; X X case WORDS: /* print octal words */ X k = 0; X for (i = 0; i < len; X i += 2) X { X temp_int = get_int (&bin_buf[i]); X sprintf (&txt_buf[posn[k++]], MSG_06o, temp_int); X } X break; X X case DWORDS: /* print octal double words */ X k = 0; X for (i = 0; i < len; X i += 4) X { X temp_long = get_long (&bin_buf[i]); X sprintf (&txt_buf[posn[k++]], MSG_011lo, temp_long); X } X break; X } X break; X X case DECIMAL: X switch (size) X { X case BYTES: /* print decimal bytes */ X for (i = 0; i < len; i++) X { X sprintf (&txt_buf[ X posn[i]], MSG_03u, 0xff & bin_buf[i]); X } X break; X X case WORDS: /* print decimal words */ X k = 0; X for (i = 0; i < len; X i += 2) X { X temp_int = get_int (&bin_buf[i]); X sprintf (&txt_buf[ X posn[k++]], MSG_05u, temp_int); X } X break; X X case DWORDS: /* print decimal double words */ X k = 0; X for (i = 0; i < len; i += 4) X { X temp_long = get_long (&bin_buf[i]); X sprintf (&txt_buf[ X posn[k++]], MSG_010lu, temp_long); X } X break; X } X break; X X case HEX: X switch (size) X { X case BYTES: /* print hex bytes and ascii chars */ X for (i = 0; i < len; i++) X { X if ((bin_buf[i] >= ' ') && (bin_buf[i] < 0x7f)) X txt_buf[posn[i + 16]] = 0xff & bin_buf[i]; X else X txt_buf[posn[i + 16]] = '.'; X sprintf (&txt_buf[posn[i]], MSG_02X, 0xff & bin_buf[i]); X } X break; X X case WORDS: /* print hex words */ X k = 0; X for (i = 0; i < len; i += 2) X { X temp_int = get_int (&bin_buf[i]); X sprintf (&txt_buf[ X posn[k++]], MSG_04X, temp_int); X } X break; X X case DWORDS: /* print hex double words */ X k = 0; X for (i = 0; i < len; i += 4) X { X temp_long = get_long (&bin_buf[i]); X sprintf (&txt_buf[ X posn[k++]], MSG_08lX, temp_long); X } X break; X } X break; X X case BINARY: X switch (size) X { X case BYTES: /* print binary bits */ X for (i = 0; i < len; i++) X { X ch = bin_buf[i];/* get char to convert */ X for (k = 0; k < 8; k++) X { X if (ch & 0x80) X txt_buf[posn[i] + k] X = '1'; X else X txt_buf[posn[i] + k] X = '0'; X ch = ch << 1;/* slide next bit into place */ X } X } X break; X X case WORDS: X j = 0; X for (i = 0; i < len; i += 2) X { X temp_int = get_int (&bin_buf[i]); X X for (k = 0; k < 16; k++) X { X if (temp_int & 0x8000) X txt_buf[posn[j] + k] X = '1'; X else X txt_buf[posn[j] + k] X = '0'; X temp_int = temp_int << 1; X /* slide next bit into place */ X } X j++; X } X break; X X case DWORDS: X j = 0; X for (i = 0; i < len; i += 4) X { X temp_long = get_long (&bin_buf[i]); X for (k = 0; k < 32; k++) X { X if (temp_long & 0x80000000) X txt_buf[posn[j] + k] X = '1'; X else X txt_buf[posn[j] + k] X = '0'; X temp_long = temp_long << 1; X /* slide next bit into place */ X } X j++; X } X break; X } X break; X#if RUNCHK X default: X writ_echo (ERR_disp_2); X break; X#endif X } X len *= (fmt_ptr -> r_chr_per_u + 1); X /* Clean up any garbage characters left by the sprintf's */ X for (i = 0; i < NCOL; i++) X { X if (txt_buf[i] == 0) X txt_buf[i] = ' '; X } X} X X/* X* Get an int from the buffer. X* Perform the Intel byte shuffle if necessary X*/ X XD16 get_int (w_buf) Xuchar *w_buf; X X{ X int temp_int; X X if (curwp -> w_intel_mode) X { X temp_int = 0xff & w_buf[1]; X temp_int <<= 8; X temp_int |= 0xff & w_buf[0]; X } X else X { X temp_int = 0xff & w_buf[0]; X temp_int <<= 8; X temp_int |= 0xff & w_buf[1]; X } X return (temp_int); X} X X/* X* Get an long from the buffer. X* Perform the Intel byte shuffle if necessary X*/ X XD32 get_long (w_buf) Xuchar *w_buf; X X{ X long temp_long; X X if (curwp -> w_intel_mode) X { X temp_long = 0xff & w_buf[3]; X temp_long <<= 8; X temp_long |= 0xff & w_buf[2]; X temp_long <<= 8; X temp_long |= 0xff & w_buf[1]; X temp_long <<= 8; X temp_long |= 0xff & w_buf[0]; X } X else X { X temp_long = 0xff & w_buf[0]; X temp_long <<= 8; X temp_long |= 0xff & w_buf[1]; X temp_long <<= 8; X temp_long |= 0xff & w_buf[2]; X temp_long <<= 8; X temp_long |= 0xff & w_buf[3]; X } X return (temp_long); X} X X X/* X* Copy a length of bytes from the buffer LINEs into the designated X* buffer. If the current LINE does not have enough bytes then X* advance to the next. Return the actual number of bytes copied. X* The number copied would be less than the number requested if X* end of file is reached. X*/ X Xuint fill_buf (wp, lin, lin_off, w_buff, cnt) XWINDOW *wp; XLINE *lin; Xuint lin_off, X cnt; Xchar *w_buff; X{ X REGI uint src, X dest, X i; X X src = lin_off; /* initialize source line index */ X dest = 0; /* initialize destination buffer index */ X X while (TRUE) X { X while (src < lin -> l_used) X { X w_buff[dest++] = lin -> l_text[src++];/* copy byte */ X X if (dest == cnt) X { /* if done */ X return (cnt); /* then leave */ X } X } X if (R_TYPE(curwp) == TEXT) X return (dest); /* in text mode don't advance to next line */ X X lin = lin -> l_fp; /* move to the next line */ X if (lin == wp -> w_bufp -> b_linep) X { /* if past last line */ X { X for (i = dest; i < cnt; ++i) X w_buff[i] = 0;/* fill rest of buffer with zeros */ X return (dest); /* return number of chars copied */ X } X } X src = 0; /* start next LINE at first byte */ X } X} X X/* X* Erase from the end of the X* software cursor to the end of the X* line on which the software cursor is X* located. The display routines will decide X* if a hardware erase to end of line command X* should be used to display this. X*/ Xvoid vteeol () X{ X register VIDEO * vp; X X vp = vscreen[vtrow]; X while (vtcol < ncol) X vp -> v_text[vtcol++] = ' '; X} X X/* X* Make sure that the display is X* right. This is a three part process. First, X* scan through all of the windows looking for dirty X* ones. Check the framing, and refresh the screen. X* Second, make the X* virtual and physical screens the same. X*/ Xvoid update () X{ X register LINE * lp; X register WINDOW * wp; X register VIDEO * vp1; X register VIDEO * vp2; X register uint i; X register int j, X k; X register int c; X register int hflag; X register int offs; X register int size; X X hflag = FALSE; /* Not hard. */ X wp = wheadp; X while (wp != NULL) X { X /* is this window to be displayed in linked mode */ X if ((curbp -> b_flag & BFLINK) && X (wp -> w_bufp == curbp)) X { /* move dot to current window's dot position */ X wp -> w_dotp = curwp -> w_dotp; X wp -> w_doto = curwp -> w_doto; X move_ptr (wp, 0L, TRUE, TRUE, TRUE); /* insure dot is aligned */ X wind_on_dot (wp); /* move window to new dot position */ X } X X if (wp -> w_flag != 0) X X { /* Need update. */ X move_ptr (wp, 0L, FALSE, TRUE, TRUE); /* window on row boundary */ X move_ptr (wp, 0L, TRUE, TRUE, TRUE); /* dot on unit boundary */ X if ((wp -> w_flag & WFFORCE) == 0) X { X wind_on_dot (wp);/* position window on dot */ X } X i = get_currow (wp); /* Redo this one line, mabey. */ X if ((wp -> w_flag & ~WFMODE) == WFEDIT) X { X vscreen[i] -> v_color = CTEXT; X vscreen[i] -> v_flag |= (VFCHG | VFHBAD); X vtmove (i, 0); X vtputd (wp, i - wp -> w_toprow);/* print line to the screen */ X } X else X if ((wp -> w_flag & ~WFMODE) == WFMOVE) X { X while (i < wp -> w_toprow + wp -> w_ntrows) X { X /* paint entire window */ X vscreen[i] -> v_color = CTEXT; X vscreen[i] -> v_flag |= (VFCHG | VFHBAD); X vtmove (i, 0); X /* print line to the screen */ X if (!vtputd (wp, i - wp -> w_toprow)) X vteeol (); X ++i; X } X } X else X if ((wp -> w_flag & (WFEDIT | WFHARD)) != 0) X { X hflag = TRUE; X i = wp -> w_toprow; X while (i < wp -> w_toprow + wp -> w_ntrows) X { X /* paint entire window */ X vscreen[i] -> v_color = CTEXT; X vscreen[i] -> v_flag |= (VFCHG | VFHBAD); X vtmove (i, 0); X /* print line to the screen */ X if (!vtputd (wp, i - wp -> w_toprow)) X vteeol (); X ++i; X } X } X if ((wp -> w_flag & WFMODE) || X (wp -> w_flag & WFMOVE) || X (wp -> w_flag & WFHARD)) X modeline (wp); X wp -> w_flag = 0; X } X wp = wp -> w_wndp; X } X if (sgarbf != FALSE) X { /* Screen is garbage. */ X sgarbf = FALSE; /* Erase-page clears */ X epresf = FALSE; /* the message area. */ X tttop = HUGE; /* Forget where you set */ X ttbot = HUGE; /* scroll region. */ X tthue = CNONE; /* Color unknown. */ X ttmove (0, 0); X tteeop (); X#if MSDOS X if (mem_map) X { X for (i = 0; i < nrow; ++i) X { X mem_line (i, vscreen[i]); X } X } X else X { X#endif X for (i = 0; i < nrow; ++i) X { X uline (i, vscreen[i], &blanks); X ucopy (vscreen[i], pscreen[i]); X } X#if MSDOS X } X#endif X ttmove (get_currow (curwp), get_curcol (curwp)); X ttflush (); X return; X } X#if GOSLING X if (hflag != FALSE) X { /* Hard update? */ X for (i = 0; i < nrow; ++i) X { /* Compute hash data. */ X hash (vscreen[i]); X hash (pscreen[i]); X } X offs = 0; /* Get top match. */ X while (offs != nrow) X { X vp1 = vscreen[offs]; X vp2 = pscreen[offs]; X if (vp1 -> v_color != vp2 -> v_color X || vp1 -> v_hash != vp2 -> v_hash) X break; X#if MSDOS X if (mem_map) X mem_line (offs, vp1); X else X#endif X { X uline (offs, vp1, vp2); X ucopy (vp1, vp2); X } X ++offs; X } X if (offs == nrow - 1) X { /* Might get it all. */ X ttmove (get_currow (curwp), get_curcol (curwp)); X ttflush (); X return; X } X size = nrow; /* Get bottom match. */ X while (size != offs) X { X vp1 = vscreen[size - 1]; X vp2 = pscreen[size - 1]; X if (vp1 -> v_color != vp2 -> v_color X || vp1 -> v_hash != vp2 -> v_hash) X break; X#if MSDOS X if (mem_map) X mem_line (size - 1, vp1); X else X#endif X { X uline (size - 1, vp1, vp2); X ucopy (vp1, vp2); X } X --size; X } X if ((size -= offs) == 0)/* Get screen size. */ X abort (); X setscores (offs, size); /* Do hard update. */ X traceback (offs, size, size, size); X for (i = 0; i < size; ++i) X ucopy (vscreen[offs + i], pscreen[offs + i]); X ttmove (get_currow (curwp), get_curcol (curwp)); X ttflush (); X return; X } X#endif X for (i = 0; i < nrow; ++i) X { /* Easy update. */ X vp1 = vscreen[i]; X vp2 = pscreen[i]; X if ((vp1 -> v_flag & VFCHG) != 0) X { X#if MSDOS X if (mem_map) X mem_line (i, vp1); X else X#endif X { X uline (i, vp1, vp2); X ucopy (vp1, vp2); X } X } X } X ttmove (get_currow (curwp), get_curcol (curwp)); X ttflush (); X} X/* X* Get the window relative row in which the cursor will X* appear. pvr X*/ Xuint get_currow (wp) X WINDOW * wp; X{ X A32 row; X /* number of bytes from start of window */ X row = DOT_POS(wp) - WIND_POS(wp); X /* number of rows down in window */ X row /= R_BYTES(wp); X row += wp -> w_toprow; X#if RUNCHK X if (row < wp -> w_toprow) X printf (ERR_disp_3); X if (row > (wp -> w_ntrows + wp -> w_toprow)) X printf (ERR_disp_4); X#endif X return (row & 0xffff); X} X X/* X* Get the window relative column in which the cursor will X* appear. pvr X*/ Xuint get_curcol (wp) X WINDOW * wp; X{ X long offset, X index; X uint b_per_u, pos; X X b_per_u = R_B_PER_U(wp); X /* dot offset from start of buffer */ X offset = DOT_POS(wp); X offset -= wp -> w_disp_shift; X offset &= ~(b_per_u - 1); X /* calculate mod of the current file position */ X index = offset & (R_BYTES(wp) - 1); X index /= b_per_u; X /* limit to window width */ X if (index >= NCOL) X index = NCOL; X pos = wp -> w_fmt_ptr -> r_positions[index] + wp -> w_unit_offset; X return (pos); X} X#if MSDOS Xvoid mem_line (row, vvp) Xint row; XVIDEO * vvp; X { X vvp -> v_flag &= ~VFCHG; /* Changes done. */ X ttcolor (vvp -> v_color); X putline (row + 1, 1, ncol, &vvp -> v_text[0]); X } X#endif X/* X* Update a saved copy of a line, X* kept in a VIDEO structure. The "vvp" is X* the one in the "vscreen". The "pvp" is the one X* in the "pscreen". This is called to make the X* virtual and physical screens the same when X* display has done an update. X*/ Xvoid ucopy (vvp, pvp) Xregister VIDEO * vvp; Xregister VIDEO * pvp; X{ X register int i; X X vvp -> v_flag &= ~VFCHG; /* Changes done. */ X pvp -> v_flag = vvp -> v_flag;/* Update model. */ X pvp -> v_hash = vvp -> v_hash; X pvp -> v_cost = vvp -> v_cost; X pvp -> v_color = vvp -> v_color; X for (i = 0; i < ncol; ++i) X pvp -> v_text[i] = vvp -> v_text[i]; X} X X/* X* Update a single line. This routine only X* uses basic functionality (no insert and delete character, X* but erase to end of line). The "vvp" points at the VIDEO X* structure for the line on the virtual screen, and the "pvp" X* is the same for the physical screen. Avoid erase to end of X* line when updating CMODE color lines, because of the way that X* reverse video works on most terminals. X*/ Xvoid uline (row, vvp, pvp) XVIDEO * vvp; XVIDEO * pvp; 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; X X if (vvp -> v_color != pvp -> v_color) X { /* Wrong color, do a */ X ttmove (row, 0); /* full redraw. */ X ttcolor (vvp -> v_color); X cp1 = &vvp -> v_text[0]; X cp2 = &vvp -> v_text[ncol]; X while (cp1 != cp2) X { X ttputc (*cp1++); X ++ttcol; X } X return; X } X cp1 = &vvp -> v_text[0]; /* Compute left match. */ X cp2 = &pvp -> v_text[0]; X while (cp1 != &vvp -> v_text[ncol] && cp1[0] == cp2[0]) X { X ++cp1; X ++cp2; X } X if (cp1 == &vvp -> v_text[ncol])/* All equal. */ X return; X nbflag = FALSE; X cp3 = &vvp -> v_text[ncol]; /* Compute right match. */ X cp4 = &pvp -> v_text[ncol]; X while (cp3[-1] == cp4[-1]) X { X --cp3; X --cp4; X if (cp3[0] != ' ') /* Note non-blanks in */ X nbflag = TRUE; /* the right match. */ X } X cp5 = cp3; /* Is erase good? */ X if (nbflag == FALSE && vvp -> v_color == CTEXT) X { X while (cp5 != cp1 && cp5[-1] == ' ') X --cp5; X /* Alcyon hack */ X if ((int) (cp3 - cp5) <= tceeol) X cp5 = cp3; X } X /* Alcyon hack */ X ttmove (row, (int) (cp1 - &vvp -> v_text[0])); X ttcolor (vvp -> v_color); X while (cp1 != cp5) X { X ttputc (*cp1++); X ++ttcol; X } X if (cp5 != cp3) /* Do erase. */ X tteeol (); X} X X/* X* Redisplay the mode line for X* the window pointed to by the "wp". X* This is the only routine that has any idea X* of how the modeline is formatted. You can X* change the modeline format by hacking at X* this routine. Called by "update" any time X* there is a dirty window. X*/ X Xvoid modeline (wp) Xregister WINDOW * wp; X{ X register char *cp, X mode, X size, X u_posn, X *s; X register int c; X register int n; X register BUFFER * bp; X register A32 posn; X X static char posn_buf[30] = X {0 X }; /* krw */ X X mode = wp -> w_fmt_ptr -> r_type;/* get type of format structure */ X size = wp -> w_fmt_ptr -> r_size;/* get size of format structure */ X X n = wp -> w_toprow + wp -> w_ntrows;/* Location. */ X vscreen[n] -> v_color = CMODE;/* Mode line color. */ X vscreen[n] -> v_flag |= (VFCHG | VFHBAD);/* Recompute, display. */ X vtmove (n, 0); /* Seek to right line. */ X bp = wp -> w_bufp; X X cp = MSG_prog_name; /* Program name. pvr */ X n = 5; X while ((c = *cp++) != 0) X { X vtputc (c); X ++n; X } X X if ((bp -> b_flag & BFBAD) != 0)/* "?" if trashed. */ X vtputc ('?'); X else X vtputc (' '); X X if ((bp -> b_flag & BFCHG) != 0)/* "*" if changed. */ X vtputc ('*'); X else X vtputc (' '); X X if (insert_mode) /* "I" if insert mode */ X vtputc ('I'); X else X vtputc ('O'); X X if (bp == blistp) X { /* special list */ X cp = MSG_disp_b_lst; X while ((c = *cp++) != 0) X { X vtputc (c); X ++n; X } X goto pad; X } X X/* Buffer name */ X vtputc (' '); X ++n; X cp = &bp -> b_bname[0]; X while ((c = *cp++) != 0) X { X vtputc (c); X ++n; X } X while ((int) (cp - &bp -> b_bname[0]) < NBUFN) X { X vtputc (' '); X n++; X cp++; X } X X /* File name. */ X vtputc (' '); X ++n; X cp = MSG_file; X while ((c = *cp++) != 0) X { X vtputc (c); X ++n; X } X cp = &bp -> b_fname[0]; X while ((c = *cp++) != 0) X { X vtputc (c); X ++n; X } X cp--; X while ((int) (cp - &bp -> b_fname[0]) < NFILE) X { X vtputc (' '); X n++; X cp++; X } X X if (bp -> b_flag & BFVIEW) X s = MSG_RO; X else if (bp -> b_flag & BFSLOCK) X s = MSG_WL; X else X s = MSG_RW; X X while (*s) X { /* krw */ X vtputc (*s++); X ++n; X } X X if (auto_update && !(bp -> b_flag & BFVIEW) && bp -> b_bname[0])/* jam */ X s = MSG_AU; X else X s = MSG_NOT_AU; X for (; *s && n < NCOL;) X { X vtputc (*s++); X ++n; X } X X /* Insert current dot position into mode line. */ X posn = DOT_POS(wp); X u_posn = R_CHR_PER_U(wp) - wp -> w_unit_offset - 1; X if (u_posn < 0) X u_posn = 0; X switch (mode) X { X case TEXT: X case ASCII: X sprintf (posn_buf, MSG_curs_asc, posn); X break; X case EBCDIC: X sprintf (posn_buf, MSG_curs_ebc, posn); X break; X case HEX: X sprintf (posn_buf, MSG_curs_hex, posn, u_posn); X break; X case BINARY: X sprintf (posn_buf, MSG_curs_bin, posn, u_posn); X break; X case DECIMAL: X sprintf (posn_buf, MSG_curs_dec, posn, u_posn); X break; X case OCTAL: X sprintf (posn_buf, MSG_curs_oct, posn, u_posn); X break; X#if RUNCHK X default: X writ_echo (ERR_disp_5); X break; X#endif X } X X cp = posn_buf; X while ((c = *cp++) != 0) X { X vtputc (c); X ++n; X } X X X if ((mode == HEX) || X (mode == DECIMAL) || X (mode == OCTAL)) X { X switch (size) X { X case BYTES: X sprintf (posn_buf, MSG_siz_8); X break; X case WORDS: X sprintf (posn_buf, MSG_siz_16); X break; X case DWORDS: X sprintf (posn_buf, MSG_siz_32); X break; X#if RUNCHK X default: X writ_echo (ERR_disp_6); X break; X#endif X } X } X else X sprintf (posn_buf, MSG_siz_null); X X cp = posn_buf; X while ((c = *cp++) != 0) X { X vtputc (c); X ++n; X } X X if (wp -> w_intel_mode) X sprintf (posn_buf, MSG_int_shift, wp -> w_disp_shift); X else X sprintf (posn_buf, MSG_mot_shift, wp -> w_disp_shift); X cp = posn_buf; X while ((c = *cp++) != 0) X { X vtputc (c); X ++n; X } X X X /* pad out */ Xpad: X while (n < ncol) X { X vtputc (' '); X ++n; X } X} X X/* X* write text to the echo line X*/ Xvoid writ_echo (buf) Xchar *buf; X { X int i, len; X char *vpp; X bool fill_spac; X X fill_spac = FALSE; X vpp = vscreen[nrow - 1] -> v_text; X vscreen[nrow - 1] -> v_color = CTEXT; X vscreen[nrow - 1] -> v_flag |= VFCHG; X epresf = TRUE; X X for (i = 0; i < NCOL; i++) X { X if (buf[i] == 0) X fill_spac = TRUE; X if (fill_spac) X vpp[i] = ' '; X else X vpp[i] = buf[i]; X } X#if MSDOS X if (mem_map) X { X mem_line (nrow - 1, vscreen[nrow - 1]); X } X else X#endif X { X uline (nrow - 1, vscreen[nrow - 1], pscreen[nrow - 1]); X/* uline (nrow - 1, vscreen[nrow - 1], &blanks); */ X ucopy (vscreen[nrow - 1], pscreen[nrow - 1]); X ttflush (); X } X } X X#if GOSLING X/* X* Compute the hash code for X* the line pointed to by the "vp". Recompute X* it if necessary. Also set the approximate redisplay X* cost. The validity of the hash code is marked by X* a flag bit. The cost understand the advantages X* of erase to end of line. Tuned for the VAX X* by Bob McNamara; better than it used to be on X* just about any machine. X*/ Xvoid hash (vp) Xregister VIDEO * vp; X{ X register int i; X register int n; X register char *s; X X if ((vp -> v_flag & VFHBAD) != 0) X { /* Hash bad. */ X s = &vp -> v_text[ncol - 1]; X for (i = ncol; i != 0; --i, --s) X if (*s != ' ') X break; X n = ncol - i; /* Erase cheaper? */ X if (n > tceeol) X n = tceeol; X vp -> v_cost = i + n; /* Bytes + blanks. */ X for (n = 0; i != 0; --i, --s) X n = (n << 5) + n + *s; X vp -> v_hash = n; /* Hash code. */ X vp -> v_flag &= ~VFHBAD;/* Flag as all done. */ X } X} X X/* X* Compute the Insert-Delete X* cost matrix. The dynamic programming algorithm X* described by James Gosling is used. This code assumes X* that the line above the echo line is the last line involved X* in the scroll region. This is easy to arrange on the VT100 X* because of the scrolling region. The "offs" is the origin 0 X* offset of the first row in the virtual/physical screen that X* is being updated; the "size" is the length of the chunk of X* screen being updated. For a full screen update, use offs=0 X* and size=nrow-1. X* X* Older versions of this code implemented the score matrix by X* a two dimensional array of SCORE nodes. This put all kinds of X* multiply instructions in the code! This version is written to X* use a linear array and pointers, and contains no multiplication X* at all. The code has been carefully looked at on the VAX, with X* only marginal checking on other machines for efficiency. In X* fact, this has been tuned twice! Bob McNamara tuned it even X* more for the VAX, which is a big issue for him because of X* the 66 line X displays. X* X* On some machines, replacing the "for (i=1; i<=size; ++i)" with X* i = 1; do X { }while (++i <=size)" will make the code quite a X* bit better; but it looks ugly. X*/ Xvoid setscores (offs, size) X{ X register SCORE * sp; X register int tempcost; X register int bestcost; X register int j; X register int i; X register VIDEO ** vp; X register VIDEO ** pp; X register SCORE * sp1; X register VIDEO ** vbase; X register VIDEO ** pbase; X X vbase = &vscreen[offs - 1]; /* By hand CSE's. */ X pbase = &pscreen[offs - 1]; X score[0].s_itrace = 0; /* [0, 0] */ X score[0].s_jtrace = 0; X score[0].s_cost = 0; X sp = &score[1]; /* Row 0, inserts. */ X tempcost = 0; X vp = &vbase[1]; X for (j = 1; j <= size; ++j) X { X sp -> s_itrace = 0; X sp -> s_jtrace = j - 1; X tempcost += tcinsl; X tempcost += (*vp) -> v_cost; X sp -> s_cost = tempcost; X ++vp; X ++sp; X } X sp = &score[NROW]; /* Column 0, deletes. */ X tempcost = 0; X for (i = 1; i <= size; ++i) X { X sp -> s_itrace = i - 1; X sp -> s_jtrace = 0; X tempcost += tcdell; X sp -> s_cost = tempcost; X sp += NROW; X } X sp1 = &score[NROW + 1]; /* [1, 1]. */ X pp = &pbase[1]; X for (i = 1; i <= size; ++i) X { X sp = sp1; X vp = &vbase[1]; X for (j = 1; j <= size; ++j) X { X sp -> s_itrace = i - 1; X sp -> s_jtrace = j; X bestcost = (sp - NROW) -> s_cost; X if (j != size) /* Cd(A[i])=0 @ Dis. */ X bestcost += tcdell; X tempcost = (sp - 1) -> s_cost; X tempcost += (*vp) -> v_cost; X if (i != size) /* Ci(B[j])=0 @ Dsj. */ X tempcost += tcinsl; X if (tempcost < bestcost) X { X sp -> s_itrace = i; X sp -> s_jtrace = j - 1; X bestcost = tempcost; X } X tempcost = (sp - NROW - 1) -> s_cost; X if ((*pp) -> v_color != (*vp) -> v_color X || (*pp) -> v_hash != (*vp) -> v_hash) X tempcost += (*vp) -> v_cost; X if (tempcost < bestcost) X { X sp -> s_itrace = i - 1; X sp -> s_jtrace = j - 1; X bestcost = tempcost; X } X sp -> s_cost = bestcost; X ++sp; /* Next column. */ X ++vp; X } X ++pp; X sp1 += NROW; /* Next row. */ X } X} X X/* X* Trace back through the dynamic programming cost X* matrix, and update the screen using an optimal sequence X* of redraws, insert lines, and delete lines. The "offs" is X* the origin 0 offset of the chunk of the screen we are about to X* update. The "i" and "j" are always started in the lower right X* corner of the matrix, and imply the size of the screen. X* A full screen traceback is called with offs=0 and i=j=nrow-1. X* There is some do-it-yourself double subscripting here, X* which is acceptable because this routine is much less compute X* intensive then the code that builds the score matrix! X*/ Xvoid traceback (offs, size, i, j) X{ X register int itrace; X register int jtrace; X register int k; X register int ninsl; X register int ndraw; X register int ndell; X X if (i == 0 && j == 0) /* End of update. */ X return; X itrace = score[(NROW * i) + j].s_itrace; X jtrace = score[(NROW * i) + j].s_jtrace; X if (itrace == i) X { /* [i, j-1] */ X ninsl = 0; /* Collect inserts. */ X if (i != size) X ninsl = 1; X ndraw = 1; X while (itrace != 0 || jtrace != 0) X { X if (score[(NROW * itrace) + jtrace].s_itrace != itrace) X break; X jtrace = score[(NROW * itrace) + jtrace].s_jtrace; X if (i != size) X ++ninsl; X ++ndraw; X } X traceback (offs, size, itrace, jtrace); X if (ninsl != 0) X { X ttcolor (CTEXT); X ttinsl (offs + j - ninsl, offs + size - 1, ninsl); X } X do X { /* B[j], A[j] blank. */ X k = offs + j - ndraw; X uline (k, vscreen[k], &blanks); X } while (--ndraw); X return; X } X if (jtrace == j) X { /* [i-1, j] */ X ndell = 0; /* Collect deletes. */ X if (j != size) X ndell = 1; X while (itrace != 0 || jtrace != 0) X { X if (score[(NROW * itrace) + jtrace].s_jtrace != jtrace) X break; X itrace = score[(NROW * itrace) + jtrace].s_itrace; X if (j != size) X ++ndell; X } X if (ndell != 0) X { X ttcolor (CTEXT); X ttdell (offs + i - ndell, offs + size - 1, ndell); X } X traceback (offs, size, itrace, jtrace); X return; X } X traceback (offs, size, itrace, jtrace); X k = offs + j - 1; X uline (k, vscreen[k], pscreen[offs + i - 1]); X} X#endif X X/* X* Print the current buffer from mark to dot using the X* current window's display format. X* Prompt for file name or io device to print to. X*/ X Xbool print () X { X LINE *dot_l_sav, *mark_l_sav, *wind_l_sav; X int dot_off_sav, mark_off_sav, wind_off_sav, i; X char s; X char fname[NFILEN]; X register int nline; X char buf[80], buf1[60]; X X /* save the original window state */ X dot_l_sav = curwp -> w_dotp; X dot_off_sav = curwp -> w_doto; X mark_l_sav = curwp -> w_markp; X mark_off_sav = curwp -> w_marko; X wind_l_sav = curwp -> w_linep; X wind_off_sav = curwp -> w_loff; X X /* if mark is not set then set it to location zero */ X if (curwp -> w_markp == NULL) X { X curwp -> w_markp = curwp -> w_bufp -> b_linep -> l_fp; X curwp -> w_marko = 0; X } X X nline = 0; X if ((s = ereply (MSG_prn_to, fname, NFILEN, NULL)) == ABORT) X return (s); X adjustcase (fname); X if ((s = ffwopen (fname)) != FIOSUC)/* Open writes message. */ X return (FALSE); X X sprintf (buf, MSG_print1, fname); X writ_echo (buf); X /* make dot before mark */ X if (DOT_POS(curwp) > MARK_POS(curwp)) X swapmark (); /* make mark first */ X X while (DOT_POS(curwp) <= MARK_POS(curwp)) X { X /* check if we should quit */ X if (ttkeyready ()) X { X ttgetc (); /* through away char that was struck */ X break; X } X nline++; X /* move window so that first line is on dot */ X move_ptr (curwp, DOT_POS(curwp), FALSE, TRUE, FALSE); X X if (vtputd (curwp, 0)) /* print line into video buffer */ X { X for (i = NCOL; (vscreen[vtrow] -> v_text[i] < '!') || X (vscreen[vtrow] -> v_text[i] > '~'); i--) X ; X i++; X if ((s = ffputline (vscreen[vtrow] -> v_text, i)) != FIOSUC) X break; X if ((s = ffputline (MSG_disp_r_n, 2)) != FIOSUC) X break; X } X else X break; X forwline (0, 1, KRANDOM); /* advance to next line */ X } X ffclose (); X sprintf (buf1, MSG_print2, R_POS_FMT(curwp)); X sprintf (buf, buf1, (long) nline); X writ_echo (buf); X X /* restore the original window state */ X curwp -> w_dotp = dot_l_sav; X curwp -> w_doto = dot_off_sav; X curwp -> w_markp = mark_l_sav; X curwp -> w_marko = mark_off_sav; X curwp -> w_linep = wind_l_sav; X curwp -> w_loff = wind_off_sav; X curwp -> w_flag |= WFHARD; /* insure that window is still presentable */ X return (TRUE); X } END_OF_FILE if test 49127 -ne `wc -c <'display.c'`; then echo shar: \"'display.c'\" unpacked with wrong size! fi chmod +x 'display.c' # end of 'display.c' fi echo shar: End of archive 11 \(of 11\). cp /dev/null ark11isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 11 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0