1 /* 2 * Copyright (C) 1984-2002 Mark Nudelman 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Less License, as specified in the README file. 6 * 7 * For more information about less, or for information on how to 8 * contact the author, see the README file. 9 */ 10 11 12 /* 13 * Routines to manipulate the "line buffer". 14 * The line buffer holds a line of output as it is being built 15 * in preparation for output to the screen. 16 */ 17 18 #include "less.h" 19 20 #define IS_CONT(c) (((c) & 0xC0) == 0x80) 21 22 public char *linebuf = NULL; /* Buffer which holds the current output line */ 23 static char *attr = NULL; /* Extension of linebuf to hold attributes */ 24 public int size_linebuf = 0; /* Size of line buffer (and attr buffer) */ 25 26 public int cshift; /* Current left-shift of output line buffer */ 27 public int hshift; /* Desired left-shift of output line buffer */ 28 public int tabstops[TABSTOP_MAX] = { 0 }; /* Custom tabstops */ 29 public int ntabstops = 1; /* Number of tabstops */ 30 public int tabdefault = 8; /* Default repeated tabstops */ 31 32 static int curr; /* Index into linebuf */ 33 static int column; /* Printable length, accounting for 34 backspaces, etc. */ 35 static int overstrike; /* Next char should overstrike previous char */ 36 static int last_overstrike = AT_NORMAL; 37 static int is_null_line; /* There is no current line */ 38 static int lmargin; /* Left margin */ 39 static int hilites; /* Number of hilites in this line */ 40 static char pendc; 41 static POSITION pendpos; 42 static char *end_ansi_chars; 43 44 static int do_append(); 45 46 extern int bs_mode; 47 extern int linenums; 48 extern int ctldisp; 49 extern int twiddle; 50 extern int binattr; 51 extern int status_col; 52 extern int auto_wrap, ignaw; 53 extern int bo_s_width, bo_e_width; 54 extern int ul_s_width, ul_e_width; 55 extern int bl_s_width, bl_e_width; 56 extern int so_s_width, so_e_width; 57 extern int sc_width, sc_height; 58 extern int utf_mode; 59 extern POSITION start_attnpos; 60 extern POSITION end_attnpos; 61 62 /* 63 * Initialize from environment variables. 64 */ 65 public void 66 init_line() 67 { 68 end_ansi_chars = lgetenv("LESSANSIENDCHARS"); 69 if (end_ansi_chars == NULL || *end_ansi_chars == '\0') 70 end_ansi_chars = "m"; 71 linebuf = (char *) ecalloc(LINEBUF_SIZE, sizeof(char)); 72 attr = (char *) ecalloc(LINEBUF_SIZE, sizeof(char)); 73 size_linebuf = LINEBUF_SIZE; 74 } 75 76 /* 77 * Expand the line buffer. 78 */ 79 static int 80 expand_linebuf() 81 { 82 int new_size = size_linebuf * 2; 83 char *new_buf; 84 char *new_attr; 85 86 new_buf = realloc(linebuf, new_size); 87 if (new_buf == NULL) 88 return 1; 89 new_attr = realloc(attr, new_size); 90 if (new_attr == NULL) { 91 /* realloc linebuf back to original size */ 92 linebuf = realloc(new_buf, size_linebuf); 93 if (linebuf == NULL) 94 err(1, NULL); 95 return 1; 96 } 97 memset(new_buf + size_linebuf, 0, new_size - size_linebuf); 98 memset(new_attr + size_linebuf, 0, new_size - size_linebuf); 99 linebuf = new_buf; 100 attr = new_attr; 101 size_linebuf = new_size; 102 return 0; 103 } 104 105 /* 106 * Rewind the line buffer. 107 */ 108 public void 109 prewind() 110 { 111 curr = 0; 112 column = 0; 113 overstrike = 0; 114 is_null_line = 0; 115 pendc = '\0'; 116 lmargin = 0; 117 if (status_col) 118 lmargin += 1; 119 #if HILITE_SEARCH 120 hilites = 0; 121 #endif 122 } 123 124 /* 125 * Insert the line number (of the given position) into the line buffer. 126 */ 127 public void 128 plinenum(pos) 129 POSITION pos; 130 { 131 register LINENUM linenum = 0; 132 register int i; 133 134 if (linenums == OPT_ONPLUS) 135 { 136 /* 137 * Get the line number and put it in the current line. 138 * {{ Note: since find_linenum calls forw_raw_line, 139 * it may seek in the input file, requiring the caller 140 * of plinenum to re-seek if necessary. }} 141 * {{ Since forw_raw_line modifies linebuf, we must 142 * do this first, before storing anything in linebuf. }} 143 */ 144 linenum = find_linenum(pos); 145 } 146 147 /* 148 * Display a status column if the -J option is set. 149 */ 150 if (status_col) 151 { 152 linebuf[curr] = ' '; 153 if (start_attnpos != NULL_POSITION && 154 pos >= start_attnpos && pos < end_attnpos) 155 attr[curr] = AT_STANDOUT; 156 else 157 attr[curr] = 0; 158 curr++; 159 column++; 160 } 161 /* 162 * Display the line number at the start of each line 163 * if the -N option is set. 164 */ 165 if (linenums == OPT_ONPLUS) 166 { 167 char buf[INT_STRLEN_BOUND(pos) + 2]; 168 int n; 169 170 linenumtoa(linenum, buf, sizeof(buf)); 171 n = strlen(buf); 172 if (n < MIN_LINENUM_WIDTH) 173 n = MIN_LINENUM_WIDTH; 174 snprintf(linebuf+curr, size_linebuf-curr, "%*s ", n, buf); 175 n++; /* One space after the line number. */ 176 for (i = 0; i < n; i++) 177 attr[curr+i] = AT_NORMAL; 178 curr += n; 179 column += n; 180 lmargin += n; 181 } 182 183 /* 184 * Append enough spaces to bring us to the lmargin. 185 */ 186 while (column < lmargin) 187 { 188 linebuf[curr] = ' '; 189 attr[curr++] = AT_NORMAL; 190 column++; 191 } 192 } 193 194 /* 195 * Determine how many characters are required to shift N columns. 196 */ 197 static int 198 shift_chars(s, len) 199 char *s; 200 int len; 201 { 202 char *p = s; 203 204 /* 205 * Each char counts for one column, except ANSI color escape 206 * sequences use no columns since they don't move the cursor. 207 */ 208 while (*p != '\0' && len > 0) 209 { 210 if (*p++ != ESC) 211 { 212 len--; 213 } else 214 { 215 while (*p != '\0') 216 { 217 if (is_ansi_end(*p++)) 218 break; 219 } 220 } 221 } 222 return (p - s); 223 } 224 225 /* 226 * Determine how many characters are required to shift N columns (UTF version). 227 * {{ FIXME: what about color escape sequences in UTF mode? }} 228 */ 229 static int 230 utf_shift_chars(s, len) 231 char *s; 232 int len; 233 { 234 int ulen = 0; 235 236 while (*s != '\0' && len > 0) 237 { 238 if (!IS_CONT(*s)) 239 len--; 240 s++; 241 ulen++; 242 } 243 while (IS_CONT(*s)) 244 { 245 s++; 246 ulen++; 247 } 248 return (ulen); 249 } 250 251 /* 252 * Shift the input line left. 253 * This means discarding N printable chars at the start of the buffer. 254 */ 255 static void 256 pshift(shift) 257 int shift; 258 { 259 int i; 260 int nchars; 261 262 if (shift > column - lmargin) 263 shift = column - lmargin; 264 if (shift > curr - lmargin) 265 shift = curr - lmargin; 266 267 if (utf_mode) 268 nchars = utf_shift_chars(linebuf + lmargin, shift); 269 else 270 nchars = shift_chars(linebuf + lmargin, shift); 271 if (nchars > curr) 272 nchars = curr; 273 for (i = 0; i < curr - nchars; i++) 274 { 275 linebuf[lmargin + i] = linebuf[lmargin + i + nchars]; 276 attr[lmargin + i] = attr[lmargin + i + nchars]; 277 } 278 curr -= nchars; 279 column -= shift; 280 cshift += shift; 281 } 282 283 /* 284 * Return the printing width of the start (enter) sequence 285 * for a given character attribute. 286 */ 287 static int 288 attr_swidth(a) 289 int a; 290 { 291 switch (a) 292 { 293 case AT_BOLD: return (bo_s_width); 294 case AT_UNDERLINE: return (ul_s_width); 295 case AT_BLINK: return (bl_s_width); 296 case AT_STANDOUT: return (so_s_width); 297 } 298 return (0); 299 } 300 301 /* 302 * Return the printing width of the end (exit) sequence 303 * for a given character attribute. 304 */ 305 static int 306 attr_ewidth(a) 307 int a; 308 { 309 switch (a) 310 { 311 case AT_BOLD: return (bo_e_width); 312 case AT_UNDERLINE: return (ul_e_width); 313 case AT_BLINK: return (bl_e_width); 314 case AT_STANDOUT: return (so_e_width); 315 } 316 return (0); 317 } 318 319 /* 320 * Return the printing width of a given character and attribute, 321 * if the character were added to the current position in the line buffer. 322 * Adding a character with a given attribute may cause an enter or exit 323 * attribute sequence to be inserted, so this must be taken into account. 324 */ 325 static int 326 pwidth(c, a) 327 int c; 328 int a; 329 { 330 register int w; 331 332 if (utf_mode && IS_CONT(c)) 333 return (0); 334 335 if (c == '\b') 336 /* 337 * Backspace moves backwards one position. 338 */ 339 return (-1); 340 341 if (control_char(c)) 342 /* 343 * Control characters do unpredicatable things, 344 * so we don't even try to guess; say it doesn't move. 345 * This can only happen if the -r flag is in effect. 346 */ 347 return (0); 348 349 /* 350 * Other characters take one space, 351 * plus the width of any attribute enter/exit sequence. 352 */ 353 w = 1; 354 if (curr > 0 && attr[curr-1] != a) 355 w += attr_ewidth(attr[curr-1]); 356 if (a && (curr == 0 || attr[curr-1] != a)) 357 w += attr_swidth(a); 358 return (w); 359 } 360 361 /* 362 * Delete the previous character in the line buffer. 363 */ 364 static void 365 backc() 366 { 367 curr--; 368 column -= pwidth(linebuf[curr], attr[curr]); 369 } 370 371 /* 372 * Are we currently within a recognized ANSI escape sequence? 373 */ 374 static int 375 in_ansi_esc_seq() 376 { 377 int i; 378 379 /* 380 * Search backwards for either an ESC (which means we ARE in a seq); 381 * or an end char (which means we're NOT in a seq). 382 */ 383 for (i = curr-1; i >= 0; i--) 384 { 385 if (linebuf[i] == ESC) 386 return (1); 387 if (is_ansi_end(linebuf[i])) 388 return (0); 389 } 390 return (0); 391 } 392 393 /* 394 * Is a character the end of an ANSI escape sequence? 395 */ 396 public int 397 is_ansi_end(c) 398 char c; 399 { 400 return (strchr(end_ansi_chars, c) != NULL); 401 } 402 403 /* 404 * Append a character and attribute to the line buffer. 405 */ 406 #define STORE_CHAR(c,a,pos) \ 407 do { if (store_char((c),(a),(pos))) return (1); else curr++; } while (0) 408 409 static int 410 store_char(c, a, pos) 411 int c; 412 int a; 413 POSITION pos; 414 { 415 register int w; 416 417 if (a != AT_NORMAL) 418 last_overstrike = a; 419 #if HILITE_SEARCH 420 if (is_hilited(pos, pos+1, 0)) 421 { 422 /* 423 * This character should be highlighted. 424 * Override the attribute passed in. 425 */ 426 a = AT_STANDOUT; 427 hilites++; 428 } 429 #endif 430 if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq()) 431 w = 0; 432 else 433 w = pwidth(c, a); 434 if (ctldisp != OPT_ON && column + w + attr_ewidth(a) > sc_width) 435 /* 436 * Won't fit on screen. 437 */ 438 return (1); 439 440 if (curr >= size_linebuf-2) 441 { 442 /* 443 * Won't fit in line buffer. 444 * Try to expand it. 445 */ 446 if (expand_linebuf()) 447 return (1); 448 } 449 450 /* 451 * Special handling for "magic cookie" terminals. 452 * If an attribute enter/exit sequence has a printing width > 0, 453 * and the sequence is adjacent to a space, delete the space. 454 * We just mark the space as invisible, to avoid having too 455 * many spaces deleted. 456 * {{ Note that even if the attribute width is > 1, we 457 * delete only one space. It's not worth trying to do more. 458 * It's hardly worth doing this much. }} 459 */ 460 if (curr > 0 && a != AT_NORMAL && 461 linebuf[curr-1] == ' ' && attr[curr-1] == AT_NORMAL && 462 attr_swidth(a) > 0) 463 { 464 /* 465 * We are about to append an enter-attribute sequence 466 * just after a space. Delete the space. 467 */ 468 attr[curr-1] = AT_INVIS; 469 column--; 470 } else if (curr > 0 && attr[curr-1] != AT_NORMAL && 471 attr[curr-1] != AT_INVIS && c == ' ' && a == AT_NORMAL && 472 attr_ewidth(attr[curr-1]) > 0) 473 { 474 /* 475 * We are about to append a space just after an 476 * exit-attribute sequence. Delete the space. 477 */ 478 a = AT_INVIS; 479 column--; 480 } 481 /* End of magic cookie handling. */ 482 483 linebuf[curr] = c; 484 attr[curr] = a; 485 column += w; 486 return (0); 487 } 488 489 /* 490 * Append a tab to the line buffer. 491 * Store spaces to represent the tab. 492 */ 493 #define STORE_TAB(a,pos) \ 494 do { if (store_tab((a),(pos))) return (1); } while (0) 495 496 static int 497 store_tab(attr, pos) 498 int attr; 499 POSITION pos; 500 { 501 int to_tab = column + cshift - lmargin; 502 int i; 503 504 if (ntabstops < 2 || to_tab >= tabstops[ntabstops-1]) 505 to_tab = tabdefault - 506 ((to_tab - tabstops[ntabstops-1]) % tabdefault); 507 else 508 { 509 for (i = ntabstops - 2; i >= 0; i--) 510 if (to_tab >= tabstops[i]) 511 break; 512 to_tab = tabstops[i+1] - to_tab; 513 } 514 515 do { 516 STORE_CHAR(' ', attr, pos); 517 } while (--to_tab > 0); 518 return 0; 519 } 520 521 /* 522 * Append a character to the line buffer. 523 * Expand tabs into spaces, handle underlining, boldfacing, etc. 524 * Returns 0 if ok, 1 if couldn't fit in buffer. 525 */ 526 public int 527 pappend(c, pos) 528 register int c; 529 POSITION pos; 530 { 531 int r; 532 533 if (pendc) 534 { 535 if (do_append(pendc, pendpos)) 536 /* 537 * Oops. We've probably lost the char which 538 * was in pendc, since caller won't back up. 539 */ 540 return (1); 541 pendc = '\0'; 542 } 543 544 if (c == '\r' && bs_mode == BS_SPECIAL) 545 { 546 /* 547 * Don't put the CR into the buffer until we see 548 * the next char. If the next char is a newline, 549 * discard the CR. 550 */ 551 pendc = c; 552 pendpos = pos; 553 return (0); 554 } 555 556 r = do_append(c, pos); 557 /* 558 * If we need to shift the line, do it. 559 * But wait until we get to at least the middle of the screen, 560 * so shifting it doesn't affect the chars we're currently 561 * pappending. (Bold & underline can get messed up otherwise.) 562 */ 563 if (cshift < hshift && column > sc_width / 2) 564 { 565 linebuf[curr] = '\0'; 566 pshift(hshift - cshift); 567 } 568 return (r); 569 } 570 571 #define IS_UTF8_4BYTE(c) ( ((c) & 0xf8) == 0xf0 ) 572 #define IS_UTF8_3BYTE(c) ( ((c) & 0xf0) == 0xe0 ) 573 #define IS_UTF8_2BYTE(c) ( ((c) & 0xe0) == 0xc0 ) 574 #define IS_UTF8_TRAIL(c) ( ((c) & 0xc0) == 0x80 ) 575 576 static int 577 do_append(c, pos) 578 int c; 579 POSITION pos; 580 { 581 register char *s; 582 register int a; 583 584 #define STOREC(c,a) \ 585 if ((c) == '\t') STORE_TAB((a),pos); else STORE_CHAR((c),(a),pos) 586 587 if (c == '\b') 588 { 589 switch (bs_mode) 590 { 591 case BS_NORMAL: 592 STORE_CHAR(c, AT_NORMAL, pos); 593 break; 594 case BS_CONTROL: 595 goto do_control_char; 596 case BS_SPECIAL: 597 if (curr == 0) 598 break; 599 backc(); 600 overstrike = 1; 601 break; 602 } 603 } else if (overstrike) 604 { 605 /* 606 * Overstrike the character at the current position 607 * in the line buffer. This will cause either 608 * underline (if a "_" is overstruck), 609 * bold (if an identical character is overstruck), 610 * or just deletion of the character in the buffer. 611 */ 612 overstrike--; 613 if (utf_mode && IS_UTF8_4BYTE(c) && curr > 2 && (char)c == linebuf[curr-3]) 614 { 615 backc(); 616 backc(); 617 backc(); 618 STORE_CHAR(linebuf[curr], AT_BOLD, pos); 619 overstrike = 3; 620 } else if (utf_mode && (IS_UTF8_3BYTE(c) || (overstrike==2 && IS_UTF8_TRAIL(c))) && curr > 1 && (char)c == linebuf[curr-2]) 621 { 622 backc(); 623 backc(); 624 STORE_CHAR(linebuf[curr], AT_BOLD, pos); 625 overstrike = 2; 626 } else if (utf_mode && curr > 0 && (IS_UTF8_2BYTE(c) || (overstrike==1 && IS_UTF8_TRAIL(c))) && (char)c == linebuf[curr-1]) 627 { 628 backc(); 629 STORE_CHAR(linebuf[curr], AT_BOLD, pos); 630 overstrike = 1; 631 } else if (utf_mode && curr > 0 && IS_UTF8_TRAIL(c) && attr[curr-1] == AT_UNDERLINE) 632 { 633 STOREC(c, AT_UNDERLINE); 634 } else if ((char)c == linebuf[curr]) 635 { 636 /* 637 * Overstriking a char with itself means make it bold. 638 * But overstriking an underscore with itself is 639 * ambiguous. It could mean make it bold, or 640 * it could mean make it underlined. 641 * Use the previous overstrike to resolve it. 642 */ 643 if (c == '_' && last_overstrike != AT_NORMAL) 644 STOREC(c, last_overstrike); 645 else 646 STOREC(c, AT_BOLD); 647 } else if (c == '_') 648 { 649 if (utf_mode) 650 { 651 int i; 652 for (i = 0; i < 5; i++) 653 { 654 if (curr <= i || !IS_CONT(linebuf[curr-i])) 655 break; 656 attr[curr-i-1] = AT_UNDERLINE; 657 } 658 } 659 STOREC(linebuf[curr], AT_UNDERLINE); 660 } else if (linebuf[curr] == '_') 661 { 662 if (utf_mode) 663 { 664 if (IS_UTF8_2BYTE(c)) 665 overstrike = 1; 666 else if (IS_UTF8_3BYTE(c)) 667 overstrike = 2; 668 else if (IS_UTF8_4BYTE(c)) 669 overstrike = 3; 670 } 671 STOREC(c, AT_UNDERLINE); 672 } else if (control_char(c)) 673 goto do_control_char; 674 else 675 STOREC(c, AT_NORMAL); 676 } else if (c == '\t') 677 { 678 /* 679 * Expand a tab into spaces. 680 */ 681 switch (bs_mode) 682 { 683 case BS_CONTROL: 684 goto do_control_char; 685 case BS_NORMAL: 686 case BS_SPECIAL: 687 STORE_TAB(AT_NORMAL, pos); 688 break; 689 } 690 } else if (control_char(c)) 691 { 692 do_control_char: 693 if (ctldisp == OPT_ON || (ctldisp == OPT_ONPLUS && c == ESC)) 694 { 695 /* 696 * Output as a normal character. 697 */ 698 STORE_CHAR(c, AT_NORMAL, pos); 699 } else 700 { 701 /* 702 * Convert to printable representation. 703 */ 704 s = prchar(c); 705 a = binattr; 706 707 /* 708 * Make sure we can get the entire representation 709 * of the character on this line. 710 */ 711 if (column + (int) strlen(s) + 712 attr_swidth(a) + attr_ewidth(a) > sc_width) 713 return (1); 714 715 for ( ; *s != 0; s++) 716 STORE_CHAR(*s, a, pos); 717 } 718 } else 719 { 720 STOREC(c, AT_NORMAL); 721 } 722 723 return (0); 724 } 725 726 /* 727 * Terminate the line in the line buffer. 728 */ 729 public void 730 pdone(endline) 731 int endline; 732 { 733 if (pendc && (pendc != '\r' || !endline)) 734 /* 735 * If we had a pending character, put it in the buffer. 736 * But discard a pending CR if we are at end of line 737 * (that is, discard the CR in a CR/LF sequence). 738 */ 739 (void) do_append(pendc, pendpos); 740 741 /* 742 * Make sure we've shifted the line, if we need to. 743 */ 744 if (cshift < hshift) 745 pshift(hshift - cshift); 746 747 /* 748 * Add a newline if necessary, 749 * and append a '\0' to the end of the line. 750 */ 751 if (column < sc_width || !auto_wrap || ignaw || ctldisp == OPT_ON) 752 { 753 linebuf[curr] = '\n'; 754 attr[curr] = AT_NORMAL; 755 curr++; 756 } 757 linebuf[curr] = '\0'; 758 attr[curr] = AT_NORMAL; 759 760 #if HILITE_SEARCH 761 if (status_col && hilites > 0) 762 { 763 linebuf[0] = '*'; 764 attr[0] = AT_STANDOUT; 765 } 766 #endif 767 /* 768 * If we are done with this line, reset the current shift. 769 */ 770 if (endline) 771 cshift = 0; 772 } 773 774 /* 775 * Get a character from the current line. 776 * Return the character as the function return value, 777 * and the character attribute in *ap. 778 */ 779 public int 780 gline(i, ap) 781 register int i; 782 register int *ap; 783 { 784 char *s; 785 786 if (is_null_line) 787 { 788 /* 789 * If there is no current line, we pretend the line is 790 * either "~" or "", depending on the "twiddle" flag. 791 */ 792 *ap = AT_BOLD; 793 s = (twiddle) ? "~\n" : "\n"; 794 return (s[i]); 795 } 796 797 *ap = attr[i]; 798 return (linebuf[i] & 0377); 799 } 800 801 /* 802 * Indicate that there is no current line. 803 */ 804 public void 805 null_line() 806 { 807 is_null_line = 1; 808 cshift = 0; 809 } 810 811 /* 812 * Analogous to forw_line(), but deals with "raw lines": 813 * lines which are not split for screen width. 814 * {{ This is supposed to be more efficient than forw_line(). }} 815 */ 816 public POSITION 817 forw_raw_line(curr_pos, linep) 818 POSITION curr_pos; 819 char **linep; 820 { 821 register int n; 822 register int c; 823 POSITION new_pos; 824 825 if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || 826 (c = ch_forw_get()) == EOI) 827 return (NULL_POSITION); 828 829 n = 0; 830 for (;;) 831 { 832 if (c == '\n' || c == EOI) 833 { 834 new_pos = ch_tell(); 835 break; 836 } 837 if (n >= size_linebuf-1) 838 { 839 if (expand_linebuf()) 840 { 841 /* 842 * Overflowed the input buffer. 843 * Pretend the line ended here. 844 */ 845 new_pos = ch_tell() - 1; 846 break; 847 } 848 } 849 linebuf[n++] = c; 850 c = ch_forw_get(); 851 } 852 linebuf[n] = '\0'; 853 if (linep != NULL) 854 *linep = linebuf; 855 return (new_pos); 856 } 857 858 /* 859 * Analogous to back_line(), but deals with "raw lines". 860 * {{ This is supposed to be more efficient than back_line(). }} 861 */ 862 public POSITION 863 back_raw_line(curr_pos, linep) 864 POSITION curr_pos; 865 char **linep; 866 { 867 register int n; 868 register int c; 869 POSITION new_pos; 870 871 if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() || 872 ch_seek(curr_pos-1)) 873 return (NULL_POSITION); 874 875 n = size_linebuf; 876 linebuf[--n] = '\0'; 877 for (;;) 878 { 879 c = ch_back_get(); 880 if (c == '\n') 881 { 882 /* 883 * This is the newline ending the previous line. 884 * We have hit the beginning of the line. 885 */ 886 new_pos = ch_tell() + 1; 887 break; 888 } 889 if (c == EOI) 890 { 891 /* 892 * We have hit the beginning of the file. 893 * This must be the first line in the file. 894 * This must, of course, be the beginning of the line. 895 */ 896 new_pos = ch_zero(); 897 break; 898 } 899 if (n <= 0) 900 { 901 int old_size_linebuf = size_linebuf; 902 if (expand_linebuf()) 903 { 904 /* 905 * Overflowed the input buffer. 906 * Pretend the line ended here. 907 */ 908 new_pos = ch_tell() + 1; 909 break; 910 } 911 /* 912 * Shift the data to the end of the new linebuf. 913 */ 914 n = size_linebuf - old_size_linebuf; 915 memmove(linebuf + n, linebuf, old_size_linebuf); 916 } 917 linebuf[--n] = c; 918 } 919 if (linep != NULL) 920 *linep = &linebuf[n]; 921 return (new_pos); 922 } 923