input.c revision 170257
11558Srgrimes/* 21558Srgrimes * Copyright (C) 1984-2007 Mark Nudelman 31558Srgrimes * 41558Srgrimes * You may distribute under the terms of either the GNU General Public 51558Srgrimes * License or the Less License, as specified in the README file. 61558Srgrimes * 71558Srgrimes * For more information about less, or for information on how to 81558Srgrimes * contact the author, see the README file. 91558Srgrimes */ 101558Srgrimes 111558Srgrimes 121558Srgrimes/* 131558Srgrimes * High level routines dealing with getting lines of input 141558Srgrimes * from the file being viewed. 151558Srgrimes * 161558Srgrimes * When we speak of "lines" here, we mean PRINTABLE lines; 171558Srgrimes * lines processed with respect to the screen width. 181558Srgrimes * We use the term "raw line" to refer to lines simply 191558Srgrimes * delimited by newlines; not processed with respect to screen width. 201558Srgrimes */ 211558Srgrimes 221558Srgrimes#include "less.h" 231558Srgrimes 241558Srgrimesextern int squeeze; 251558Srgrimesextern int chopline; 261558Srgrimesextern int hshift; 271558Srgrimesextern int quit_if_one_screen; 281558Srgrimesextern int sigs; 291558Srgrimesextern int ignore_eoi; 301558Srgrimesextern int status_col; 311558Srgrimesextern POSITION start_attnpos; 321558Srgrimesextern POSITION end_attnpos; 331558Srgrimes#if HILITE_SEARCH 341558Srgrimesextern int hilite_search; 3541477Sjulianextern int size_linebuf; 3623675Speter#endif 3741477Sjulian 3841477Sjulian/* 3950476Speter * Get the next line. 401558Srgrimes * A "current" position is passed and a "new" position is returned. 411558Srgrimes * The current position is the position of the first character of 421558Srgrimes * a line. The new position is the position of the first character 431558Srgrimes * of the NEXT line. The line obtained is the line starting at curr_pos. 441558Srgrimes */ 451558Srgrimes public POSITION 461558Srgrimesforw_line(curr_pos) 4723675Speter POSITION curr_pos; 4823675Speter{ 4923675Speter POSITION base_pos; 5023675Speter POSITION new_pos; 5123675Speter register int c; 5223675Speter int blankline; 531558Srgrimes int endline; 541558Srgrimes int backchars; 5523675Speter 561558Srgrimes if (curr_pos == NULL_POSITION) 571558Srgrimes { 581558Srgrimes null_line(); 591558Srgrimes return (NULL_POSITION); 601558Srgrimes } 611558Srgrimes#if HILITE_SEARCH 6223675Speter if (hilite_search == OPT_ONPLUS || status_col) 6323675Speter /* 6423675Speter * If we are ignoring EOI (command F), only prepare 6523675Speter * one line ahead, to avoid getting stuck waiting for 661558Srgrimes * slow data without displaying the data we already have. 6723675Speter * If we're not ignoring EOI, we *could* do the same, but 6823675Speter * for efficiency we prepare several lines ahead at once. 6923675Speter */ 7023675Speter prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 7123675Speter ignore_eoi ? 1 : -1); 727585Sbde#endif 731558Srgrimes if (ch_seek(curr_pos)) 741558Srgrimes { 751558Srgrimes null_line(); 761558Srgrimes return (NULL_POSITION); 7723675Speter } 781558Srgrimes 791558Srgrimes base_pos = curr_pos; 801558Srgrimes for (;;) 811558Srgrimes { 821558Srgrimes if (ABORT_SIGS()) 831558Srgrimes { 841558Srgrimes null_line(); 8541474Sjulian return (NULL_POSITION); 861558Srgrimes } 871558Srgrimes c = ch_back_get(); 881558Srgrimes if (c == EOI) 891558Srgrimes break; 9053781Sphk if (c == '\n') 9153781Sphk { 9253781Sphk (void) ch_forw_get(); 931558Srgrimes break; 941558Srgrimes } 951558Srgrimes --base_pos; 961558Srgrimes } 971558Srgrimes 981558Srgrimes prewind(); 991558Srgrimes plinenum(base_pos); 1001558Srgrimes (void) ch_seek(base_pos); 1011558Srgrimes while (base_pos < curr_pos) 1021558Srgrimes { 1031558Srgrimes if (ABORT_SIGS()) 1041558Srgrimes { 1051558Srgrimes null_line(); 1061558Srgrimes return (NULL_POSITION); 1071558Srgrimes } 1081558Srgrimes c = ch_forw_get(); 1091558Srgrimes backchars = pappend(c, base_pos); 1101558Srgrimes base_pos++; 1111558Srgrimes if (backchars > 0) 1121558Srgrimes { 1131558Srgrimes pshift_all(); 1141558Srgrimes base_pos -= backchars; 1151558Srgrimes while (--backchars >= 0) 1161558Srgrimes (void) ch_back_get(); 11723675Speter } 11841474Sjulian } 1191558Srgrimes (void) pflushmbc(); 1201558Srgrimes pshift_all(); 1211558Srgrimes 1221558Srgrimes c = ch_forw_get(); 1231558Srgrimes if (c == EOI) 1241558Srgrimes { 1251558Srgrimes null_line(); 12623675Speter return (NULL_POSITION); 1271558Srgrimes } 1281558Srgrimes blankline = (c == '\n' || c == '\r'); 1291558Srgrimes 1301558Srgrimes for (;;) 1311558Srgrimes { 1321558Srgrimes if (ABORT_SIGS()) 1331558Srgrimes { 1341558Srgrimes null_line(); 1351558Srgrimes return (NULL_POSITION); 1361558Srgrimes } 1371558Srgrimes if (c == '\n' || c == EOI) 1381558Srgrimes { 1391558Srgrimes /* 1401558Srgrimes * End of the line. 1411558Srgrimes */ 1421558Srgrimes backchars = pflushmbc(); 1431558Srgrimes new_pos = ch_tell(); 1446280Sbde if (backchars > 0 && !chopline && hshift == 0) 1451558Srgrimes { 1461558Srgrimes new_pos -= backchars + 1; 1471558Srgrimes endline = FALSE; 1486280Sbde } else 1491558Srgrimes endline = TRUE; 15041474Sjulian break; 15141474Sjulian } 15241474Sjulian if (c != '\r') 15341474Sjulian blankline = 0; 1541558Srgrimes 1551558Srgrimes /* 1561558Srgrimes * Append the char to the line and get the next char. 1571558Srgrimes */ 1581558Srgrimes backchars = pappend(c, ch_tell()-1); 1591558Srgrimes if (backchars > 0) 1601558Srgrimes { 1611558Srgrimes /* 1621558Srgrimes * The char won't fit in the line; the line 1631558Srgrimes * is too long to print in the screen width. 1641558Srgrimes * End the line here. 1651558Srgrimes */ 1661558Srgrimes if (chopline || hshift > 0) 1671558Srgrimes { 1681558Srgrimes do 1691558Srgrimes { 1701558Srgrimes c = ch_forw_get(); 1711558Srgrimes } while (c != '\n' && c != EOI); 1721558Srgrimes new_pos = ch_tell(); 1731558Srgrimes endline = TRUE; 1748871Srgrimes quit_if_one_screen = FALSE; 1751558Srgrimes } else 1761558Srgrimes { 1771558Srgrimes new_pos = ch_tell() - backchars; 1781558Srgrimes endline = FALSE; 1791558Srgrimes } 1801558Srgrimes break; 1811558Srgrimes } 1821558Srgrimes c = ch_forw_get(); 1831558Srgrimes } 1841558Srgrimes pdone(endline); 1851558Srgrimes 1868871Srgrimes if (squeeze && blankline) 1871558Srgrimes { 1881558Srgrimes /* 1891558Srgrimes * This line is blank. 1901558Srgrimes * Skip down to the last contiguous blank line 1911558Srgrimes * and pretend it is the one which we are returning. 1921558Srgrimes */ 1931558Srgrimes while ((c = ch_forw_get()) == '\n' || c == '\r') 1941558Srgrimes if (ABORT_SIGS()) 1951558Srgrimes { 1961558Srgrimes null_line(); 1971558Srgrimes return (NULL_POSITION); 1981558Srgrimes } 1991558Srgrimes if (c != EOI) 2001558Srgrimes (void) ch_back_get(); 2011558Srgrimes new_pos = ch_tell(); 2021558Srgrimes } 2031558Srgrimes 2041558Srgrimes return (new_pos); 2051558Srgrimes} 2061558Srgrimes 2071558Srgrimes/* 2081558Srgrimes * Get the previous line. 2091558Srgrimes * A "current" position is passed and a "new" position is returned. 2101558Srgrimes * The current position is the position of the first character of 2111558Srgrimes * a line. The new position is the position of the first character 2121558Srgrimes * of the PREVIOUS line. The line obtained is the one starting at new_pos. 2131558Srgrimes */ 2141558Srgrimes public POSITION 2151558Srgrimesback_line(curr_pos) 2161558Srgrimes POSITION curr_pos; 2171558Srgrimes{ 2181558Srgrimes POSITION new_pos, begin_new_pos; 2191558Srgrimes int c; 2201558Srgrimes int endline; 2211558Srgrimes int backchars; 2221558Srgrimes 2231558Srgrimes if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 2241558Srgrimes { 2251558Srgrimes null_line(); 2261558Srgrimes return (NULL_POSITION); 2271558Srgrimes } 2281558Srgrimes#if HILITE_SEARCH 2291558Srgrimes if (hilite_search == OPT_ONPLUS || status_col) 2301558Srgrimes prep_hilite((curr_pos < 3*size_linebuf) ? 2311558Srgrimes 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 2321558Srgrimes#endif 2331558Srgrimes if (ch_seek(curr_pos-1)) 2341558Srgrimes { 2351558Srgrimes null_line(); 2361558Srgrimes return (NULL_POSITION); 2371558Srgrimes } 2381558Srgrimes 2391558Srgrimes if (squeeze) 24023675Speter { 2411558Srgrimes /* 24223675Speter * Find out if the "current" line was blank. 2431558Srgrimes */ 2441558Srgrimes (void) ch_forw_get(); /* Skip the newline */ 2451558Srgrimes c = ch_forw_get(); /* First char of "current" line */ 2461558Srgrimes (void) ch_back_get(); /* Restore our position */ 2471558Srgrimes (void) ch_back_get(); 24823675Speter 24923675Speter if (c == '\n' || c == '\r') 2501558Srgrimes { 2511558Srgrimes /* 2521558Srgrimes * The "current" line was blank. 2531558Srgrimes * Skip over any preceding blank lines, 2541558Srgrimes * since we skipped them in forw_line(). 2551558Srgrimes */ 2561558Srgrimes while ((c = ch_back_get()) == '\n' || c == '\r') 2571558Srgrimes if (ABORT_SIGS()) 2581558Srgrimes { 2591558Srgrimes null_line(); 2601558Srgrimes return (NULL_POSITION); 2611558Srgrimes } 2621558Srgrimes if (c == EOI) 2631558Srgrimes { 26434266Sjulian null_line(); 26534266Sjulian return (NULL_POSITION); 26623675Speter } 26734266Sjulian (void) ch_forw_get(); 2681558Srgrimes } 2691558Srgrimes } 2701558Srgrimes 2711558Srgrimes /* 2721558Srgrimes * Scan backwards until we hit the beginning of the line. 2731558Srgrimes */ 2741558Srgrimes for (;;) 2751558Srgrimes { 2761558Srgrimes if (ABORT_SIGS()) 2771558Srgrimes { 2781558Srgrimes null_line(); 2791558Srgrimes return (NULL_POSITION); 2801558Srgrimes } 28141474Sjulian c = ch_back_get(); 28241474Sjulian if (c == '\n') 28341474Sjulian { 28441474Sjulian /* 28541474Sjulian * This is the newline ending the previous line. 2861558Srgrimes * We have hit the beginning of the line. 2871558Srgrimes */ 2881558Srgrimes new_pos = ch_tell() + 1; 28934033Sphk break; 29034033Sphk } 29134033Sphk if (c == EOI) 29234033Sphk { 2931558Srgrimes /* 2941558Srgrimes * We have hit the beginning of the file. 2951558Srgrimes * This must be the first line in the file. 2961558Srgrimes * This must, of course, be the beginning of the line. 2971558Srgrimes */ 2981558Srgrimes new_pos = ch_tell(); 2991558Srgrimes break; 3008871Srgrimes } 3011558Srgrimes } 3021558Srgrimes 3031558Srgrimes /* 3041558Srgrimes * Now scan forwards from the beginning of this line. 30534266Sjulian * We keep discarding "printable lines" (based on screen width) 30634266Sjulian * until we reach the curr_pos. 30734266Sjulian * 30834266Sjulian * {{ This algorithm is pretty inefficient if the lines 3091558Srgrimes * are much longer than the screen width, 3101558Srgrimes * but I don't know of any better way. }} 3111558Srgrimes */ 31223675Speter if (ch_seek(new_pos)) 3131558Srgrimes { 3141558Srgrimes null_line(); 3151558Srgrimes return (NULL_POSITION); 3161558Srgrimes } 3171558Srgrimes endline = FALSE; 3181558Srgrimes prewind(); 3197585Sbde plinenum(new_pos); 3201558Srgrimes loop: 3211558Srgrimes begin_new_pos = new_pos; 3221558Srgrimes (void) ch_seek(new_pos); 32323675Speter 3241558Srgrimes do 3251558Srgrimes { 3261558Srgrimes c = ch_forw_get(); 3271558Srgrimes if (c == EOI || ABORT_SIGS()) 3281558Srgrimes { 3291558Srgrimes null_line(); 3301558Srgrimes return (NULL_POSITION); 3311558Srgrimes } 3321558Srgrimes new_pos++; 3331558Srgrimes if (c == '\n') 3341558Srgrimes { 3351558Srgrimes backchars = pflushmbc(); 3361558Srgrimes if (backchars > 0 && !chopline && hshift == 0) 3371558Srgrimes { 3381558Srgrimes backchars++; 3391558Srgrimes goto shift; 3401558Srgrimes } 3411558Srgrimes endline = TRUE; 3421558Srgrimes break; 3431558Srgrimes } 3441558Srgrimes backchars = pappend(c, ch_tell()-1); 3451558Srgrimes if (backchars > 0) 3461558Srgrimes { 3471558Srgrimes /* 3481558Srgrimes * Got a full printable line, but we haven't 3491558Srgrimes * reached our curr_pos yet. Discard the line 3501558Srgrimes * and start a new one. 3511558Srgrimes */ 3521558Srgrimes if (chopline || hshift > 0) 3531558Srgrimes { 3541558Srgrimes endline = TRUE; 3551558Srgrimes quit_if_one_screen = FALSE; 3561558Srgrimes break; 3571558Srgrimes } 3581558Srgrimes shift: 3591558Srgrimes pshift_all(); 3601558Srgrimes while (backchars-- > 0) 3611558Srgrimes { 3621558Srgrimes (void) ch_back_get(); 36323675Speter new_pos--; 36423675Speter } 3651558Srgrimes goto loop; 3661558Srgrimes } 3671558Srgrimes } while (new_pos < curr_pos); 3681558Srgrimes 3691558Srgrimes pdone(endline); 3701558Srgrimes 3711558Srgrimes return (begin_new_pos); 3721558Srgrimes} 3731558Srgrimes 3741558Srgrimes/* 3751558Srgrimes * Set attnpos. 3761558Srgrimes */ 37723675Speter public void 37823675Speterset_attnpos(pos) 37923675Speter POSITION pos; 38023675Speter{ 38123675Speter int c; 3821558Srgrimes 3831558Srgrimes if (pos != NULL_POSITION) 3841558Srgrimes { 3851558Srgrimes if (ch_seek(pos)) 3861558Srgrimes return; 3871558Srgrimes for (;;) 3881558Srgrimes { 38923675Speter c = ch_forw_get(); 3901558Srgrimes if (c == EOI) 3911558Srgrimes return; 3921558Srgrimes if (c != '\n' && c != '\r') 3931558Srgrimes break; 39423675Speter pos++; 39523675Speter } 39623675Speter } 39723675Speter start_attnpos = pos; 39823675Speter for (;;) 39923675Speter { 40023675Speter c = ch_forw_get(); 40123675Speter pos++; 40223675Speter if (c == EOI || c == '\n' || c == '\r') 40323675Speter break; 40423675Speter } 40537236Sbde end_attnpos = pos; 40637236Sbde} 40723675Speter