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