/* TECO for DOS Copyright (C) 1986-1991 Matt Fichtenbaum */ /* Based on Ultrix TECO (C) 1986-1990 GenRad Inc., Concord, MA 01742 */ /* These programs may be copied if this copyright notice is included and */ /* only on a "not for sale or profit" basis */ /* te_vga.c VGA drivers 03/21/91 21.45 */ /* allocate only as much screen storage as needed 01/19/92 14.40 */ /* version with compose in memory, then copy to video memory */ /* and updated non-scroll mode display operation: */ /* ^W or W: display current buffer full screen, cursor at home */ /* y,xW: set cursor coordinates as given */ /* y,x^W: set cursor coordinates and refresh */ /* version with horizontally split screen 09/16/91 20.36 */ /* both 'mark' coordinates independent of 'dot' 09/02/92 21.34 */ /* 4 buffers 03/14/93 22.30 */ /* assignable windows/buffers 12/09/93 11.15 */ #include "te_defs.h" #include "te_graph.h" #include #include #define W_MAX_V 86 #define W_MAX_H 132 #define MAX 0x7fffffffL /* window parameters */ /* 0: display type, 1: width, 2: height, 3: seeall, 4: mark position, */ /* 5: hold mode, 6: upper left corner position, 7: scroll region size */ /* 8: secondary window size, 9: secondary window origin, 10: primary window size (read only) */ /* 11: other mark position, 12, 13: size of windows 3 and 4, 14, 15: origins of windows 3 and 4 */ /* 0 1 2 3 4 5 6 7 8 9 10 11, 12, 13 14 15 */ static long win_min[] = { 1, 20, 4, 0, 0, -1, 1, 0, -W_MAX_H, 1, 1, 0, 0, 0, 1, 1 } ; /* min values */ static long win_max[] = { -1, W_MAX_H, W_MAX_V, 1, MAX, 12, -1, 20, 20, -1, -1, MAX, 20, 20, -1, -1 } ; /* max values */ short win_data[] = { 3, 132, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } ; /* window params */ /* structure to specify one row in buffer window */ struct win_row { long start; /* buffer pos of first displayed character */ long end; /* and last */ unsigned char cflag; /* flag bits */ unsigned char n; /* number of character positions used */ unsigned char col; /* starting column */ }; /* define "this line is continued" / "this line is a continuation" flags */ #define WF_BEG 1 #define WF_CONT 2 /* define mark control flags */ #define MARK_INIT 0 #define MARK_SET 1 #define MARK_CLEAR 2 #define MARK_RESTORE 3 #define MARK_BEGIN 4 /* structure to specify each window */ struct window { unsigned char norm; /* normal color */ unsigned char curs_1; /* cursor when window selected */ unsigned char curs_2; /* cursor when not selected */ unsigned char mark; /* color for marked text */ unsigned char line_cont; /* color for "line continuation" char */ unsigned char line_feed_1; /* color for "line feed" char with cursor (sel'd) */ unsigned char line_feed_2; /* color for "line feed" char with cursor (not sel'd) */ unsigned char last_y; /* last used row in window */ struct lbh *buff; /* pointer to associated logical buffer header */ struct win_row *image; /* pointer to screen data array */ long last_dot; /* previous pointer position */ long last_mark; /* previous position of "mark" */ long last_mark2; /* previous position of other end of "mark" */ unsigned char *curs_loc; /* cursor location */ unsigned char curs_y, curs_x; /* cursor coordinates */ unsigned char curs_char; /* char at cursor */ unsigned char curs_attr; /* cursor attributes */ unsigned char start; /* top screen row */ unsigned char end; /* bottom screen row */ unsigned char size; /* number of rows in window */ unsigned char half_size; /* approx. half size */ unsigned char left; /* left margin */ unsigned char width; /* width */ }; /* windows - colors */ /* colors are subscripts into color table */ /* norm crs(sel) crs(nsel) mark cont LF (sel) LF (unsel) */ static struct window cmd_win = /* command window */ { 0, 1, 1, 0, 2, 3, 3, 0, &lbuffs[0] }; static struct window buffer_wins[4] = /* display buffers */ { { 4, 5, 6, 7, 8, 9, 10, 0, &lbuffs[0] }, /* buffer 0 */ { 11, 12, 13, 14, 15, 16, 17, 0, &lbuffs[1] }, /* buffer 1 */ { 18, 19, 20, 21, 22, 23, 24, 0, &lbuffs[2] }, /* buffer 2 */ { 25, 26, 27, 28, 29, 30, 31, 0, &lbuffs[3] } /* buffer 3 */ }; #define buff1_win buffer_wins[0] #define buff2_win buffer_wins[1] #define buff3_win buffer_wins[2] #define buff4_win buffer_wins[3] static struct window whole_win = /* full screen */ { 0, 1, 1, 0, 2, 3, 3, 0, &lbuffs[0] }; static struct window bottom_win = /* last screen line */ { 0, 1, 1, 0, 2, 3, 3, 0, &lbuffs[0] }; /* table of color pairs - */ /* colors: 0:black 1:blue 2:green 3:cyan 4:red 5:mgnta 6:brown 7:white */ /* 8:dkgry 9:ltblu a:ltgrn b:ltcyn c:ltred d:ltmgn e:ltyel f:brtwh */ static unsigned char color_pairs[] = /* for color displays */ { 0x07, /* 0: command windows, normal */ 0x70, /* 1: command window, highlight */ 0x0e, /* 2: command window, continuation */ 0x2e, /* 3: command window, LF */ 0x87, /* 4: window 1, normal */ 0x20, /* 5: window 1, cursor (sel'd) */ 0x67, /* 6: window 1, cursor (unsel'd) */ 0x78, /* 7: window 1, mark */ 0x8e, /* 8: window 1, continuation */ 0x2e, /* 9: window 1, LF (sel'd) */ 0x6e, /* 10: window 1, LF (unsel'd) */ 0x17, /* 11: window 2, normal */ 0x20, /* 12: window 2, cursor (sel'd) */ 0x67, /* 13: window 2, cursor (unsel'd) */ 0x71, /* 14: window 2, mark */ 0x1e, /* 15: window 2, continuation */ 0x2e, /* 16: window 2, LF (sel'd) */ 0x6e, /* 17: window 2, LF (unsel'd) */ 0x57, /* 18: window 3, normal */ 0x20, /* 19: window 3, cursor (sel'd) */ 0x67, /* 20: window 3, cursor (unsel'd) */ 0x71, /* 21: window 3, mark */ 0x1e, /* 22: window 3, continuation */ 0x2e, /* 23: window 3, LF (sel'd) */ 0x6e, /* 24: window 3, LF (unsel'd) */ 0x47, /* 25: window 4, normal */ 0x20, /* 26: window 4, cursor (sel'd) */ 0x67, /* 27: window 4, cursor (unsel'd) */ 0x71, /* 28: window 4, mark */ 0x1e, /* 29: window 4, continuation */ 0x2e, /* 30: window 4, LF (sel'd) */ 0x6e /* 31: window 4, LF (unsel'd) */ }; static unsigned char color_pairs_mono[] = /* for mono displays */ { 0x02, /* 0: command windows, normal */ 0x10, /* 1: command window, highlight */ 0x0a, /* 2: command window, continuation */ 0x10, /* 3: command window, LF */ 0x02, /* 4: window 1, normal */ 0x90, /* 5: window 1, cursor (sel'd) */ 0x10, /* 6: window 1, cursor (unsel'd) */ 0x01, /* 7: window 1, mark */ 0x02, /* 8: window 1, continuation */ 0x90, /* 9: window 1, LF (sel'd) */ 0x10, /* 10: window 1, LF (unsel'd) */ 0x02, /* 11: window 2, normal */ 0x90, /* 12: window 2, cursor (sel'd) */ 0x10, /* 13: window 2, cursor (unsel'd) */ 0x01, /* 14: window 2, mark */ 0x02, /* 15: window 2, continuation */ 0x90, /* 16: window 2, LF (sel'd) */ 0x10, /* 17: window 2, LF (unsel'd) */ 0x02, /* 11: window 3, normal */ 0x90, /* 12: window 3, cursor (sel'd) */ 0x10, /* 13: window 3, cursor (unsel'd) */ 0x01, /* 14: window 3, mark */ 0x02, /* 15: window 3, continuation */ 0x90, /* 16: window 3, LF (sel'd) */ 0x10, /* 17: window 3, LF (unsel'd) */ 0x02, /* 11: window 4, normal */ 0x90, /* 12: window 4, cursor (sel'd) */ 0x10, /* 13: window 4, cursor (unsel'd) */ 0x01, /* 14: window 4, mark */ 0x02, /* 15: window 4, continuation */ 0x90, /* 16: window 4, LF (sel'd) */ 0x10 /* 17: window 4, LF (unsel'd) */ }; /* data for each row of buffer windows */ static struct win_row *row_data; /* function prototypes */ static short w_lines(int n, struct qp *ps, struct qp *pd); static short w_setptr(struct lbh *pbuff, long loc, struct qp *pp); void set_term_par(); static void set_color(unsigned char ccolor); static void set_window(struct window *pw, short clr_flag); void out_flush(); void out_char(unsigned char c); void out_str(unsigned char *p); void vt(int func); void do_window(int ctlw_flag); void window(short func); static void window0(short num); static void window1(struct window *pw, struct lbh *pb); static void window1_abs(void); static void window1_both(void); static void window1_after(void); static void w_type(unsigned char c); static short w_overflow(long wd); static void w_makecurs(unsigned char); static void w_rmcurs(void); static void w_mark(unsigned char f); static void clear_margins(); long xy_to_dot(long x, long y, long *p_bufsel); void display_lines(void); unsigned char getvideoconfig(unsigned short *mode, short *rows, short *cols); /* globals */ static struct window *cur_win = &cmd_win; /* pointer to current window */ static struct win_row *image; /* pointer to row data array */ static unsigned char *color_table; /* pointer to active color table */ short term_rows, term_cols; /* screen dimensions */ static unsigned short term_mode; /* display mode */ short redraw_sw = -1; /* nonzero => full redraw */ static struct lbh *pb0; /* pointer to current logical buffer header */ static struct qp w_p1; /* pointer for window access to buffer */ void (*outtext_p)(unsigned const char *buffer) = _outtext; static unsigned char *screen; /* working buffer for screen window */ /* get screen size and set initial window limits */ static unsigned char mono_display; void set_term_par() { unsigned char video_type; void outtext_stderr(unsigned const char *buffer); video_type = getvideoconfig(&term_mode, &term_rows, &term_cols); screen = malloc(2 * term_rows * term_cols); /* allocate screen image */ row_data = (struct win_row *) malloc(term_rows * sizeof(struct win_row)); if (screen == NULL || row_data == NULL) { outtext_stderr("Can't allocate display buffers\n"); exit(1); } mono_display = video_type & 1; /* "mono" bit */ if (video_type & 2) { et_val |= ET_GRAPH; /* "graphics mode" bit */ outtext_p = outtext_stderr; } color_table = mono_display ? color_pairs_mono : color_pairs; WN_height = win_max[2] = term_rows; WN_width = win_max[1] = term_cols; win_data[0] = term_mode; cmd_win.start = whole_win.start = bottom_win.size = 1; cmd_win.end = cmd_win.size = whole_win.end = whole_win.size = bottom_win.start = bottom_win.end = term_rows; cmd_win.left = whole_win.left = 0; cmd_win.width = whole_win.width = term_cols; } /* set a color pair */ /* argument is a subscript to the current color table */ static void set_color(unsigned char ccolor) { _settextcolor(*(color_table + ccolor) & 0x0f); /* text to foreground color */ _setbkcolor((long) *(color_table + ccolor) >> 4); /* background to background color */ } /* set a given window */ /* first arg is window descriptor; second nonzero clears window */ static void set_window(struct window *pw, short clr_flag) { short i; out_flush(); /* force out any pending output */ cur_win = pw; _settextwindow(pw->start, pw->left+1, pw->end, pw->left+pw->width); /* set window */ set_color(pw->norm); image = pw->image; if (clr_flag != 0) { _clearscreen(_GWINDOW); if (image) for (i = 0; i < pw->size; i++) (image+i)->n = 0; } } /* routines to output characters using display routines */ static unsigned char outc_buff[CELLSIZE+1]; /* output buffer so far */ static unsigned char *outc_p = outc_buff; /* pointer to current buffer position */ /* flush output buffer */ void out_flush() { if (outc_p > outc_buff) { *outc_p = '\0'; outc_p = outc_buff; (*outtext_p)(outc_buff); } } /* write a character to buffer */ void out_char(unsigned char c) { if ( outc_p >= (outc_buff + sizeof(outc_buff) -1) ) out_flush(); *outc_p++ = c; if (c == LF) out_flush(); } /* output a string */ void out_str(unsigned char *p) { out_flush(); (*outtext_p)(p); } void outtext_stderr(unsigned const char *buffer) { void out_stderr(unsigned char); while (*buffer != '\0') out_stderr(*buffer++); } /* routine to perform simple scope operations */ void vt(int func) { struct rccoord curs_loc; unsigned short temp_row; if (et_val & ET_GRAPH) return; out_flush(); switch(func) { case VT_CLEAR: _clearscreen(_GWINDOW); break; case VT_BS1: curs_loc = _gettextposition(); /* get current cursor */ if (curs_loc.col > 1) --curs_loc.col; _settextposition(curs_loc.row, curs_loc.col); (*outtext_p)(" "); goto vt_setcurs; case VT_BS2: curs_loc = _gettextposition(); /* get current cursor */ if (curs_loc.col > 2) curs_loc.col -= 2; _settextposition(curs_loc.row, curs_loc.col); (*outtext_p)(" "); goto vt_setcurs; case VT_LINEUP: curs_loc = _gettextposition(); if (curs_loc.row > 1) --curs_loc.row; goto vt_setcurs; case VT_SETSPEC1: set_color(cur_win->curs_1); break; case VT_SETCURS: set_color( (unsigned char) (cur_win->buff == pbuff ? cur_win->curs_1 : cur_win->curs_2)); break; case VT_LINEFEED: set_color( (unsigned char) (cur_win->buff == pbuff ? cur_win->line_feed_1 : cur_win->line_feed_2)); break; case VT_LINECONT: set_color(cur_win->line_cont); break; case VT_SETMARK: set_color(cur_win->mark); break; case VT_CLRSPEC: set_color(cur_win->norm); break; case VT_EEOL: curs_loc = _gettextposition(); temp_row = curs_loc.row + cur_win->start-1; _settextwindow(temp_row, curs_loc.col, temp_row, WN_width); _clearscreen(_GWINDOW); set_window(cur_win, 0); goto vt_setcurs; case VT_EBOL: curs_loc = _gettextposition(); temp_row = curs_loc.row + cur_win->start-1; _settextwindow(temp_row, 1, temp_row, curs_loc.col-1); _clearscreen(_GWINDOW); set_window(cur_win, 0); goto vt_setcurs; case VT_BSP1: curs_loc = _gettextposition(); if ((curs_loc.col -= 1) < 1) curs_loc.col = 1; goto vt_setcurs; case VT_BSP2: curs_loc = _gettextposition(); if ((curs_loc.col -= 2) < 1) curs_loc.col = 1; vt_setcurs: _settextposition(curs_loc.row, curs_loc.col); break; } } /* set window parameters */ /* arg is 0 for W, 1 for ^W commands */ void do_window(int ctlw_flag) { int i; short change_flag = 0; /* flag for changed value */ unsigned char *color_ptr; struct rccoord curs_loc; extern unsigned char mousepointer[]; if (colonflag && !ctlw_flag) { i = get_value(0); /* get sub-function */ if (i >= 20 && i <= 53) /* if modifying color */ { if (i >= 52) color_ptr = &mousepointer[i-52]; else color_ptr = i - 20 + (mono_display ? color_pairs_mono : color_pairs); if (!esp->flag2) { esp->val1 = *color_ptr; /* fetch */ esp->flag1 = 1; } else { change_flag = (esp->val2 & 0xff) ^ *color_ptr; *color_ptr = esp->val2 & 0xff; /* set */ esp->flag1 = 0; /* if updating command window normal color, do it now */ if (i == 20) { out_flush(); set_color((unsigned char) (i - 20)); } } } else { if ((i < 0) || (i > (sizeof(win_data)/sizeof(int)))) ERROR(E_IWA); if (!esp->flag2) /* it's a "get" */ { if (i == 4) esp->val1 = pbuff->mark; /* mark loc is stored in buffer */ else if (i == 11) esp->val1 = pbuff->mark2; else 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 (!(et_val & ET_GRAPH)) /* don't update window if graphics mode */ { if (i == 4) { change_flag = (pbuff->mark != esp->val2); pbuff->mark = esp->val2; /* mark loc is stored in buffer */ } else if (i == 11) { change_flag = (pbuff->mark2 != esp->val2); pbuff->mark2 = esp->val2; } else { change_flag = (win_data[i] != esp->val2); /* save if a change occurs */ win_data[i] = esp->val2; /* set new value and consume argument */ } } /* if changing screen dimensions or scroll size, update secondary window size too */ if (i == 1 || i == 2 || i == 7) { win_max[8] = term_rows - WN_scroll -2; if (WN_secondary > win_max[8]) WN_secondary = win_max[8]; } /* if changing screen size or scroll status or window is on, redraw */ if (change_flag != 0 && (i == 7 || i == 2 || (WN_scroll != 0 && (i == 1 || i == 8 || i == 12 || i == 13)))) window(WIN_INIT); } } } else if (WN_scroll && ctlw_flag) window(WIN_DISP); else if (!WN_scroll && !(et_val & ET_GRAPH)) /* no colon, or ^W command, and display off */ { if (ctlw_flag) /* ^W - refresh display */ { if (esp->flag1 && esp->val1 == -1) /* -1^W clears screen to command background */ set_window(&cmd_win, 1); else if (esp->flag1 && esp->val1 == -2) /* -2^W clears screen to primary window background */ set_window(&buff1_win, 1); else /* other ^W displays current buffer in primary window */ window1(&buff1_win, pbuff); _settextposition(1, 1); /* leave cursor at home */ } else /* W - set text position */ { out_flush(); curs_loc = _gettextposition(); /* get current cursor */ if (esp->flag2) curs_loc.row = esp->val2 + 1; if (esp->flag1) curs_loc.col = esp->val1 + 1; if (curs_loc.row < 1) curs_loc.row = 1; if (curs_loc.row > term_rows) curs_loc.row = term_rows; if (curs_loc.col < 1) curs_loc.col = 1; if (curs_loc.col > term_cols) curs_loc.col = term_cols; _settextposition(curs_loc.row, curs_loc.col); } esp->flag1 = 0; /* no colon, consume args */ } esp->flag2 = colonflag = 0; esp->op = OP_START; if (change_flag) window(WIN_REDRAW); /* redraw window next time if something changed */ } void window(short func) { int i; union REGS xr; extern void set_mouse_range(); pb0 = pbuff; /* point to current window */ switch(func) { case WIN_INIT: /* initialize window */ case WIN_RESUME: /* redo window */ cmd_win.start = (WN_scroll != 0) ? term_rows - WN_scroll + 1 : 1; cmd_win.end = term_rows; cmd_win.size = cmd_win.end - cmd_win.start + 1; cmd_win.left = 0; cmd_win.width = WN_width; buff1_win.start = 1; if (WN_scroll == 0) /* screen display is off */ { buff1_win.end = term_rows; buff1_win.size = buff1_win.end - buff1_win.start + 1; WN_primary = buff1_win.size = buff1_win.end - buff1_win.start + 1; buff1_win.image = &row_data[0]; buff1_win.left = 0; buff1_win.width = WN_width; } else if (WN_secondary >= 0) /* if no horiz split */ { for (i = 0; (term_rows - WN_scroll - (WN_secondary + WN_buff3 + WN_buff4)) < 4; i++) /* adjust sizes */ { if ((i % 3) == 0 && WN_secondary > 2) --WN_secondary; else if ((i % 3) == 1 && WN_buff3 > 2) --WN_buff3; else if ((i % 3) == 2 && WN_buff4 > 2) --WN_buff4; } buff4_win.end = term_rows - WN_scroll; buff3_win.end = buff4_win.end - WN_buff4; buff2_win.end = buff3_win.end - WN_buff3; buff1_win.end = buff2_win.end - WN_secondary; buff1_win.size = WN_primary = buff1_win.end - buff1_win.start + 1; buff2_win.size = WN_secondary; buff3_win.size = WN_buff3; buff4_win.size = WN_buff4; buff1_win.image = &row_data[0]; buff2_win.image = &row_data[buff2_win.start = buff1_win.end + 1]; buff3_win.image = &row_data[buff3_win.start = buff2_win.end + 1]; buff4_win.image = &row_data[buff4_win.start = buff3_win.end + 1]; buff1_win.left = buff2_win.left = buff3_win.left = buff4_win.left = 0; /* full margins */ buff1_win.width = buff2_win.width = buff3_win.width = buff4_win.width = WN_width; } else /* horizontal split screen */ { buff1_win.end = buff2_win.end = term_rows - WN_scroll; /* two windows full height */ buff1_win.size = buff2_win.size = buff1_win.end; buff1_win.left = 0; /* primary starts at left */ buff2_win.start = 1; buff3_win.size = buff4_win.size = 0; if (-WN_secondary >= WN_width - 10 || WN_secondary > -10) WN_secondary = -WN_width/2; /* set width */ buff2_win.left = (buff1_win.width = -WN_secondary) + 1; /* sec to right of primary */ buff2_win.width = WN_width - buff2_win.left; buff1_win.image = &row_data[0]; buff2_win.image = &row_data[buff1_win.size]; clear_margins(); } for (i = 0; i < 4; i++) /* set half sizes and clear active windows */ { buffer_wins[i].half_size = (buffer_wins[i].size + 1)/2; if (buffer_wins[i].size != 0) set_window(&buffer_wins[i], 1); } set_window(&cmd_win, (func == WIN_INIT) ); /* and command window (clear it) */ _settextposition((WN_scroll != 0) ? cmd_win.size : 1, 1); /* col 1, last line */ _wrapon(_GWRAPOFF); xr.x.ax = 0x1003; /* set high attributes bit to "intensity" */ xr.h.bl = 0; int86(0x10, &xr, &xr); if (fm_ctrl != 0) set_mouse_range(); /* if mouse is on, reset screen range */ redraw_sw = -1; break; case WIN_REDRAW: /* force window redraw */ if (!redraw_sw) redraw_sw = 1; break; case WIN_OFF: /* disable window */ case WIN_SUSP: /* suspend window */ if (WN_scroll) /* if split-screen is enabled */ { set_window(&bottom_win, 1); /* clear last line */ set_window(&whole_win, 0); /* and set full screen */ _settextposition(term_rows, 1); /* set last line in window */ } break; case WIN_DISP: /* display window */ window1_both(); 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(pb0, pb0->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) window(WIN_DISP); /* 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(pb0, pb0->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; } } /* 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 */ static struct qp w_lines_p; /* to compute # of display lines in -N lines */ static short w_lines(int n, struct qp *ps, struct qp *pd) { BUFFPTR tp = ps->p; /* local copy of the qp */ long tdot = ps->dot; /* copy of dot */ int tc = ps->c; int tn; int tcnt, tl; /* chars/line and display line count */ unsigned char tch; if (n > 0) /* argument is positive */ { for (tcnt = tl = tn = 0; (tn < n) && (tdot < pb0->phys->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 & char_mask & 0340)) /* if character is a control char */ { if (tch == CR) /* CR resets count */ { if (tcnt > cur_win->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 */ } 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); } /* routine to set a pointer to a given location (like set_pointer) */ /* returns nonzero if a text buffer exists, otherwise 0 */ static short w_setptr(struct lbh *pbuff, long loc, struct qp *pp) { short i; if (pbuff->phys->f) { for (i = loc / CELLSIZE, pp->p = pbuff->phys->f; i > 0; i--) pp->p = pp->p->f; pp->c = loc % CELLSIZE; pp->dot = loc; } return( (int) (pbuff->phys->f != 0)); } /* routine to type n lines with character at "dot" in reverse video */ /* used for ev, es, and or as immediate commands */ /* starting char position is in w_p1; argument is number of lines */ static void window0(short num) { long wi; unsigned char wc; /* temp char */ struct lbh *pb = pb0; for (wi = w_p1.dot; (num > 0) && (wi < pb->phys->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 { vt(VT_LINECONT); out_str("\015\012\030 "); /* arrow */ vt(VT_CLRSPEC); char_count = 2; } } if (wi == pb->dot) /* if this char is at the pointer */ { if (et_val & ET_GRAPH) type_char((unsigned char) 178); else vt(VT_SETSPEC1); /* 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_CLRSPEC); vt(VT_EEOL); /* erase to eol */ } type_char(wc); /* type the char, or exec CR */ if (wc == LF) { vt(VT_LINEFEED); out_char('\031'); /* */ ++char_count; } vt(VT_CLRSPEC); /* clear reverse video */ } } else /* this is not char at pointer */ { if (wc == CR && char_count < 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 (pb->dot == pb->phys->z) { w_makecurs(' '); /* type one space */ type_char(' '); vt(VT_CLRSPEC); } vt(VT_EEOL); /* erase rest of line */ } /* routine to do actual display refresh */ /* called with w_p1 at starting char, curr_y, curr_x at starting coord */ static unsigned char curr_x; /* character count (0 origin) */ static unsigned char curr_y; /* line count (0 origin) */ static unsigned char curr_color; /* current attributes */ static unsigned char curr_norm_color; /* current background color */ static unsigned char *row_p; /* start of current row in video memory */ static unsigned char *ps; /* current loc in video memory */ static void window2(unsigned char incr_flag) { register struct lbh *pb = pb0; /* local pointer to current text buffer */ long wdot; /* current character position */ unsigned long wmark = pb->mark - 1; /* marked char location */ unsigned long wmark2 = pb->mark2; unsigned char wc; /* current char */ unsigned char dflag; /* nonzero if this is char at dot */ unsigned char cr_found = 0; /* indicates a cr found on this line */ unsigned char mflag = /* nonzero if display a mark */ (pb->mark != 0); unsigned char *pt; /* temporary pointer - for clearing line */ unsigned short width2 = 2 * term_cols; unsigned short w2_offset = (cur_win->start-1 + curr_y) * width2 + 2 * cur_win->left; unsigned short w2_count = (cur_win->size - curr_y) * width2; (image+curr_y)->start = w_p1.dot; (image+curr_y)->col = (image+curr_y)->n = 0; row_p = screen + w2_offset; ps = row_p + 2 * curr_x; curr_color = curr_norm_color = *(color_table + cur_win->norm); *row_p = ' '; /* clear first part of window */ *(row_p+1) = curr_norm_color; (void) memcpy(row_p+2, row_p, 2 * cur_win->width - 2); /* clear rest of row */ if (WN_secondary < 0) for (pt = row_p + width2; pt < row_p + cur_win->size * width2; pt += width2) (void) memcpy(pt, row_p, 2 * cur_win->width); /* clear remaining rows */ else (void) memcpy(row_p+2, row_p, w2_count-2); /* clear rest of window */ if (wmark2 == 0) wmark2 = pb->dot; else --wmark2; if (wmark > wmark2) wmark = wmark2, wmark2 = pb->mark-1; if (mflag && wmark < w_p1.dot && wmark2 >= w_p1.dot) w_mark(MARK_SET); /* marked area is before screen */ else w_mark(MARK_INIT); for (wdot = w_p1.dot; (curr_y < cur_win->size) && (wdot < pb->phys->z); wdot++) /* for each character */ { wc = w_p1.p->ch[w_p1.c] & char_mask; /* get character */ dflag = (wdot == pb->dot); /* save "this is char at dot" */ if (wdot == wmark && mflag) w_mark((unsigned char) MARK_SET); /* start marked region */ if (wdot == wmark2 && mflag) w_mark((unsigned char) MARK_CLEAR); /* end marked region */ if (wc < ' ') switch (wc) /* dispatch control characters */ { case CR: if (dflag && (curr_x < cur_win->width)) /* if cursor on this CR and room for final space */ { w_makecurs(' '); *ps++ = ' '; *ps++ = curr_color; /* write char at cursor */ ++curr_x; } if ((image+curr_y)->n < curr_x) (image+curr_y)->n = curr_x; cr_found = 1; /* set cr flag */ (image+curr_y)->cflag &= ~WF_BEG; /* this line is not continued */ while (curr_y && ((image+curr_y)->cflag & WF_CONT)) /* if line is a continuation, scan up */ { --curr_y; row_p -= width2; } curr_x = 0; ps = row_p; break; case TAB: if (curr_x >= cur_win->width) { if (et_val & ET_TRUNC) goto noprint; if (w_overflow(wdot)) goto w2_exit; /* extend line */ } if (dflag) w_makecurs((unsigned char)(WN_seeall ? '\032' : ' ')); /* mark cursor */ *ps++ = (unsigned char) (WN_seeall ? '\032' : ' '); /* "tab" char or space */ *ps++ = curr_color; ++curr_x; if (dflag) { w_mark(MARK_RESTORE); /* end reverse video */ dflag = 0; incr_flag = -incr_flag; } while ((curr_x & tabmask) && (curr_x < cur_win->width)) /* finish tab */ { *ps++ = (unsigned char) (WN_seeall ? '\372' : ' '); /* center dot or space */ *ps++ = curr_color; /* write char at cursor */ ++curr_x; } break; case LF: while ((curr_y <= cur_win->end) && ((image+curr_y)->cflag & WF_BEG)) /* last screen row of this line */ { ++curr_y; row_p += width2; ps += width2; } if ((image+curr_y)->n < curr_x) (image+curr_y)->n = curr_x; (image+curr_y)->end = wdot; /* save char position that ended this line */ if (incr_flag < 0) goto w2_exit; /* incremental redraw..done */ if (dflag) /* if this LF is at dot */ { /* put cursor there, save char that was there */ #pragma check_pointer(off) cur_win->curs_loc = ps; /* save cursor location */ cur_win->curs_char = *ps; /* save character */ cur_win->curs_attr = *(ps+1); *ps = '\031'; *(ps+1) = *(color_table + (cur_win->buff == pbuff ? cur_win->line_feed_1 : cur_win->line_feed_2)); #pragma check_pointer() } /* if no cr found and not in last column, erase rest of line */ if (!cr_found && (curr_x < (image+curr_y)->n-1)) { (image+curr_y)->n = curr_x+1; if (curr_x < cur_win->width-1) /* if nonblanks to right, clear them */ for (pt = ps+2; pt < row_p + 2 * cur_win->width; ) { *pt++ = ' '; *pt++ = curr_norm_color; } } if (curr_y >= cur_win->size-1) /* if at end of screen, exit, but... */ goto w2_exit; if (((image+curr_y)->cflag & WF_CONT) && ((image+curr_y)->end - (image+curr_y)->start == 1)) /* if a now-empty cont. line, */ { /* flush it */ if (curr_y > 0) (image+curr_y-1)->cflag &= ~WF_BEG; /* remove "cont'd" flag from prev line */ } else { ++curr_y; /* down one line if not absorbing blank contin. line */ (image+curr_y)->n = 0; /* no chars yet on that line */ row_p += width2; ps += width2; } (image+curr_y)->start = wdot + 1; /* assume line starts with next char */ (image+curr_y)->col = curr_x; /* save starting column */ cr_found = 0; /* clear line continuation flags */ (image+curr_y)->cflag &= ~WF_CONT; if (curr_x) /* if not at left margin, erase beginning of line */ for (pt = row_p; pt < ps; ) { *pt++ = ' '; *pt++ = curr_norm_color; } break; case ESC: if (curr_x >= cur_win->width) { if (et_val & ET_TRUNC) goto noprint; if (w_overflow(wdot)) goto w2_exit; /* extend line */ } if (dflag) w_makecurs('$'); *ps++ = '$'; *ps++ = curr_color; ++curr_x; break; default: /* all other control chars print as ^X */ if (curr_x >= cur_win->width - 1) { if (et_val & ET_TRUNC) goto noprint; if (w_overflow(wdot)) goto w2_exit; } if (dflag) w_makecurs('^'); *ps++ = '^'; *ps++ = curr_color; if (dflag) { w_mark(MARK_RESTORE); /* if at cursor, clear reverse video */ dflag = 0; incr_flag = -incr_flag; } *ps++ = wc | 0100; *ps++ = curr_color; curr_x += 2; break; } /* end "switch" */ else /* a printing character */ { if (curr_x >= cur_win->width) { if (et_val & ET_TRUNC) goto noprint; if (w_overflow(wdot)) goto w2_exit; /* extend line */ } if (dflag) w_makecurs(wc); *ps++ = wc; *ps++ = curr_color; ++curr_x; } if (dflag) w_mark(MARK_RESTORE); /* if at cursor, clear reverse video */ if ((wc == FF) || (wc == VT)) /* these chars leave a display line blank */ { if (redraw_sw || (curr_x < (image+curr_y)->n)) { (image+curr_y)->n = curr_x; if (curr_x < cur_win->width) /* erase rest of line */ for (pt = ps; pt < row_p + 2 * cur_win->width; ) { *pt++ = ' '; *pt++ = curr_norm_color; } } (image+curr_y)->end = wdot; if (curr_y >= cur_win->size-1) goto w2_exit; /* quit if overflow screen */ row_p += width2; ps += width2 - 4; (image+ ++curr_y)->start = wdot + 1; cr_found = (image+curr_y)->cflag = 0; /* init new line */ if (curr_x -= 2) /* back up over ^X; if not at left margin, erase beginning of line */ for (pt = row_p; pt < ps; ) { *pt++ = ' '; *pt++ = curr_norm_color; } (image+curr_y)->col = curr_x; /* save starting column */ } 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 (pb->dot == pb->phys->z) { if (curr_x < cur_win->width) { w_makecurs(' '); *ps++ = ' '; *ps++ = curr_color; ++curr_x; } } /* clear rest of line if needed */ if (!cr_found && (redraw_sw || (curr_x < (image+curr_y)->n))) { (image+curr_y)->n = curr_x; if (curr_x < cur_win->width) for (pt = ps; pt < row_p + 2 * cur_win->width; ) { *pt++ = ' '; *pt++ = curr_norm_color; } } (image+curr_y)->end = wdot; /* save char at end of last line */ if ((image+curr_y)->n < curr_x) (image+curr_y)->n = curr_x; /* update length of last line */ w2_exit: cur_win->last_y = curr_y; /* record last used line on screen */ /* copy working buffer to video memory */ _fmemcpy((unsigned char _far *) video_buffer + w2_offset, screen + w2_offset, w2_count - 2* cur_win->left); } /* routine to handle line overflow */ /* returns nonzero if at end of window, zero otherwise */ /* arg is current character position */ static short w_overflow(long wd) { (image+curr_y)->end = wd - 1; /* last char ended a line */ (image+curr_y)->n = curr_x; if (curr_y >= cur_win->size -1) return(1); /* end of line at bottom of window */ (image+curr_y)->cflag |= WF_BEG; /* this line is continued */ (image+ ++curr_y)->cflag = WF_CONT; /* next line is a continuation */ (image+curr_y)->start = wd; /* char about to be printed is this line's first */ (image+curr_y)->col = 0; /* new line starts at left margin */ ps = (row_p += 2 * term_cols); /* next row */ *ps++ = '\030'; /* contin char */ *ps++ = *(color_table + cur_win->line_cont); /* contin color */ curr_x = 1; curr_color = curr_norm_color; return(0); } /* routine to set cursor attributes and save cursor location */ static void w_makecurs(unsigned char curs_c) { curr_color = *(color_table + (cur_win->buff == pbuff ? cur_win->curs_1 : cur_win->curs_2)); cur_win->curs_loc = ps; cur_win->curs_char = curs_c; cur_win->curs_y = curr_y; /* save location */ cur_win->curs_x = curr_x; } /* routine to clear margin between horizontal windows */ void clear_margins() { unsigned short i; unsigned char *p; for (i = buff1_win.start; i <= buff1_win.end; i++) { p = screen + 2 * (buff1_win.width + (WN_width * (i - 1))); *p++ = ' '; *p++ = 0; } } /* routine to handle marked region in window */ static void w_mark(unsigned char f) { static unsigned char mark_state; switch (f) { case MARK_CLEAR: curr_color = *(color_table + cur_win->norm); case MARK_INIT: mark_state = 0; break; case MARK_SET: curr_color = *(color_table + cur_win->mark); case MARK_BEGIN: mark_state = 1; break; case MARK_RESTORE: curr_color = *(color_table +(mark_state ? cur_win->mark :cur_win->norm)); break; } } /* routine to draw all windows */ static struct lbh *old_pbuff; static void window1_both(void) { display_mouse(MOUSE_SUSPEND); if (WN_scroll) { window1(&buff1_win, &lbuffs[0]); /* display primary window */ WN_origin = buff1_win.image->start; /* save first screen char pos */ if (WN_secondary) { window1(&buff2_win, &lbuffs[1]); /* display other windows */ WN_sec_origin = buff2_win.image->start; } if (WN_buff3 && buff3_win.size) { window1(&buff3_win, &lbuffs[2]); WN_buff3_origin = buff3_win.image->start; } if (WN_buff4 && buff4_win.size) { window1(&buff4_win, &lbuffs[3]); WN_buff4_origin = buff4_win.image->start; } set_window(&cmd_win, 0); /* command window again */ _settextposition(cur_win->size, char_count+1); buffs[0].buff_mod = MAX; /* reset "buffer modified" indicators */ buffs[1].buff_mod = MAX; buffs[2].buff_mod = MAX; buffs[3].buff_mod = MAX; } else { set_window(&whole_win, 0); /* full screen window */ _settextposition(1, char_count+1); } redraw_sw = 0; /* mark screen as updated */ old_pbuff = pbuff; /* save old pbuff */ display_mouse(MOUSE_RESUME); } /* routine to remove cursor */ static void w_rmcurs(void) { register unsigned char *p = cur_win->curs_loc; #pragma check_pointer(off) if (p != 0) { *p = cur_win->curs_char; *++p = cur_win->curs_attr; cur_win->curs_loc = NULL; } #pragma check_pointer() } /* routine to maintain the screen window */ /* if scroll mode is enabled, the screen is split and only the upper part */ /* is used by this routine; else the whole screen is used. */ static void window1(struct window *pw, struct lbh *pb) { int i, j, m, lflag; /* return if nothing has changed */ if (!redraw_sw && pbuff == old_pbuff && pb->dot == pw->last_dot && pb->phys->buff_mod == MAX && pw->last_mark == pb->mark && pw->last_mark2 == pb->mark2) return; set_window(pw, 0); /* set window and clear it */ pb0 = pb; /* save buffer pointer */ curr_x = curr_y = 0; /* indicate top row of window */ /* check forced redraw, or z before start of screen */ if (redraw_sw < 0 || pb->phys->z <= image->start || pw->size <= 1) window1_abs(); /* check whether pointer is before modified buffer location */ else if (pb->phys->buff_mod >= pb->dot) /* yes */ { if (pb->dot < image->start) /* if dot is before screen */ { w_setptr(pb, image->start, &w_p1); /* get to beginning of screen */ /* check whether screen begins with the last part of a continued line */ for (j = 0; ((image+j)->cflag & WF_CONT) && (j < pw->half_size); j++); if (j < pw->half_size) /* 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 */ } /* 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; (pb->dot < w_p1.dot) && (i < pw->half_size); ) i -= w_lines(-1, &w_p1, &w_p1); if ((pb->dot >= w_p1.dot) && (i < pw->size)) /* found point within reason */ window2(0); /* 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 (pb->dot <= (image+pw->last_y)->end) { w_setptr(pb, image->start, &w_p1); /* get to beginning of screen */ window2(0); } 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 (pb->phys->buff_mod < image->start) window1_abs(); /* modified point before screen - redraw fully */ else if (pb->phys->buff_mod <= (image+pw->last_y)->end) /* modified point on screen */ { for (m = 0; pb->phys->buff_mod > (image+m)->end; m++); /* find line with buff_mod */ w_setptr(pb, (image+m)->start, &w_p1); /* set a pointer to start of line with buff_mod */ j = (m < pw->half_size) ? pw->size - 1 - m : pw->half_size; /* maximum # of lines between buff_mod & dot */ for (i = 0; (pb->dot >= w_p1.dot) && (w_p1.dot < pb->phys->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 && (pb->dot == pb->phys->z)) i++; /* if at end, following a LF */ w_setptr(pb, image->start, &w_p1); /* get to beginning of screen */ if (i >= pw->size - m) /* if there are not enough blank lines on screen */ w_lines(i - pw->size + m, &w_p1, &w_p1); /* move start of screen up */ window2(0); /* rewrite newly cleared region */ } } /* end "modified point on screen */ else window1_after(); /* modified point after screen: scroll or redraw as appropriate */ } pw->last_dot = pb->dot; pw->last_mark = pb->mark; pw->last_mark2 = pb->mark2; } /* routine to redraw screen absolutely */ static void window1_abs(void) { int i, j; struct lbh *save_pbuff; /* save old pbuff during set_pointer call */ register struct lbh *pb = pb0; struct window *pw = cur_win; curr_y = curr_x = image->col = 0; /* y to start of window, x to 0 */ save_pbuff = pbuff; /* we need to use set_pointer in case there's no buffer */ pbuff = pb; /* but it needs to point to our buffer */ set_pointer(pb->dot, &w_p1); /* make a text buffer, if none, and refresh the display */ pbuff = save_pbuff; w_lines(0, &w_p1, &w_p1); /* do 0L */ if ((i = w_lines(pw->half_size, &w_p1, NULL)) == 0) i = 1; /* check how many lines after dot */ if (i > pw->half_size) i = pw->half_size; /* limit amount after dot */ for (j = 0; (j < pw->size - i) && (w_p1.dot > 0); ) /* find start of display area */ j -= w_lines(-1, &w_p1, &w_p1); if (j > pw->size - i) w_lines(1, &w_p1, &w_p1); /* if too far back, move up one line */ image->start = w_p1.dot; /* indicate where first window line starts */ window2(0); /* refresh the whole display */ } /* routine to move window downwards: scroll up or redraw as appropriate */ static void window1_after(void) { int i, lflag; register struct lbh *pb = pb0; register struct window *pw = cur_win; w_setptr(pb, (image+pw->size-1)->start, &w_p1); /* set pointer to start of last line on screen */ for (i = 0; (pb->dot >= w_p1.dot) && (w_p1.dot < pb->phys->z) && (i <= pw->half_size); ) 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 <= pw->half_size) /* found within n lines */ { if (lflag && (pb->dot == pb->phys->z)) ++i; /* if dot is at end of buffer after a LF */ w_setptr(pb, image->start, &w_p1); /* point to start of screen */ w_lines(i-1, &w_p1, &w_p1); /* and advance approp. # of lines */ window2(0); /* rewrite newly cleared region */ } else window1_abs(); /* move down is too far: redraw fully */ } /* routine to convert screen x,y coordinates to a character position */ /* called with coordinates and address of a variable */ /* returns char position as value, buffer selection in variable */ /* returns -1 if window not on, -2 if in middle margin of horizontal split screen */ long xy_to_dot(long x, long y, long *p_bufsel) { struct window *win_p; /* pointer to window containing mouse pointer */ struct win_row *row_p; /* pointer to a row in display data table */ struct qp m_dot; /* character pointer */ unsigned short m_count; /* character position */ unsigned char m_char; /* character */ long return_val; short i, bufsel; if (WN_scroll != 0) /* if window is on */ { if (WN_secondary >= 0) /* if not horizontal screen split */ { for (bufsel = 0, i = 0; i < MAX_BUFFERS; i++) /* set buffer ("end" is 1-based, y 0-based) */ if (buffer_wins[i].size != 0 && y >= buffer_wins[i].start-1) bufsel = i; *p_bufsel = bufsel; } else { if (x == buff1_win.width) /* if in middle margin */ return(-2); /* ...indicate so */ *p_bufsel = (x > buff1_win.width) ? 1 : 0; } win_p = &buffer_wins[*p_bufsel]; /* point to corresponding window */ x -= win_p->left; /* and normalize x to window's left margin */ /* point to row containing mouse pointer */ row_p = win_p->image + y - win_p->start + 1; if (y > win_p->start + win_p->last_y - 1) /* if mouse is beyond screen active area */ { return_val = (win_p->image + win_p->last_y)->end; /* set last char position on screen + 1 */ if (return_val > win_p->buff->phys->z) return_val = win_p->buff->phys->z; } else if (x <= row_p->col) return_val = row_p->start; /* at or before first column */ else if (x >= row_p->n) { return_val = row_p->end; /* at or after last column */ w_setptr(win_p->buff, return_val, &m_dot); /* if last char is a LF */ if (m_dot.p->ch[m_dot.c] == LF) --return_val; /* point before it */ } else /* somewhere in between */ { (void) w_setptr(win_p->buff, row_p->start, &m_dot); /* set pointer to first char on line */ m_count = row_p->col; if (row_p->cflag & WF_CONT) m_count += 1; /* contin lines start at col 2 */ for ( ; m_count < x; fwdc(&m_dot)) /* for each character on line */ { m_char = m_dot.p->ch[m_dot.c]; /* character */ if (m_char < ' ') switch (m_char) /* dispatch on control chars */ { case CR: /* CR with no LF in middle of line */ m_count = 0; break; case TAB: /* move to next tab stop */ m_count = (m_count | tabmask) + 1; if (m_count > x) --m_dot.dot; break; case ESC: /* ESC prints as $ - one position */ m_count++; break; default: /* other control chars print as ^X - 2 chars */ m_count += 2; if (m_count > x) --m_dot.dot; break; } else ++m_count; /* printing chars take one space */ } return_val = m_dot.dot; /* character position found */ } } else return_val = *p_bufsel = -1; /* window off: set dot to -1 */ return(return_val); } /* routine to move n chars on line */ /* call with # of columns, return new dot value */ static long x_to_dot(unsigned short x) { struct qp m_dot; unsigned short m_count; unsigned char m_char; (void) w_setptr(pbuff, pbuff->dot, &m_dot); /* set pointer to first char on line */ for (m_count = 0; m_count < x && m_dot.dot < pbuff->phys->z; fwdc(&m_dot)) /* for each character on line */ { m_char = m_dot.p->ch[m_dot.c]; /* character */ if (m_char < ' ') switch (m_char) /* dispatch on control chars */ { case FF: case VT: case CR: return(m_dot.dot); /* at end of line, for now */ case TAB: /* move to next tab stop */ m_count = (m_count | tabmask) + 1; if (m_count > x) --m_dot.dot; break; case ESC: /* ESC prints as $ - one position */ m_count++; break; default: /* other control chars print as ^X - 2 chars */ m_count += 2; if (m_count > x) --m_dot.dot; break; } else ++m_count; /* printing chars take one space */ } return(m_dot.dot); /* character position found */ } /* routine to move up or down n lines on display */ /* finds character location, then does nL, then moves to x position */ static long last_dis_dot; static long last_dis_buff; static unsigned short last_dis_x; static unsigned short last_dis_wrap; void display_lines(void) { struct window *pw = &buffer_wins[pbuff - &lbuffs[0]]; unsigned char window_on = (WN_scroll != 0) && (pw->size != 0); if (window_on != 0 /* screen must be on */ && (pbuff != &lbuffs[last_dis_buff] || pbuff->dot != last_dis_dot) ) { /* if dot has changed since last we looked... */ for (last_dis_wrap = 0; last_dis_wrap <= pw->curs_y; last_dis_wrap++) if (!((pw->image + pw->curs_y - last_dis_wrap)->cflag & WF_CONT)) break; if (last_dis_wrap > pw->curs_y) last_dis_wrap = 0; last_dis_x = pw->curs_x; last_dis_buff = pbuff - &lbuffs[0]; } pbuff->dot += lines(get_value(1)); /* move that many lines */ if (window_on != 0) last_dis_dot = pbuff->dot = x_to_dot(last_dis_x + (cur_win->width-1) * last_dis_wrap); }