line.c revision 60786
160786Sps/* 260786Sps * Copyright (C) 1984-2000 Mark Nudelman 360786Sps * 460786Sps * You may distribute under the terms of either the GNU General Public 560786Sps * License or the Less License, as specified in the README file. 660786Sps * 760786Sps * For more information about less, or for information on how to 860786Sps * contact the author, see the README file. 960786Sps */ 1060786Sps 1160786Sps 1260786Sps/* 1360786Sps * Routines to manipulate the "line buffer". 1460786Sps * The line buffer holds a line of output as it is being built 1560786Sps * in preparation for output to the screen. 1660786Sps */ 1760786Sps 1860786Sps#include "less.h" 1960786Sps 2060786Sps#define IS_CONT(c) (((c) & 0xC0) == 0x80) 2160786Sps 2260786Sps/* Buffer which holds the current output line */ 2360786Spspublic char linebuf[LINEBUF_SIZE]; 2460786Spspublic int size_linebuf = sizeof(linebuf); 2560786Sps 2660786Spspublic int cshift; /* Current left-shift of output line buffer */ 2760786Spspublic int hshift; /* Desired left-shift of output line buffer */ 2860786Sps 2960786Spsstatic char attr[LINEBUF_SIZE]; /* Extension of linebuf to hold attributes */ 3060786Spsstatic int curr; /* Index into linebuf */ 3160786Spsstatic int column; /* Printable length, accounting for 3260786Sps backspaces, etc. */ 3360786Spsstatic int overstrike; /* Next char should overstrike previous char */ 3460786Spsstatic int is_null_line; /* There is no current line */ 3560786Spsstatic char pendc; 3660786Spsstatic POSITION pendpos; 3760786Spsstatic char *end_ansi_chars; 3860786Sps 3960786Spsstatic int do_append(); 4060786Sps 4160786Spsextern int bs_mode; 4260786Spsextern int tabstop; 4360786Spsextern int linenums; 4460786Spsextern int ctldisp; 4560786Spsextern int twiddle; 4660786Spsextern int binattr; 4760786Spsextern int auto_wrap, ignaw; 4860786Spsextern int bo_s_width, bo_e_width; 4960786Spsextern int ul_s_width, ul_e_width; 5060786Spsextern int bl_s_width, bl_e_width; 5160786Spsextern int so_s_width, so_e_width; 5260786Spsextern int sc_width, sc_height; 5360786Spsextern int utf_mode; 5460786Sps 5560786Sps/* 5660786Sps * Initialize from environment variables. 5760786Sps */ 5860786Sps public void 5960786Spsinit_line() 6060786Sps{ 6160786Sps end_ansi_chars = lgetenv("LESSANSIENDCHARS"); 6260786Sps if (end_ansi_chars == NULL || *end_ansi_chars == '\0') 6360786Sps end_ansi_chars = "m"; 6460786Sps} 6560786Sps 6660786Sps/* 6760786Sps * Rewind the line buffer. 6860786Sps */ 6960786Sps public void 7060786Spsprewind() 7160786Sps{ 7260786Sps curr = 0; 7360786Sps column = 0; 7460786Sps overstrike = 0; 7560786Sps is_null_line = 0; 7660786Sps pendc = '\0'; 7760786Sps} 7860786Sps 7960786Sps/* 8060786Sps * Insert the line number (of the given position) into the line buffer. 8160786Sps */ 8260786Sps public void 8360786Spsplinenum(pos) 8460786Sps POSITION pos; 8560786Sps{ 8660786Sps register int lno; 8760786Sps register int i; 8860786Sps register int n; 8960786Sps 9060786Sps /* 9160786Sps * We display the line number at the start of each line 9260786Sps * only if the -N option is set. 9360786Sps */ 9460786Sps if (linenums != OPT_ONPLUS) 9560786Sps return; 9660786Sps 9760786Sps /* 9860786Sps * Get the line number and put it in the current line. 9960786Sps * {{ Note: since find_linenum calls forw_raw_line, 10060786Sps * it may seek in the input file, requiring the caller 10160786Sps * of plinenum to re-seek if necessary. }} 10260786Sps */ 10360786Sps lno = find_linenum(pos); 10460786Sps 10560786Sps sprintf(&linebuf[curr], "%6d", lno); 10660786Sps n = strlen(&linebuf[curr]); 10760786Sps column += n; 10860786Sps for (i = 0; i < n; i++) 10960786Sps attr[curr++] = 0; 11060786Sps 11160786Sps /* 11260786Sps * Append enough spaces to bring us to the next tab stop. 11360786Sps * {{ We could avoid this at the cost of adding some 11460786Sps * complication to the tab stop logic in pappend(). }} 11560786Sps */ 11660786Sps if (tabstop == 0) 11760786Sps tabstop = 1; 11860786Sps do 11960786Sps { 12060786Sps linebuf[curr] = ' '; 12160786Sps attr[curr++] = AT_NORMAL; 12260786Sps column++; 12360786Sps } while (((column + cshift) % tabstop) != 0); 12460786Sps} 12560786Sps 12660786Sps/* 12760786Sps * 12860786Sps */ 12960786Sps static int 13060786Spsutf_len(char *s, int len) 13160786Sps{ 13260786Sps int ulen = 0; 13360786Sps 13460786Sps while (*s != '\0' && len > 0) 13560786Sps { 13660786Sps if (!IS_CONT(*s)) 13760786Sps len--; 13860786Sps s++; 13960786Sps ulen++; 14060786Sps } 14160786Sps while (IS_CONT(*s)) 14260786Sps { 14360786Sps s++; 14460786Sps ulen++; 14560786Sps } 14660786Sps return (ulen); 14760786Sps} 14860786Sps 14960786Sps/* 15060786Sps * Shift the input line left. 15160786Sps * This means discarding N printable chars at the start of the buffer. 15260786Sps */ 15360786Sps static void 15460786Spspshift(shift) 15560786Sps int shift; 15660786Sps{ 15760786Sps int i; 15860786Sps int real_shift; 15960786Sps 16060786Sps if (shift > column) 16160786Sps shift = column; 16260786Sps if (shift > curr) 16360786Sps shift = curr; 16460786Sps 16560786Sps if (!utf_mode) 16660786Sps real_shift = shift; 16760786Sps else 16860786Sps { 16960786Sps real_shift = utf_len(linebuf, shift); 17060786Sps if (real_shift > curr) 17160786Sps real_shift = curr; 17260786Sps } 17360786Sps for (i = 0; i < curr - real_shift; i++) 17460786Sps { 17560786Sps linebuf[i] = linebuf[i + real_shift]; 17660786Sps attr[i] = attr[i + real_shift]; 17760786Sps } 17860786Sps column -= shift; 17960786Sps curr -= real_shift; 18060786Sps cshift += shift; 18160786Sps} 18260786Sps 18360786Sps/* 18460786Sps * Return the printing width of the start (enter) sequence 18560786Sps * for a given character attribute. 18660786Sps */ 18760786Sps static int 18860786Spsattr_swidth(a) 18960786Sps int a; 19060786Sps{ 19160786Sps switch (a) 19260786Sps { 19360786Sps case AT_BOLD: return (bo_s_width); 19460786Sps case AT_UNDERLINE: return (ul_s_width); 19560786Sps case AT_BLINK: return (bl_s_width); 19660786Sps case AT_STANDOUT: return (so_s_width); 19760786Sps } 19860786Sps return (0); 19960786Sps} 20060786Sps 20160786Sps/* 20260786Sps * Return the printing width of the end (exit) sequence 20360786Sps * for a given character attribute. 20460786Sps */ 20560786Sps static int 20660786Spsattr_ewidth(a) 20760786Sps int a; 20860786Sps{ 20960786Sps switch (a) 21060786Sps { 21160786Sps case AT_BOLD: return (bo_e_width); 21260786Sps case AT_UNDERLINE: return (ul_e_width); 21360786Sps case AT_BLINK: return (bl_e_width); 21460786Sps case AT_STANDOUT: return (so_e_width); 21560786Sps } 21660786Sps return (0); 21760786Sps} 21860786Sps 21960786Sps/* 22060786Sps * Return the printing width of a given character and attribute, 22160786Sps * if the character were added to the current position in the line buffer. 22260786Sps * Adding a character with a given attribute may cause an enter or exit 22360786Sps * attribute sequence to be inserted, so this must be taken into account. 22460786Sps */ 22560786Sps static int 22660786Spspwidth(c, a) 22760786Sps int c; 22860786Sps int a; 22960786Sps{ 23060786Sps register int w; 23160786Sps 23260786Sps if (utf_mode && IS_CONT(c)) 23360786Sps return (0); 23460786Sps 23560786Sps if (c == '\b') 23660786Sps /* 23760786Sps * Backspace moves backwards one position. 23860786Sps */ 23960786Sps return (-1); 24060786Sps 24160786Sps if (control_char(c)) 24260786Sps /* 24360786Sps * Control characters do unpredicatable things, 24460786Sps * so we don't even try to guess; say it doesn't move. 24560786Sps * This can only happen if the -r flag is in effect. 24660786Sps */ 24760786Sps return (0); 24860786Sps 24960786Sps /* 25060786Sps * Other characters take one space, 25160786Sps * plus the width of any attribute enter/exit sequence. 25260786Sps */ 25360786Sps w = 1; 25460786Sps if (curr > 0 && attr[curr-1] != a) 25560786Sps w += attr_ewidth(attr[curr-1]); 25660786Sps if (a && (curr == 0 || attr[curr-1] != a)) 25760786Sps w += attr_swidth(a); 25860786Sps return (w); 25960786Sps} 26060786Sps 26160786Sps/* 26260786Sps * Delete the previous character in the line buffer. 26360786Sps */ 26460786Sps static void 26560786Spsbackc() 26660786Sps{ 26760786Sps curr--; 26860786Sps column -= pwidth(linebuf[curr], attr[curr]); 26960786Sps} 27060786Sps 27160786Sps/* 27260786Sps * Are we currently within a recognized ANSI escape sequence? 27360786Sps */ 27460786Sps static int 27560786Spsin_ansi_esc_seq() 27660786Sps{ 27760786Sps int i; 27860786Sps 27960786Sps /* 28060786Sps * Search backwards for either an ESC (which means we ARE in a seq); 28160786Sps * or an end char (which means we're NOT in a seq). 28260786Sps */ 28360786Sps for (i = curr-1; i >= 0; i--) 28460786Sps { 28560786Sps if (linebuf[i] == ESC) 28660786Sps return (1); 28760786Sps if (strchr(end_ansi_chars, linebuf[i]) != NULL) 28860786Sps return (0); 28960786Sps } 29060786Sps return (0); 29160786Sps} 29260786Sps 29360786Sps/* 29460786Sps * Append a character and attribute to the line buffer. 29560786Sps */ 29660786Sps static int 29760786Spsstorec(c, a, pos) 29860786Sps int c; 29960786Sps int a; 30060786Sps POSITION pos; 30160786Sps{ 30260786Sps register int w; 30360786Sps 30460786Sps#if HILITE_SEARCH 30560786Sps if (is_hilited(pos, pos+1, 0)) 30660786Sps /* 30760786Sps * This character should be highlighted. 30860786Sps * Override the attribute passed in. 30960786Sps */ 31060786Sps a = AT_STANDOUT; 31160786Sps#endif 31260786Sps if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq()) 31360786Sps w = 0; 31460786Sps else 31560786Sps w = pwidth(c, a); 31660786Sps if (ctldisp != OPT_ON && column + w + attr_ewidth(a) > sc_width) 31760786Sps /* 31860786Sps * Won't fit on screen. 31960786Sps */ 32060786Sps return (1); 32160786Sps 32260786Sps if (curr >= sizeof(linebuf)-2) 32360786Sps /* 32460786Sps * Won't fit in line buffer. 32560786Sps */ 32660786Sps return (1); 32760786Sps 32860786Sps /* 32960786Sps * Special handling for "magic cookie" terminals. 33060786Sps * If an attribute enter/exit sequence has a printing width > 0, 33160786Sps * and the sequence is adjacent to a space, delete the space. 33260786Sps * We just mark the space as invisible, to avoid having too 33360786Sps * many spaces deleted. 33460786Sps * {{ Note that even if the attribute width is > 1, we 33560786Sps * delete only one space. It's not worth trying to do more. 33660786Sps * It's hardly worth doing this much. }} 33760786Sps */ 33860786Sps if (curr > 0 && a != AT_NORMAL && 33960786Sps linebuf[curr-1] == ' ' && attr[curr-1] == AT_NORMAL && 34060786Sps attr_swidth(a) > 0) 34160786Sps { 34260786Sps /* 34360786Sps * We are about to append an enter-attribute sequence 34460786Sps * just after a space. Delete the space. 34560786Sps */ 34660786Sps attr[curr-1] = AT_INVIS; 34760786Sps column--; 34860786Sps } else if (curr > 0 && attr[curr-1] != AT_NORMAL && 34960786Sps attr[curr-1] != AT_INVIS && c == ' ' && a == AT_NORMAL && 35060786Sps attr_ewidth(attr[curr-1]) > 0) 35160786Sps { 35260786Sps /* 35360786Sps * We are about to append a space just after an 35460786Sps * exit-attribute sequence. Delete the space. 35560786Sps */ 35660786Sps a = AT_INVIS; 35760786Sps column--; 35860786Sps } 35960786Sps /* End of magic cookie handling. */ 36060786Sps 36160786Sps linebuf[curr] = c; 36260786Sps attr[curr] = a; 36360786Sps column += w; 36460786Sps return (0); 36560786Sps} 36660786Sps 36760786Sps/* 36860786Sps * Append a character to the line buffer. 36960786Sps * Expand tabs into spaces, handle underlining, boldfacing, etc. 37060786Sps * Returns 0 if ok, 1 if couldn't fit in buffer. 37160786Sps */ 37260786Sps public int 37360786Spspappend(c, pos) 37460786Sps register int c; 37560786Sps POSITION pos; 37660786Sps{ 37760786Sps int r; 37860786Sps 37960786Sps if (pendc) 38060786Sps { 38160786Sps if (do_append(pendc, pendpos)) 38260786Sps /* 38360786Sps * Oops. We've probably lost the char which 38460786Sps * was in pendc, since caller won't back up. 38560786Sps */ 38660786Sps return (1); 38760786Sps pendc = '\0'; 38860786Sps } 38960786Sps 39060786Sps if (c == '\r' && bs_mode == BS_SPECIAL) 39160786Sps { 39260786Sps /* 39360786Sps * Don't put the CR into the buffer until we see 39460786Sps * the next char. If the next char is a newline, 39560786Sps * discard the CR. 39660786Sps */ 39760786Sps pendc = c; 39860786Sps pendpos = pos; 39960786Sps return (0); 40060786Sps } 40160786Sps 40260786Sps r = do_append(c, pos); 40360786Sps /* 40460786Sps * If we need to shift the line, do it. 40560786Sps * But wait until we get to at least the middle of the screen, 40660786Sps * so shifting it doesn't affect the chars we're currently 40760786Sps * pappending. (Bold & underline can get messed up otherwise.) 40860786Sps */ 40960786Sps if (cshift < hshift && column > sc_width / 2) 41060786Sps pshift(hshift - cshift); 41160786Sps return (r); 41260786Sps} 41360786Sps 41460786Sps static int 41560786Spsdo_append(c, pos) 41660786Sps int c; 41760786Sps POSITION pos; 41860786Sps{ 41960786Sps register char *s; 42060786Sps register int a; 42160786Sps 42260786Sps#define STOREC(c,a) \ 42360786Sps if (storec((c),(a),pos)) return (1); else curr++ 42460786Sps 42560786Sps if (c == '\b') 42660786Sps { 42760786Sps switch (bs_mode) 42860786Sps { 42960786Sps case BS_NORMAL: 43060786Sps STOREC(c, AT_NORMAL); 43160786Sps break; 43260786Sps case BS_CONTROL: 43360786Sps goto do_control_char; 43460786Sps case BS_SPECIAL: 43560786Sps if (curr == 0) 43660786Sps break; 43760786Sps backc(); 43860786Sps overstrike = 1; 43960786Sps break; 44060786Sps } 44160786Sps } else if (overstrike) 44260786Sps { 44360786Sps /* 44460786Sps * Overstrike the character at the current position 44560786Sps * in the line buffer. This will cause either 44660786Sps * underline (if a "_" is overstruck), 44760786Sps * bold (if an identical character is overstruck), 44860786Sps * or just deletion of the character in the buffer. 44960786Sps */ 45060786Sps overstrike = 0; 45160786Sps if ((char)c == linebuf[curr]) 45260786Sps STOREC(linebuf[curr], AT_BOLD); 45360786Sps else if (c == '_') 45460786Sps STOREC(linebuf[curr], AT_UNDERLINE); 45560786Sps else if (linebuf[curr] == '_') 45660786Sps STOREC(c, AT_UNDERLINE); 45760786Sps else if (control_char(c)) 45860786Sps goto do_control_char; 45960786Sps else 46060786Sps STOREC(c, AT_NORMAL); 46160786Sps } else if (c == '\t') 46260786Sps { 46360786Sps /* 46460786Sps * Expand a tab into spaces. 46560786Sps */ 46660786Sps if (tabstop == 0) 46760786Sps tabstop = 1; 46860786Sps switch (bs_mode) 46960786Sps { 47060786Sps case BS_CONTROL: 47160786Sps goto do_control_char; 47260786Sps case BS_NORMAL: 47360786Sps case BS_SPECIAL: 47460786Sps do 47560786Sps { 47660786Sps STOREC(' ', AT_NORMAL); 47760786Sps } while (((column + cshift) % tabstop) != 0); 47860786Sps break; 47960786Sps } 48060786Sps } else if (control_char(c)) 48160786Sps { 48260786Sps do_control_char: 48360786Sps if (ctldisp == OPT_ON || (ctldisp == OPT_ONPLUS && c == ESC)) 48460786Sps { 48560786Sps /* 48660786Sps * Output as a normal character. 48760786Sps */ 48860786Sps STOREC(c, AT_NORMAL); 48960786Sps } else 49060786Sps { 49160786Sps /* 49260786Sps * Convert to printable representation. 49360786Sps */ 49460786Sps s = prchar(c); 49560786Sps a = binattr; 49660786Sps 49760786Sps /* 49860786Sps * Make sure we can get the entire representation 49960786Sps * of the character on this line. 50060786Sps */ 50160786Sps if (column + (int) strlen(s) + 50260786Sps attr_swidth(a) + attr_ewidth(a) > sc_width) 50360786Sps return (1); 50460786Sps 50560786Sps for ( ; *s != 0; s++) 50660786Sps STOREC(*s, a); 50760786Sps } 50860786Sps } else 50960786Sps { 51060786Sps STOREC(c, AT_NORMAL); 51160786Sps } 51260786Sps 51360786Sps return (0); 51460786Sps} 51560786Sps 51660786Sps/* 51760786Sps * Terminate the line in the line buffer. 51860786Sps */ 51960786Sps public void 52060786Spspdone(endline) 52160786Sps int endline; 52260786Sps{ 52360786Sps if (pendc && (pendc != '\r' || !endline)) 52460786Sps /* 52560786Sps * If we had a pending character, put it in the buffer. 52660786Sps * But discard a pending CR if we are at end of line 52760786Sps * (that is, discard the CR in a CR/LF sequence). 52860786Sps */ 52960786Sps (void) do_append(pendc, pendpos); 53060786Sps 53160786Sps /* 53260786Sps * Make sure we've shifted the line, if we need to. 53360786Sps */ 53460786Sps if (cshift < hshift) 53560786Sps pshift(hshift - cshift); 53660786Sps 53760786Sps /* 53860786Sps * Add a newline if necessary, 53960786Sps * and append a '\0' to the end of the line. 54060786Sps */ 54160786Sps if (column < sc_width || !auto_wrap || ignaw || ctldisp == OPT_ON) 54260786Sps { 54360786Sps linebuf[curr] = '\n'; 54460786Sps attr[curr] = AT_NORMAL; 54560786Sps curr++; 54660786Sps } 54760786Sps linebuf[curr] = '\0'; 54860786Sps attr[curr] = AT_NORMAL; 54960786Sps /* 55060786Sps * If we are done with this line, reset the current shift. 55160786Sps */ 55260786Sps if (endline) 55360786Sps cshift = 0; 55460786Sps} 55560786Sps 55660786Sps/* 55760786Sps * Get a character from the current line. 55860786Sps * Return the character as the function return value, 55960786Sps * and the character attribute in *ap. 56060786Sps */ 56160786Sps public int 56260786Spsgline(i, ap) 56360786Sps register int i; 56460786Sps register int *ap; 56560786Sps{ 56660786Sps char *s; 56760786Sps 56860786Sps if (is_null_line) 56960786Sps { 57060786Sps /* 57160786Sps * If there is no current line, we pretend the line is 57260786Sps * either "~" or "", depending on the "twiddle" flag. 57360786Sps */ 57460786Sps *ap = AT_BOLD; 57560786Sps s = (twiddle) ? "~\n" : "\n"; 57660786Sps return (s[i]); 57760786Sps } 57860786Sps 57960786Sps *ap = attr[i]; 58060786Sps return (linebuf[i] & 0377); 58160786Sps} 58260786Sps 58360786Sps/* 58460786Sps * Indicate that there is no current line. 58560786Sps */ 58660786Sps public void 58760786Spsnull_line() 58860786Sps{ 58960786Sps is_null_line = 1; 59060786Sps cshift = 0; 59160786Sps} 59260786Sps 59360786Sps/* 59460786Sps * Analogous to forw_line(), but deals with "raw lines": 59560786Sps * lines which are not split for screen width. 59660786Sps * {{ This is supposed to be more efficient than forw_line(). }} 59760786Sps */ 59860786Sps public POSITION 59960786Spsforw_raw_line(curr_pos, linep) 60060786Sps POSITION curr_pos; 60160786Sps char **linep; 60260786Sps{ 60360786Sps register char *p; 60460786Sps register int c; 60560786Sps POSITION new_pos; 60660786Sps 60760786Sps if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || 60860786Sps (c = ch_forw_get()) == EOI) 60960786Sps return (NULL_POSITION); 61060786Sps 61160786Sps p = linebuf; 61260786Sps 61360786Sps for (;;) 61460786Sps { 61560786Sps if (c == '\n' || c == EOI) 61660786Sps { 61760786Sps new_pos = ch_tell(); 61860786Sps break; 61960786Sps } 62060786Sps if (p >= &linebuf[sizeof(linebuf)-1]) 62160786Sps { 62260786Sps /* 62360786Sps * Overflowed the input buffer. 62460786Sps * Pretend the line ended here. 62560786Sps * {{ The line buffer is supposed to be big 62660786Sps * enough that this never happens. }} 62760786Sps */ 62860786Sps new_pos = ch_tell() - 1; 62960786Sps break; 63060786Sps } 63160786Sps *p++ = c; 63260786Sps c = ch_forw_get(); 63360786Sps } 63460786Sps *p = '\0'; 63560786Sps if (linep != NULL) 63660786Sps *linep = linebuf; 63760786Sps return (new_pos); 63860786Sps} 63960786Sps 64060786Sps/* 64160786Sps * Analogous to back_line(), but deals with "raw lines". 64260786Sps * {{ This is supposed to be more efficient than back_line(). }} 64360786Sps */ 64460786Sps public POSITION 64560786Spsback_raw_line(curr_pos, linep) 64660786Sps POSITION curr_pos; 64760786Sps char **linep; 64860786Sps{ 64960786Sps register char *p; 65060786Sps register int c; 65160786Sps POSITION new_pos; 65260786Sps 65360786Sps if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() || 65460786Sps ch_seek(curr_pos-1)) 65560786Sps return (NULL_POSITION); 65660786Sps 65760786Sps p = &linebuf[sizeof(linebuf)]; 65860786Sps *--p = '\0'; 65960786Sps 66060786Sps for (;;) 66160786Sps { 66260786Sps c = ch_back_get(); 66360786Sps if (c == '\n') 66460786Sps { 66560786Sps /* 66660786Sps * This is the newline ending the previous line. 66760786Sps * We have hit the beginning of the line. 66860786Sps */ 66960786Sps new_pos = ch_tell() + 1; 67060786Sps break; 67160786Sps } 67260786Sps if (c == EOI) 67360786Sps { 67460786Sps /* 67560786Sps * We have hit the beginning of the file. 67660786Sps * This must be the first line in the file. 67760786Sps * This must, of course, be the beginning of the line. 67860786Sps */ 67960786Sps new_pos = ch_zero(); 68060786Sps break; 68160786Sps } 68260786Sps if (p <= linebuf) 68360786Sps { 68460786Sps /* 68560786Sps * Overflowed the input buffer. 68660786Sps * Pretend the line ended here. 68760786Sps */ 68860786Sps new_pos = ch_tell() + 1; 68960786Sps break; 69060786Sps } 69160786Sps *--p = c; 69260786Sps } 69360786Sps if (linep != NULL) 69460786Sps *linep = p; 69560786Sps return (new_pos); 69660786Sps} 697