1a5f0fb15SPaul Saab /* 26dcb072bSXin LI * Copyright (C) 1984-2005 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 * 7a5f0fb15SPaul Saab * For more information about less, or for information on how to 8a5f0fb15SPaul Saab * contact the author, see the README file. 9a5f0fb15SPaul Saab */ 10a5f0fb15SPaul Saab 11a5f0fb15SPaul Saab 12a5f0fb15SPaul Saab /* 13a5f0fb15SPaul Saab * High level routines dealing with getting lines of input 14a5f0fb15SPaul Saab * from the file being viewed. 15a5f0fb15SPaul Saab * 16a5f0fb15SPaul Saab * When we speak of "lines" here, we mean PRINTABLE lines; 17a5f0fb15SPaul Saab * lines processed with respect to the screen width. 18a5f0fb15SPaul Saab * We use the term "raw line" to refer to lines simply 19a5f0fb15SPaul Saab * delimited by newlines; not processed with respect to screen width. 20a5f0fb15SPaul Saab */ 21a5f0fb15SPaul Saab 22a5f0fb15SPaul Saab #include "less.h" 23a5f0fb15SPaul Saab 24a5f0fb15SPaul Saab extern int squeeze; 25a5f0fb15SPaul Saab extern int chopline; 268ed69c6fSPaul Saab extern int hshift; 27a5f0fb15SPaul Saab extern int quit_if_one_screen; 28a5f0fb15SPaul Saab extern int sigs; 29a5f0fb15SPaul Saab extern int ignore_eoi; 306dcb072bSXin LI extern int status_col; 31a5f0fb15SPaul Saab extern POSITION start_attnpos; 32a5f0fb15SPaul Saab extern POSITION end_attnpos; 33a5f0fb15SPaul Saab #if HILITE_SEARCH 34a5f0fb15SPaul Saab extern int hilite_search; 35a5f0fb15SPaul Saab extern int size_linebuf; 36a5f0fb15SPaul Saab #endif 37a5f0fb15SPaul Saab 38a5f0fb15SPaul Saab /* 39a5f0fb15SPaul Saab * Get the next line. 40a5f0fb15SPaul Saab * A "current" position is passed and a "new" position is returned. 41a5f0fb15SPaul Saab * The current position is the position of the first character of 42a5f0fb15SPaul Saab * a line. The new position is the position of the first character 43a5f0fb15SPaul Saab * of the NEXT line. The line obtained is the line starting at curr_pos. 44a5f0fb15SPaul Saab */ 45a5f0fb15SPaul Saab public POSITION 46a5f0fb15SPaul Saab forw_line(curr_pos) 47a5f0fb15SPaul Saab POSITION curr_pos; 48a5f0fb15SPaul Saab { 496dcb072bSXin LI POSITION base_pos; 50a5f0fb15SPaul Saab POSITION new_pos; 51a5f0fb15SPaul Saab register int c; 52a5f0fb15SPaul Saab int blankline; 53a5f0fb15SPaul Saab int endline; 546dcb072bSXin LI int backchars; 55a5f0fb15SPaul Saab 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 626dcb072bSXin LI if (hilite_search == OPT_ONPLUS || 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 796dcb072bSXin LI base_pos = curr_pos; 806dcb072bSXin LI for (;;) 816dcb072bSXin LI { 826dcb072bSXin LI if (ABORT_SIGS()) 836dcb072bSXin LI { 846dcb072bSXin LI null_line(); 856dcb072bSXin LI return (NULL_POSITION); 866dcb072bSXin LI } 876dcb072bSXin LI c = ch_back_get(); 886dcb072bSXin LI if (c == EOI) 896dcb072bSXin LI break; 906dcb072bSXin LI if (c == '\n') 916dcb072bSXin LI { 926dcb072bSXin LI (void) ch_forw_get(); 936dcb072bSXin LI break; 946dcb072bSXin LI } 956dcb072bSXin LI --base_pos; 966dcb072bSXin LI } 976dcb072bSXin LI 98a5f0fb15SPaul Saab prewind(); 996dcb072bSXin LI plinenum(base_pos); 1006dcb072bSXin LI (void) ch_seek(base_pos); 1016dcb072bSXin LI while (base_pos < curr_pos) 1026dcb072bSXin LI { 1036dcb072bSXin LI if (ABORT_SIGS()) 1046dcb072bSXin LI { 1056dcb072bSXin LI null_line(); 1066dcb072bSXin LI return (NULL_POSITION); 1076dcb072bSXin LI } 1086dcb072bSXin LI c = ch_forw_get(); 1096dcb072bSXin LI backchars = pappend(c, base_pos); 1106dcb072bSXin LI base_pos++; 1116dcb072bSXin LI if (backchars > 0) 1126dcb072bSXin LI { 1136dcb072bSXin LI pshift_all(); 1146dcb072bSXin LI base_pos -= backchars; 1156dcb072bSXin LI while (--backchars >= 0) 1166dcb072bSXin LI (void) ch_back_get(); 1176dcb072bSXin LI } 1186dcb072bSXin LI } 1196dcb072bSXin LI (void) pflushmbc(); 1206dcb072bSXin LI pshift_all(); 121a5f0fb15SPaul Saab 122a5f0fb15SPaul Saab c = ch_forw_get(); 123a5f0fb15SPaul Saab if (c == EOI) 124a5f0fb15SPaul Saab { 125a5f0fb15SPaul Saab null_line(); 126a5f0fb15SPaul Saab return (NULL_POSITION); 127a5f0fb15SPaul Saab } 128a5f0fb15SPaul Saab blankline = (c == '\n' || c == '\r'); 129a5f0fb15SPaul Saab 130a5f0fb15SPaul Saab for (;;) 131a5f0fb15SPaul Saab { 132a5f0fb15SPaul Saab if (ABORT_SIGS()) 133a5f0fb15SPaul Saab { 134a5f0fb15SPaul Saab null_line(); 135a5f0fb15SPaul Saab return (NULL_POSITION); 136a5f0fb15SPaul Saab } 137a5f0fb15SPaul Saab if (c == '\n' || c == EOI) 138a5f0fb15SPaul Saab { 139a5f0fb15SPaul Saab /* 140a5f0fb15SPaul Saab * End of the line. 141a5f0fb15SPaul Saab */ 1426dcb072bSXin LI backchars = pflushmbc(); 143a5f0fb15SPaul Saab new_pos = ch_tell(); 1446dcb072bSXin LI if (backchars > 0 && !chopline && hshift == 0) 1456dcb072bSXin LI { 1466dcb072bSXin LI new_pos -= backchars + 1; 1476dcb072bSXin LI endline = FALSE; 1486dcb072bSXin LI } else 149a5f0fb15SPaul Saab endline = TRUE; 150a5f0fb15SPaul Saab break; 151a5f0fb15SPaul Saab } 1526dcb072bSXin LI if (c != '\r') 1536dcb072bSXin LI blankline = 0; 154a5f0fb15SPaul Saab 155a5f0fb15SPaul Saab /* 156a5f0fb15SPaul Saab * Append the char to the line and get the next char. 157a5f0fb15SPaul Saab */ 1586dcb072bSXin LI backchars = pappend(c, ch_tell()-1); 1596dcb072bSXin LI if (backchars > 0) 160a5f0fb15SPaul Saab { 161a5f0fb15SPaul Saab /* 162a5f0fb15SPaul Saab * The char won't fit in the line; the line 163a5f0fb15SPaul Saab * is too long to print in the screen width. 164a5f0fb15SPaul Saab * End the line here. 165a5f0fb15SPaul Saab */ 1668ed69c6fSPaul Saab if (chopline || hshift > 0) 167a5f0fb15SPaul Saab { 168a5f0fb15SPaul Saab do 169a5f0fb15SPaul Saab { 170a5f0fb15SPaul Saab c = ch_forw_get(); 171a5f0fb15SPaul Saab } while (c != '\n' && c != EOI); 172a5f0fb15SPaul Saab new_pos = ch_tell(); 173a5f0fb15SPaul Saab endline = TRUE; 174a5f0fb15SPaul Saab quit_if_one_screen = FALSE; 175a5f0fb15SPaul Saab } else 176a5f0fb15SPaul Saab { 1776dcb072bSXin LI new_pos = ch_tell() - backchars; 178a5f0fb15SPaul Saab endline = FALSE; 179a5f0fb15SPaul Saab } 180a5f0fb15SPaul Saab break; 181a5f0fb15SPaul Saab } 182a5f0fb15SPaul Saab c = ch_forw_get(); 183a5f0fb15SPaul Saab } 184a5f0fb15SPaul Saab pdone(endline); 185a5f0fb15SPaul Saab 186a5f0fb15SPaul Saab if (squeeze && blankline) 187a5f0fb15SPaul Saab { 188a5f0fb15SPaul Saab /* 189a5f0fb15SPaul Saab * This line is blank. 190a5f0fb15SPaul Saab * Skip down to the last contiguous blank line 191a5f0fb15SPaul Saab * and pretend it is the one which we are returning. 192a5f0fb15SPaul Saab */ 193a5f0fb15SPaul Saab while ((c = ch_forw_get()) == '\n' || c == '\r') 194a5f0fb15SPaul Saab if (ABORT_SIGS()) 195a5f0fb15SPaul Saab { 196a5f0fb15SPaul Saab null_line(); 197a5f0fb15SPaul Saab return (NULL_POSITION); 198a5f0fb15SPaul Saab } 199a5f0fb15SPaul Saab if (c != EOI) 200a5f0fb15SPaul Saab (void) ch_back_get(); 201a5f0fb15SPaul Saab new_pos = ch_tell(); 202a5f0fb15SPaul Saab } 203a5f0fb15SPaul Saab 204a5f0fb15SPaul Saab return (new_pos); 205a5f0fb15SPaul Saab } 206a5f0fb15SPaul Saab 207a5f0fb15SPaul Saab /* 208a5f0fb15SPaul Saab * Get the previous line. 209a5f0fb15SPaul Saab * A "current" position is passed and a "new" position is returned. 210a5f0fb15SPaul Saab * The current position is the position of the first character of 211a5f0fb15SPaul Saab * a line. The new position is the position of the first character 212a5f0fb15SPaul Saab * of the PREVIOUS line. The line obtained is the one starting at new_pos. 213a5f0fb15SPaul Saab */ 214a5f0fb15SPaul Saab public POSITION 215a5f0fb15SPaul Saab back_line(curr_pos) 216a5f0fb15SPaul Saab POSITION curr_pos; 217a5f0fb15SPaul Saab { 218a5f0fb15SPaul Saab POSITION new_pos, begin_new_pos; 219a5f0fb15SPaul Saab int c; 220a5f0fb15SPaul Saab int endline; 2216dcb072bSXin LI int backchars; 222a5f0fb15SPaul Saab 223a5f0fb15SPaul Saab if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 224a5f0fb15SPaul Saab { 225a5f0fb15SPaul Saab null_line(); 226a5f0fb15SPaul Saab return (NULL_POSITION); 227a5f0fb15SPaul Saab } 228a5f0fb15SPaul Saab #if HILITE_SEARCH 2296dcb072bSXin LI if (hilite_search == OPT_ONPLUS || status_col) 230a5f0fb15SPaul Saab prep_hilite((curr_pos < 3*size_linebuf) ? 231a5f0fb15SPaul Saab 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 232a5f0fb15SPaul Saab #endif 233a5f0fb15SPaul Saab if (ch_seek(curr_pos-1)) 234a5f0fb15SPaul Saab { 235a5f0fb15SPaul Saab null_line(); 236a5f0fb15SPaul Saab return (NULL_POSITION); 237a5f0fb15SPaul Saab } 238a5f0fb15SPaul Saab 239a5f0fb15SPaul Saab if (squeeze) 240a5f0fb15SPaul Saab { 241a5f0fb15SPaul Saab /* 242a5f0fb15SPaul Saab * Find out if the "current" line was blank. 243a5f0fb15SPaul Saab */ 244a5f0fb15SPaul Saab (void) ch_forw_get(); /* Skip the newline */ 245a5f0fb15SPaul Saab c = ch_forw_get(); /* First char of "current" line */ 246a5f0fb15SPaul Saab (void) ch_back_get(); /* Restore our position */ 247a5f0fb15SPaul Saab (void) ch_back_get(); 248a5f0fb15SPaul Saab 249a5f0fb15SPaul Saab if (c == '\n' || c == '\r') 250a5f0fb15SPaul Saab { 251a5f0fb15SPaul Saab /* 252a5f0fb15SPaul Saab * The "current" line was blank. 253a5f0fb15SPaul Saab * Skip over any preceding blank lines, 254a5f0fb15SPaul Saab * since we skipped them in forw_line(). 255a5f0fb15SPaul Saab */ 256a5f0fb15SPaul Saab while ((c = ch_back_get()) == '\n' || c == '\r') 257a5f0fb15SPaul Saab if (ABORT_SIGS()) 258a5f0fb15SPaul Saab { 259a5f0fb15SPaul Saab null_line(); 260a5f0fb15SPaul Saab return (NULL_POSITION); 261a5f0fb15SPaul Saab } 262a5f0fb15SPaul Saab if (c == EOI) 263a5f0fb15SPaul Saab { 264a5f0fb15SPaul Saab null_line(); 265a5f0fb15SPaul Saab return (NULL_POSITION); 266a5f0fb15SPaul Saab } 267a5f0fb15SPaul Saab (void) ch_forw_get(); 268a5f0fb15SPaul Saab } 269a5f0fb15SPaul Saab } 270a5f0fb15SPaul Saab 271a5f0fb15SPaul Saab /* 272a5f0fb15SPaul Saab * Scan backwards until we hit the beginning of the line. 273a5f0fb15SPaul Saab */ 274a5f0fb15SPaul Saab for (;;) 275a5f0fb15SPaul Saab { 276a5f0fb15SPaul Saab if (ABORT_SIGS()) 277a5f0fb15SPaul Saab { 278a5f0fb15SPaul Saab null_line(); 279a5f0fb15SPaul Saab return (NULL_POSITION); 280a5f0fb15SPaul Saab } 281a5f0fb15SPaul Saab c = ch_back_get(); 282a5f0fb15SPaul Saab if (c == '\n') 283a5f0fb15SPaul Saab { 284a5f0fb15SPaul Saab /* 285a5f0fb15SPaul Saab * This is the newline ending the previous line. 286a5f0fb15SPaul Saab * We have hit the beginning of the line. 287a5f0fb15SPaul Saab */ 288a5f0fb15SPaul Saab new_pos = ch_tell() + 1; 289a5f0fb15SPaul Saab break; 290a5f0fb15SPaul Saab } 291a5f0fb15SPaul Saab if (c == EOI) 292a5f0fb15SPaul Saab { 293a5f0fb15SPaul Saab /* 294a5f0fb15SPaul Saab * We have hit the beginning of the file. 295a5f0fb15SPaul Saab * This must be the first line in the file. 296a5f0fb15SPaul Saab * This must, of course, be the beginning of the line. 297a5f0fb15SPaul Saab */ 298a5f0fb15SPaul Saab new_pos = ch_tell(); 299a5f0fb15SPaul Saab break; 300a5f0fb15SPaul Saab } 301a5f0fb15SPaul Saab } 302a5f0fb15SPaul Saab 303a5f0fb15SPaul Saab /* 304a5f0fb15SPaul Saab * Now scan forwards from the beginning of this line. 305a5f0fb15SPaul Saab * We keep discarding "printable lines" (based on screen width) 306a5f0fb15SPaul Saab * until we reach the curr_pos. 307a5f0fb15SPaul Saab * 308a5f0fb15SPaul Saab * {{ This algorithm is pretty inefficient if the lines 309a5f0fb15SPaul Saab * are much longer than the screen width, 310a5f0fb15SPaul Saab * but I don't know of any better way. }} 311a5f0fb15SPaul Saab */ 312a5f0fb15SPaul Saab if (ch_seek(new_pos)) 313a5f0fb15SPaul Saab { 314a5f0fb15SPaul Saab null_line(); 315a5f0fb15SPaul Saab return (NULL_POSITION); 316a5f0fb15SPaul Saab } 317a5f0fb15SPaul Saab endline = FALSE; 318a5f0fb15SPaul Saab prewind(); 319a5f0fb15SPaul Saab plinenum(new_pos); 3206dcb072bSXin LI loop: 3216dcb072bSXin LI begin_new_pos = new_pos; 322a5f0fb15SPaul Saab (void) ch_seek(new_pos); 323a5f0fb15SPaul Saab 324a5f0fb15SPaul Saab do 325a5f0fb15SPaul Saab { 326a5f0fb15SPaul Saab c = ch_forw_get(); 327a5f0fb15SPaul Saab if (c == EOI || ABORT_SIGS()) 328a5f0fb15SPaul Saab { 329a5f0fb15SPaul Saab null_line(); 330a5f0fb15SPaul Saab return (NULL_POSITION); 331a5f0fb15SPaul Saab } 332a5f0fb15SPaul Saab new_pos++; 333a5f0fb15SPaul Saab if (c == '\n') 334a5f0fb15SPaul Saab { 3356dcb072bSXin LI backchars = pflushmbc(); 3366dcb072bSXin LI if (backchars > 0 && !chopline && hshift == 0) 3376dcb072bSXin LI { 3386dcb072bSXin LI backchars++; 3396dcb072bSXin LI goto shift; 3406dcb072bSXin LI } 341a5f0fb15SPaul Saab endline = TRUE; 342a5f0fb15SPaul Saab break; 343a5f0fb15SPaul Saab } 3446dcb072bSXin LI backchars = pappend(c, ch_tell()-1); 3456dcb072bSXin LI if (backchars > 0) 346a5f0fb15SPaul Saab { 347a5f0fb15SPaul Saab /* 348a5f0fb15SPaul Saab * Got a full printable line, but we haven't 349a5f0fb15SPaul Saab * reached our curr_pos yet. Discard the line 350a5f0fb15SPaul Saab * and start a new one. 351a5f0fb15SPaul Saab */ 3528ed69c6fSPaul Saab if (chopline || hshift > 0) 353a5f0fb15SPaul Saab { 354a5f0fb15SPaul Saab endline = TRUE; 355a5f0fb15SPaul Saab quit_if_one_screen = FALSE; 356a5f0fb15SPaul Saab break; 357a5f0fb15SPaul Saab } 3586dcb072bSXin LI shift: 3596dcb072bSXin LI pshift_all(); 3606dcb072bSXin LI while (backchars-- > 0) 3616dcb072bSXin LI { 362a5f0fb15SPaul Saab (void) ch_back_get(); 363a5f0fb15SPaul Saab new_pos--; 3646dcb072bSXin LI } 365a5f0fb15SPaul Saab goto loop; 366a5f0fb15SPaul Saab } 367a5f0fb15SPaul Saab } while (new_pos < curr_pos); 368a5f0fb15SPaul Saab 369a5f0fb15SPaul Saab pdone(endline); 370a5f0fb15SPaul Saab 371a5f0fb15SPaul Saab return (begin_new_pos); 372a5f0fb15SPaul Saab } 373a5f0fb15SPaul Saab 374a5f0fb15SPaul Saab /* 375a5f0fb15SPaul Saab * Set attnpos. 376a5f0fb15SPaul Saab */ 377a5f0fb15SPaul Saab public void 378a5f0fb15SPaul Saab set_attnpos(pos) 379a5f0fb15SPaul Saab POSITION pos; 380a5f0fb15SPaul Saab { 381a5f0fb15SPaul Saab int c; 382a5f0fb15SPaul Saab 383a5f0fb15SPaul Saab if (pos != NULL_POSITION) 384a5f0fb15SPaul Saab { 385a5f0fb15SPaul Saab if (ch_seek(pos)) 386a5f0fb15SPaul Saab return; 387a5f0fb15SPaul Saab for (;;) 388a5f0fb15SPaul Saab { 389a5f0fb15SPaul Saab c = ch_forw_get(); 390a5f0fb15SPaul Saab if (c == EOI) 391a5f0fb15SPaul Saab return; 392a5f0fb15SPaul Saab if (c != '\n' && c != '\r') 393a5f0fb15SPaul Saab break; 394a5f0fb15SPaul Saab pos++; 395a5f0fb15SPaul Saab } 396a5f0fb15SPaul Saab } 397a5f0fb15SPaul Saab start_attnpos = pos; 398a5f0fb15SPaul Saab for (;;) 399a5f0fb15SPaul Saab { 400a5f0fb15SPaul Saab c = ch_forw_get(); 401a5f0fb15SPaul Saab pos++; 402a5f0fb15SPaul Saab if (c == EOI || c == '\n' || c == '\r') 403a5f0fb15SPaul Saab break; 404a5f0fb15SPaul Saab } 405a5f0fb15SPaul Saab end_attnpos = pos; 406a5f0fb15SPaul Saab } 407