1a5f0fb15SPaul Saab /* 2*b7780dbeSXin LI * Copyright (C) 1984-2019 Mark Nudelman 3a5f0fb15SPaul Saab * 4a5f0fb15SPaul Saab * You may distribute under the terms of either the GNU General Public 5a5f0fb15SPaul Saab * License or the Less License, as specified in the README file. 6a5f0fb15SPaul Saab * 796e55cc7SXin LI * For more information, see the README file. 8a5f0fb15SPaul Saab */ 9a5f0fb15SPaul Saab 10a5f0fb15SPaul Saab /* 11a5f0fb15SPaul Saab * Routines to manipulate the "line buffer". 12a5f0fb15SPaul Saab * The line buffer holds a line of output as it is being built 13a5f0fb15SPaul Saab * in preparation for output to the screen. 14a5f0fb15SPaul Saab */ 15a5f0fb15SPaul Saab 16a5f0fb15SPaul Saab #include "less.h" 1789dd99dcSXin LI #include "charset.h" 18f6b74a7dSXin LI #include "position.h" 19a5f0fb15SPaul Saab 20b2ea2440SXin LI #if MSDOS_COMPILER==WIN32C 21b2ea2440SXin LI #define WIN32_LEAN_AND_MEAN 22b2ea2440SXin LI #include <windows.h> 23b2ea2440SXin LI #endif 24b2ea2440SXin LI 2589dd99dcSXin LI static char *linebuf = NULL; /* Buffer which holds the current output line */ 26c9346414SPaul Saab static char *attr = NULL; /* Extension of linebuf to hold attributes */ 27c9346414SPaul Saab public int size_linebuf = 0; /* Size of line buffer (and attr buffer) */ 28a5f0fb15SPaul Saab 2989dd99dcSXin LI static int cshift; /* Current left-shift of output line buffer */ 30a5f0fb15SPaul Saab public int hshift; /* Desired left-shift of output line buffer */ 31c9346414SPaul Saab public int tabstops[TABSTOP_MAX] = { 0 }; /* Custom tabstops */ 32c9346414SPaul Saab public int ntabstops = 1; /* Number of tabstops */ 33c9346414SPaul Saab public int tabdefault = 8; /* Default repeated tabstops */ 3496e55cc7SXin LI public POSITION highest_hilite; /* Pos of last hilite in file found so far */ 35a5f0fb15SPaul Saab 36a5f0fb15SPaul Saab static int curr; /* Index into linebuf */ 37a5f0fb15SPaul Saab static int column; /* Printable length, accounting for 38a5f0fb15SPaul Saab backspaces, etc. */ 39b2ea2440SXin LI static int right_curr; 40b2ea2440SXin LI static int right_column; 41a5f0fb15SPaul Saab static int overstrike; /* Next char should overstrike previous char */ 42000ba3e8STim J. Robbins static int last_overstrike = AT_NORMAL; 43a5f0fb15SPaul Saab static int is_null_line; /* There is no current line */ 448ed69c6fSPaul Saab static int lmargin; /* Left margin */ 45a15691bfSXin LI static LWCHAR pendc; 46a5f0fb15SPaul Saab static POSITION pendpos; 47a5f0fb15SPaul Saab static char *end_ansi_chars; 4889dd99dcSXin LI static char *mid_ansi_chars; 49a5f0fb15SPaul Saab 50b2ea2440SXin LI static int attr_swidth LESSPARAMS ((int a)); 51b2ea2440SXin LI static int attr_ewidth LESSPARAMS ((int a)); 52b2ea2440SXin LI static int do_append LESSPARAMS ((LWCHAR ch, char *rep, POSITION pos)); 53a5f0fb15SPaul Saab 5489dd99dcSXin LI extern int sigs; 55a5f0fb15SPaul Saab extern int bs_mode; 56a5f0fb15SPaul Saab extern int linenums; 57a5f0fb15SPaul Saab extern int ctldisp; 58a5f0fb15SPaul Saab extern int twiddle; 59a5f0fb15SPaul Saab extern int binattr; 608ed69c6fSPaul Saab extern int status_col; 61a5f0fb15SPaul Saab extern int auto_wrap, ignaw; 62a5f0fb15SPaul Saab extern int bo_s_width, bo_e_width; 63a5f0fb15SPaul Saab extern int ul_s_width, ul_e_width; 64a5f0fb15SPaul Saab extern int bl_s_width, bl_e_width; 65a5f0fb15SPaul Saab extern int so_s_width, so_e_width; 66a5f0fb15SPaul Saab extern int sc_width, sc_height; 67a5f0fb15SPaul Saab extern int utf_mode; 688ed69c6fSPaul Saab extern POSITION start_attnpos; 698ed69c6fSPaul Saab extern POSITION end_attnpos; 70*b7780dbeSXin LI extern char rscroll_char; 71b2ea2440SXin LI extern int rscroll_attr; 72a5f0fb15SPaul Saab 7389dd99dcSXin LI static char mbc_buf[MAX_UTF_CHAR_LEN]; 7489dd99dcSXin LI static int mbc_buf_len = 0; 7589dd99dcSXin LI static int mbc_buf_index = 0; 7689dd99dcSXin LI static POSITION mbc_pos; 7789dd99dcSXin LI 78a5f0fb15SPaul Saab /* 79a5f0fb15SPaul Saab * Initialize from environment variables. 80a5f0fb15SPaul Saab */ 81a5f0fb15SPaul Saab public void 82*b7780dbeSXin LI init_line(VOID_PARAM) 83a5f0fb15SPaul Saab { 84a5f0fb15SPaul Saab end_ansi_chars = lgetenv("LESSANSIENDCHARS"); 85*b7780dbeSXin LI if (isnullenv(end_ansi_chars)) 86a5f0fb15SPaul Saab end_ansi_chars = "m"; 8789dd99dcSXin LI 8889dd99dcSXin LI mid_ansi_chars = lgetenv("LESSANSIMIDCHARS"); 89*b7780dbeSXin LI if (isnullenv(mid_ansi_chars)) 90a15691bfSXin LI mid_ansi_chars = "0123456789:;[?!\"'#%()*+ "; 9189dd99dcSXin LI 92c9346414SPaul Saab linebuf = (char *) ecalloc(LINEBUF_SIZE, sizeof(char)); 93c9346414SPaul Saab attr = (char *) ecalloc(LINEBUF_SIZE, sizeof(char)); 94c9346414SPaul Saab size_linebuf = LINEBUF_SIZE; 95c9346414SPaul Saab } 96c9346414SPaul Saab 97c9346414SPaul Saab /* 98c9346414SPaul Saab * Expand the line buffer. 99c9346414SPaul Saab */ 100c9346414SPaul Saab static int 101*b7780dbeSXin LI expand_linebuf(VOID_PARAM) 102c9346414SPaul Saab { 10389dd99dcSXin LI /* Double the size of the line buffer. */ 10489dd99dcSXin LI int new_size = size_linebuf * 2; 10589dd99dcSXin LI 10689dd99dcSXin LI /* Just realloc to expand the buffer, if we can. */ 10789dd99dcSXin LI #if HAVE_REALLOC 10889dd99dcSXin LI char *new_buf = (char *) realloc(linebuf, new_size); 10989dd99dcSXin LI char *new_attr = (char *) realloc(attr, new_size); 11089dd99dcSXin LI #else 111c9346414SPaul Saab char *new_buf = (char *) calloc(new_size, sizeof(char)); 112c9346414SPaul Saab char *new_attr = (char *) calloc(new_size, sizeof(char)); 11389dd99dcSXin LI #endif 114c9346414SPaul Saab if (new_buf == NULL || new_attr == NULL) 115c9346414SPaul Saab { 116c9346414SPaul Saab if (new_attr != NULL) 117c9346414SPaul Saab free(new_attr); 118c9346414SPaul Saab if (new_buf != NULL) 119c9346414SPaul Saab free(new_buf); 120c9346414SPaul Saab return 1; 121c9346414SPaul Saab } 122*b7780dbeSXin LI #if !HAVE_REALLOC 12389dd99dcSXin LI /* 12489dd99dcSXin LI * We just calloc'd the buffers; copy the old contents. 12589dd99dcSXin LI */ 126c9346414SPaul Saab memcpy(new_buf, linebuf, size_linebuf * sizeof(char)); 127c9346414SPaul Saab memcpy(new_attr, attr, size_linebuf * sizeof(char)); 128000ba3e8STim J. Robbins free(attr); 129000ba3e8STim J. Robbins free(linebuf); 13089dd99dcSXin LI #endif 131c9346414SPaul Saab linebuf = new_buf; 132c9346414SPaul Saab attr = new_attr; 133c9346414SPaul Saab size_linebuf = new_size; 134c9346414SPaul Saab return 0; 135a5f0fb15SPaul Saab } 136a5f0fb15SPaul Saab 137a5f0fb15SPaul Saab /* 13889dd99dcSXin LI * Is a character ASCII? 13989dd99dcSXin LI */ 14089dd99dcSXin LI public int 141f6b74a7dSXin LI is_ascii_char(ch) 142f6b74a7dSXin LI LWCHAR ch; 14389dd99dcSXin LI { 14489dd99dcSXin LI return (ch <= 0x7F); 14589dd99dcSXin LI } 14689dd99dcSXin LI 14789dd99dcSXin LI /* 148a5f0fb15SPaul Saab * Rewind the line buffer. 149a5f0fb15SPaul Saab */ 150a5f0fb15SPaul Saab public void 151*b7780dbeSXin LI prewind(VOID_PARAM) 152a5f0fb15SPaul Saab { 153a5f0fb15SPaul Saab curr = 0; 154a5f0fb15SPaul Saab column = 0; 155b2ea2440SXin LI right_curr = 0; 156b2ea2440SXin LI right_column = 0; 15789dd99dcSXin LI cshift = 0; 158a5f0fb15SPaul Saab overstrike = 0; 15989dd99dcSXin LI last_overstrike = AT_NORMAL; 16089dd99dcSXin LI mbc_buf_len = 0; 161a5f0fb15SPaul Saab is_null_line = 0; 162a5f0fb15SPaul Saab pendc = '\0'; 1638ed69c6fSPaul Saab lmargin = 0; 164000ba3e8STim J. Robbins if (status_col) 165b2ea2440SXin LI lmargin += 2; 166b2ea2440SXin LI } 167b2ea2440SXin LI 168b2ea2440SXin LI /* 169b2ea2440SXin LI * Set a character in the line buffer. 170b2ea2440SXin LI */ 171b2ea2440SXin LI static void 172b2ea2440SXin LI set_linebuf(n, ch, a) 173b2ea2440SXin LI int n; 174*b7780dbeSXin LI char ch; 175b2ea2440SXin LI char a; 176b2ea2440SXin LI { 177b2ea2440SXin LI linebuf[n] = ch; 178b2ea2440SXin LI attr[n] = a; 179b2ea2440SXin LI } 180b2ea2440SXin LI 181b2ea2440SXin LI /* 182b2ea2440SXin LI * Append a character to the line buffer. 183b2ea2440SXin LI */ 184b2ea2440SXin LI static void 185b2ea2440SXin LI add_linebuf(ch, a, w) 186*b7780dbeSXin LI char ch; 187b2ea2440SXin LI char a; 188b2ea2440SXin LI int w; 189b2ea2440SXin LI { 190b2ea2440SXin LI set_linebuf(curr++, ch, a); 191b2ea2440SXin LI column += w; 192a5f0fb15SPaul Saab } 193a5f0fb15SPaul Saab 194a5f0fb15SPaul Saab /* 195a5f0fb15SPaul Saab * Insert the line number (of the given position) into the line buffer. 196a5f0fb15SPaul Saab */ 197a5f0fb15SPaul Saab public void 198f6b74a7dSXin LI plinenum(pos) 199f6b74a7dSXin LI POSITION pos; 200a5f0fb15SPaul Saab { 2011ea31627SRobert Watson LINENUM linenum = 0; 2021ea31627SRobert Watson int i; 203a5f0fb15SPaul Saab 2048ed69c6fSPaul Saab if (linenums == OPT_ONPLUS) 2058ed69c6fSPaul Saab { 206a5f0fb15SPaul Saab /* 207a5f0fb15SPaul Saab * Get the line number and put it in the current line. 208a5f0fb15SPaul Saab * {{ Note: since find_linenum calls forw_raw_line, 209a5f0fb15SPaul Saab * it may seek in the input file, requiring the caller 210a5f0fb15SPaul Saab * of plinenum to re-seek if necessary. }} 2118ed69c6fSPaul Saab * {{ Since forw_raw_line modifies linebuf, we must 2128ed69c6fSPaul Saab * do this first, before storing anything in linebuf. }} 213a5f0fb15SPaul Saab */ 214000ba3e8STim J. Robbins linenum = find_linenum(pos); 2158ed69c6fSPaul Saab } 216a5f0fb15SPaul Saab 217a5f0fb15SPaul Saab /* 2188ed69c6fSPaul Saab * Display a status column if the -J option is set. 219a5f0fb15SPaul Saab */ 2208ed69c6fSPaul Saab if (status_col) 2218ed69c6fSPaul Saab { 222b2ea2440SXin LI int a = AT_NORMAL; 223b2ea2440SXin LI char c = posmark(pos); 224b2ea2440SXin LI if (c != 0) 225b2ea2440SXin LI a |= AT_HILITE; 2268ed69c6fSPaul Saab else 227b2ea2440SXin LI { 228b2ea2440SXin LI c = ' '; 229b2ea2440SXin LI if (start_attnpos != NULL_POSITION && 230b2ea2440SXin LI pos >= start_attnpos && pos <= end_attnpos) 231b2ea2440SXin LI a |= AT_HILITE; 2328ed69c6fSPaul Saab } 233b2ea2440SXin LI add_linebuf(c, a, 1); /* column 0: status */ 234b2ea2440SXin LI add_linebuf(' ', AT_NORMAL, 1); /* column 1: empty */ 235b2ea2440SXin LI } 236b2ea2440SXin LI 2378ed69c6fSPaul Saab /* 2388ed69c6fSPaul Saab * Display the line number at the start of each line 2398ed69c6fSPaul Saab * if the -N option is set. 2408ed69c6fSPaul Saab */ 2418ed69c6fSPaul Saab if (linenums == OPT_ONPLUS) 2428ed69c6fSPaul Saab { 243b2ea2440SXin LI char buf[INT_STRLEN_BOUND(linenum) + 2]; 244b2ea2440SXin LI int pad = 0; 245000ba3e8STim J. Robbins int n; 246000ba3e8STim J. Robbins 247000ba3e8STim J. Robbins linenumtoa(linenum, buf); 248a15691bfSXin LI n = (int) strlen(buf); 249000ba3e8STim J. Robbins if (n < MIN_LINENUM_WIDTH) 250b2ea2440SXin LI pad = MIN_LINENUM_WIDTH - n; 251b2ea2440SXin LI for (i = 0; i < pad; i++) 252b2ea2440SXin LI add_linebuf(' ', AT_NORMAL, 1); 253000ba3e8STim J. Robbins for (i = 0; i < n; i++) 254b2ea2440SXin LI add_linebuf(buf[i], AT_BOLD, 1); 255b2ea2440SXin LI add_linebuf(' ', AT_NORMAL, 1); 256b2ea2440SXin LI lmargin += n + pad + 1; 2578ed69c6fSPaul Saab } 2588ed69c6fSPaul Saab /* 2598ed69c6fSPaul Saab * Append enough spaces to bring us to the lmargin. 2608ed69c6fSPaul Saab */ 2618ed69c6fSPaul Saab while (column < lmargin) 262a5f0fb15SPaul Saab { 263b2ea2440SXin LI add_linebuf(' ', AT_NORMAL, 1); 2648ed69c6fSPaul Saab } 265a5f0fb15SPaul Saab } 266a5f0fb15SPaul Saab 267a5f0fb15SPaul Saab /* 268a5f0fb15SPaul Saab * Shift the input line left. 269a5f0fb15SPaul Saab * This means discarding N printable chars at the start of the buffer. 270a5f0fb15SPaul Saab */ 271a5f0fb15SPaul Saab static void 272f6b74a7dSXin LI pshift(shift) 273f6b74a7dSXin LI int shift; 274a5f0fb15SPaul Saab { 27589dd99dcSXin LI LWCHAR prev_ch = 0; 27689dd99dcSXin LI unsigned char c; 27789dd99dcSXin LI int shifted = 0; 27889dd99dcSXin LI int to; 27989dd99dcSXin LI int from; 28089dd99dcSXin LI int len; 28189dd99dcSXin LI int width; 28289dd99dcSXin LI int prev_attr; 28389dd99dcSXin LI int next_attr; 284a5f0fb15SPaul Saab 2858ed69c6fSPaul Saab if (shift > column - lmargin) 2868ed69c6fSPaul Saab shift = column - lmargin; 2878ed69c6fSPaul Saab if (shift > curr - lmargin) 2888ed69c6fSPaul Saab shift = curr - lmargin; 289a5f0fb15SPaul Saab 29089dd99dcSXin LI to = from = lmargin; 29189dd99dcSXin LI /* 29289dd99dcSXin LI * We keep on going when shifted == shift 29389dd99dcSXin LI * to get all combining chars. 29489dd99dcSXin LI */ 29589dd99dcSXin LI while (shifted <= shift && from < curr) 296a5f0fb15SPaul Saab { 29789dd99dcSXin LI c = linebuf[from]; 29859a2d077SXin LI if (ctldisp == OPT_ONPLUS && IS_CSI_START(c)) 29989dd99dcSXin LI { 30089dd99dcSXin LI /* Keep cumulative effect. */ 30189dd99dcSXin LI linebuf[to] = c; 30289dd99dcSXin LI attr[to++] = attr[from++]; 30389dd99dcSXin LI while (from < curr && linebuf[from]) 30489dd99dcSXin LI { 30589dd99dcSXin LI linebuf[to] = linebuf[from]; 30689dd99dcSXin LI attr[to++] = attr[from]; 30789dd99dcSXin LI if (!is_ansi_middle(linebuf[from++])) 30889dd99dcSXin LI break; 309a5f0fb15SPaul Saab } 31089dd99dcSXin LI continue; 31189dd99dcSXin LI } 31289dd99dcSXin LI 31389dd99dcSXin LI width = 0; 31489dd99dcSXin LI 31589dd99dcSXin LI if (!IS_ASCII_OCTET(c) && utf_mode) 31689dd99dcSXin LI { 31789dd99dcSXin LI /* Assumes well-formedness validation already done. */ 31889dd99dcSXin LI LWCHAR ch; 31989dd99dcSXin LI 32089dd99dcSXin LI len = utf_len(c); 32189dd99dcSXin LI if (from + len > curr) 32289dd99dcSXin LI break; 32389dd99dcSXin LI ch = get_wchar(linebuf + from); 32489dd99dcSXin LI if (!is_composing_char(ch) && !is_combining_char(prev_ch, ch)) 32589dd99dcSXin LI width = is_wide_char(ch) ? 2 : 1; 32689dd99dcSXin LI prev_ch = ch; 32789dd99dcSXin LI } else 32889dd99dcSXin LI { 32989dd99dcSXin LI len = 1; 33089dd99dcSXin LI if (c == '\b') 33189dd99dcSXin LI /* XXX - Incorrect if several '\b' in a row. */ 33289dd99dcSXin LI width = (utf_mode && is_wide_char(prev_ch)) ? -2 : -1; 33389dd99dcSXin LI else if (!control_char(c)) 33489dd99dcSXin LI width = 1; 33589dd99dcSXin LI prev_ch = 0; 33689dd99dcSXin LI } 33789dd99dcSXin LI 33889dd99dcSXin LI if (width == 2 && shift - shifted == 1) { 33989dd99dcSXin LI /* Should never happen when called by pshift_all(). */ 34089dd99dcSXin LI attr[to] = attr[from]; 34189dd99dcSXin LI /* 34289dd99dcSXin LI * Assume a wide_char will never be the first half of a 34389dd99dcSXin LI * combining_char pair, so reset prev_ch in case we're 34489dd99dcSXin LI * followed by a '\b'. 34589dd99dcSXin LI */ 34689dd99dcSXin LI prev_ch = linebuf[to++] = ' '; 34789dd99dcSXin LI from += len; 34889dd99dcSXin LI shifted++; 34989dd99dcSXin LI continue; 35089dd99dcSXin LI } 35189dd99dcSXin LI 35289dd99dcSXin LI /* Adjust width for magic cookies. */ 35389dd99dcSXin LI prev_attr = (to > 0) ? attr[to-1] : AT_NORMAL; 35489dd99dcSXin LI next_attr = (from + len < curr) ? attr[from + len] : prev_attr; 35589dd99dcSXin LI if (!is_at_equiv(attr[from], prev_attr) && 35689dd99dcSXin LI !is_at_equiv(attr[from], next_attr)) 35789dd99dcSXin LI { 35889dd99dcSXin LI width += attr_swidth(attr[from]); 35989dd99dcSXin LI if (from + len < curr) 36089dd99dcSXin LI width += attr_ewidth(attr[from]); 36189dd99dcSXin LI if (is_at_equiv(prev_attr, next_attr)) 36289dd99dcSXin LI { 36389dd99dcSXin LI width += attr_ewidth(prev_attr); 36489dd99dcSXin LI if (from + len < curr) 36589dd99dcSXin LI width += attr_swidth(next_attr); 36689dd99dcSXin LI } 36789dd99dcSXin LI } 36889dd99dcSXin LI 36989dd99dcSXin LI if (shift - shifted < width) 37089dd99dcSXin LI break; 37189dd99dcSXin LI from += len; 37289dd99dcSXin LI shifted += width; 37389dd99dcSXin LI if (shifted < 0) 37489dd99dcSXin LI shifted = 0; 37589dd99dcSXin LI } 37689dd99dcSXin LI while (from < curr) 37789dd99dcSXin LI { 37889dd99dcSXin LI linebuf[to] = linebuf[from]; 37989dd99dcSXin LI attr[to++] = attr[from++]; 38089dd99dcSXin LI } 38189dd99dcSXin LI curr = to; 38289dd99dcSXin LI column -= shifted; 38389dd99dcSXin LI cshift += shifted; 38489dd99dcSXin LI } 38589dd99dcSXin LI 38689dd99dcSXin LI /* 38789dd99dcSXin LI * 38889dd99dcSXin LI */ 38989dd99dcSXin LI public void 390*b7780dbeSXin LI pshift_all(VOID_PARAM) 39189dd99dcSXin LI { 39289dd99dcSXin LI pshift(column); 393a5f0fb15SPaul Saab } 394a5f0fb15SPaul Saab 395a5f0fb15SPaul Saab /* 396a5f0fb15SPaul Saab * Return the printing width of the start (enter) sequence 397a5f0fb15SPaul Saab * for a given character attribute. 398a5f0fb15SPaul Saab */ 399a5f0fb15SPaul Saab static int 400f6b74a7dSXin LI attr_swidth(a) 401f6b74a7dSXin LI int a; 402a5f0fb15SPaul Saab { 40389dd99dcSXin LI int w = 0; 40489dd99dcSXin LI 40589dd99dcSXin LI a = apply_at_specials(a); 40689dd99dcSXin LI 40789dd99dcSXin LI if (a & AT_UNDERLINE) 40889dd99dcSXin LI w += ul_s_width; 40989dd99dcSXin LI if (a & AT_BOLD) 41089dd99dcSXin LI w += bo_s_width; 41189dd99dcSXin LI if (a & AT_BLINK) 41289dd99dcSXin LI w += bl_s_width; 41389dd99dcSXin LI if (a & AT_STANDOUT) 41489dd99dcSXin LI w += so_s_width; 41589dd99dcSXin LI 41689dd99dcSXin LI return w; 417a5f0fb15SPaul Saab } 418a5f0fb15SPaul Saab 419a5f0fb15SPaul Saab /* 420a5f0fb15SPaul Saab * Return the printing width of the end (exit) sequence 421a5f0fb15SPaul Saab * for a given character attribute. 422a5f0fb15SPaul Saab */ 423a5f0fb15SPaul Saab static int 424f6b74a7dSXin LI attr_ewidth(a) 425f6b74a7dSXin LI int a; 426a5f0fb15SPaul Saab { 42789dd99dcSXin LI int w = 0; 42889dd99dcSXin LI 42989dd99dcSXin LI a = apply_at_specials(a); 43089dd99dcSXin LI 43189dd99dcSXin LI if (a & AT_UNDERLINE) 43289dd99dcSXin LI w += ul_e_width; 43389dd99dcSXin LI if (a & AT_BOLD) 43489dd99dcSXin LI w += bo_e_width; 43589dd99dcSXin LI if (a & AT_BLINK) 43689dd99dcSXin LI w += bl_e_width; 43789dd99dcSXin LI if (a & AT_STANDOUT) 43889dd99dcSXin LI w += so_e_width; 43989dd99dcSXin LI 44089dd99dcSXin LI return w; 441a5f0fb15SPaul Saab } 442a5f0fb15SPaul Saab 443a5f0fb15SPaul Saab /* 444a5f0fb15SPaul Saab * Return the printing width of a given character and attribute, 445a5f0fb15SPaul Saab * if the character were added to the current position in the line buffer. 446a5f0fb15SPaul Saab * Adding a character with a given attribute may cause an enter or exit 447a5f0fb15SPaul Saab * attribute sequence to be inserted, so this must be taken into account. 448a5f0fb15SPaul Saab */ 449a5f0fb15SPaul Saab static int 450f6b74a7dSXin LI pwidth(ch, a, prev_ch) 451f6b74a7dSXin LI LWCHAR ch; 452f6b74a7dSXin LI int a; 453f6b74a7dSXin LI LWCHAR prev_ch; 454a5f0fb15SPaul Saab { 45589dd99dcSXin LI int w; 456a5f0fb15SPaul Saab 45789dd99dcSXin LI if (ch == '\b') 458a5f0fb15SPaul Saab /* 45989dd99dcSXin LI * Backspace moves backwards one or two positions. 46089dd99dcSXin LI * XXX - Incorrect if several '\b' in a row. 461a5f0fb15SPaul Saab */ 46289dd99dcSXin LI return (utf_mode && is_wide_char(prev_ch)) ? -2 : -1; 463a5f0fb15SPaul Saab 46489dd99dcSXin LI if (!utf_mode || is_ascii_char(ch)) 46589dd99dcSXin LI { 46689dd99dcSXin LI if (control_char((char)ch)) 46789dd99dcSXin LI { 468a5f0fb15SPaul Saab /* 46989dd99dcSXin LI * Control characters do unpredictable things, 470a5f0fb15SPaul Saab * so we don't even try to guess; say it doesn't move. 471a5f0fb15SPaul Saab * This can only happen if the -r flag is in effect. 472a5f0fb15SPaul Saab */ 473a5f0fb15SPaul Saab return (0); 47489dd99dcSXin LI } 47589dd99dcSXin LI } else 47689dd99dcSXin LI { 47789dd99dcSXin LI if (is_composing_char(ch) || is_combining_char(prev_ch, ch)) 47889dd99dcSXin LI { 47989dd99dcSXin LI /* 48089dd99dcSXin LI * Composing and combining chars take up no space. 48189dd99dcSXin LI * 48289dd99dcSXin LI * Some terminals, upon failure to compose a 48389dd99dcSXin LI * composing character with the character(s) that 48489dd99dcSXin LI * precede(s) it will actually take up one column 48589dd99dcSXin LI * for the composing character; there isn't much 48689dd99dcSXin LI * we could do short of testing the (complex) 48789dd99dcSXin LI * composition process ourselves and printing 48889dd99dcSXin LI * a binary representation when it fails. 48989dd99dcSXin LI */ 49089dd99dcSXin LI return (0); 49189dd99dcSXin LI } 49289dd99dcSXin LI } 493a5f0fb15SPaul Saab 494a5f0fb15SPaul Saab /* 49589dd99dcSXin LI * Other characters take one or two columns, 496a5f0fb15SPaul Saab * plus the width of any attribute enter/exit sequence. 497a5f0fb15SPaul Saab */ 498a5f0fb15SPaul Saab w = 1; 49989dd99dcSXin LI if (is_wide_char(ch)) 50089dd99dcSXin LI w++; 50189dd99dcSXin LI if (curr > 0 && !is_at_equiv(attr[curr-1], a)) 502a5f0fb15SPaul Saab w += attr_ewidth(attr[curr-1]); 50389dd99dcSXin LI if ((apply_at_specials(a) != AT_NORMAL) && 50489dd99dcSXin LI (curr == 0 || !is_at_equiv(attr[curr-1], a))) 505a5f0fb15SPaul Saab w += attr_swidth(a); 506a5f0fb15SPaul Saab return (w); 507a5f0fb15SPaul Saab } 508a5f0fb15SPaul Saab 509a5f0fb15SPaul Saab /* 51089dd99dcSXin LI * Delete to the previous base character in the line buffer. 51189dd99dcSXin LI * Return 1 if one is found. 512a5f0fb15SPaul Saab */ 51389dd99dcSXin LI static int 514*b7780dbeSXin LI backc(VOID_PARAM) 515a5f0fb15SPaul Saab { 51689dd99dcSXin LI LWCHAR prev_ch; 517f6b74a7dSXin LI char *p = linebuf + curr; 51889dd99dcSXin LI LWCHAR ch = step_char(&p, -1, linebuf + lmargin); 51989dd99dcSXin LI int width; 52089dd99dcSXin LI 52189dd99dcSXin LI /* This assumes that there is no '\b' in linebuf. */ 52289dd99dcSXin LI while ( curr > lmargin 52389dd99dcSXin LI && column > lmargin 52489dd99dcSXin LI && (!(attr[curr - 1] & (AT_ANSI|AT_BINARY)))) 52589dd99dcSXin LI { 526a15691bfSXin LI curr = (int) (p - linebuf); 52789dd99dcSXin LI prev_ch = step_char(&p, -1, linebuf + lmargin); 52889dd99dcSXin LI width = pwidth(ch, attr[curr], prev_ch); 52989dd99dcSXin LI column -= width; 53089dd99dcSXin LI if (width > 0) 53189dd99dcSXin LI return 1; 53289dd99dcSXin LI ch = prev_ch; 53389dd99dcSXin LI } 53489dd99dcSXin LI 53589dd99dcSXin LI return 0; 536a5f0fb15SPaul Saab } 537a5f0fb15SPaul Saab 538a5f0fb15SPaul Saab /* 539a5f0fb15SPaul Saab * Are we currently within a recognized ANSI escape sequence? 540a5f0fb15SPaul Saab */ 541a5f0fb15SPaul Saab static int 542*b7780dbeSXin LI in_ansi_esc_seq(VOID_PARAM) 543a5f0fb15SPaul Saab { 544f6b74a7dSXin LI char *p; 545a5f0fb15SPaul Saab 546a5f0fb15SPaul Saab /* 547a5f0fb15SPaul Saab * Search backwards for either an ESC (which means we ARE in a seq); 548a5f0fb15SPaul Saab * or an end char (which means we're NOT in a seq). 549a5f0fb15SPaul Saab */ 55089dd99dcSXin LI for (p = &linebuf[curr]; p > linebuf; ) 551a5f0fb15SPaul Saab { 55289dd99dcSXin LI LWCHAR ch = step_char(&p, -1, linebuf); 55359a2d077SXin LI if (IS_CSI_START(ch)) 554a5f0fb15SPaul Saab return (1); 55589dd99dcSXin LI if (!is_ansi_middle(ch)) 556a5f0fb15SPaul Saab return (0); 557a5f0fb15SPaul Saab } 558a5f0fb15SPaul Saab return (0); 559a5f0fb15SPaul Saab } 560a5f0fb15SPaul Saab 561a5f0fb15SPaul Saab /* 562c9346414SPaul Saab * Is a character the end of an ANSI escape sequence? 563c9346414SPaul Saab */ 564c9346414SPaul Saab public int 565f6b74a7dSXin LI is_ansi_end(ch) 566f6b74a7dSXin LI LWCHAR ch; 567c9346414SPaul Saab { 56889dd99dcSXin LI if (!is_ascii_char(ch)) 56989dd99dcSXin LI return (0); 57089dd99dcSXin LI return (strchr(end_ansi_chars, (char) ch) != NULL); 57189dd99dcSXin LI } 57289dd99dcSXin LI 57389dd99dcSXin LI /* 574b2ea2440SXin LI * Can a char appear in an ANSI escape sequence, before the end char? 57589dd99dcSXin LI */ 57689dd99dcSXin LI public int 577f6b74a7dSXin LI is_ansi_middle(ch) 578f6b74a7dSXin LI LWCHAR ch; 57989dd99dcSXin LI { 58089dd99dcSXin LI if (!is_ascii_char(ch)) 58189dd99dcSXin LI return (0); 58289dd99dcSXin LI if (is_ansi_end(ch)) 58389dd99dcSXin LI return (0); 58489dd99dcSXin LI return (strchr(mid_ansi_chars, (char) ch) != NULL); 585c9346414SPaul Saab } 586c9346414SPaul Saab 587c9346414SPaul Saab /* 588b2ea2440SXin LI * Skip past an ANSI escape sequence. 589b2ea2440SXin LI * pp is initially positioned just after the CSI_START char. 590b2ea2440SXin LI */ 591b2ea2440SXin LI public void 592b2ea2440SXin LI skip_ansi(pp, limit) 593b2ea2440SXin LI char **pp; 594b2ea2440SXin LI constant char *limit; 595b2ea2440SXin LI { 596b2ea2440SXin LI LWCHAR c; 597b2ea2440SXin LI do { 598b2ea2440SXin LI c = step_char(pp, +1, limit); 599b2ea2440SXin LI } while (*pp < limit && is_ansi_middle(c)); 600b2ea2440SXin LI /* Note that we discard final char, for which is_ansi_middle is false. */ 601b2ea2440SXin LI } 602b2ea2440SXin LI 603b2ea2440SXin LI 604b2ea2440SXin LI /* 605a5f0fb15SPaul Saab * Append a character and attribute to the line buffer. 606a5f0fb15SPaul Saab */ 60789dd99dcSXin LI #define STORE_CHAR(ch,a,rep,pos) \ 60889dd99dcSXin LI do { \ 60989dd99dcSXin LI if (store_char((ch),(a),(rep),(pos))) return (1); \ 61089dd99dcSXin LI } while (0) 611c9346414SPaul Saab 612a5f0fb15SPaul Saab static int 613f6b74a7dSXin LI store_char(ch, a, rep, pos) 614f6b74a7dSXin LI LWCHAR ch; 615f6b74a7dSXin LI int a; 616f6b74a7dSXin LI char *rep; 617f6b74a7dSXin LI POSITION pos; 618a5f0fb15SPaul Saab { 61989dd99dcSXin LI int w; 62089dd99dcSXin LI int replen; 62189dd99dcSXin LI char cs; 622a5f0fb15SPaul Saab 62389dd99dcSXin LI w = (a & (AT_UNDERLINE|AT_BOLD)); /* Pre-use w. */ 62489dd99dcSXin LI if (w != AT_NORMAL) 62589dd99dcSXin LI last_overstrike = w; 62689dd99dcSXin LI 627a5f0fb15SPaul Saab #if HILITE_SEARCH 62889dd99dcSXin LI { 62989dd99dcSXin LI int matches; 63089dd99dcSXin LI if (is_hilited(pos, pos+1, 0, &matches)) 631c9346414SPaul Saab { 632a5f0fb15SPaul Saab /* 633a5f0fb15SPaul Saab * This character should be highlighted. 634a5f0fb15SPaul Saab * Override the attribute passed in. 635a5f0fb15SPaul Saab */ 63689dd99dcSXin LI if (a != AT_ANSI) 63796e55cc7SXin LI { 63896e55cc7SXin LI if (highest_hilite != NULL_POSITION && 63996e55cc7SXin LI pos > highest_hilite) 64096e55cc7SXin LI highest_hilite = pos; 64189dd99dcSXin LI a |= AT_HILITE; 64289dd99dcSXin LI } 643c9346414SPaul Saab } 64496e55cc7SXin LI } 645a5f0fb15SPaul Saab #endif 64689dd99dcSXin LI 647a5f0fb15SPaul Saab if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq()) 64889dd99dcSXin LI { 64989dd99dcSXin LI if (!is_ansi_end(ch) && !is_ansi_middle(ch)) { 65089dd99dcSXin LI /* Remove whole unrecognized sequence. */ 651f6b74a7dSXin LI char *p = &linebuf[curr]; 6527374caaaSXin LI LWCHAR bch; 6537374caaaSXin LI do { 6547374caaaSXin LI bch = step_char(&p, -1, linebuf); 6557374caaaSXin LI } while (p > linebuf && !IS_CSI_START(bch)); 656a15691bfSXin LI curr = (int) (p - linebuf); 65789dd99dcSXin LI return 0; 65889dd99dcSXin LI } 65989dd99dcSXin LI a = AT_ANSI; /* Will force re-AT_'ing around it. */ 660a5f0fb15SPaul Saab w = 0; 66189dd99dcSXin LI } 66259a2d077SXin LI else if (ctldisp == OPT_ONPLUS && IS_CSI_START(ch)) 66389dd99dcSXin LI { 66489dd99dcSXin LI a = AT_ANSI; /* Will force re-AT_'ing around it. */ 66589dd99dcSXin LI w = 0; 66689dd99dcSXin LI } 667a5f0fb15SPaul Saab else 66889dd99dcSXin LI { 669f6b74a7dSXin LI char *p = &linebuf[curr]; 67089dd99dcSXin LI LWCHAR prev_ch = step_char(&p, -1, linebuf); 67189dd99dcSXin LI w = pwidth(ch, a, prev_ch); 67289dd99dcSXin LI } 67389dd99dcSXin LI 674a5f0fb15SPaul Saab if (ctldisp != OPT_ON && column + w + attr_ewidth(a) > sc_width) 675a5f0fb15SPaul Saab /* 676a5f0fb15SPaul Saab * Won't fit on screen. 677a5f0fb15SPaul Saab */ 678a5f0fb15SPaul Saab return (1); 679a5f0fb15SPaul Saab 68089dd99dcSXin LI if (rep == NULL) 68189dd99dcSXin LI { 68289dd99dcSXin LI cs = (char) ch; 68389dd99dcSXin LI rep = &cs; 68489dd99dcSXin LI replen = 1; 68589dd99dcSXin LI } else 68689dd99dcSXin LI { 68789dd99dcSXin LI replen = utf_len(rep[0]); 68889dd99dcSXin LI } 68989dd99dcSXin LI if (curr + replen >= size_linebuf-6) 690c9346414SPaul Saab { 691a5f0fb15SPaul Saab /* 692a5f0fb15SPaul Saab * Won't fit in line buffer. 693c9346414SPaul Saab * Try to expand it. 694a5f0fb15SPaul Saab */ 695c9346414SPaul Saab if (expand_linebuf()) 696a5f0fb15SPaul Saab return (1); 697c9346414SPaul Saab } 698a5f0fb15SPaul Saab 699b2ea2440SXin LI if (column > right_column && w > 0) 700b2ea2440SXin LI { 701b2ea2440SXin LI right_column = column; 702b2ea2440SXin LI right_curr = curr; 703b2ea2440SXin LI } 704b2ea2440SXin LI 70589dd99dcSXin LI while (replen-- > 0) 706a5f0fb15SPaul Saab { 707b2ea2440SXin LI add_linebuf(*rep++, a, 0); 70889dd99dcSXin LI } 709a5f0fb15SPaul Saab column += w; 710a5f0fb15SPaul Saab return (0); 711a5f0fb15SPaul Saab } 712a5f0fb15SPaul Saab 713a5f0fb15SPaul Saab /* 714c9346414SPaul Saab * Append a tab to the line buffer. 715c9346414SPaul Saab * Store spaces to represent the tab. 716c9346414SPaul Saab */ 717c9346414SPaul Saab #define STORE_TAB(a,pos) \ 718c9346414SPaul Saab do { if (store_tab((a),(pos))) return (1); } while (0) 719c9346414SPaul Saab 720c9346414SPaul Saab static int 721f6b74a7dSXin LI store_tab(attr, pos) 722f6b74a7dSXin LI int attr; 723f6b74a7dSXin LI POSITION pos; 724c9346414SPaul Saab { 725c9346414SPaul Saab int to_tab = column + cshift - lmargin; 726c9346414SPaul Saab int i; 727c9346414SPaul Saab 728c9346414SPaul Saab if (ntabstops < 2 || to_tab >= tabstops[ntabstops-1]) 729c9346414SPaul Saab to_tab = tabdefault - 730c9346414SPaul Saab ((to_tab - tabstops[ntabstops-1]) % tabdefault); 731c9346414SPaul Saab else 732c9346414SPaul Saab { 733c9346414SPaul Saab for (i = ntabstops - 2; i >= 0; i--) 734c9346414SPaul Saab if (to_tab >= tabstops[i]) 735c9346414SPaul Saab break; 736c9346414SPaul Saab to_tab = tabstops[i+1] - to_tab; 737c9346414SPaul Saab } 738c9346414SPaul Saab 73989dd99dcSXin LI if (column + to_tab - 1 + pwidth(' ', attr, 0) + attr_ewidth(attr) > sc_width) 74089dd99dcSXin LI return 1; 74189dd99dcSXin LI 742c9346414SPaul Saab do { 74389dd99dcSXin LI STORE_CHAR(' ', attr, " ", pos); 744c9346414SPaul Saab } while (--to_tab > 0); 745c9346414SPaul Saab return 0; 746c9346414SPaul Saab } 747c9346414SPaul Saab 74889dd99dcSXin LI #define STORE_PRCHAR(c, pos) \ 74989dd99dcSXin LI do { if (store_prchar((c), (pos))) return 1; } while (0) 75089dd99dcSXin LI 75189dd99dcSXin LI static int 752f6b74a7dSXin LI store_prchar(c, pos) 753f6b74a7dSXin LI LWCHAR c; 754f6b74a7dSXin LI POSITION pos; 75589dd99dcSXin LI { 75689dd99dcSXin LI char *s; 75789dd99dcSXin LI 75889dd99dcSXin LI /* 75989dd99dcSXin LI * Convert to printable representation. 76089dd99dcSXin LI */ 76189dd99dcSXin LI s = prchar(c); 76289dd99dcSXin LI 76389dd99dcSXin LI /* 76489dd99dcSXin LI * Make sure we can get the entire representation 76589dd99dcSXin LI * of the character on this line. 76689dd99dcSXin LI */ 76789dd99dcSXin LI if (column + (int) strlen(s) - 1 + 76889dd99dcSXin LI pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width) 76989dd99dcSXin LI return 1; 77089dd99dcSXin LI 77189dd99dcSXin LI for ( ; *s != 0; s++) 77289dd99dcSXin LI STORE_CHAR(*s, AT_BINARY, NULL, pos); 77389dd99dcSXin LI 77489dd99dcSXin LI return 0; 77589dd99dcSXin LI } 77689dd99dcSXin LI 77789dd99dcSXin LI static int 778f6b74a7dSXin LI flush_mbc_buf(pos) 779f6b74a7dSXin LI POSITION pos; 78089dd99dcSXin LI { 78189dd99dcSXin LI int i; 78289dd99dcSXin LI 78389dd99dcSXin LI for (i = 0; i < mbc_buf_index; i++) 78489dd99dcSXin LI if (store_prchar(mbc_buf[i], pos)) 78589dd99dcSXin LI return mbc_buf_index - i; 78689dd99dcSXin LI 78789dd99dcSXin LI return 0; 78889dd99dcSXin LI } 78989dd99dcSXin LI 790c9346414SPaul Saab /* 791a5f0fb15SPaul Saab * Append a character to the line buffer. 792a5f0fb15SPaul Saab * Expand tabs into spaces, handle underlining, boldfacing, etc. 793a5f0fb15SPaul Saab * Returns 0 if ok, 1 if couldn't fit in buffer. 794a5f0fb15SPaul Saab */ 795a5f0fb15SPaul Saab public int 796f6b74a7dSXin LI pappend(c, pos) 797f6b74a7dSXin LI unsigned char c; 798f6b74a7dSXin LI POSITION pos; 799a5f0fb15SPaul Saab { 800a5f0fb15SPaul Saab int r; 801a5f0fb15SPaul Saab 802a5f0fb15SPaul Saab if (pendc) 803a5f0fb15SPaul Saab { 804a15691bfSXin LI if (c == '\r' && pendc == '\r') 805a15691bfSXin LI return (0); 80689dd99dcSXin LI if (do_append(pendc, NULL, pendpos)) 807a5f0fb15SPaul Saab /* 808a5f0fb15SPaul Saab * Oops. We've probably lost the char which 809a5f0fb15SPaul Saab * was in pendc, since caller won't back up. 810a5f0fb15SPaul Saab */ 811a5f0fb15SPaul Saab return (1); 812a5f0fb15SPaul Saab pendc = '\0'; 813a5f0fb15SPaul Saab } 814a5f0fb15SPaul Saab 815a5f0fb15SPaul Saab if (c == '\r' && bs_mode == BS_SPECIAL) 816a5f0fb15SPaul Saab { 81789dd99dcSXin LI if (mbc_buf_len > 0) /* utf_mode must be on. */ 81889dd99dcSXin LI { 81989dd99dcSXin LI /* Flush incomplete (truncated) sequence. */ 82089dd99dcSXin LI r = flush_mbc_buf(mbc_pos); 82189dd99dcSXin LI mbc_buf_index = r + 1; 82289dd99dcSXin LI mbc_buf_len = 0; 82389dd99dcSXin LI if (r) 82489dd99dcSXin LI return (mbc_buf_index); 82589dd99dcSXin LI } 82689dd99dcSXin LI 827a5f0fb15SPaul Saab /* 828a5f0fb15SPaul Saab * Don't put the CR into the buffer until we see 829a5f0fb15SPaul Saab * the next char. If the next char is a newline, 830a5f0fb15SPaul Saab * discard the CR. 831a5f0fb15SPaul Saab */ 832a5f0fb15SPaul Saab pendc = c; 833a5f0fb15SPaul Saab pendpos = pos; 834a5f0fb15SPaul Saab return (0); 835a5f0fb15SPaul Saab } 836a5f0fb15SPaul Saab 83789dd99dcSXin LI if (!utf_mode) 83889dd99dcSXin LI { 839a15691bfSXin LI r = do_append(c, NULL, pos); 84089dd99dcSXin LI } else 84189dd99dcSXin LI { 84289dd99dcSXin LI /* Perform strict validation in all possible cases. */ 84389dd99dcSXin LI if (mbc_buf_len == 0) 84489dd99dcSXin LI { 84589dd99dcSXin LI retry: 84689dd99dcSXin LI mbc_buf_index = 1; 84789dd99dcSXin LI *mbc_buf = c; 84889dd99dcSXin LI if (IS_ASCII_OCTET(c)) 849a15691bfSXin LI r = do_append(c, NULL, pos); 85089dd99dcSXin LI else if (IS_UTF8_LEAD(c)) 85189dd99dcSXin LI { 85289dd99dcSXin LI mbc_buf_len = utf_len(c); 85389dd99dcSXin LI mbc_pos = pos; 85489dd99dcSXin LI return (0); 85589dd99dcSXin LI } else 85689dd99dcSXin LI /* UTF8_INVALID or stray UTF8_TRAIL */ 85789dd99dcSXin LI r = flush_mbc_buf(pos); 85889dd99dcSXin LI } else if (IS_UTF8_TRAIL(c)) 85989dd99dcSXin LI { 86089dd99dcSXin LI mbc_buf[mbc_buf_index++] = c; 86189dd99dcSXin LI if (mbc_buf_index < mbc_buf_len) 86289dd99dcSXin LI return (0); 863a15691bfSXin LI if (is_utf8_well_formed(mbc_buf, mbc_buf_index)) 86489dd99dcSXin LI r = do_append(get_wchar(mbc_buf), mbc_buf, mbc_pos); 86589dd99dcSXin LI else 86689dd99dcSXin LI /* Complete, but not shortest form, sequence. */ 86789dd99dcSXin LI mbc_buf_index = r = flush_mbc_buf(mbc_pos); 86889dd99dcSXin LI mbc_buf_len = 0; 86989dd99dcSXin LI } else 87089dd99dcSXin LI { 87189dd99dcSXin LI /* Flush incomplete (truncated) sequence. */ 87289dd99dcSXin LI r = flush_mbc_buf(mbc_pos); 87389dd99dcSXin LI mbc_buf_index = r + 1; 87489dd99dcSXin LI mbc_buf_len = 0; 87589dd99dcSXin LI /* Handle new char. */ 87689dd99dcSXin LI if (!r) 87789dd99dcSXin LI goto retry; 87889dd99dcSXin LI } 87989dd99dcSXin LI } 88089dd99dcSXin LI 881a5f0fb15SPaul Saab /* 882a5f0fb15SPaul Saab * If we need to shift the line, do it. 883a5f0fb15SPaul Saab * But wait until we get to at least the middle of the screen, 884a5f0fb15SPaul Saab * so shifting it doesn't affect the chars we're currently 885a5f0fb15SPaul Saab * pappending. (Bold & underline can get messed up otherwise.) 886a5f0fb15SPaul Saab */ 887a5f0fb15SPaul Saab if (cshift < hshift && column > sc_width / 2) 888c9346414SPaul Saab { 889c9346414SPaul Saab linebuf[curr] = '\0'; 890a5f0fb15SPaul Saab pshift(hshift - cshift); 891c9346414SPaul Saab } 89289dd99dcSXin LI if (r) 89389dd99dcSXin LI { 89489dd99dcSXin LI /* How many chars should caller back up? */ 89589dd99dcSXin LI r = (!utf_mode) ? 1 : mbc_buf_index; 89689dd99dcSXin LI } 897a5f0fb15SPaul Saab return (r); 898a5f0fb15SPaul Saab } 899a5f0fb15SPaul Saab 900a5f0fb15SPaul Saab static int 901f6b74a7dSXin LI do_append(ch, rep, pos) 902f6b74a7dSXin LI LWCHAR ch; 903f6b74a7dSXin LI char *rep; 904f6b74a7dSXin LI POSITION pos; 905a5f0fb15SPaul Saab { 9061ea31627SRobert Watson int a; 90789dd99dcSXin LI LWCHAR prev_ch; 908a5f0fb15SPaul Saab 90989dd99dcSXin LI a = AT_NORMAL; 910a5f0fb15SPaul Saab 91189dd99dcSXin LI if (ch == '\b') 912a5f0fb15SPaul Saab { 91389dd99dcSXin LI if (bs_mode == BS_CONTROL) 914a5f0fb15SPaul Saab goto do_control_char; 91589dd99dcSXin LI 91689dd99dcSXin LI /* 91789dd99dcSXin LI * A better test is needed here so we don't 91889dd99dcSXin LI * backspace over part of the printed 91989dd99dcSXin LI * representation of a binary character. 92089dd99dcSXin LI */ 92189dd99dcSXin LI if ( curr <= lmargin 92289dd99dcSXin LI || column <= lmargin 92389dd99dcSXin LI || (attr[curr - 1] & (AT_ANSI|AT_BINARY))) 92489dd99dcSXin LI STORE_PRCHAR('\b', pos); 92589dd99dcSXin LI else if (bs_mode == BS_NORMAL) 92689dd99dcSXin LI STORE_CHAR(ch, AT_NORMAL, NULL, pos); 92789dd99dcSXin LI else if (bs_mode == BS_SPECIAL) 92889dd99dcSXin LI overstrike = backc(); 92989dd99dcSXin LI 93089dd99dcSXin LI return 0; 931a5f0fb15SPaul Saab } 93289dd99dcSXin LI 93389dd99dcSXin LI if (overstrike > 0) 934a5f0fb15SPaul Saab { 935a5f0fb15SPaul Saab /* 936a5f0fb15SPaul Saab * Overstrike the character at the current position 937a5f0fb15SPaul Saab * in the line buffer. This will cause either 938a5f0fb15SPaul Saab * underline (if a "_" is overstruck), 939a5f0fb15SPaul Saab * bold (if an identical character is overstruck), 940a5f0fb15SPaul Saab * or just deletion of the character in the buffer. 941a5f0fb15SPaul Saab */ 94289dd99dcSXin LI overstrike = utf_mode ? -1 : 0; 943a15691bfSXin LI if (utf_mode) 944a15691bfSXin LI { 94589dd99dcSXin LI /* To be correct, this must be a base character. */ 94689dd99dcSXin LI prev_ch = get_wchar(linebuf + curr); 947a15691bfSXin LI } else 948a15691bfSXin LI { 949a15691bfSXin LI prev_ch = (unsigned char) linebuf[curr]; 950a15691bfSXin LI } 95189dd99dcSXin LI a = attr[curr]; 95289dd99dcSXin LI if (ch == prev_ch) 953c9346414SPaul Saab { 954000ba3e8STim J. Robbins /* 955000ba3e8STim J. Robbins * Overstriking a char with itself means make it bold. 956000ba3e8STim J. Robbins * But overstriking an underscore with itself is 957000ba3e8STim J. Robbins * ambiguous. It could mean make it bold, or 958000ba3e8STim J. Robbins * it could mean make it underlined. 959000ba3e8STim J. Robbins * Use the previous overstrike to resolve it. 960000ba3e8STim J. Robbins */ 96189dd99dcSXin LI if (ch == '_') 96289dd99dcSXin LI { 96389dd99dcSXin LI if ((a & (AT_BOLD|AT_UNDERLINE)) != AT_NORMAL) 96489dd99dcSXin LI a |= (AT_BOLD|AT_UNDERLINE); 96589dd99dcSXin LI else if (last_overstrike != AT_NORMAL) 96689dd99dcSXin LI a |= last_overstrike; 967000ba3e8STim J. Robbins else 96889dd99dcSXin LI a |= AT_BOLD; 96989dd99dcSXin LI } else 97089dd99dcSXin LI a |= AT_BOLD; 97189dd99dcSXin LI } else if (ch == '_') 972c9346414SPaul Saab { 97389dd99dcSXin LI a |= AT_UNDERLINE; 97489dd99dcSXin LI ch = prev_ch; 97589dd99dcSXin LI rep = linebuf + curr; 97689dd99dcSXin LI } else if (prev_ch == '_') 977c9346414SPaul Saab { 97889dd99dcSXin LI a |= AT_UNDERLINE; 979000ba3e8STim J. Robbins } 98089dd99dcSXin LI /* Else we replace prev_ch, but we keep its attributes. */ 98189dd99dcSXin LI } else if (overstrike < 0) 982c9346414SPaul Saab { 98389dd99dcSXin LI if ( is_composing_char(ch) 98489dd99dcSXin LI || is_combining_char(get_wchar(linebuf + curr), ch)) 98589dd99dcSXin LI /* Continuation of the same overstrike. */ 98689dd99dcSXin LI a = last_overstrike; 987a5f0fb15SPaul Saab else 98889dd99dcSXin LI overstrike = 0; 98989dd99dcSXin LI } 99089dd99dcSXin LI 99189dd99dcSXin LI if (ch == '\t') 992a5f0fb15SPaul Saab { 993a5f0fb15SPaul Saab /* 994a5f0fb15SPaul Saab * Expand a tab into spaces. 995a5f0fb15SPaul Saab */ 996a5f0fb15SPaul Saab switch (bs_mode) 997a5f0fb15SPaul Saab { 998a5f0fb15SPaul Saab case BS_CONTROL: 999a5f0fb15SPaul Saab goto do_control_char; 1000a5f0fb15SPaul Saab case BS_NORMAL: 1001a5f0fb15SPaul Saab case BS_SPECIAL: 100289dd99dcSXin LI STORE_TAB(a, pos); 1003a5f0fb15SPaul Saab break; 1004a5f0fb15SPaul Saab } 100589dd99dcSXin LI } else if ((!utf_mode || is_ascii_char(ch)) && control_char((char)ch)) 1006a5f0fb15SPaul Saab { 1007a5f0fb15SPaul Saab do_control_char: 100859a2d077SXin LI if (ctldisp == OPT_ON || (ctldisp == OPT_ONPLUS && IS_CSI_START(ch))) 1009a5f0fb15SPaul Saab { 1010a5f0fb15SPaul Saab /* 1011a5f0fb15SPaul Saab * Output as a normal character. 1012a5f0fb15SPaul Saab */ 101389dd99dcSXin LI STORE_CHAR(ch, AT_NORMAL, rep, pos); 1014a5f0fb15SPaul Saab } else 1015a5f0fb15SPaul Saab { 101689dd99dcSXin LI STORE_PRCHAR((char) ch, pos); 101789dd99dcSXin LI } 101889dd99dcSXin LI } else if (utf_mode && ctldisp != OPT_ON && is_ubin_char(ch)) 101989dd99dcSXin LI { 102089dd99dcSXin LI char *s; 1021a5f0fb15SPaul Saab 102289dd99dcSXin LI s = prutfchar(ch); 102389dd99dcSXin LI 102489dd99dcSXin LI if (column + (int) strlen(s) - 1 + 102589dd99dcSXin LI pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width) 1026a5f0fb15SPaul Saab return (1); 1027a5f0fb15SPaul Saab 1028a5f0fb15SPaul Saab for ( ; *s != 0; s++) 102989dd99dcSXin LI STORE_CHAR(*s, AT_BINARY, NULL, pos); 1030a5f0fb15SPaul Saab } else 1031a5f0fb15SPaul Saab { 103289dd99dcSXin LI STORE_CHAR(ch, a, rep, pos); 103389dd99dcSXin LI } 103489dd99dcSXin LI return (0); 1035a5f0fb15SPaul Saab } 1036a5f0fb15SPaul Saab 103789dd99dcSXin LI /* 103889dd99dcSXin LI * 103989dd99dcSXin LI */ 104089dd99dcSXin LI public int 1041*b7780dbeSXin LI pflushmbc(VOID_PARAM) 104289dd99dcSXin LI { 104389dd99dcSXin LI int r = 0; 104489dd99dcSXin LI 104589dd99dcSXin LI if (mbc_buf_len > 0) 104689dd99dcSXin LI { 104789dd99dcSXin LI /* Flush incomplete (truncated) sequence. */ 104889dd99dcSXin LI r = flush_mbc_buf(mbc_pos); 104989dd99dcSXin LI mbc_buf_len = 0; 105089dd99dcSXin LI } 105189dd99dcSXin LI return r; 1052a5f0fb15SPaul Saab } 1053a5f0fb15SPaul Saab 1054a5f0fb15SPaul Saab /* 1055b2ea2440SXin LI * Switch to normal attribute at end of line. 1056b2ea2440SXin LI */ 1057b2ea2440SXin LI static void 1058*b7780dbeSXin LI add_attr_normal(VOID_PARAM) 1059b2ea2440SXin LI { 1060b2ea2440SXin LI char *p = "\033[m"; 1061b2ea2440SXin LI 1062b2ea2440SXin LI if (ctldisp != OPT_ONPLUS || !is_ansi_end('m')) 1063b2ea2440SXin LI return; 1064b2ea2440SXin LI for ( ; *p != '\0'; p++) 1065b2ea2440SXin LI add_linebuf(*p, AT_ANSI, 0); 1066b2ea2440SXin LI } 1067b2ea2440SXin LI 1068b2ea2440SXin LI /* 1069a5f0fb15SPaul Saab * Terminate the line in the line buffer. 1070a5f0fb15SPaul Saab */ 1071a5f0fb15SPaul Saab public void 1072b2ea2440SXin LI pdone(endline, chopped, forw) 1073f6b74a7dSXin LI int endline; 1074b2ea2440SXin LI int chopped; 1075f6b74a7dSXin LI int forw; 1076a5f0fb15SPaul Saab { 107789dd99dcSXin LI (void) pflushmbc(); 107889dd99dcSXin LI 1079a5f0fb15SPaul Saab if (pendc && (pendc != '\r' || !endline)) 1080a5f0fb15SPaul Saab /* 1081a5f0fb15SPaul Saab * If we had a pending character, put it in the buffer. 1082a5f0fb15SPaul Saab * But discard a pending CR if we are at end of line 1083a5f0fb15SPaul Saab * (that is, discard the CR in a CR/LF sequence). 1084a5f0fb15SPaul Saab */ 108589dd99dcSXin LI (void) do_append(pendc, NULL, pendpos); 1086a5f0fb15SPaul Saab 1087a5f0fb15SPaul Saab /* 1088a5f0fb15SPaul Saab * Make sure we've shifted the line, if we need to. 1089a5f0fb15SPaul Saab */ 1090a5f0fb15SPaul Saab if (cshift < hshift) 1091a5f0fb15SPaul Saab pshift(hshift - cshift); 1092a5f0fb15SPaul Saab 1093b2ea2440SXin LI if (chopped && rscroll_char) 109489dd99dcSXin LI { 1095b2ea2440SXin LI /* 1096b2ea2440SXin LI * Display the right scrolling char. 1097b2ea2440SXin LI * If we've already filled the rightmost screen char 1098b2ea2440SXin LI * (in the buffer), overwrite it. 1099b2ea2440SXin LI */ 1100b2ea2440SXin LI if (column >= sc_width) 110189dd99dcSXin LI { 1102b2ea2440SXin LI /* We've already written in the rightmost char. */ 1103b2ea2440SXin LI column = right_column; 1104b2ea2440SXin LI curr = right_curr; 110589dd99dcSXin LI } 1106b2ea2440SXin LI add_attr_normal(); 1107b2ea2440SXin LI while (column < sc_width-1) 1108b2ea2440SXin LI { 1109b2ea2440SXin LI /* 1110b2ea2440SXin LI * Space to last (rightmost) char on screen. 1111b2ea2440SXin LI * This may be necessary if the char we overwrote 1112b2ea2440SXin LI * was double-width. 1113b2ea2440SXin LI */ 1114b2ea2440SXin LI add_linebuf(' ', AT_NORMAL, 1); 1115b2ea2440SXin LI } 1116b2ea2440SXin LI /* Print rscroll char. It must be single-width. */ 1117b2ea2440SXin LI add_linebuf(rscroll_char, rscroll_attr, 1); 1118b2ea2440SXin LI } else 1119b2ea2440SXin LI { 1120b2ea2440SXin LI add_attr_normal(); 112189dd99dcSXin LI } 112289dd99dcSXin LI 1123a5f0fb15SPaul Saab /* 1124a5f0fb15SPaul Saab * Add a newline if necessary, 1125a5f0fb15SPaul Saab * and append a '\0' to the end of the line. 1126720c436cSXin LI * We output a newline if we're not at the right edge of the screen, 1127720c436cSXin LI * or if the terminal doesn't auto wrap, 1128720c436cSXin LI * or if this is really the end of the line AND the terminal ignores 1129720c436cSXin LI * a newline at the right edge. 1130720c436cSXin LI * (In the last case we don't want to output a newline if the terminal 1131720c436cSXin LI * doesn't ignore it since that would produce an extra blank line. 1132720c436cSXin LI * But we do want to output a newline if the terminal ignores it in case 1133720c436cSXin LI * the next line is blank. In that case the single newline output for 1134720c436cSXin LI * that blank line would be ignored!) 1135a5f0fb15SPaul Saab */ 11367374caaaSXin LI if (column < sc_width || !auto_wrap || (endline && ignaw) || ctldisp == OPT_ON) 1137a5f0fb15SPaul Saab { 1138b2ea2440SXin LI add_linebuf('\n', AT_NORMAL, 0); 1139a5f0fb15SPaul Saab } 1140f0be0a1fSXin LI else if (ignaw && column >= sc_width && forw) 1141423c5ce5SXin LI { 1142423c5ce5SXin LI /* 11437374caaaSXin LI * Terminals with "ignaw" don't wrap until they *really* need 11447374caaaSXin LI * to, i.e. when the character *after* the last one to fit on a 11457374caaaSXin LI * line is output. But they are too hard to deal with when they 11467374caaaSXin LI * get in the state where a full screen width of characters 11477374caaaSXin LI * have been output but the cursor is sitting on the right edge 11487374caaaSXin LI * instead of at the start of the next line. 1149f0be0a1fSXin LI * So we nudge them into wrapping by outputting a space 1150f0be0a1fSXin LI * character plus a backspace. But do this only if moving 1151f0be0a1fSXin LI * forward; if we're moving backward and drawing this line at 1152f0be0a1fSXin LI * the top of the screen, the space would overwrite the first 1153f0be0a1fSXin LI * char on the next line. We don't need to do this "nudge" 1154f0be0a1fSXin LI * at the top of the screen anyway. 1155423c5ce5SXin LI */ 1156b2ea2440SXin LI add_linebuf(' ', AT_NORMAL, 1); 1157b2ea2440SXin LI add_linebuf('\b', AT_NORMAL, -1); 1158423c5ce5SXin LI } 1159b2ea2440SXin LI set_linebuf(curr, '\0', AT_NORMAL); 1160c9346414SPaul Saab } 11617374caaaSXin LI 11627374caaaSXin LI /* 11637374caaaSXin LI * 11647374caaaSXin LI */ 11657374caaaSXin LI public void 1166f6b74a7dSXin LI set_status_col(c) 1167f6b74a7dSXin LI char c; 11687374caaaSXin LI { 1169b2ea2440SXin LI set_linebuf(0, c, AT_NORMAL|AT_HILITE); 1170a5f0fb15SPaul Saab } 1171a5f0fb15SPaul Saab 1172a5f0fb15SPaul Saab /* 1173a5f0fb15SPaul Saab * Get a character from the current line. 1174a5f0fb15SPaul Saab * Return the character as the function return value, 1175a5f0fb15SPaul Saab * and the character attribute in *ap. 1176a5f0fb15SPaul Saab */ 1177a5f0fb15SPaul Saab public int 1178f6b74a7dSXin LI gline(i, ap) 1179f6b74a7dSXin LI int i; 1180f6b74a7dSXin LI int *ap; 1181a5f0fb15SPaul Saab { 1182a5f0fb15SPaul Saab if (is_null_line) 1183a5f0fb15SPaul Saab { 1184a5f0fb15SPaul Saab /* 1185a5f0fb15SPaul Saab * If there is no current line, we pretend the line is 1186a5f0fb15SPaul Saab * either "~" or "", depending on the "twiddle" flag. 1187a5f0fb15SPaul Saab */ 118889dd99dcSXin LI if (twiddle) 118989dd99dcSXin LI { 119089dd99dcSXin LI if (i == 0) 119189dd99dcSXin LI { 1192a5f0fb15SPaul Saab *ap = AT_BOLD; 119389dd99dcSXin LI return '~'; 119489dd99dcSXin LI } 119589dd99dcSXin LI --i; 119689dd99dcSXin LI } 119789dd99dcSXin LI /* Make sure we're back to AT_NORMAL before the '\n'. */ 119889dd99dcSXin LI *ap = AT_NORMAL; 119989dd99dcSXin LI return i ? '\0' : '\n'; 1200a5f0fb15SPaul Saab } 1201a5f0fb15SPaul Saab 1202a5f0fb15SPaul Saab *ap = attr[i]; 120389dd99dcSXin LI return (linebuf[i] & 0xFF); 1204a5f0fb15SPaul Saab } 1205a5f0fb15SPaul Saab 1206a5f0fb15SPaul Saab /* 1207a5f0fb15SPaul Saab * Indicate that there is no current line. 1208a5f0fb15SPaul Saab */ 1209a5f0fb15SPaul Saab public void 1210*b7780dbeSXin LI null_line(VOID_PARAM) 1211a5f0fb15SPaul Saab { 1212a5f0fb15SPaul Saab is_null_line = 1; 1213a5f0fb15SPaul Saab cshift = 0; 1214a5f0fb15SPaul Saab } 1215a5f0fb15SPaul Saab 1216a5f0fb15SPaul Saab /* 1217a5f0fb15SPaul Saab * Analogous to forw_line(), but deals with "raw lines": 1218a5f0fb15SPaul Saab * lines which are not split for screen width. 1219a5f0fb15SPaul Saab * {{ This is supposed to be more efficient than forw_line(). }} 1220a5f0fb15SPaul Saab */ 1221a5f0fb15SPaul Saab public POSITION 1222f6b74a7dSXin LI forw_raw_line(curr_pos, linep, line_lenp) 1223f6b74a7dSXin LI POSITION curr_pos; 1224f6b74a7dSXin LI char **linep; 1225f6b74a7dSXin LI int *line_lenp; 1226a5f0fb15SPaul Saab { 12271ea31627SRobert Watson int n; 12281ea31627SRobert Watson int c; 1229a5f0fb15SPaul Saab POSITION new_pos; 1230a5f0fb15SPaul Saab 1231a5f0fb15SPaul Saab if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || 1232a5f0fb15SPaul Saab (c = ch_forw_get()) == EOI) 1233a5f0fb15SPaul Saab return (NULL_POSITION); 1234a5f0fb15SPaul Saab 1235c9346414SPaul Saab n = 0; 1236a5f0fb15SPaul Saab for (;;) 1237a5f0fb15SPaul Saab { 123889dd99dcSXin LI if (c == '\n' || c == EOI || ABORT_SIGS()) 1239a5f0fb15SPaul Saab { 1240a5f0fb15SPaul Saab new_pos = ch_tell(); 1241a5f0fb15SPaul Saab break; 1242a5f0fb15SPaul Saab } 1243c9346414SPaul Saab if (n >= size_linebuf-1) 1244c9346414SPaul Saab { 1245c9346414SPaul Saab if (expand_linebuf()) 1246a5f0fb15SPaul Saab { 1247a5f0fb15SPaul Saab /* 1248a5f0fb15SPaul Saab * Overflowed the input buffer. 1249a5f0fb15SPaul Saab * Pretend the line ended here. 1250a5f0fb15SPaul Saab */ 1251a5f0fb15SPaul Saab new_pos = ch_tell() - 1; 1252a5f0fb15SPaul Saab break; 1253a5f0fb15SPaul Saab } 1254c9346414SPaul Saab } 1255c9346414SPaul Saab linebuf[n++] = c; 1256a5f0fb15SPaul Saab c = ch_forw_get(); 1257a5f0fb15SPaul Saab } 1258c9346414SPaul Saab linebuf[n] = '\0'; 1259a5f0fb15SPaul Saab if (linep != NULL) 1260a5f0fb15SPaul Saab *linep = linebuf; 1261720c436cSXin LI if (line_lenp != NULL) 1262720c436cSXin LI *line_lenp = n; 1263a5f0fb15SPaul Saab return (new_pos); 1264a5f0fb15SPaul Saab } 1265a5f0fb15SPaul Saab 1266a5f0fb15SPaul Saab /* 1267a5f0fb15SPaul Saab * Analogous to back_line(), but deals with "raw lines". 1268a5f0fb15SPaul Saab * {{ This is supposed to be more efficient than back_line(). }} 1269a5f0fb15SPaul Saab */ 1270a5f0fb15SPaul Saab public POSITION 1271f6b74a7dSXin LI back_raw_line(curr_pos, linep, line_lenp) 1272f6b74a7dSXin LI POSITION curr_pos; 1273f6b74a7dSXin LI char **linep; 1274f6b74a7dSXin LI int *line_lenp; 1275a5f0fb15SPaul Saab { 12761ea31627SRobert Watson int n; 12771ea31627SRobert Watson int c; 1278a5f0fb15SPaul Saab POSITION new_pos; 1279a5f0fb15SPaul Saab 1280a5f0fb15SPaul Saab if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() || 1281a5f0fb15SPaul Saab ch_seek(curr_pos-1)) 1282a5f0fb15SPaul Saab return (NULL_POSITION); 1283a5f0fb15SPaul Saab 1284c9346414SPaul Saab n = size_linebuf; 1285c9346414SPaul Saab linebuf[--n] = '\0'; 1286a5f0fb15SPaul Saab for (;;) 1287a5f0fb15SPaul Saab { 1288a5f0fb15SPaul Saab c = ch_back_get(); 128989dd99dcSXin LI if (c == '\n' || ABORT_SIGS()) 1290a5f0fb15SPaul Saab { 1291a5f0fb15SPaul Saab /* 1292a5f0fb15SPaul Saab * This is the newline ending the previous line. 1293a5f0fb15SPaul Saab * We have hit the beginning of the line. 1294a5f0fb15SPaul Saab */ 1295a5f0fb15SPaul Saab new_pos = ch_tell() + 1; 1296a5f0fb15SPaul Saab break; 1297a5f0fb15SPaul Saab } 1298a5f0fb15SPaul Saab if (c == EOI) 1299a5f0fb15SPaul Saab { 1300a5f0fb15SPaul Saab /* 1301a5f0fb15SPaul Saab * We have hit the beginning of the file. 1302a5f0fb15SPaul Saab * This must be the first line in the file. 1303a5f0fb15SPaul Saab * This must, of course, be the beginning of the line. 1304a5f0fb15SPaul Saab */ 1305a5f0fb15SPaul Saab new_pos = ch_zero(); 1306a5f0fb15SPaul Saab break; 1307a5f0fb15SPaul Saab } 1308c9346414SPaul Saab if (n <= 0) 1309c9346414SPaul Saab { 1310c9346414SPaul Saab int old_size_linebuf = size_linebuf; 1311c9346414SPaul Saab char *fm; 1312c9346414SPaul Saab char *to; 1313c9346414SPaul Saab if (expand_linebuf()) 1314a5f0fb15SPaul Saab { 1315a5f0fb15SPaul Saab /* 1316a5f0fb15SPaul Saab * Overflowed the input buffer. 1317a5f0fb15SPaul Saab * Pretend the line ended here. 1318a5f0fb15SPaul Saab */ 1319a5f0fb15SPaul Saab new_pos = ch_tell() + 1; 1320a5f0fb15SPaul Saab break; 1321a5f0fb15SPaul Saab } 1322c9346414SPaul Saab /* 1323c9346414SPaul Saab * Shift the data to the end of the new linebuf. 1324c9346414SPaul Saab */ 13251d5cfebaSTim J. Robbins for (fm = linebuf + old_size_linebuf - 1, 13261d5cfebaSTim J. Robbins to = linebuf + size_linebuf - 1; 1327c9346414SPaul Saab fm >= linebuf; fm--, to--) 1328c9346414SPaul Saab *to = *fm; 1329c9346414SPaul Saab n = size_linebuf - old_size_linebuf; 1330c9346414SPaul Saab } 1331c9346414SPaul Saab linebuf[--n] = c; 1332a5f0fb15SPaul Saab } 1333a5f0fb15SPaul Saab if (linep != NULL) 1334c9346414SPaul Saab *linep = &linebuf[n]; 1335720c436cSXin LI if (line_lenp != NULL) 1336720c436cSXin LI *line_lenp = size_linebuf - 1 - n; 1337a5f0fb15SPaul Saab return (new_pos); 1338a5f0fb15SPaul Saab } 1339f6b74a7dSXin LI 1340f6b74a7dSXin LI /* 1341f6b74a7dSXin LI * Find the shift necessary to show the end of the longest displayed line. 1342f6b74a7dSXin LI */ 1343f6b74a7dSXin LI public int 1344*b7780dbeSXin LI rrshift(VOID_PARAM) 1345f6b74a7dSXin LI { 1346f6b74a7dSXin LI POSITION pos; 1347f6b74a7dSXin LI int save_width; 1348f6b74a7dSXin LI int line; 1349f6b74a7dSXin LI int longest = 0; 1350f6b74a7dSXin LI 1351f6b74a7dSXin LI save_width = sc_width; 1352f6b74a7dSXin LI sc_width = INT_MAX; 1353f6b74a7dSXin LI hshift = 0; 1354f6b74a7dSXin LI pos = position(TOP); 1355f6b74a7dSXin LI for (line = 0; line < sc_height && pos != NULL_POSITION; line++) 1356f6b74a7dSXin LI { 1357f6b74a7dSXin LI pos = forw_line(pos); 1358f6b74a7dSXin LI if (column > longest) 1359f6b74a7dSXin LI longest = column; 1360f6b74a7dSXin LI } 1361f6b74a7dSXin LI sc_width = save_width; 1362f6b74a7dSXin LI if (longest < sc_width) 1363f6b74a7dSXin LI return 0; 1364f6b74a7dSXin LI return longest - sc_width; 1365f6b74a7dSXin LI } 1366