1a5f0fb15SPaul Saab /* 2a5f0fb15SPaul Saab * Copyright (C) 1984-2000 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; 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 { 48a5f0fb15SPaul Saab POSITION new_pos; 49a5f0fb15SPaul Saab register int c; 50a5f0fb15SPaul Saab int blankline; 51a5f0fb15SPaul Saab int endline; 52a5f0fb15SPaul Saab 53a5f0fb15SPaul Saab if (curr_pos == NULL_POSITION) 54a5f0fb15SPaul Saab { 55a5f0fb15SPaul Saab null_line(); 56a5f0fb15SPaul Saab return (NULL_POSITION); 57a5f0fb15SPaul Saab } 58a5f0fb15SPaul Saab #if HILITE_SEARCH 59a5f0fb15SPaul Saab if (hilite_search == OPT_ONPLUS) 60a5f0fb15SPaul Saab /* 61a5f0fb15SPaul Saab * If we are ignoring EOI (command F), only prepare 62a5f0fb15SPaul Saab * one line ahead, to avoid getting stuck waiting for 63a5f0fb15SPaul Saab * slow data without displaying the data we already have. 64a5f0fb15SPaul Saab * If we're not ignoring EOI, we *could* do the same, but 65a5f0fb15SPaul Saab * for efficiency we prepare several lines ahead at once. 66a5f0fb15SPaul Saab */ 67a5f0fb15SPaul Saab prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 68a5f0fb15SPaul Saab ignore_eoi ? 1 : -1); 69a5f0fb15SPaul Saab #endif 70a5f0fb15SPaul Saab if (ch_seek(curr_pos)) 71a5f0fb15SPaul Saab { 72a5f0fb15SPaul Saab null_line(); 73a5f0fb15SPaul Saab return (NULL_POSITION); 74a5f0fb15SPaul Saab } 75a5f0fb15SPaul Saab 76a5f0fb15SPaul Saab prewind(); 77a5f0fb15SPaul Saab plinenum(curr_pos); 78a5f0fb15SPaul Saab (void) ch_seek(curr_pos); 79a5f0fb15SPaul Saab 80a5f0fb15SPaul Saab c = ch_forw_get(); 81a5f0fb15SPaul Saab if (c == EOI) 82a5f0fb15SPaul Saab { 83a5f0fb15SPaul Saab null_line(); 84a5f0fb15SPaul Saab return (NULL_POSITION); 85a5f0fb15SPaul Saab } 86a5f0fb15SPaul Saab blankline = (c == '\n' || c == '\r'); 87a5f0fb15SPaul Saab 88a5f0fb15SPaul Saab for (;;) 89a5f0fb15SPaul Saab { 90a5f0fb15SPaul Saab if (ABORT_SIGS()) 91a5f0fb15SPaul Saab { 92a5f0fb15SPaul Saab null_line(); 93a5f0fb15SPaul Saab return (NULL_POSITION); 94a5f0fb15SPaul Saab } 95a5f0fb15SPaul Saab if (c == '\n' || c == EOI) 96a5f0fb15SPaul Saab { 97a5f0fb15SPaul Saab /* 98a5f0fb15SPaul Saab * End of the line. 99a5f0fb15SPaul Saab */ 100a5f0fb15SPaul Saab new_pos = ch_tell(); 101a5f0fb15SPaul Saab endline = TRUE; 102a5f0fb15SPaul Saab break; 103a5f0fb15SPaul Saab } 104a5f0fb15SPaul Saab 105a5f0fb15SPaul Saab /* 106a5f0fb15SPaul Saab * Append the char to the line and get the next char. 107a5f0fb15SPaul Saab */ 108a5f0fb15SPaul Saab if (pappend(c, ch_tell()-1)) 109a5f0fb15SPaul Saab { 110a5f0fb15SPaul Saab /* 111a5f0fb15SPaul Saab * The char won't fit in the line; the line 112a5f0fb15SPaul Saab * is too long to print in the screen width. 113a5f0fb15SPaul Saab * End the line here. 114a5f0fb15SPaul Saab */ 1158ed69c6fSPaul Saab if (chopline || hshift > 0) 116a5f0fb15SPaul Saab { 117a5f0fb15SPaul Saab do 118a5f0fb15SPaul Saab { 119a5f0fb15SPaul Saab c = ch_forw_get(); 120a5f0fb15SPaul Saab } while (c != '\n' && c != EOI); 121a5f0fb15SPaul Saab new_pos = ch_tell(); 122a5f0fb15SPaul Saab endline = TRUE; 123a5f0fb15SPaul Saab quit_if_one_screen = FALSE; 124a5f0fb15SPaul Saab } else 125a5f0fb15SPaul Saab { 126a5f0fb15SPaul Saab new_pos = ch_tell() - 1; 127a5f0fb15SPaul Saab endline = FALSE; 128a5f0fb15SPaul Saab } 129a5f0fb15SPaul Saab break; 130a5f0fb15SPaul Saab } 131a5f0fb15SPaul Saab c = ch_forw_get(); 132a5f0fb15SPaul Saab } 133a5f0fb15SPaul Saab pdone(endline); 134a5f0fb15SPaul Saab 135a5f0fb15SPaul Saab if (squeeze && blankline) 136a5f0fb15SPaul Saab { 137a5f0fb15SPaul Saab /* 138a5f0fb15SPaul Saab * This line is blank. 139a5f0fb15SPaul Saab * Skip down to the last contiguous blank line 140a5f0fb15SPaul Saab * and pretend it is the one which we are returning. 141a5f0fb15SPaul Saab */ 142a5f0fb15SPaul Saab while ((c = ch_forw_get()) == '\n' || c == '\r') 143a5f0fb15SPaul Saab if (ABORT_SIGS()) 144a5f0fb15SPaul Saab { 145a5f0fb15SPaul Saab null_line(); 146a5f0fb15SPaul Saab return (NULL_POSITION); 147a5f0fb15SPaul Saab } 148a5f0fb15SPaul Saab if (c != EOI) 149a5f0fb15SPaul Saab (void) ch_back_get(); 150a5f0fb15SPaul Saab new_pos = ch_tell(); 151a5f0fb15SPaul Saab } 152a5f0fb15SPaul Saab 153a5f0fb15SPaul Saab return (new_pos); 154a5f0fb15SPaul Saab } 155a5f0fb15SPaul Saab 156a5f0fb15SPaul Saab /* 157a5f0fb15SPaul Saab * Get the previous line. 158a5f0fb15SPaul Saab * A "current" position is passed and a "new" position is returned. 159a5f0fb15SPaul Saab * The current position is the position of the first character of 160a5f0fb15SPaul Saab * a line. The new position is the position of the first character 161a5f0fb15SPaul Saab * of the PREVIOUS line. The line obtained is the one starting at new_pos. 162a5f0fb15SPaul Saab */ 163a5f0fb15SPaul Saab public POSITION 164a5f0fb15SPaul Saab back_line(curr_pos) 165a5f0fb15SPaul Saab POSITION curr_pos; 166a5f0fb15SPaul Saab { 167a5f0fb15SPaul Saab POSITION new_pos, begin_new_pos; 168a5f0fb15SPaul Saab int c; 169a5f0fb15SPaul Saab int endline; 170a5f0fb15SPaul Saab 171a5f0fb15SPaul Saab if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 172a5f0fb15SPaul Saab { 173a5f0fb15SPaul Saab null_line(); 174a5f0fb15SPaul Saab return (NULL_POSITION); 175a5f0fb15SPaul Saab } 176a5f0fb15SPaul Saab #if HILITE_SEARCH 177a5f0fb15SPaul Saab if (hilite_search == OPT_ONPLUS) 178a5f0fb15SPaul Saab prep_hilite((curr_pos < 3*size_linebuf) ? 179a5f0fb15SPaul Saab 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 180a5f0fb15SPaul Saab #endif 181a5f0fb15SPaul Saab if (ch_seek(curr_pos-1)) 182a5f0fb15SPaul Saab { 183a5f0fb15SPaul Saab null_line(); 184a5f0fb15SPaul Saab return (NULL_POSITION); 185a5f0fb15SPaul Saab } 186a5f0fb15SPaul Saab 187a5f0fb15SPaul Saab if (squeeze) 188a5f0fb15SPaul Saab { 189a5f0fb15SPaul Saab /* 190a5f0fb15SPaul Saab * Find out if the "current" line was blank. 191a5f0fb15SPaul Saab */ 192a5f0fb15SPaul Saab (void) ch_forw_get(); /* Skip the newline */ 193a5f0fb15SPaul Saab c = ch_forw_get(); /* First char of "current" line */ 194a5f0fb15SPaul Saab (void) ch_back_get(); /* Restore our position */ 195a5f0fb15SPaul Saab (void) ch_back_get(); 196a5f0fb15SPaul Saab 197a5f0fb15SPaul Saab if (c == '\n' || c == '\r') 198a5f0fb15SPaul Saab { 199a5f0fb15SPaul Saab /* 200a5f0fb15SPaul Saab * The "current" line was blank. 201a5f0fb15SPaul Saab * Skip over any preceding blank lines, 202a5f0fb15SPaul Saab * since we skipped them in forw_line(). 203a5f0fb15SPaul Saab */ 204a5f0fb15SPaul Saab while ((c = ch_back_get()) == '\n' || c == '\r') 205a5f0fb15SPaul Saab if (ABORT_SIGS()) 206a5f0fb15SPaul Saab { 207a5f0fb15SPaul Saab null_line(); 208a5f0fb15SPaul Saab return (NULL_POSITION); 209a5f0fb15SPaul Saab } 210a5f0fb15SPaul Saab if (c == EOI) 211a5f0fb15SPaul Saab { 212a5f0fb15SPaul Saab null_line(); 213a5f0fb15SPaul Saab return (NULL_POSITION); 214a5f0fb15SPaul Saab } 215a5f0fb15SPaul Saab (void) ch_forw_get(); 216a5f0fb15SPaul Saab } 217a5f0fb15SPaul Saab } 218a5f0fb15SPaul Saab 219a5f0fb15SPaul Saab /* 220a5f0fb15SPaul Saab * Scan backwards until we hit the beginning of the line. 221a5f0fb15SPaul Saab */ 222a5f0fb15SPaul Saab for (;;) 223a5f0fb15SPaul Saab { 224a5f0fb15SPaul Saab if (ABORT_SIGS()) 225a5f0fb15SPaul Saab { 226a5f0fb15SPaul Saab null_line(); 227a5f0fb15SPaul Saab return (NULL_POSITION); 228a5f0fb15SPaul Saab } 229a5f0fb15SPaul Saab c = ch_back_get(); 230a5f0fb15SPaul Saab if (c == '\n') 231a5f0fb15SPaul Saab { 232a5f0fb15SPaul Saab /* 233a5f0fb15SPaul Saab * This is the newline ending the previous line. 234a5f0fb15SPaul Saab * We have hit the beginning of the line. 235a5f0fb15SPaul Saab */ 236a5f0fb15SPaul Saab new_pos = ch_tell() + 1; 237a5f0fb15SPaul Saab break; 238a5f0fb15SPaul Saab } 239a5f0fb15SPaul Saab if (c == EOI) 240a5f0fb15SPaul Saab { 241a5f0fb15SPaul Saab /* 242a5f0fb15SPaul Saab * We have hit the beginning of the file. 243a5f0fb15SPaul Saab * This must be the first line in the file. 244a5f0fb15SPaul Saab * This must, of course, be the beginning of the line. 245a5f0fb15SPaul Saab */ 246a5f0fb15SPaul Saab new_pos = ch_tell(); 247a5f0fb15SPaul Saab break; 248a5f0fb15SPaul Saab } 249a5f0fb15SPaul Saab } 250a5f0fb15SPaul Saab 251a5f0fb15SPaul Saab /* 252a5f0fb15SPaul Saab * Now scan forwards from the beginning of this line. 253a5f0fb15SPaul Saab * We keep discarding "printable lines" (based on screen width) 254a5f0fb15SPaul Saab * until we reach the curr_pos. 255a5f0fb15SPaul Saab * 256a5f0fb15SPaul Saab * {{ This algorithm is pretty inefficient if the lines 257a5f0fb15SPaul Saab * are much longer than the screen width, 258a5f0fb15SPaul Saab * but I don't know of any better way. }} 259a5f0fb15SPaul Saab */ 260a5f0fb15SPaul Saab if (ch_seek(new_pos)) 261a5f0fb15SPaul Saab { 262a5f0fb15SPaul Saab null_line(); 263a5f0fb15SPaul Saab return (NULL_POSITION); 264a5f0fb15SPaul Saab } 265a5f0fb15SPaul Saab endline = FALSE; 266a5f0fb15SPaul Saab loop: 267a5f0fb15SPaul Saab begin_new_pos = new_pos; 268a5f0fb15SPaul Saab prewind(); 269a5f0fb15SPaul Saab plinenum(new_pos); 270a5f0fb15SPaul Saab (void) ch_seek(new_pos); 271a5f0fb15SPaul Saab 272a5f0fb15SPaul Saab do 273a5f0fb15SPaul Saab { 274a5f0fb15SPaul Saab c = ch_forw_get(); 275a5f0fb15SPaul Saab if (c == EOI || ABORT_SIGS()) 276a5f0fb15SPaul Saab { 277a5f0fb15SPaul Saab null_line(); 278a5f0fb15SPaul Saab return (NULL_POSITION); 279a5f0fb15SPaul Saab } 280a5f0fb15SPaul Saab new_pos++; 281a5f0fb15SPaul Saab if (c == '\n') 282a5f0fb15SPaul Saab { 283a5f0fb15SPaul Saab endline = TRUE; 284a5f0fb15SPaul Saab break; 285a5f0fb15SPaul Saab } 286a5f0fb15SPaul Saab if (pappend(c, ch_tell()-1)) 287a5f0fb15SPaul Saab { 288a5f0fb15SPaul Saab /* 289a5f0fb15SPaul Saab * Got a full printable line, but we haven't 290a5f0fb15SPaul Saab * reached our curr_pos yet. Discard the line 291a5f0fb15SPaul Saab * and start a new one. 292a5f0fb15SPaul Saab */ 2938ed69c6fSPaul Saab if (chopline || hshift > 0) 294a5f0fb15SPaul Saab { 295a5f0fb15SPaul Saab endline = TRUE; 296a5f0fb15SPaul Saab quit_if_one_screen = FALSE; 297a5f0fb15SPaul Saab break; 298a5f0fb15SPaul Saab } 299a5f0fb15SPaul Saab pdone(0); 300a5f0fb15SPaul Saab (void) ch_back_get(); 301a5f0fb15SPaul Saab new_pos--; 302a5f0fb15SPaul Saab goto loop; 303a5f0fb15SPaul Saab } 304a5f0fb15SPaul Saab } while (new_pos < curr_pos); 305a5f0fb15SPaul Saab 306a5f0fb15SPaul Saab pdone(endline); 307a5f0fb15SPaul Saab 308a5f0fb15SPaul Saab return (begin_new_pos); 309a5f0fb15SPaul Saab } 310a5f0fb15SPaul Saab 311a5f0fb15SPaul Saab /* 312a5f0fb15SPaul Saab * Set attnpos. 313a5f0fb15SPaul Saab */ 314a5f0fb15SPaul Saab public void 315a5f0fb15SPaul Saab set_attnpos(pos) 316a5f0fb15SPaul Saab POSITION pos; 317a5f0fb15SPaul Saab { 318a5f0fb15SPaul Saab int c; 319a5f0fb15SPaul Saab 320a5f0fb15SPaul Saab if (pos != NULL_POSITION) 321a5f0fb15SPaul Saab { 322a5f0fb15SPaul Saab if (ch_seek(pos)) 323a5f0fb15SPaul Saab return; 324a5f0fb15SPaul Saab for (;;) 325a5f0fb15SPaul Saab { 326a5f0fb15SPaul Saab c = ch_forw_get(); 327a5f0fb15SPaul Saab if (c == EOI) 328a5f0fb15SPaul Saab return; 329a5f0fb15SPaul Saab if (c != '\n' && c != '\r') 330a5f0fb15SPaul Saab break; 331a5f0fb15SPaul Saab pos++; 332a5f0fb15SPaul Saab } 333a5f0fb15SPaul Saab } 334a5f0fb15SPaul Saab start_attnpos = pos; 335a5f0fb15SPaul Saab for (;;) 336a5f0fb15SPaul Saab { 337a5f0fb15SPaul Saab c = ch_forw_get(); 338a5f0fb15SPaul Saab pos++; 339a5f0fb15SPaul Saab if (c == EOI || c == '\n' || c == '\r') 340a5f0fb15SPaul Saab break; 341a5f0fb15SPaul Saab } 342a5f0fb15SPaul Saab end_attnpos = pos; 343a5f0fb15SPaul Saab } 344