line.c revision 63128
1157114Sscottl/* 2157114Sscottl * Copyright (C) 1984-2000 Mark Nudelman 3157114Sscottl * 4157114Sscottl * You may distribute under the terms of either the GNU General Public 5157114Sscottl * License or the Less License, as specified in the README file. 6157114Sscottl * 7157114Sscottl * For more information about less, or for information on how to 8157114Sscottl * contact the author, see the README file. 9157114Sscottl */ 10157114Sscottl 11157114Sscottl 12157114Sscottl/* 13157114Sscottl * Routines to manipulate the "line buffer". 14157114Sscottl * The line buffer holds a line of output as it is being built 15157114Sscottl * in preparation for output to the screen. 16157114Sscottl */ 17157114Sscottl 18157114Sscottl#include "less.h" 19157114Sscottl 20157114Sscottl#define IS_CONT(c) (((c) & 0xC0) == 0x80) 21157114Sscottl#define LINENUM_WIDTH 8 /* Chars to use for line number */ 22157114Sscottl 23157114Sscottl/* Buffer which holds the current output line */ 24157114Sscottlpublic char linebuf[LINEBUF_SIZE]; 25157114Sscottlpublic int size_linebuf = sizeof(linebuf); 26171980Sscottl 27171980Sscottlpublic int cshift; /* Current left-shift of output line buffer */ 28171980Sscottlpublic int hshift; /* Desired left-shift of output line buffer */ 29171980Sscottl 30171980Sscottlstatic char attr[LINEBUF_SIZE]; /* Extension of linebuf to hold attributes */ 31171980Sscottlstatic int curr; /* Index into linebuf */ 32171980Sscottlstatic int column; /* Printable length, accounting for 33171980Sscottl backspaces, etc. */ 34171980Sscottlstatic int overstrike; /* Next char should overstrike previous char */ 35171980Sscottlstatic int is_null_line; /* There is no current line */ 36171980Sscottlstatic int lmargin; /* Left margin */ 37171980Sscottlstatic char pendc; 38171980Sscottlstatic POSITION pendpos; 39171980Sscottlstatic char *end_ansi_chars; 40171980Sscottl 41171980Sscottlstatic int do_append(); 42171980Sscottl 43171980Sscottlextern int bs_mode; 44171980Sscottlextern int tabstop; 45171980Sscottlextern int linenums; 46171980Sscottlextern int ctldisp; 47171980Sscottlextern int twiddle; 48171980Sscottlextern int binattr; 49171980Sscottlextern int status_col; 50171980Sscottlextern int auto_wrap, ignaw; 51171980Sscottlextern int bo_s_width, bo_e_width; 52157114Sscottlextern int ul_s_width, ul_e_width; 53157114Sscottlextern int bl_s_width, bl_e_width; 54157114Sscottlextern int so_s_width, so_e_width; 55157114Sscottlextern int sc_width, sc_height; 56157114Sscottlextern int utf_mode; 57157114Sscottlextern POSITION start_attnpos; 58157114Sscottlextern POSITION end_attnpos; 59157114Sscottl 60157114Sscottl/* 61157114Sscottl * Initialize from environment variables. 62157114Sscottl */ 63157114Sscottl public void 64157114Sscottlinit_line() 65157114Sscottl{ 66157114Sscottl end_ansi_chars = lgetenv("LESSANSIENDCHARS"); 67233711Sambrisko if (end_ansi_chars == NULL || *end_ansi_chars == '\0') 68157114Sscottl end_ansi_chars = "m"; 69157114Sscottl} 70157114Sscottl 71157114Sscottl/* 72157114Sscottl * Rewind the line buffer. 73157114Sscottl */ 74157114Sscottl public void 75157114Sscottlprewind() 76157114Sscottl{ 77157114Sscottl curr = 0; 78157114Sscottl column = 0; 79157114Sscottl overstrike = 0; 80157114Sscottl is_null_line = 0; 81157114Sscottl pendc = '\0'; 82157114Sscottl lmargin = 0; 83157114Sscottl if (status_col) 84157114Sscottl lmargin += 1; 85171980Sscottl if (linenums == OPT_ONPLUS) 86233711Sambrisko lmargin += LINENUM_WIDTH+1; 87233711Sambrisko} 88233711Sambrisko 89247369Ssmh/* 90233711Sambrisko * Insert the line number (of the given position) into the line buffer. 91233711Sambrisko */ 92233711Sambrisko public void 93233711Sambriskoplinenum(pos) 94233711Sambrisko POSITION pos; 95171980Sscottl{ 96171980Sscottl register int lno; 97171980Sscottl register int i; 98171980Sscottl 99171980Sscottl if (linenums == OPT_ONPLUS) 100171980Sscottl { 101233711Sambrisko /* 102171980Sscottl * Get the line number and put it in the current line. 103171980Sscottl * {{ Note: since find_linenum calls forw_raw_line, 104171980Sscottl * it may seek in the input file, requiring the caller 105233711Sambrisko * of plinenum to re-seek if necessary. }} 106233711Sambrisko * {{ Since forw_raw_line modifies linebuf, we must 107233711Sambrisko * do this first, before storing anything in linebuf. }} 108233711Sambrisko */ 109233711Sambrisko lno = find_linenum(pos); 110184897Sambrisko } 111184897Sambrisko 112184897Sambrisko /* 113184897Sambrisko * Display a status column if the -J option is set. 114184897Sambrisko */ 115184897Sambrisko if (status_col) 116233711Sambrisko { 117233711Sambrisko linebuf[curr] = ' '; 118233711Sambrisko if (start_attnpos != NULL_POSITION && 119233711Sambrisko pos >= start_attnpos && pos < end_attnpos) 120233711Sambrisko attr[curr] = AT_STANDOUT; 121233711Sambrisko else 122233711Sambrisko attr[curr] = 0; 123233711Sambrisko curr++; 124157114Sscottl column++; 125157114Sscottl } 126157114Sscottl /* 127233711Sambrisko * Display the line number at the start of each line 128233711Sambrisko * if the -N option is set. 129233711Sambrisko */ 130233711Sambrisko if (linenums == OPT_ONPLUS) 131157114Sscottl { 132157114Sscottl sprintf(&linebuf[curr], "%*d", LINENUM_WIDTH, lno); 133157114Sscottl column += LINENUM_WIDTH; 134157114Sscottl for (i = 0; i < LINENUM_WIDTH; i++) 135157114Sscottl attr[curr++] = 0; 136157114Sscottl } 137157114Sscottl /* 138157114Sscottl * Append enough spaces to bring us to the lmargin. 139157114Sscottl */ 140157114Sscottl while (column < lmargin) 141224041Sjhb { 142157114Sscottl linebuf[curr] = ' '; 143157114Sscottl attr[curr++] = AT_NORMAL; 144157114Sscottl column++; 145157114Sscottl } 146157114Sscottl} 147157114Sscottl 148233711Sambrisko/* 149233711Sambrisko * 150233711Sambrisko */ 151157114Sscottl static int 152233711Sambriskoutf_len(char *s, int len) 153233711Sambrisko{ 154233711Sambrisko int ulen = 0; 155233711Sambrisko 156233711Sambrisko while (*s != '\0' && len > 0) 157233711Sambrisko { 158233711Sambrisko if (!IS_CONT(*s)) 159157114Sscottl len--; 160157114Sscottl s++; 161157114Sscottl ulen++; 162157114Sscottl } 163157114Sscottl while (IS_CONT(*s)) 164157114Sscottl { 165157114Sscottl s++; 166157114Sscottl ulen++; 167224041Sjhb } 168157114Sscottl return (ulen); 169233711Sambrisko} 170233711Sambrisko 171233711Sambrisko/* 172233711Sambrisko * Shift the input line left. 173233711Sambrisko * This means discarding N printable chars at the start of the buffer. 174233711Sambrisko */ 175157114Sscottl static void 176157114Sscottlpshift(shift) 177157114Sscottl int shift; 178157114Sscottl{ 179157114Sscottl int i; 180157114Sscottl int real_shift; 181157114Sscottl 182157114Sscottl if (shift > column - lmargin) 183157114Sscottl shift = column - lmargin; 184157114Sscottl if (shift > curr - lmargin) 185157114Sscottl shift = curr - lmargin; 186157114Sscottl 187157114Sscottl if (!utf_mode) 188157114Sscottl real_shift = shift; 189157114Sscottl else 190157114Sscottl { 191233711Sambrisko real_shift = utf_len(linebuf + lmargin, shift); 192163398Sscottl if (real_shift > curr) 193163398Sscottl real_shift = curr; 194157114Sscottl } 195255806Ssbruno for (i = 0; i < curr - real_shift; i++) 196255806Ssbruno { 197157114Sscottl linebuf[lmargin + i] = linebuf[lmargin + i + real_shift]; 198157114Sscottl attr[lmargin + i] = attr[lmargin + i + real_shift]; 199157114Sscottl } 200157114Sscottl column -= shift; 201196200Sscottl curr -= real_shift; 202196200Sscottl cshift += shift; 203196200Sscottl} 204196200Sscottl 205196200Sscottl/* 206196200Sscottl * Return the printing width of the start (enter) sequence 207196200Sscottl * for a given character attribute. 208196200Sscottl */ 209196200Sscottl static int 210196200Sscottlattr_swidth(a) 211196200Sscottl int a; 212233711Sambrisko{ 213196200Sscottl switch (a) 214196200Sscottl { 215196200Sscottl case AT_BOLD: return (bo_s_width); 216196200Sscottl case AT_UNDERLINE: return (ul_s_width); 217196200Sscottl case AT_BLINK: return (bl_s_width); 218196200Sscottl case AT_STANDOUT: return (so_s_width); 219196200Sscottl } 220196200Sscottl return (0); 221196200Sscottl} 222233711Sambrisko 223233711Sambrisko/* 224159811Sps * Return the printing width of the end (exit) sequence 225159811Sps * for a given character attribute. 226157114Sscottl */ 227159811Sps static int 228196200Sscottlattr_ewidth(a) 229171821Sjhb int a; 230163398Sscottl{ 231163398Sscottl switch (a) 232163398Sscottl { 233196200Sscottl case AT_BOLD: return (bo_e_width); 234233711Sambrisko case AT_UNDERLINE: return (ul_e_width); 235251516Ssbruno case AT_BLINK: return (bl_e_width); 236251516Ssbruno case AT_STANDOUT: return (so_e_width); 237251516Ssbruno } 238184897Sambrisko return (0); 239251516Ssbruno} 240196200Sscottl 241196200Sscottl/* 242196200Sscottl * Return the printing width of a given character and attribute, 243249257Smarkj * if the character were added to the current position in the line buffer. 244249257Smarkj * Adding a character with a given attribute may cause an enter or exit 245249257Smarkj * attribute sequence to be inserted, so this must be taken into account. 246157114Sscottl */ 247157114Sscottl static int 248157114Sscottlpwidth(c, a) 249157114Sscottl int c; 250157114Sscottl int a; 251157114Sscottl{ 252157114Sscottl register int w; 253157114Sscottl 254157114Sscottl if (utf_mode && IS_CONT(c)) 255157114Sscottl return (0); 256157114Sscottl 257157114Sscottl if (c == '\b') 258157114Sscottl /* 259158737Sambrisko * Backspace moves backwards one position. 260157114Sscottl */ 261157114Sscottl return (-1); 262157114Sscottl 263157114Sscottl if (control_char(c)) 264157114Sscottl /* 265157114Sscottl * Control characters do unpredicatable things, 266157114Sscottl * so we don't even try to guess; say it doesn't move. 267157114Sscottl * This can only happen if the -r flag is in effect. 268157114Sscottl */ 269157114Sscottl return (0); 270157114Sscottl 271233711Sambrisko /* 272247369Ssmh * Other characters take one space, 273247369Ssmh * plus the width of any attribute enter/exit sequence. 274247369Ssmh */ 275247369Ssmh w = 1; 276247369Ssmh if (curr > 0 && attr[curr-1] != a) 277247369Ssmh w += attr_ewidth(attr[curr-1]); 278247369Ssmh if (a && (curr == 0 || attr[curr-1] != a)) 279157114Sscottl w += attr_swidth(a); 280233711Sambrisko return (w); 281233711Sambrisko} 282233711Sambrisko 283233711Sambrisko/* 284233711Sambrisko * Delete the previous character in the line buffer. 285233711Sambrisko */ 286233711Sambrisko static void 287233711Sambriskobackc() 288233711Sambrisko{ 289233711Sambrisko curr--; 290233711Sambrisko column -= pwidth(linebuf[curr], attr[curr]); 291233711Sambrisko} 292233711Sambrisko 293233711Sambrisko/* 294233711Sambrisko * Are we currently within a recognized ANSI escape sequence? 295233711Sambrisko */ 296233711Sambrisko static int 297233711Sambriskoin_ansi_esc_seq() 298233711Sambrisko{ 299233711Sambrisko int i; 300233711Sambrisko 301233711Sambrisko /* 302233711Sambrisko * Search backwards for either an ESC (which means we ARE in a seq); 303233711Sambrisko * or an end char (which means we're NOT in a seq). 304233711Sambrisko */ 305233711Sambrisko for (i = curr-1; i >= 0; i--) 306233711Sambrisko { 307233711Sambrisko if (linebuf[i] == ESC) 308233711Sambrisko return (1); 309157114Sscottl if (strchr(end_ansi_chars, linebuf[i]) != NULL) 310157114Sscottl return (0); 311157114Sscottl } 312157114Sscottl return (0); 313157114Sscottl} 314157114Sscottl 315157114Sscottl/* 316157114Sscottl * Append a character and attribute to the line buffer. 317157114Sscottl */ 318157114Sscottl static int 319157114Sscottlstorec(c, a, pos) 320157114Sscottl int c; 321157114Sscottl int a; 322157114Sscottl POSITION pos; 323157114Sscottl{ 324157114Sscottl register int w; 325157114Sscottl 326157114Sscottl#if HILITE_SEARCH 327157114Sscottl if (is_hilited(pos, pos+1, 0)) 328157114Sscottl /* 329157114Sscottl * This character should be highlighted. 330157114Sscottl * Override the attribute passed in. 331157114Sscottl */ 332157114Sscottl a = AT_STANDOUT; 333157114Sscottl#endif 334157114Sscottl if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq()) 335157114Sscottl w = 0; 336157114Sscottl else 337157114Sscottl w = pwidth(c, a); 338157114Sscottl if (ctldisp != OPT_ON && column + w + attr_ewidth(a) > sc_width) 339157114Sscottl /* 340157114Sscottl * Won't fit on screen. 341157114Sscottl */ 342157114Sscottl return (1); 343157114Sscottl 344157114Sscottl if (curr >= sizeof(linebuf)-2) 345157114Sscottl /* 346157114Sscottl * Won't fit in line buffer. 347157114Sscottl */ 348157114Sscottl return (1); 349157114Sscottl 350157114Sscottl /* 351157114Sscottl * Special handling for "magic cookie" terminals. 352157114Sscottl * If an attribute enter/exit sequence has a printing width > 0, 353157114Sscottl * and the sequence is adjacent to a space, delete the space. 354157114Sscottl * We just mark the space as invisible, to avoid having too 355157114Sscottl * many spaces deleted. 356157114Sscottl * {{ Note that even if the attribute width is > 1, we 357157114Sscottl * delete only one space. It's not worth trying to do more. 358157114Sscottl * It's hardly worth doing this much. }} 359157114Sscottl */ 360157114Sscottl if (curr > 0 && a != AT_NORMAL && 361157114Sscottl linebuf[curr-1] == ' ' && attr[curr-1] == AT_NORMAL && 362157114Sscottl attr_swidth(a) > 0) 363157114Sscottl { 364157114Sscottl /* 365157114Sscottl * We are about to append an enter-attribute sequence 366157114Sscottl * just after a space. Delete the space. 367157114Sscottl */ 368196200Sscottl attr[curr-1] = AT_INVIS; 369196200Sscottl column--; 370196200Sscottl } else if (curr > 0 && attr[curr-1] != AT_NORMAL && 371157114Sscottl attr[curr-1] != AT_INVIS && c == ' ' && a == AT_NORMAL && 372157114Sscottl attr_ewidth(attr[curr-1]) > 0) 373157114Sscottl { 374157114Sscottl /* 375157114Sscottl * We are about to append a space just after an 376157114Sscottl * exit-attribute sequence. Delete the space. 377157114Sscottl */ 378157114Sscottl a = AT_INVIS; 379157114Sscottl column--; 380157114Sscottl } 381157114Sscottl /* End of magic cookie handling. */ 382157114Sscottl 383157114Sscottl linebuf[curr] = c; 384157114Sscottl attr[curr] = a; 385157114Sscottl column += w; 386157114Sscottl return (0); 387157114Sscottl} 388157114Sscottl 389157114Sscottl/* 390157114Sscottl * Append a character to the line buffer. 391157114Sscottl * Expand tabs into spaces, handle underlining, boldfacing, etc. 392157114Sscottl * Returns 0 if ok, 1 if couldn't fit in buffer. 393157114Sscottl */ 394157114Sscottl public int 395157114Sscottlpappend(c, pos) 396157114Sscottl register int c; 397158737Sambrisko POSITION pos; 398158737Sambrisko{ 399158737Sambrisko int r; 400158737Sambrisko 401158737Sambrisko if (pendc) 402158737Sambrisko { 403158737Sambrisko if (do_append(pendc, pendpos)) 404158737Sambrisko /* 405158737Sambrisko * Oops. We've probably lost the char which 406158737Sambrisko * was in pendc, since caller won't back up. 407158737Sambrisko */ 408158737Sambrisko return (1); 409158737Sambrisko pendc = '\0'; 410158737Sambrisko } 411158737Sambrisko 412158737Sambrisko if (c == '\r' && bs_mode == BS_SPECIAL) 413158737Sambrisko { 414158737Sambrisko /* 415158737Sambrisko * Don't put the CR into the buffer until we see 416158737Sambrisko * the next char. If the next char is a newline, 417158737Sambrisko * discard the CR. 418157114Sscottl */ 419157114Sscottl pendc = c; 420233711Sambrisko pendpos = pos; 421233711Sambrisko return (0); 422233711Sambrisko } 423235014Sambrisko 424233711Sambrisko r = do_append(c, pos); 425163398Sscottl /* 426163398Sscottl * If we need to shift the line, do it. 427163398Sscottl * But wait until we get to at least the middle of the screen, 428163398Sscottl * so shifting it doesn't affect the chars we're currently 429163398Sscottl * pappending. (Bold & underline can get messed up otherwise.) 430163398Sscottl */ 431163398Sscottl if (cshift < hshift && column > sc_width / 2) 432163398Sscottl pshift(hshift - cshift); 433163398Sscottl return (r); 434196200Sscottl} 435163398Sscottl 436196200Sscottl static int 437196200Sscottldo_append(c, pos) 438196200Sscottl int c; 439196200Sscottl POSITION pos; 440196200Sscottl{ 441196200Sscottl register char *s; 442196200Sscottl register int a; 443196200Sscottl 444196200Sscottl#define STOREC(c,a) \ 445196200Sscottl if (storec((c),(a),pos)) return (1); else curr++ 446163398Sscottl 447163398Sscottl if (c == '\b') 448163398Sscottl { 449163398Sscottl switch (bs_mode) 450163398Sscottl { 451163398Sscottl case BS_NORMAL: 452233711Sambrisko STOREC(c, AT_NORMAL); 453233711Sambrisko break; 454233711Sambrisko case BS_CONTROL: 455233711Sambrisko goto do_control_char; 456233711Sambrisko case BS_SPECIAL: 457233711Sambrisko if (curr == 0) 458233711Sambrisko break; 459233711Sambrisko backc(); 460233711Sambrisko overstrike = 1; 461157114Sscottl break; 462157114Sscottl } 463157114Sscottl } else if (overstrike) 464157114Sscottl { 465157114Sscottl /* 466157114Sscottl * Overstrike the character at the current position 467157114Sscottl * in the line buffer. This will cause either 468157114Sscottl * underline (if a "_" is overstruck), 469157114Sscottl * bold (if an identical character is overstruck), 470157114Sscottl * or just deletion of the character in the buffer. 471196200Sscottl */ 472157114Sscottl overstrike = 0; 473157114Sscottl if ((char)c == linebuf[curr]) 474157114Sscottl STOREC(linebuf[curr], AT_BOLD); 475157114Sscottl else if (c == '_') 476247369Ssmh STOREC(linebuf[curr], AT_UNDERLINE); 477247369Ssmh else if (linebuf[curr] == '_') 478157114Sscottl STOREC(c, AT_UNDERLINE); 479157114Sscottl else if (control_char(c)) 480157114Sscottl goto do_control_char; 481157114Sscottl else 482157114Sscottl STOREC(c, AT_NORMAL); 483157114Sscottl } else if (c == '\t') 484157114Sscottl { 485157114Sscottl /* 486157114Sscottl * Expand a tab into spaces. 487157114Sscottl */ 488157114Sscottl if (tabstop == 0) 489157114Sscottl tabstop = 1; 490157114Sscottl switch (bs_mode) 491157114Sscottl { 492157114Sscottl case BS_CONTROL: 493233711Sambrisko goto do_control_char; 494233711Sambrisko case BS_NORMAL: 495233711Sambrisko case BS_SPECIAL: 496233711Sambrisko do 497233711Sambrisko { 498233711Sambrisko STOREC(' ', AT_NORMAL); 499157114Sscottl } while (((column + cshift - lmargin) % tabstop) != 0); 500233711Sambrisko break; 501233711Sambrisko } 502233711Sambrisko } else if (control_char(c)) 503157114Sscottl { 504157114Sscottl do_control_char: 505157114Sscottl if (ctldisp == OPT_ON || (ctldisp == OPT_ONPLUS && c == ESC)) 506157114Sscottl { 507157114Sscottl /* 508157114Sscottl * Output as a normal character. 509157114Sscottl */ 510157114Sscottl STOREC(c, AT_NORMAL); 511157114Sscottl } else 512157114Sscottl { 513157114Sscottl /* 514157114Sscottl * Convert to printable representation. 515157114Sscottl */ 516233711Sambrisko s = prchar(c); 517233711Sambrisko a = binattr; 518233711Sambrisko 519233711Sambrisko /* 520157114Sscottl * Make sure we can get the entire representation 521157114Sscottl * of the character on this line. 522175897Sambrisko */ 523175897Sambrisko if (column + (int) strlen(s) + 524157114Sscottl attr_swidth(a) + attr_ewidth(a) > sc_width) 525157114Sscottl return (1); 526157114Sscottl 527157114Sscottl for ( ; *s != 0; s++) 528157114Sscottl STOREC(*s, a); 529157114Sscottl } 530157114Sscottl } else 531157114Sscottl { 532157114Sscottl STOREC(c, AT_NORMAL); 533157114Sscottl } 534233711Sambrisko 535233711Sambrisko return (0); 536233711Sambrisko} 537233711Sambrisko 538233711Sambrisko/* 539233711Sambrisko * Terminate the line in the line buffer. 540157114Sscottl */ 541157114Sscottl public void 542233711Sambriskopdone(endline) 543233711Sambrisko int endline; 544233711Sambrisko{ 545233711Sambrisko if (pendc && (pendc != '\r' || !endline)) 546233711Sambrisko /* 547233711Sambrisko * If we had a pending character, put it in the buffer. 548233711Sambrisko * But discard a pending CR if we are at end of line 549233711Sambrisko * (that is, discard the CR in a CR/LF sequence). 550233711Sambrisko */ 551233711Sambrisko (void) do_append(pendc, pendpos); 552233711Sambrisko 553233711Sambrisko /* 554233711Sambrisko * Make sure we've shifted the line, if we need to. 555233711Sambrisko */ 556233711Sambrisko if (cshift < hshift) 557157114Sscottl pshift(hshift - cshift); 558157114Sscottl 559157114Sscottl /* 560157114Sscottl * Add a newline if necessary, 561157114Sscottl * and append a '\0' to the end of the line. 562157114Sscottl */ 563157114Sscottl if (column < sc_width || !auto_wrap || ignaw || ctldisp == OPT_ON) 564157114Sscottl { 565157114Sscottl linebuf[curr] = '\n'; 566157114Sscottl attr[curr] = AT_NORMAL; 567157114Sscottl curr++; 568157114Sscottl } 569157114Sscottl linebuf[curr] = '\0'; 570157114Sscottl attr[curr] = AT_NORMAL; 571157114Sscottl /* 572157114Sscottl * If we are done with this line, reset the current shift. 573157114Sscottl */ 574157114Sscottl if (endline) 575157114Sscottl cshift = 0; 576157114Sscottl} 577157114Sscottl 578157114Sscottl/* 579157114Sscottl * Get a character from the current line. 580157114Sscottl * Return the character as the function return value, 581157114Sscottl * and the character attribute in *ap. 582157114Sscottl */ 583157114Sscottl public int 584157114Sscottlgline(i, ap) 585157114Sscottl register int i; 586157114Sscottl register int *ap; 587233711Sambrisko{ 588233711Sambrisko char *s; 589157114Sscottl 590157114Sscottl if (is_null_line) 591233711Sambrisko { 592157114Sscottl /* 593157114Sscottl * If there is no current line, we pretend the line is 594157114Sscottl * either "~" or "", depending on the "twiddle" flag. 595157114Sscottl */ 596157114Sscottl *ap = AT_BOLD; 597157114Sscottl s = (twiddle) ? "~\n" : "\n"; 598157114Sscottl return (s[i]); 599157114Sscottl } 600157114Sscottl 601157114Sscottl *ap = attr[i]; 602157114Sscottl return (linebuf[i] & 0377); 603157114Sscottl} 604157114Sscottl 605157114Sscottl/* 606157114Sscottl * Indicate that there is no current line. 607157114Sscottl */ 608157114Sscottl public void 609157114Sscottlnull_line() 610157114Sscottl{ 611157114Sscottl is_null_line = 1; 612157114Sscottl cshift = 0; 613157114Sscottl} 614157114Sscottl 615157114Sscottl/* 616233711Sambrisko * Analogous to forw_line(), but deals with "raw lines": 617157114Sscottl * lines which are not split for screen width. 618157114Sscottl * {{ This is supposed to be more efficient than forw_line(). }} 619157114Sscottl */ 620157114Sscottl public POSITION 621157114Sscottlforw_raw_line(curr_pos, linep) 622157114Sscottl POSITION curr_pos; 623157114Sscottl char **linep; 624157114Sscottl{ 625157114Sscottl register char *p; 626157114Sscottl register int c; 627157114Sscottl POSITION new_pos; 628157114Sscottl 629157114Sscottl if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || 630157114Sscottl (c = ch_forw_get()) == EOI) 631157114Sscottl return (NULL_POSITION); 632157114Sscottl 633157114Sscottl p = linebuf; 634157114Sscottl 635157114Sscottl for (;;) 636157114Sscottl { 637157114Sscottl if (c == '\n' || c == EOI) 638157114Sscottl { 639157114Sscottl new_pos = ch_tell(); 640157114Sscottl break; 641157114Sscottl } 642157114Sscottl if (p >= &linebuf[sizeof(linebuf)-1]) 643157114Sscottl { 644157114Sscottl /* 645157114Sscottl * Overflowed the input buffer. 646157114Sscottl * Pretend the line ended here. 647157114Sscottl * {{ The line buffer is supposed to be big 648157114Sscottl * enough that this never happens. }} 649157114Sscottl */ 650157114Sscottl new_pos = ch_tell() - 1; 651157114Sscottl break; 652157114Sscottl } 653157114Sscottl *p++ = c; 654157114Sscottl c = ch_forw_get(); 655157114Sscottl } 656157114Sscottl *p = '\0'; 657157114Sscottl if (linep != NULL) 658157114Sscottl *linep = linebuf; 659157114Sscottl return (new_pos); 660157114Sscottl} 661157114Sscottl 662157114Sscottl/* 663157114Sscottl * Analogous to back_line(), but deals with "raw lines". 664157114Sscottl * {{ This is supposed to be more efficient than back_line(). }} 665157114Sscottl */ 666233711Sambrisko public POSITION 667233711Sambriskoback_raw_line(curr_pos, linep) 668233711Sambrisko POSITION curr_pos; 669233711Sambrisko char **linep; 670233711Sambrisko{ 671233711Sambrisko register char *p; 672233711Sambrisko register int c; 673233711Sambrisko POSITION new_pos; 674233711Sambrisko 675233711Sambrisko if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() || 676233711Sambrisko ch_seek(curr_pos-1)) 677233711Sambrisko return (NULL_POSITION); 678233711Sambrisko 679233711Sambrisko p = &linebuf[sizeof(linebuf)]; 680233711Sambrisko *--p = '\0'; 681233711Sambrisko 682233711Sambrisko for (;;) 683233711Sambrisko { 684233711Sambrisko c = ch_back_get(); 685233711Sambrisko if (c == '\n') 686233711Sambrisko { 687233711Sambrisko /* 688233711Sambrisko * This is the newline ending the previous line. 689233711Sambrisko * We have hit the beginning of the line. 690233711Sambrisko */ 691233711Sambrisko new_pos = ch_tell() + 1; 692233711Sambrisko break; 693233711Sambrisko } 694233711Sambrisko if (c == EOI) 695233711Sambrisko { 696233711Sambrisko /* 697233711Sambrisko * We have hit the beginning of the file. 698233711Sambrisko * This must be the first line in the file. 699233711Sambrisko * This must, of course, be the beginning of the line. 700233711Sambrisko */ 701233711Sambrisko new_pos = ch_zero(); 702233711Sambrisko break; 703233711Sambrisko } 704233711Sambrisko if (p <= linebuf) 705233711Sambrisko { 706233711Sambrisko /* 707233711Sambrisko * Overflowed the input buffer. 708233711Sambrisko * Pretend the line ended here. 709233711Sambrisko */ 710233711Sambrisko new_pos = ch_tell() + 1; 711233711Sambrisko break; 712233711Sambrisko } 713233711Sambrisko *--p = c; 714233711Sambrisko } 715233711Sambrisko if (linep != NULL) 716233711Sambrisko *linep = p; 717233711Sambrisko return (new_pos); 718233711Sambrisko} 719233711Sambrisko