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