1 /* 2 * Copyright (C) 1984-2012 Mark Nudelman 3 * 4 * You may distribute under the terms of either the GNU General Public 5 * License or the Less License, as specified in the README file. 6 * 7 * For more information, see the README file. 8 */ 9 10 11 /* 12 * High level routines dealing with getting lines of input 13 * from the file being viewed. 14 * 15 * When we speak of "lines" here, we mean PRINTABLE lines; 16 * lines processed with respect to the screen width. 17 * We use the term "raw line" to refer to lines simply 18 * delimited by newlines; not processed with respect to screen width. 19 */ 20 21 #include "less.h" 22 23 extern int squeeze; 24 extern int chopline; 25 extern int hshift; 26 extern int quit_if_one_screen; 27 extern int sigs; 28 extern int ignore_eoi; 29 extern int status_col; 30 extern POSITION start_attnpos; 31 extern POSITION end_attnpos; 32 #if HILITE_SEARCH 33 extern int hilite_search; 34 extern int size_linebuf; 35 #endif 36 37 /* 38 * Get the next line. 39 * A "current" position is passed and a "new" position is returned. 40 * The current position is the position of the first character of 41 * a line. The new position is the position of the first character 42 * of the NEXT line. The line obtained is the line starting at curr_pos. 43 */ 44 public POSITION 45 forw_line(curr_pos) 46 POSITION curr_pos; 47 { 48 POSITION base_pos; 49 POSITION new_pos; 50 register int c; 51 int blankline; 52 int endline; 53 int backchars; 54 55 get_forw_line: 56 if (curr_pos == NULL_POSITION) 57 { 58 null_line(); 59 return (NULL_POSITION); 60 } 61 #if HILITE_SEARCH 62 if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 63 /* 64 * If we are ignoring EOI (command F), only prepare 65 * one line ahead, to avoid getting stuck waiting for 66 * slow data without displaying the data we already have. 67 * If we're not ignoring EOI, we *could* do the same, but 68 * for efficiency we prepare several lines ahead at once. 69 */ 70 prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 71 ignore_eoi ? 1 : -1); 72 #endif 73 if (ch_seek(curr_pos)) 74 { 75 null_line(); 76 return (NULL_POSITION); 77 } 78 79 /* 80 * Step back to the beginning of the line. 81 */ 82 base_pos = curr_pos; 83 for (;;) 84 { 85 if (ABORT_SIGS()) 86 { 87 null_line(); 88 return (NULL_POSITION); 89 } 90 c = ch_back_get(); 91 if (c == EOI) 92 break; 93 if (c == '\n') 94 { 95 (void) ch_forw_get(); 96 break; 97 } 98 --base_pos; 99 } 100 101 /* 102 * Read forward again to the position we should start at. 103 */ 104 prewind(); 105 plinenum(base_pos); 106 (void) ch_seek(base_pos); 107 new_pos = base_pos; 108 while (new_pos < curr_pos) 109 { 110 if (ABORT_SIGS()) 111 { 112 null_line(); 113 return (NULL_POSITION); 114 } 115 c = ch_forw_get(); 116 backchars = pappend(c, new_pos); 117 new_pos++; 118 if (backchars > 0) 119 { 120 pshift_all(); 121 new_pos -= backchars; 122 while (--backchars >= 0) 123 (void) ch_back_get(); 124 } 125 } 126 (void) pflushmbc(); 127 pshift_all(); 128 129 /* 130 * Read the first character to display. 131 */ 132 c = ch_forw_get(); 133 if (c == EOI) 134 { 135 null_line(); 136 return (NULL_POSITION); 137 } 138 blankline = (c == '\n' || c == '\r'); 139 140 /* 141 * Read each character in the line and append to the line buffer. 142 */ 143 for (;;) 144 { 145 if (ABORT_SIGS()) 146 { 147 null_line(); 148 return (NULL_POSITION); 149 } 150 if (c == '\n' || c == EOI) 151 { 152 /* 153 * End of the line. 154 */ 155 backchars = pflushmbc(); 156 new_pos = ch_tell(); 157 if (backchars > 0 && !chopline && hshift == 0) 158 { 159 new_pos -= backchars + 1; 160 endline = FALSE; 161 } else 162 endline = TRUE; 163 break; 164 } 165 if (c != '\r') 166 blankline = 0; 167 168 /* 169 * Append the char to the line and get the next char. 170 */ 171 backchars = pappend(c, ch_tell()-1); 172 if (backchars > 0) 173 { 174 /* 175 * The char won't fit in the line; the line 176 * is too long to print in the screen width. 177 * End the line here. 178 */ 179 if (chopline || hshift > 0) 180 { 181 do 182 { 183 if (ABORT_SIGS()) 184 { 185 null_line(); 186 return (NULL_POSITION); 187 } 188 c = ch_forw_get(); 189 } while (c != '\n' && c != EOI); 190 new_pos = ch_tell(); 191 endline = TRUE; 192 quit_if_one_screen = FALSE; 193 } else 194 { 195 new_pos = ch_tell() - backchars; 196 endline = FALSE; 197 } 198 break; 199 } 200 c = ch_forw_get(); 201 } 202 203 pdone(endline, 1); 204 205 #if HILITE_SEARCH 206 if (is_filtered(base_pos)) 207 { 208 /* 209 * We don't want to display this line. 210 * Get the next line. 211 */ 212 curr_pos = new_pos; 213 goto get_forw_line; 214 } 215 216 if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL)) 217 set_status_col('*'); 218 #endif 219 220 if (squeeze && blankline) 221 { 222 /* 223 * This line is blank. 224 * Skip down to the last contiguous blank line 225 * and pretend it is the one which we are returning. 226 */ 227 while ((c = ch_forw_get()) == '\n' || c == '\r') 228 if (ABORT_SIGS()) 229 { 230 null_line(); 231 return (NULL_POSITION); 232 } 233 if (c != EOI) 234 (void) ch_back_get(); 235 new_pos = ch_tell(); 236 } 237 238 return (new_pos); 239 } 240 241 /* 242 * Get the previous line. 243 * A "current" position is passed and a "new" position is returned. 244 * The current position is the position of the first character of 245 * a line. The new position is the position of the first character 246 * of the PREVIOUS line. The line obtained is the one starting at new_pos. 247 */ 248 public POSITION 249 back_line(curr_pos) 250 POSITION curr_pos; 251 { 252 POSITION new_pos, begin_new_pos, base_pos; 253 int c; 254 int endline; 255 int backchars; 256 257 get_back_line: 258 if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 259 { 260 null_line(); 261 return (NULL_POSITION); 262 } 263 #if HILITE_SEARCH 264 if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 265 prep_hilite((curr_pos < 3*size_linebuf) ? 266 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 267 #endif 268 if (ch_seek(curr_pos-1)) 269 { 270 null_line(); 271 return (NULL_POSITION); 272 } 273 274 if (squeeze) 275 { 276 /* 277 * Find out if the "current" line was blank. 278 */ 279 (void) ch_forw_get(); /* Skip the newline */ 280 c = ch_forw_get(); /* First char of "current" line */ 281 (void) ch_back_get(); /* Restore our position */ 282 (void) ch_back_get(); 283 284 if (c == '\n' || c == '\r') 285 { 286 /* 287 * The "current" line was blank. 288 * Skip over any preceding blank lines, 289 * since we skipped them in forw_line(). 290 */ 291 while ((c = ch_back_get()) == '\n' || c == '\r') 292 if (ABORT_SIGS()) 293 { 294 null_line(); 295 return (NULL_POSITION); 296 } 297 if (c == EOI) 298 { 299 null_line(); 300 return (NULL_POSITION); 301 } 302 (void) ch_forw_get(); 303 } 304 } 305 306 /* 307 * Scan backwards until we hit the beginning of the line. 308 */ 309 for (;;) 310 { 311 if (ABORT_SIGS()) 312 { 313 null_line(); 314 return (NULL_POSITION); 315 } 316 c = ch_back_get(); 317 if (c == '\n') 318 { 319 /* 320 * This is the newline ending the previous line. 321 * We have hit the beginning of the line. 322 */ 323 base_pos = ch_tell() + 1; 324 break; 325 } 326 if (c == EOI) 327 { 328 /* 329 * We have hit the beginning of the file. 330 * This must be the first line in the file. 331 * This must, of course, be the beginning of the line. 332 */ 333 base_pos = ch_tell(); 334 break; 335 } 336 } 337 338 /* 339 * Now scan forwards from the beginning of this line. 340 * We keep discarding "printable lines" (based on screen width) 341 * until we reach the curr_pos. 342 * 343 * {{ This algorithm is pretty inefficient if the lines 344 * are much longer than the screen width, 345 * but I don't know of any better way. }} 346 */ 347 new_pos = base_pos; 348 if (ch_seek(new_pos)) 349 { 350 null_line(); 351 return (NULL_POSITION); 352 } 353 endline = FALSE; 354 prewind(); 355 plinenum(new_pos); 356 loop: 357 begin_new_pos = new_pos; 358 (void) ch_seek(new_pos); 359 360 do 361 { 362 c = ch_forw_get(); 363 if (c == EOI || ABORT_SIGS()) 364 { 365 null_line(); 366 return (NULL_POSITION); 367 } 368 new_pos++; 369 if (c == '\n') 370 { 371 backchars = pflushmbc(); 372 if (backchars > 0 && !chopline && hshift == 0) 373 { 374 backchars++; 375 goto shift; 376 } 377 endline = TRUE; 378 break; 379 } 380 backchars = pappend(c, ch_tell()-1); 381 if (backchars > 0) 382 { 383 /* 384 * Got a full printable line, but we haven't 385 * reached our curr_pos yet. Discard the line 386 * and start a new one. 387 */ 388 if (chopline || hshift > 0) 389 { 390 endline = TRUE; 391 quit_if_one_screen = FALSE; 392 break; 393 } 394 shift: 395 pshift_all(); 396 while (backchars-- > 0) 397 { 398 (void) ch_back_get(); 399 new_pos--; 400 } 401 goto loop; 402 } 403 } while (new_pos < curr_pos); 404 405 pdone(endline, 0); 406 407 #if HILITE_SEARCH 408 if (is_filtered(base_pos)) 409 { 410 /* 411 * We don't want to display this line. 412 * Get the previous line. 413 */ 414 curr_pos = begin_new_pos; 415 goto get_back_line; 416 } 417 418 if (status_col && curr_pos > 0 && is_hilited(base_pos, curr_pos-1, 1, NULL)) 419 set_status_col('*'); 420 #endif 421 422 return (begin_new_pos); 423 } 424 425 /* 426 * Set attnpos. 427 */ 428 public void 429 set_attnpos(pos) 430 POSITION pos; 431 { 432 int c; 433 434 if (pos != NULL_POSITION) 435 { 436 if (ch_seek(pos)) 437 return; 438 for (;;) 439 { 440 c = ch_forw_get(); 441 if (c == EOI) 442 return; 443 if (c != '\n' && c != '\r') 444 break; 445 pos++; 446 } 447 } 448 start_attnpos = pos; 449 for (;;) 450 { 451 c = ch_forw_get(); 452 pos++; 453 if (c == EOI || c == '\n' || c == '\r') 454 break; 455 } 456 end_attnpos = pos; 457 } 458