|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T t
Length: 33018 (0x80fa) Types: TextFile Names: »te_window.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/euug-87hel/sec1/teco/te_window.c«
/* TECO for Ultrix Copyright 1986 Matt Fichtenbaum */ /* This program and its components belong to GenRad Inc, Concord MA 01742 */ /* They may be copied if this copyright notice is included */ /* te_window.c window for teco 10/10/86 */ /* This attempts to be a real window, without unecessary redraw */ /* it is very VT-100 specific, and ought to be rewritten to be general */ #include "te_defs.h" /* maximum screen height and width (horiz and vert, not height and vidth) */ #define W_MAX_V 70 #define W_MAX_H 150 #define MAX 0x7fffffff /* maximum positive integer, for "last modified" location */ #define W_MARK 0200 /* "this loc is special" in screen image */ /* image of current window */ struct w_line /* data associated with one screen line */ { int start, end; /* dot at beginning, at end */ short n, cflag, col; /* number of char positions used, line continuation flag, starting col */ char ch[W_MAX_H]; /* image of line */ } w_image[W_MAX_V]; /* define "this line is continued" / "this line is a continuation" flags */ #define WF_BEG 1 #define WF_CONT 2 struct w_line *wlp[W_MAX_V]; /* each word points to the corresponding line's data structure */ struct qp w_p1; /* pointer for window access to buffer */ short curr_x, curr_y; /* active character position */ short term_x, term_y; /* current terminal cursor position */ short curs_x, curs_y; /* current teco dot screen coordinates */ short last_y; /* last used line in window */ char curs_c; /* code for char at cursor */ char *curs_p; /* pointer to cursor loc in window image */ short curs_crflag; /* flag that cursor is on a CR */ short redraw_sw; /* forces absolute redraw */ /* fill characters and terminal speeds: 0th entry used when std out is not a terminal */ char win_speeds[] = { 0, 0, B9600, B4800, B2400, B1800, B1200, B600, B300, B200, B150, B134, B110 }; char win_dlye[] = { 0, 90, 45, 23, 11, 9, 6, 3, 1, 1, 1, 1, 1 }; /* delay for erase-screen */ char win_dlys[] = { 0, 60, 30, 15, 7, 6, 4, 2, 1, 1, 0, 0, 0 }; /* delay for scroll ops */ char win_dlyl[] = { 0, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* delay for erase line */ char win_dlyc[] = { 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* delay for other control functions */ short win_speed; \f /* routine to perform simple scope operations */ /* (an attempt to concentrate VT-100 specific things in one place) */ vt(func) int func; { short t; switch (func) { case VT_CLEAR: /* clear screen */ fputs("\033[H\033[J", stdout); for (t = 0; t < win_dlye[win_speed]; t++) putchar('\0'); /* fill chars */ break; case VT_EEOL: /* erase to end of line */ fputs("\033[K", stdout); for (t = 0; t < win_dlyl[win_speed]; t++) putchar('\0'); /* fill chars */ break; case VT_EBOL: /* erase from beginning of line */ fputs("\033[1K", stdout); for (t = 0; t < win_dlyl[win_speed]; t++) putchar('\0'); /* fill chars */ break; case VT_SETSPEC1: /* reverse video */ fputs("\033[7m", stdout); break; case VT_SETSPEC2: /* bright reverse video */ fputs("\033[1;7m", stdout); break; case VT_CLRSPEC: /* normal video */ fputs("\033[0m", stdout); break; case VT_BS1: /* backspace 1 spot */ fputs("\b \b", stdout); break; case VT_BS2: /* backspace 2 spots */ fputs("\b \b\b \b", stdout); break; case VT_LINEUP: /* up one line */ fputs("\033[1A", stdout); break; } } \f /* routine to set window parameters */ /* 0: scope type, 1: width, 2: height, 3: seeall, 4: mark position, */ /* 5: hold mode, 6: upper left corner position, 7: scroll region size */ /* 0 1 2 3 4 5 6 7 */ int win_min[] = { 4, 20, 4, 0, 0, -1, 1, 0 } ; /* min values for window parameters */ int win_max[] = { 4, W_MAX_H, W_MAX_V, 1, MAX, 12, -1, 20 } ; /* max values */ int win_data[] = { 4, 132, 24, 0, 0, 0, 0, 0 } ; /* window parameters */ int window_size; /* # of lines in a window */ do_window(ref_flag) int ref_flag; /* nonzero forces "refresh" operation */ { int i; if (colonflag && !ref_flag) { i = get_value(0); /* get sub-function */ if ((i < 0) || (i > 7)) ERROR(E_IWA); if (!esp->flag2) /* it's a "get" */ { esp->val1 = win_data[i]; esp->flag1 = 1; } else { if ((esp->val2 < win_min[i]) || (esp->val2 > win_max[i])) /* check range */ ERROR(E_IWA); if (i == 7) { if (esp->val2) { WN_scroll = esp->val2; window_size = WN_height - WN_scroll; /* define size of window area */ window(WIN_INIT); /* turn on window */ } else window(WIN_OFF); /* turn off window */ } win_data[i] = esp->val2; /* redundant for ~0,7:w, but no harm */ esp->flag2 = 0; window(WIN_REDRAW); /* redraw window */ } } else /* no colon, or ^W command */ { if (esp->flag1 || ref_flag) { if (!ref_flag && (esp->val1 == -1000)) redraw_sw = 0; /* -1000W: "forget that output was done" */ else window(WIN_DISP); /* nW or ^W refreshes window */ } esp->flag2 = esp->flag1 = 0; /* no colon, consume args */ } colonflag = 0; esp->op = OP_START; } \f /* routine to update screen size with numbers obtained from environment */ /* (called by main program's initialization) */ set_term_par(lines, cols) int lines, cols; { if ((lines >= win_min[2]) && (lines <= win_max[2])) window_size = win_data[2] = lines; if ((cols >= win_min[1]) && (cols <= win_max[1])) win_data[1] = cols; } /* window routine. performs function as indicated by argument */ /* WIN_OFF: disables split-screen scrolling */ /* WIN_SUSP: disables split-screen scrolling temporarily */ /* WIN_INIT: sets up display support if split-screen scrolling enabled, else nop */ /* WIN_RESUME: re-enables display support */ /* WIN_REDRAW: causes window to be redrawn on next refresh call */ /* WIN_REFR: if scrolling enabled, redoes window, else if ev or es enabled, does */ /* that, else nop */ /* WIN_LINE: does WIN_REFR unless that wouldn't do anything, in which case */ /* it does effective 1EV output */ int last_dot = -1; /* last dot location */ window(arg) int arg; { int i; switch (arg) { case WIN_OFF: /* final window off */ case WIN_SUSP: /* temp window off */ if (WN_scroll) /* if reset/clean up */ { /* full margins, cursor to last line, erase line */ printf("\033[r\033[%d;0H\033[K", WN_height); } break; case WIN_INIT: /* initialize window - find output speed */ if (out_noterm) win_speed = 0; /* std out is not a terminal */ else { for (win_speed = 1; (win_speeds[win_speed] != ttybuf.sg_ospeed) && (win_speed < 13); win_speed++); if (win_speed == 13) win_speed = 1; } w_init(); /* set up screen image buffer */ if (WN_scroll) vt(VT_CLEAR); /* if split-screen is enabled, clear screen */ /* (fall through to "resume") */ case WIN_RESUME: /* re-enable window */ if (WN_scroll) /* set scroll region, cursor to bottom */ printf("\033[%d;%dr\033[%d;0H", WN_height - WN_scroll + 1, WN_height, WN_height); break; \f case WIN_REDRAW: /* force redraw of window */ redraw_sw = 1; break; case WIN_LINE: /* display one line unless window enabled or ev */ if (WN_scroll || ev_val) window(WIN_REFR); /* if a real window is set, do it */ else if (w_setptr(dot, &w_p1)) /* set pointer to dot... and if there's a buffer */ { w_lines(0, &w_p1, &w_p1); /* get to beginning of line */ window0(1); /* and type 1 line */ } break; case WIN_REFR: /* if enabled, refresh window; else do ev or es */ if (WN_scroll) window1(); /* if scrolling enabled, refresh the window */ else if ((ev_val) || (es_val && search_flag)) /* else if ev or es, do that */ { i = (ev_val) ? ev_val : es_val; if (w_setptr(dot, &w_p1)) /* set a pointer at dot... and if there's a buffer */ window0(i - w_lines(1 - i, &w_p1, &w_p1)); /* go back (i-1) lines and ahead (i) lines */ } break; case WIN_DISP: /* display buffer independent of whether scroll mode is enabled */ window1(); break; } /* end of switch */ fflush(stdout); /* send output out */ } /* end of window() */ \f /* routine to type n lines with character at "dot" in reverse video */ /* used for ev, es, and <BS> or <LF> as immediate commands */ /* starting char position is in w_p1; argument is number of lines */ window0(num) int num; { int wi; char wc; /* temp char */ for (wi = w_p1.dot; (num > 0) && (wi < z); wi++) /* for each character */ { wc = w_p1.p->ch[w_p1.c]; /* get character */ if ((char_count >= WN_width) && (wc != CR) && !(spec_chars[wc] & A_L)) /* if about to exceed width */ { if (et_val & ET_TRUNC) goto w0_noprint; /* truncate: don't print this */ else { fputs("\033[K\015\012\033(0h\033(B ", stdout); /* <eeol> "NL space" */ char_count = 2; --num; /* one fewer line remaining */ } } if (wi == dot) /* if this char is at the pointer */ { vt(VT_SETSPEC2); /* set reverse video */ if (wc == TAB) { type_char(' '); /* illuminate the first sp of a tab */ vt(VT_CLRSPEC); /* clear reverse video */ if (char_count & tabmask) type_char(TAB); } else /* not a tab */ { if ((wc == CR) && (char_count < WN_width)) /* CR at rh margin: don't display cursor */ { type_char(' '); /* cr: put a space after line */ vt(VT_EEOL); /* erase to eol */ } type_char(wc); /* type the char, or exec CR */ if (wc == LF) { fputs("\033(0", stdout); type_char('e'); fputs("\033(B", stdout); } vt(VT_CLRSPEC); /* clear reverse video */ } } \f else /* this is not char at pointer */ { if (wc == CR && curr_x < WN_width) vt(VT_EEOL); /* erase to EOL */ type_char(wc); } if ((wc == FF) || (wc == VT)) /* FF & VT end a line */ { vt(VT_EEOL); /* erase rest of this line */ crlf(); /* and leave a blank one */ if (!(ez_val & EZ_NOVTFF)) --num; /* if FF and VT count as line sep's, count them */ } w0_noprint: if (++w_p1.c > CELLSIZE-1) w_p1.p = w_p1.p->f, w_p1.c = 0; /* next char */ if (wc == LF) --num; /* if this is a line feed, count lines */ } if (dot == z) fputs("\033[1;7m \033[0m\033[0K", stdout); /* type one space and erase rest of line */ else fputs("\033[0K", stdout); /* else just erase to EOL */ } \f /* routine to maintain the screen window */ /* if scroll mode is enabled, the VT100 screen is split and only the upper part */ /* is used by this routine; else the whole screen is used. */ window1() { int i, j, m, lflag; if (!redraw_sw && (dot == last_dot) && (buff_mod == MAX)) return; /* return if nothing has changed */ block_inter(1); /* disable ^C interrupts */ if (WN_scroll) printf("\033[1;%dr", window_size); /* scroll mode: redefine scroll region */ printf("\033[H"); /* home */ term_y = term_x = 0; /* indicate cursor is at home */ if ((redraw_sw) || (z <= wlp[0]->start)) window1_abs(); /* forced redraw, or z before start of screen */ /* check whether pointer is before modified buffer location */ else if (buff_mod >= dot) /* yes */ { if (dot < wlp[0]->start) /* if dot is before screen */ { w_setptr(wlp[0]->start, &w_p1); /* get to beginning of screen */ /* check whether screen begins with the last part of a continued line */ for (j = 0; (wlp[j]->cflag & WF_CONT) && (j < window_size/2); j++); if (j < window_size/2) /* if so, does it continue less than halfway down the screen? */ { if (j) /* is there a partial line? */ { w_lines(0, &w_p1, &w_p1); /* 0L */ j -= w_lines(1, &w_p1, NULL); /* now j is number of display lines before screen */ } \f /* now look for how many lines back "dot" is: if screen starts with partial line, w_p1 has already been moved */ /* to beginning of the line and j equals the count of extra lines to scroll */ for (i = 0; (dot < w_p1.dot) && (i < window_size/2); ) i -= w_lines(-1, &w_p1, &w_p1); if ((dot >= w_p1.dot) && (i < window_size)) /* found point within reason */ { w_scroll(j - i); /* scroll screen down that many lines */ curr_y = wlp[0]->cflag = wlp[0]->col = curr_x = 0; /* start from top of screen */ wlp[0]->start = w_p1.dot; /* save starting char position */ window2(0); /* and rewrite screen */ } else window1_abs(); /* farther back than that - redraw */ } else window1_abs(); /* continuation was too long: give up and redraw */ } /* end of "dot is before screen" */ else if (dot <= wlp[last_y]->end) window1_inc(dot); /* on screen - redraw incrementally */ else window1_after(); /* dot is after screen: scroll or redraw */ } /* end of "dot is before modified point" */ /* the modified point in the buffer is before dot */ else { if (buff_mod < wlp[0]->start) window1_abs(); /* modified point before screen - redraw fully */ else if (buff_mod <= wlp[last_y]->end) /* modified point on screen */ { for (m = 0; buff_mod > wlp[m]->end; m++); /* find line with buff_mod */ w_setptr(wlp[m]->start, &w_p1); /* set a pointer to start of line with buff_mod */ j = (m < window_size/2) ? window_size - 1 - m : window_size/2; /* maximum # of lines between buff_mod & dot */ for (i = 0; (dot >= w_p1.dot) && (w_p1.dot < z) && (i <= j); ) i += (lflag = w_lines(1, &w_p1, &w_p1) ) ? lflag : 1; /* count lines from buff_mod to first line after dot */ if (i > j) window1_abs(); /* too far - redraw */ else { if (lflag && (dot == z)) i++; /* if at end, following a LF */ w_setptr(wlp[m]->start, &w_p1); /* pointer to start of area to redraw */ if (i >= window_size - m) /* if there are not enough blank lines on screen */ w_scroll(i = i - window_size + m), curr_y = m - i, curs_y -= i; /* scroll up the difference */ else curr_y = m; curr_x = (wlp[curr_y]->cflag & WF_CONT) ? 2 : wlp[curr_y]->col; /* line starts at left unless continuation */ if ((curr_y > curs_y) && (curs_y >= 0)) w_rmcurs(); /* remove old cursor if it won't be written over */ window2(0); /* rewrite newly cleared region */ for (curr_x = 0; ++curr_y < window_size; ) /* clear rest of screen if needed */ { wlp[curr_y]->cflag = 0; if (wlp[curr_y]->n) wlp[curr_y]->n = 0, vtm(VT_EEOL); } } } /* end "modified point on screen */ else window1_after(); /* modified point after screen: scroll or redraw as appropriate */ } \f /* done redrawing: do cleanup work */ if (WN_scroll) { printf("\033[%d;%dr", window_size+1, WN_height); /* reset margins */ printf("\033[%d;0H", WN_height); /* cursor to bottom */ } else printf("\033[H"); /* no split screen: set home */ fflush(stdout); /* flush output */ WN_origin = wlp[0]->start; /* save first char pos on screen */ redraw_sw = 0; /* mark screen as updated */ buff_mod = MAX; last_dot = dot; block_inter(0); /* reenable interrupts */ } \f /* routine to redraw screen absolutely */ window1_abs() { int i, j; curr_y = wlp[0]->col = curr_x = 0; /* indicate where refresh starts */ set_pointer(dot, &w_p1); /* make a text buffer, if none, and refresh the display */ w_lines(0, &w_p1, &w_p1); /* do 0L */ if ((i = w_lines(window_size/2, &w_p1, NULL)) == 0) i = 1; /* check how many lines after dot */ if (i > window_size/2) i = window_size/2; /* limit amount after dot */ for (j = 0; (j < window_size - i) && (w_p1.dot > 0); ) /* find start of display area */ j -= w_lines(-1, &w_p1, &w_p1); if (j > window_size - i) w_lines(1, &w_p1, &w_p1); /* if too far back, move up one line */ wlp[0]->start = w_p1.dot; /* indicate where first window line starts */ window2(0); /* refresh the whole display */ for (curr_x = 0; ++curr_y < window_size; ) /* blank out lines not written by window2 */ if (wlp[curr_y]->n || redraw_sw) wlp[curr_y]->n = 0, vtm(VT_EEOL); } /* redraw screen incrementally */ window1_inc(wd) int wd; /* argument is earliest change */ { short temp_y; /* find the line containing the character at wd */ for (temp_y = 0; wd > wlp[temp_y]->end; temp_y++); if ((curs_y != temp_y) || (buff_mod == MAX) || curs_crflag) /* if the cursor line won't be rewritten */ w_rmcurs(); /* remove the old cursor */ curr_y = temp_y; /* and go to work on the beginning of the line with dot */ curr_x = (wlp[curr_y]->cflag & WF_CONT) ? 2 : wlp[curr_y]->col; /* line starts at left unless continuation */ w_setptr(wlp[curr_y]->start, &w_p1); /* make a pointer there */ window2(buff_mod == MAX); /* if buffer not modified, redraw only the line with dot */ if (buff_mod < MAX) /* if buffer has changed, erase display lines beyond end of buffer */ for (curr_x = 0; ++curr_y < window_size; ) if ( ((wlp[curr_y]->start >= z) || (wlp[curr_y]->start <= wlp[curr_y-1]->end)) && (wlp[curr_y]->n || redraw_sw) ) wlp[curr_y]->n = 0, vtm(VT_EEOL), wlp[curr_y]->cflag = 0; } \f /* routine to move window downwards: scroll up or redraw as appropriate */ window1_after() { int i, lflag; w_rmcurs(); /* remove old cursor */ w_setptr(wlp[window_size-1]->start, &w_p1); /* set pointer to start of last line on screen */ for (i = 0; (dot >= w_p1.dot) && (w_p1.dot < z) && (i <= window_size/2); ) i += (lflag = w_lines(1, &w_p1, &w_p1)) ? lflag : 1; /* fwd one line at a time until > dot or end of buffer */ if (i <= window_size/2) /* found within n lines */ { if (lflag && (dot == z)) ++i; /* if dot is at end of buffer after a LF */ if (i >= window_size - last_y) /* if there are not enough blank lines on screen */ w_scroll(i - window_size + last_y), curr_y = window_size - i; /* scroll up the difference */ else curr_y = last_y; while (curr_y && (wlp[curr_y]->cflag & WF_CONT)) --curr_y; /* get to start of cont'd lines */ w_setptr(wlp[curr_y]->start, &w_p1); /* pointer to start of area to redraw */ curr_x = wlp[curr_y]->col; /* redraw starts at line's first column */ window2(0); /* rewrite newly cleared region */ } else window1_abs(); /* move down is too far: redraw fully */ } /* routine to remove the existing cursor */ w_rmcurs() { if (curs_c) /* if there was a cursor */ { w_move(curs_y, curs_x); /* go remove the old cursor */ if (curs_c & W_MARK) fputs("\033(0", stdout); /* if prev char was a spec char */ putchar(*curs_p = curs_c); /* put back the char that was there */ if (curs_c & W_MARK) fputs("\033(B", stdout); ++term_x; /* and keep the terminal cursor loc. happy */ } } \f /* routine to do actual display refresh */ /* called with w_p1 at starting char, curr_y, curr_x at starting coordinate */ /* rewrites to end of screen if arg = 0, or only until line with cursor if arg = 1 */ window2(arg) int arg; { register int wdot; register char wc; /* temp char */ register short dflag; /* nonzero if this is char at dot */ short cr_found; /* indicates a cr found on this line */ cr_found = 0; /* clear "cr" flag in first line written */ for (wdot = w_p1.dot; (curr_y < window_size) && (wdot < z); wdot++) /* for each character */ { wc = w_p1.p->ch[w_p1.c] & 0177; /* get character */ if (dflag = (wdot == dot)) if (arg) arg = -1; /* save "this is char at dot", "on line with dot" */ if (wc < ' ') switch (wc) /* dispatch control characters */ { case CR: if (dflag) /* if cursor on this CR */ { if (curr_x < WN_width) w_makecurs(' ', 1), w_type(' ', 1); /* display a space, unless at end */ else curs_crflag = curs_c = 0; /* else set "no cursor displayed" */ } /* trim remainder of line if this is first cr and old line was longer */ if (!cr_found && ((curr_x < wlp[curr_y]->n) || redraw_sw)) { wlp[curr_y]->n = curr_x; if (curr_x < WN_width) vtm(VT_EEOL); } cr_found = 1; /* set cr flag */ wlp[curr_y]->cflag &= ~WF_BEG; /* this line is not continued */ while (curr_y && (wlp[curr_y]->cflag & WF_CONT)) --curr_y; /* if line is a continuation, scan up */ curr_x = 0; break; case TAB: if (curr_x >= WN_width) { if (et_val & ET_TRUNC) goto noprint; if (w_overflow(wdot)) goto w2_exit; /* extend line */ } if (dflag) w_makecurs(' ', 0); w_type(' ', dflag); /* type one space */ if (dflag) { vt(VT_CLRSPEC); /* end reverse video */ dflag = 0; } while ((curr_x & tabmask) && (curr_x < WN_width)) w_type(' ', 0); /* finish tab */ break; \f case LF: while ((curr_y < window_size) && (wlp[curr_y]->cflag & WF_BEG)) ++curr_y; /* last screen row of this line */ wlp[curr_y]->end = wdot; /* save char position that ended this line */ if (dflag) /* if this LF is at dot */ { /* put cursor there, save char that was there */ w_makecurs( (curr_x < wlp[curr_y]->n) ? wlp[curr_y]->ch[curr_x] : ' ', 0); fputs("\033(0", stdout); /* put in a "LF" char */ w_type('e', 1); fputs("\033(B", stdout); } /* if no cr found and not in last column, erase rest of line */ if (!cr_found && (curr_x < wlp[curr_y]->n)) { wlp[curr_y]->n = curr_x; if (curr_x < WN_width) vtm(VT_EEOL); } if (dflag) --curr_x; /* put the cursor back before the artificial LF char, if any */ if (curr_y >= window_size-1) /* if at end of screen, exit, but... */ { if (dflag) vt(VT_CLRSPEC); /* if cursor is here, clear reverse video first */ goto w2_exit; } if ((wlp[curr_y]->cflag & WF_CONT) && (wlp[curr_y]->end - wlp[curr_y]->start == 1)) /* if a now-empty cont. line, */ { /* flush it */ if (curr_y > 0) wlp[curr_y-1]->cflag &= ~WF_BEG; /* remove "cont'd" flag from prev line */ arg = 0; /* and force redraw of rest of screen */ if (curs_y == curr_y) curs_c = 0; /* if cursor was on this line, it will disappear */ } else ++curr_y; /* down one line if not absorbing blank contin. line */ wlp[curr_y]->start = wdot + 1; /* assume line starts with next char */ wlp[curr_y]->col = curr_x; /* save starting column */ cr_found = wlp[curr_y]->cflag = 0; /* clear line continuation flags */ if (curr_x) w_ebol(); /* if not at left margin, erase beginning of line */ if (arg == -1) /* finished line with dot... quit if spec'd */ { if (dflag) /* but first, if at cursor, clear reverse video */ { vt(VT_CLRSPEC); dflag = 0; } return; } break; case ESC: if (curr_x >= WN_width) { if (et_val & ET_TRUNC) goto noprint; if (w_overflow(wdot)) goto w2_exit; /* extend line */ } if (dflag) w_makecurs('$', 0); w_type('$', dflag); break; \f default: /* all other control chars print as ^X */ if (curr_x >= WN_width - 1) { if (et_val & ET_TRUNC) goto noprint; if (w_overflow(wdot)) goto w2_exit; } if (dflag) w_makecurs('^', 0); w_type('^', dflag); /* ^ */ if (dflag) { vt(VT_CLRSPEC); /* if at cursor, clear reverse video */ dflag = 0; } w_type(wc | 0100, 0); break; } /* end "switch" */ else /* a printing character */ { if (curr_x >= WN_width) { if (et_val & ET_TRUNC) goto noprint; if (w_overflow(wdot)) goto w2_exit; /* extend line */ } if (dflag) w_makecurs(wc, 0); w_type(wc, dflag); } if (dflag) { vt(VT_CLRSPEC); /* if at cursor, clear reverse video */ } if ((wc == FF) || (wc == VT)) /* these chars leave a display line blank */ { if (redraw_sw || (curr_x < wlp[curr_y]->n)) { wlp[curr_y]->n = curr_x; if (curr_x < WN_width) vtm(VT_EEOL); /* erase rest of line */ } wlp[curr_y]->end = wdot; if (curr_y >= window_size-1) goto w2_exit; /* quit if overflow screen */ wlp[++curr_y]->start = wdot + 1; cr_found = wlp[curr_y]->cflag = 0; /* init new line */ if (curr_x -= 2) w_ebol(); /* back up over ^X; if not at left margin, erase beginning of line */ wlp[curr_y]->col = curr_x; /* save starting column */ } \f noprint: if (++ w_p1.c > CELLSIZE - 1) w_p1.p = w_p1.p->f, w_p1.c = 0; /* next char in buffer */ } /* end of "for all characters" */ if (dot == z) { if (curr_x < WN_width) w_makecurs(' ', 1), w_type(' ', 1), vt(VT_CLRSPEC); /* display a space, unless at end */ else curs_crflag = curs_c = 0; /* else set "no cursor displayed" */ } /* clear rest of line if needed */ if (!cr_found && (redraw_sw || (curr_x < wlp[curr_y]->n))) { wlp[curr_y]->n = curr_x; if (curr_x < WN_width) vtm(VT_EEOL); } wlp[curr_y]->end = wdot; /* save char at end of last line */ w2_exit: last_y = curr_y; /* record last used line on screen */ } \f /* routine to move cursor to current location and then call vt */ vtm(arg) int arg; { w_move(curr_y, curr_x); vt(arg); } /* routine to set reverse video and save cursor location */ /* first argument is char at cursor, 2nd is value for curs_crflag */ w_makecurs(wc, crflag) char wc; short crflag; { curs_y = curr_y, curs_x = curr_x, curs_c = wc; /* save cursor coord and char */ curs_p = &wlp[curr_y]->ch[curr_x]; /* save location of cursor spot in window image */ curs_crflag = crflag; /* save crflag */ vt(VT_SETSPEC2); /* set flag and reverse video */ } /* routine to handle line overflow */ /* returns nonzero if at end of screen, zero otherwise */ /* arg is current character position */ int w_overflow(wd) { wlp[curr_y]->end = wd-1; /* last character was end of this line */ if (wlp[curr_y]->n > curr_x) { wlp[curr_y]->n = curr_x; if (curr_x < WN_width) vtm(VT_EEOL); /* if old line was wider, erase */ } if (curr_y >= window_size-1) return(1); wlp[curr_y]->cflag |= WF_BEG; /* mark this line as "continued" */ wlp[++curr_y]->cflag = WF_CONT; /* next line is a continuation line */ wlp[curr_y]->start = wd; /* char about to be printed is this line's first */ wlp[curr_y]->col = curr_x = 0; /* new line starts at left margin */ fputs("\033(0", stdout); /* alternate char set */ w_type('h', W_MARK); /* "NL" space */ w_type(' ', W_MARK); fputs("\033(B", stdout); return(0); } \f /* routine to type one character: arguments are char and a */ /* "mark" bit. If mark is set, the char is always retyped */ w_type(c, m) char c; int m; { register char *p; p = &wlp[curr_y]->ch[curr_x]; /* pointer to char image */ if ((c != *p) || (m) || (redraw_sw) || (curr_x >= wlp[curr_y]->n)) { w_move(curr_y, curr_x); putchar(c); *p = (m) ? c | W_MARK : c; ++term_x; } ++curr_x; if (wlp[curr_y]->n < curr_x) wlp[curr_y]->n = curr_x; /* if we've lengthened the line, record that fact */ } /* initialize display image */ w_init() { short i, j; for (i = 0; i < window_size; i++) /* for each row */ { wlp[i] = &w_image[i]; /* set pointer to this line's data */ w_image[i].n = w_image[i].cflag = 0; /* no chars used, cr flag clear */ for (j = 0; j < W_MAX_H; w_image[i].ch[j++] = ' '); /* clear line */ } } /* put character followed by appropriate number of nulls for "other control function" */ /* if argument is 0, output filler chars only */ putchar_d(c) char c; { int i; if (c) putchar(c); /* output character */ for (i = 0; i < win_dlyc[win_speed]; i++) putchar('\0'); /* output filler */ } \f /* put out appropriate number of filler chars for display function that scrolls (LF, etc.) */ scroll_dly() { int i; for (i = 0; i < win_dlys[win_speed]; i++) putchar('\0'); /* output filler */ } /* move terminal cursor to stated y, x position */ /* uses incremental moves or absolute cursor position, whichever is shorter */ w_move(y, x) short y, x; { register short i; /* if practical, use CR to get to left margin */ if ((curr_x == 0) && (term_x != 0)) putchar(CR), term_x = 0; if ((y == term_y) && (term_x < WN_width)) /* if term x is beyond last char, use abs positioning */ { if (x == term_x) return; if (x > term_x) { if (x - term_x == 1) fputs("\033[C", stdout); else printf("\033[%dC", x - term_x); } else { if ((i = term_x - x) < 4) for (; i > 0; i--) putchar('\b'); /* use BS */ else printf("\033[%dD", term_x - x); /* use incremental jump */ } term_x = x; } else { if ((x == term_x) && (term_x < WN_width)) { if (y > term_y) { if ((i = y - term_y) < 4) for (; i >0; i--) putchar(LF); /* use LF */ else printf("\033[%dB", i); /* use incremental jump */ } else if ((i = term_y - y) == 1) fputs("\033[A", stdout); /* move 1 */ else printf("\033[%dA", i); term_y = y; } else printf("\033[%d;%dH", (term_y = y) + 1, (term_x = x) + 1); /* absolute jump */ } } \f /* scroll screen: argument is count: + up, - down */ w_scroll(count) int count; { register int i, ic; struct w_line *p[W_MAX_V]; /* temp copy of pointer array */ if (count > 0) /* scrolling up */ { w_move(window_size-1, 0); /* cursor to bottom of window */ for (i = 0; i < count; i++) { putchar(LF), wlp[i]->n = 0; /* scroll terminal, blank out image line */ } } else /* scroll down */ { w_move(0, 0); /* cursor to top */ for (i = 0; i > count; i--) { fputs("\033M", stdout), wlp[window_size-1+i]->n = 0; } } for (i = 0; i < window_size; i++) p[i] = wlp[(window_size + i + count) % window_size]; /* rearrange */ for (i = 0; i < window_size; i++) wlp[i] = p[i]; } /* clear line to left of curr_x */ /* if some chars nonblank, does erase from start of line */ w_ebol() { short i, j; for (j = i = 0; i < curr_x; i++) if (wlp[curr_y]->ch[i] != ' ') wlp[curr_y]->ch[i] = ' ', j++; if (j || redraw_sw) w_move(curr_y, curr_x-1), vt(VT_EBOL); } /* routine to set a pointer to a given location (like set_pointer) */ /* returns nonzero if a text buffer exists, otherwise 0 */ int w_setptr(loc, pp) register int loc; /* location */ register struct qp *pp; /* address of pointer */ { register int i; if (buff.f) { for (i = loc / CELLSIZE, pp->p = buff.f; i > 0; i--) pp->p = pp->p->f; pp->c = loc % CELLSIZE; pp->dot = loc; } return( (int) buff.f); } \f /* routine to move N lines (back, forward, or 0) */ /* w_lines(n, &source, &dest) where n is the line count, source */ /* points to a qp at the current pointer, dest, if nonzero, */ /* it points to a qp where the result is to go. */ /* routine returns actual number of display lines */ struct qp w_lines_p; /* to compute # of display lines in -N lines */ int w_lines(n, ps, pd) int n; /* number of lines */ register struct qp *ps, *pd; /* source, destination qp's */ { register struct buffcell *tp; /* local copy of the qp */ register int tc, tdot, tn; int tcnt, tl; /* chars/line and display line count */ char tch; tdot = ps->dot; tp = ps->p; tc = ps->c; if (n > 0) /* argument is positive */ { for (tcnt = tl = tn = 0; (tn < n) && (tdot < z); tdot++) /* forward over N line separators */ { if (spec_chars[ tch = tp->ch[tc] ] & A_L) ++tl, ++tn; /* count separators */ else if (!(et_val & ET_TRUNC)) /* if text lines can overflow screen lines */ { if (!(tch & 0140)) /* if character is a control char */ { if (tch == CR) /* CR resets count */ { if (tcnt > WN_width) ++tl; tcnt = 0; } else if (tch == TAB) tcnt = (tcnt | tabmask) +1; /* tab to next tab stop */ else if (tch == ESC) ++tcnt; /* ESC takes one space */ else tcnt += 2; /* normal control chars take 2 spaces */ } else ++tcnt; /* not a control char: takes one space */ if (tcnt > WN_width) ++tl, tcnt = 2; /* if overflow, one more line */ } if (++tc > CELLSIZE-1) tp = tp->f, tc = 0; /* next character position */ } if (tl > tn) tn = tl; /* if counting display lines and there's more of them, return that */ } \f else /* argument is zero or negative */ { for (tn = 0; (tn >= n) && (tdot > 0); ) /* back up over (n+1) line feeds */ { --tdot; if (--tc < 0) tp = tp->b, tc = CELLSIZE -1; if (spec_chars[tp->ch[tc]] & A_L) --tn; } if (tn < n) /* if stopped on a line sep, fwd over it */ { ++tn; ++tdot; if (++tc > CELLSIZE-1) tp = tp->f, tc = 0; } if (!(et_val & ET_TRUNC) && (n != 0)) /* if text line can overflow display line */ { w_lines_p.dot = tdot, w_lines_p.p = tp, w_lines_p.c = tc; /* then count the number of display */ tn = -w_lines(-n, &w_lines_p, 0); /* lines in the N text lines we just backed up over */ } } if (pd) pd->dot = tdot, pd->p = tp, pd->c = tc; /* if an "after" pointer given, update it */ return(tn); }