1a5f0fb15SPaul Saab /* 2*96e55cc7SXin LI * Copyright (C) 1984-2012 Mark Nudelman 3a5f0fb15SPaul Saab * 4a5f0fb15SPaul Saab * You may distribute under the terms of either the GNU General Public 5a5f0fb15SPaul Saab * License or the Less License, as specified in the README file. 6a5f0fb15SPaul Saab * 7*96e55cc7SXin LI * For more information, see the README file. 8a5f0fb15SPaul Saab */ 9a5f0fb15SPaul Saab 10a5f0fb15SPaul Saab 11a5f0fb15SPaul Saab /* 12a5f0fb15SPaul Saab * High level routines dealing with getting lines of input 13a5f0fb15SPaul Saab * from the file being viewed. 14a5f0fb15SPaul Saab * 15a5f0fb15SPaul Saab * When we speak of "lines" here, we mean PRINTABLE lines; 16a5f0fb15SPaul Saab * lines processed with respect to the screen width. 17a5f0fb15SPaul Saab * We use the term "raw line" to refer to lines simply 18a5f0fb15SPaul Saab * delimited by newlines; not processed with respect to screen width. 19a5f0fb15SPaul Saab */ 20a5f0fb15SPaul Saab 21a5f0fb15SPaul Saab #include "less.h" 22a5f0fb15SPaul Saab 23a5f0fb15SPaul Saab extern int squeeze; 24a5f0fb15SPaul Saab extern int chopline; 258ed69c6fSPaul Saab extern int hshift; 26a5f0fb15SPaul Saab extern int quit_if_one_screen; 27a5f0fb15SPaul Saab extern int sigs; 28a5f0fb15SPaul Saab extern int ignore_eoi; 296dcb072bSXin LI extern int status_col; 30a5f0fb15SPaul Saab extern POSITION start_attnpos; 31a5f0fb15SPaul Saab extern POSITION end_attnpos; 32a5f0fb15SPaul Saab #if HILITE_SEARCH 33a5f0fb15SPaul Saab extern int hilite_search; 34a5f0fb15SPaul Saab extern int size_linebuf; 35a5f0fb15SPaul Saab #endif 36a5f0fb15SPaul Saab 37a5f0fb15SPaul Saab /* 38a5f0fb15SPaul Saab * Get the next line. 39a5f0fb15SPaul Saab * A "current" position is passed and a "new" position is returned. 40a5f0fb15SPaul Saab * The current position is the position of the first character of 41a5f0fb15SPaul Saab * a line. The new position is the position of the first character 42a5f0fb15SPaul Saab * of the NEXT line. The line obtained is the line starting at curr_pos. 43a5f0fb15SPaul Saab */ 44a5f0fb15SPaul Saab public POSITION 45a5f0fb15SPaul Saab forw_line(curr_pos) 46a5f0fb15SPaul Saab POSITION curr_pos; 47a5f0fb15SPaul Saab { 486dcb072bSXin LI POSITION base_pos; 49a5f0fb15SPaul Saab POSITION new_pos; 50a5f0fb15SPaul Saab register int c; 51a5f0fb15SPaul Saab int blankline; 52a5f0fb15SPaul Saab int endline; 536dcb072bSXin LI int backchars; 54a5f0fb15SPaul Saab 557374caaaSXin LI get_forw_line: 56a5f0fb15SPaul Saab if (curr_pos == NULL_POSITION) 57a5f0fb15SPaul Saab { 58a5f0fb15SPaul Saab null_line(); 59a5f0fb15SPaul Saab return (NULL_POSITION); 60a5f0fb15SPaul Saab } 61a5f0fb15SPaul Saab #if HILITE_SEARCH 627374caaaSXin LI if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 63a5f0fb15SPaul Saab /* 64a5f0fb15SPaul Saab * If we are ignoring EOI (command F), only prepare 65a5f0fb15SPaul Saab * one line ahead, to avoid getting stuck waiting for 66a5f0fb15SPaul Saab * slow data without displaying the data we already have. 67a5f0fb15SPaul Saab * If we're not ignoring EOI, we *could* do the same, but 68a5f0fb15SPaul Saab * for efficiency we prepare several lines ahead at once. 69a5f0fb15SPaul Saab */ 70a5f0fb15SPaul Saab prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 71a5f0fb15SPaul Saab ignore_eoi ? 1 : -1); 72a5f0fb15SPaul Saab #endif 73a5f0fb15SPaul Saab if (ch_seek(curr_pos)) 74a5f0fb15SPaul Saab { 75a5f0fb15SPaul Saab null_line(); 76a5f0fb15SPaul Saab return (NULL_POSITION); 77a5f0fb15SPaul Saab } 78a5f0fb15SPaul Saab 797374caaaSXin LI /* 807374caaaSXin LI * Step back to the beginning of the line. 817374caaaSXin LI */ 826dcb072bSXin LI base_pos = curr_pos; 836dcb072bSXin LI for (;;) 846dcb072bSXin LI { 856dcb072bSXin LI if (ABORT_SIGS()) 866dcb072bSXin LI { 876dcb072bSXin LI null_line(); 886dcb072bSXin LI return (NULL_POSITION); 896dcb072bSXin LI } 906dcb072bSXin LI c = ch_back_get(); 916dcb072bSXin LI if (c == EOI) 926dcb072bSXin LI break; 936dcb072bSXin LI if (c == '\n') 946dcb072bSXin LI { 956dcb072bSXin LI (void) ch_forw_get(); 966dcb072bSXin LI break; 976dcb072bSXin LI } 986dcb072bSXin LI --base_pos; 996dcb072bSXin LI } 1006dcb072bSXin LI 1017374caaaSXin LI /* 1027374caaaSXin LI * Read forward again to the position we should start at. 1037374caaaSXin LI */ 104a5f0fb15SPaul Saab prewind(); 1056dcb072bSXin LI plinenum(base_pos); 1066dcb072bSXin LI (void) ch_seek(base_pos); 1077374caaaSXin LI new_pos = base_pos; 1087374caaaSXin LI while (new_pos < curr_pos) 1096dcb072bSXin LI { 1106dcb072bSXin LI if (ABORT_SIGS()) 1116dcb072bSXin LI { 1126dcb072bSXin LI null_line(); 1136dcb072bSXin LI return (NULL_POSITION); 1146dcb072bSXin LI } 1156dcb072bSXin LI c = ch_forw_get(); 1167374caaaSXin LI backchars = pappend(c, new_pos); 1177374caaaSXin LI new_pos++; 1186dcb072bSXin LI if (backchars > 0) 1196dcb072bSXin LI { 1206dcb072bSXin LI pshift_all(); 1217374caaaSXin LI new_pos -= backchars; 1226dcb072bSXin LI while (--backchars >= 0) 1236dcb072bSXin LI (void) ch_back_get(); 1246dcb072bSXin LI } 1256dcb072bSXin LI } 1266dcb072bSXin LI (void) pflushmbc(); 1276dcb072bSXin LI pshift_all(); 128a5f0fb15SPaul Saab 1297374caaaSXin LI /* 1307374caaaSXin LI * Read the first character to display. 1317374caaaSXin LI */ 132a5f0fb15SPaul Saab c = ch_forw_get(); 133a5f0fb15SPaul Saab if (c == EOI) 134a5f0fb15SPaul Saab { 135a5f0fb15SPaul Saab null_line(); 136a5f0fb15SPaul Saab return (NULL_POSITION); 137a5f0fb15SPaul Saab } 138a5f0fb15SPaul Saab blankline = (c == '\n' || c == '\r'); 139a5f0fb15SPaul Saab 1407374caaaSXin LI /* 1417374caaaSXin LI * Read each character in the line and append to the line buffer. 1427374caaaSXin LI */ 143a5f0fb15SPaul Saab for (;;) 144a5f0fb15SPaul Saab { 145a5f0fb15SPaul Saab if (ABORT_SIGS()) 146a5f0fb15SPaul Saab { 147a5f0fb15SPaul Saab null_line(); 148a5f0fb15SPaul Saab return (NULL_POSITION); 149a5f0fb15SPaul Saab } 150a5f0fb15SPaul Saab if (c == '\n' || c == EOI) 151a5f0fb15SPaul Saab { 152a5f0fb15SPaul Saab /* 153a5f0fb15SPaul Saab * End of the line. 154a5f0fb15SPaul Saab */ 1556dcb072bSXin LI backchars = pflushmbc(); 156a5f0fb15SPaul Saab new_pos = ch_tell(); 1576dcb072bSXin LI if (backchars > 0 && !chopline && hshift == 0) 1586dcb072bSXin LI { 1596dcb072bSXin LI new_pos -= backchars + 1; 1606dcb072bSXin LI endline = FALSE; 1616dcb072bSXin LI } else 162a5f0fb15SPaul Saab endline = TRUE; 163a5f0fb15SPaul Saab break; 164a5f0fb15SPaul Saab } 1656dcb072bSXin LI if (c != '\r') 1666dcb072bSXin LI blankline = 0; 167a5f0fb15SPaul Saab 168a5f0fb15SPaul Saab /* 169a5f0fb15SPaul Saab * Append the char to the line and get the next char. 170a5f0fb15SPaul Saab */ 1716dcb072bSXin LI backchars = pappend(c, ch_tell()-1); 1726dcb072bSXin LI if (backchars > 0) 173a5f0fb15SPaul Saab { 174a5f0fb15SPaul Saab /* 175a5f0fb15SPaul Saab * The char won't fit in the line; the line 176a5f0fb15SPaul Saab * is too long to print in the screen width. 177a5f0fb15SPaul Saab * End the line here. 178a5f0fb15SPaul Saab */ 1798ed69c6fSPaul Saab if (chopline || hshift > 0) 180a5f0fb15SPaul Saab { 181a5f0fb15SPaul Saab do 182a5f0fb15SPaul Saab { 18333096f16SXin LI if (ABORT_SIGS()) 18433096f16SXin LI { 18533096f16SXin LI null_line(); 18633096f16SXin LI return (NULL_POSITION); 18733096f16SXin LI } 188a5f0fb15SPaul Saab c = ch_forw_get(); 189a5f0fb15SPaul Saab } while (c != '\n' && c != EOI); 190a5f0fb15SPaul Saab new_pos = ch_tell(); 191a5f0fb15SPaul Saab endline = TRUE; 192a5f0fb15SPaul Saab quit_if_one_screen = FALSE; 193a5f0fb15SPaul Saab } else 194a5f0fb15SPaul Saab { 1956dcb072bSXin LI new_pos = ch_tell() - backchars; 196a5f0fb15SPaul Saab endline = FALSE; 197a5f0fb15SPaul Saab } 198a5f0fb15SPaul Saab break; 199a5f0fb15SPaul Saab } 200a5f0fb15SPaul Saab c = ch_forw_get(); 201a5f0fb15SPaul Saab } 2027374caaaSXin LI 203f0be0a1fSXin LI pdone(endline, 1); 2047374caaaSXin LI 2057374caaaSXin LI #if HILITE_SEARCH 2067374caaaSXin LI if (is_filtered(base_pos)) 2077374caaaSXin LI { 2087374caaaSXin LI /* 2097374caaaSXin LI * We don't want to display this line. 2107374caaaSXin LI * Get the next line. 2117374caaaSXin LI */ 2127374caaaSXin LI curr_pos = new_pos; 2137374caaaSXin LI goto get_forw_line; 2147374caaaSXin LI } 2157374caaaSXin LI 2167374caaaSXin LI if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL)) 2177374caaaSXin LI set_status_col('*'); 2187374caaaSXin LI #endif 219a5f0fb15SPaul Saab 220a5f0fb15SPaul Saab if (squeeze && blankline) 221a5f0fb15SPaul Saab { 222a5f0fb15SPaul Saab /* 223a5f0fb15SPaul Saab * This line is blank. 224a5f0fb15SPaul Saab * Skip down to the last contiguous blank line 225a5f0fb15SPaul Saab * and pretend it is the one which we are returning. 226a5f0fb15SPaul Saab */ 227a5f0fb15SPaul Saab while ((c = ch_forw_get()) == '\n' || c == '\r') 228a5f0fb15SPaul Saab if (ABORT_SIGS()) 229a5f0fb15SPaul Saab { 230a5f0fb15SPaul Saab null_line(); 231a5f0fb15SPaul Saab return (NULL_POSITION); 232a5f0fb15SPaul Saab } 233a5f0fb15SPaul Saab if (c != EOI) 234a5f0fb15SPaul Saab (void) ch_back_get(); 235a5f0fb15SPaul Saab new_pos = ch_tell(); 236a5f0fb15SPaul Saab } 237a5f0fb15SPaul Saab 238a5f0fb15SPaul Saab return (new_pos); 239a5f0fb15SPaul Saab } 240a5f0fb15SPaul Saab 241a5f0fb15SPaul Saab /* 242a5f0fb15SPaul Saab * Get the previous line. 243a5f0fb15SPaul Saab * A "current" position is passed and a "new" position is returned. 244a5f0fb15SPaul Saab * The current position is the position of the first character of 245a5f0fb15SPaul Saab * a line. The new position is the position of the first character 246a5f0fb15SPaul Saab * of the PREVIOUS line. The line obtained is the one starting at new_pos. 247a5f0fb15SPaul Saab */ 248a5f0fb15SPaul Saab public POSITION 249a5f0fb15SPaul Saab back_line(curr_pos) 250a5f0fb15SPaul Saab POSITION curr_pos; 251a5f0fb15SPaul Saab { 2527374caaaSXin LI POSITION new_pos, begin_new_pos, base_pos; 253a5f0fb15SPaul Saab int c; 254a5f0fb15SPaul Saab int endline; 2556dcb072bSXin LI int backchars; 256a5f0fb15SPaul Saab 2577374caaaSXin LI get_back_line: 258a5f0fb15SPaul Saab if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 259a5f0fb15SPaul Saab { 260a5f0fb15SPaul Saab null_line(); 261a5f0fb15SPaul Saab return (NULL_POSITION); 262a5f0fb15SPaul Saab } 263a5f0fb15SPaul Saab #if HILITE_SEARCH 2647374caaaSXin LI if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 265a5f0fb15SPaul Saab prep_hilite((curr_pos < 3*size_linebuf) ? 266a5f0fb15SPaul Saab 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 267a5f0fb15SPaul Saab #endif 268a5f0fb15SPaul Saab if (ch_seek(curr_pos-1)) 269a5f0fb15SPaul Saab { 270a5f0fb15SPaul Saab null_line(); 271a5f0fb15SPaul Saab return (NULL_POSITION); 272a5f0fb15SPaul Saab } 273a5f0fb15SPaul Saab 274a5f0fb15SPaul Saab if (squeeze) 275a5f0fb15SPaul Saab { 276a5f0fb15SPaul Saab /* 277a5f0fb15SPaul Saab * Find out if the "current" line was blank. 278a5f0fb15SPaul Saab */ 279a5f0fb15SPaul Saab (void) ch_forw_get(); /* Skip the newline */ 280a5f0fb15SPaul Saab c = ch_forw_get(); /* First char of "current" line */ 281a5f0fb15SPaul Saab (void) ch_back_get(); /* Restore our position */ 282a5f0fb15SPaul Saab (void) ch_back_get(); 283a5f0fb15SPaul Saab 284a5f0fb15SPaul Saab if (c == '\n' || c == '\r') 285a5f0fb15SPaul Saab { 286a5f0fb15SPaul Saab /* 287a5f0fb15SPaul Saab * The "current" line was blank. 288a5f0fb15SPaul Saab * Skip over any preceding blank lines, 289a5f0fb15SPaul Saab * since we skipped them in forw_line(). 290a5f0fb15SPaul Saab */ 291a5f0fb15SPaul Saab while ((c = ch_back_get()) == '\n' || c == '\r') 292a5f0fb15SPaul Saab if (ABORT_SIGS()) 293a5f0fb15SPaul Saab { 294a5f0fb15SPaul Saab null_line(); 295a5f0fb15SPaul Saab return (NULL_POSITION); 296a5f0fb15SPaul Saab } 297a5f0fb15SPaul Saab if (c == EOI) 298a5f0fb15SPaul Saab { 299a5f0fb15SPaul Saab null_line(); 300a5f0fb15SPaul Saab return (NULL_POSITION); 301a5f0fb15SPaul Saab } 302a5f0fb15SPaul Saab (void) ch_forw_get(); 303a5f0fb15SPaul Saab } 304a5f0fb15SPaul Saab } 305a5f0fb15SPaul Saab 306a5f0fb15SPaul Saab /* 307a5f0fb15SPaul Saab * Scan backwards until we hit the beginning of the line. 308a5f0fb15SPaul Saab */ 309a5f0fb15SPaul Saab for (;;) 310a5f0fb15SPaul Saab { 311a5f0fb15SPaul Saab if (ABORT_SIGS()) 312a5f0fb15SPaul Saab { 313a5f0fb15SPaul Saab null_line(); 314a5f0fb15SPaul Saab return (NULL_POSITION); 315a5f0fb15SPaul Saab } 316a5f0fb15SPaul Saab c = ch_back_get(); 317a5f0fb15SPaul Saab if (c == '\n') 318a5f0fb15SPaul Saab { 319a5f0fb15SPaul Saab /* 320a5f0fb15SPaul Saab * This is the newline ending the previous line. 321a5f0fb15SPaul Saab * We have hit the beginning of the line. 322a5f0fb15SPaul Saab */ 3237374caaaSXin LI base_pos = ch_tell() + 1; 324a5f0fb15SPaul Saab break; 325a5f0fb15SPaul Saab } 326a5f0fb15SPaul Saab if (c == EOI) 327a5f0fb15SPaul Saab { 328a5f0fb15SPaul Saab /* 329a5f0fb15SPaul Saab * We have hit the beginning of the file. 330a5f0fb15SPaul Saab * This must be the first line in the file. 331a5f0fb15SPaul Saab * This must, of course, be the beginning of the line. 332a5f0fb15SPaul Saab */ 3337374caaaSXin LI base_pos = ch_tell(); 334a5f0fb15SPaul Saab break; 335a5f0fb15SPaul Saab } 336a5f0fb15SPaul Saab } 337a5f0fb15SPaul Saab 338a5f0fb15SPaul Saab /* 339a5f0fb15SPaul Saab * Now scan forwards from the beginning of this line. 340a5f0fb15SPaul Saab * We keep discarding "printable lines" (based on screen width) 341a5f0fb15SPaul Saab * until we reach the curr_pos. 342a5f0fb15SPaul Saab * 343a5f0fb15SPaul Saab * {{ This algorithm is pretty inefficient if the lines 344a5f0fb15SPaul Saab * are much longer than the screen width, 345a5f0fb15SPaul Saab * but I don't know of any better way. }} 346a5f0fb15SPaul Saab */ 3477374caaaSXin LI new_pos = base_pos; 348a5f0fb15SPaul Saab if (ch_seek(new_pos)) 349a5f0fb15SPaul Saab { 350a5f0fb15SPaul Saab null_line(); 351a5f0fb15SPaul Saab return (NULL_POSITION); 352a5f0fb15SPaul Saab } 353a5f0fb15SPaul Saab endline = FALSE; 354a5f0fb15SPaul Saab prewind(); 355a5f0fb15SPaul Saab plinenum(new_pos); 3566dcb072bSXin LI loop: 3576dcb072bSXin LI begin_new_pos = new_pos; 358a5f0fb15SPaul Saab (void) ch_seek(new_pos); 359a5f0fb15SPaul Saab 360a5f0fb15SPaul Saab do 361a5f0fb15SPaul Saab { 362a5f0fb15SPaul Saab c = ch_forw_get(); 363a5f0fb15SPaul Saab if (c == EOI || ABORT_SIGS()) 364a5f0fb15SPaul Saab { 365a5f0fb15SPaul Saab null_line(); 366a5f0fb15SPaul Saab return (NULL_POSITION); 367a5f0fb15SPaul Saab } 368a5f0fb15SPaul Saab new_pos++; 369a5f0fb15SPaul Saab if (c == '\n') 370a5f0fb15SPaul Saab { 3716dcb072bSXin LI backchars = pflushmbc(); 3726dcb072bSXin LI if (backchars > 0 && !chopline && hshift == 0) 3736dcb072bSXin LI { 3746dcb072bSXin LI backchars++; 3756dcb072bSXin LI goto shift; 3766dcb072bSXin LI } 377a5f0fb15SPaul Saab endline = TRUE; 378a5f0fb15SPaul Saab break; 379a5f0fb15SPaul Saab } 3806dcb072bSXin LI backchars = pappend(c, ch_tell()-1); 3816dcb072bSXin LI if (backchars > 0) 382a5f0fb15SPaul Saab { 383a5f0fb15SPaul Saab /* 384a5f0fb15SPaul Saab * Got a full printable line, but we haven't 385a5f0fb15SPaul Saab * reached our curr_pos yet. Discard the line 386a5f0fb15SPaul Saab * and start a new one. 387a5f0fb15SPaul Saab */ 3888ed69c6fSPaul Saab if (chopline || hshift > 0) 389a5f0fb15SPaul Saab { 390a5f0fb15SPaul Saab endline = TRUE; 391a5f0fb15SPaul Saab quit_if_one_screen = FALSE; 392a5f0fb15SPaul Saab break; 393a5f0fb15SPaul Saab } 3946dcb072bSXin LI shift: 3956dcb072bSXin LI pshift_all(); 3966dcb072bSXin LI while (backchars-- > 0) 3976dcb072bSXin LI { 398a5f0fb15SPaul Saab (void) ch_back_get(); 399a5f0fb15SPaul Saab new_pos--; 4006dcb072bSXin LI } 401a5f0fb15SPaul Saab goto loop; 402a5f0fb15SPaul Saab } 403a5f0fb15SPaul Saab } while (new_pos < curr_pos); 404a5f0fb15SPaul Saab 405f0be0a1fSXin LI pdone(endline, 0); 4067374caaaSXin LI 4077374caaaSXin LI #if HILITE_SEARCH 4087374caaaSXin LI if (is_filtered(base_pos)) 4097374caaaSXin LI { 4107374caaaSXin LI /* 4117374caaaSXin LI * We don't want to display this line. 4127374caaaSXin LI * Get the previous line. 4137374caaaSXin LI */ 4147374caaaSXin LI curr_pos = begin_new_pos; 4157374caaaSXin LI goto get_back_line; 4167374caaaSXin LI } 4177374caaaSXin LI 418*96e55cc7SXin LI if (status_col && curr_pos > 0 && is_hilited(base_pos, curr_pos-1, 1, NULL)) 4197374caaaSXin LI set_status_col('*'); 4207374caaaSXin LI #endif 421a5f0fb15SPaul Saab 422a5f0fb15SPaul Saab return (begin_new_pos); 423a5f0fb15SPaul Saab } 424a5f0fb15SPaul Saab 425a5f0fb15SPaul Saab /* 426a5f0fb15SPaul Saab * Set attnpos. 427a5f0fb15SPaul Saab */ 428a5f0fb15SPaul Saab public void 429a5f0fb15SPaul Saab set_attnpos(pos) 430a5f0fb15SPaul Saab POSITION pos; 431a5f0fb15SPaul Saab { 432a5f0fb15SPaul Saab int c; 433a5f0fb15SPaul Saab 434a5f0fb15SPaul Saab if (pos != NULL_POSITION) 435a5f0fb15SPaul Saab { 436a5f0fb15SPaul Saab if (ch_seek(pos)) 437a5f0fb15SPaul Saab return; 438a5f0fb15SPaul Saab for (;;) 439a5f0fb15SPaul Saab { 440a5f0fb15SPaul Saab c = ch_forw_get(); 441a5f0fb15SPaul Saab if (c == EOI) 442a5f0fb15SPaul Saab return; 443a5f0fb15SPaul Saab if (c != '\n' && c != '\r') 444a5f0fb15SPaul Saab break; 445a5f0fb15SPaul Saab pos++; 446a5f0fb15SPaul Saab } 447a5f0fb15SPaul Saab } 448a5f0fb15SPaul Saab start_attnpos = pos; 449a5f0fb15SPaul Saab for (;;) 450a5f0fb15SPaul Saab { 451a5f0fb15SPaul Saab c = ch_forw_get(); 452a5f0fb15SPaul Saab pos++; 453a5f0fb15SPaul Saab if (c == EOI || c == '\n' || c == '\r') 454a5f0fb15SPaul Saab break; 455a5f0fb15SPaul Saab } 456a5f0fb15SPaul Saab end_attnpos = pos; 457a5f0fb15SPaul Saab } 458