input.c revision 225736
1275970Scy/* 2275970Scy * Copyright (C) 1984-2011 Mark Nudelman 3275970Scy * 4275970Scy * You may distribute under the terms of either the GNU General Public 5275970Scy * License or the Less License, as specified in the README file. 6275970Scy * 7275970Scy * For more information about less, or for information on how to 8275970Scy * contact the author, see the README file. 9338531Sdelphij */ 10275970Scy 11275970Scy 12275970Scy/* 13275970Scy * High level routines dealing with getting lines of input 14275970Scy * from the file being viewed. 15275970Scy * 16275970Scy * When we speak of "lines" here, we mean PRINTABLE lines; 17275970Scy * lines processed with respect to the screen width. 18275970Scy * We use the term "raw line" to refer to lines simply 19275970Scy * delimited by newlines; not processed with respect to screen width. 20275970Scy */ 21275970Scy 22275970Scy#include "less.h" 23275970Scy 24275970Scyextern int squeeze; 25275970Scyextern int chopline; 26275970Scyextern int hshift; 27275970Scyextern int quit_if_one_screen; 28275970Scyextern int sigs; 29275970Scyextern int ignore_eoi; 30275970Scyextern int status_col; 31275970Scyextern POSITION start_attnpos; 32275970Scyextern POSITION end_attnpos; 33275970Scy#if HILITE_SEARCH 34275970Scyextern int hilite_search; 35275970Scyextern int size_linebuf; 36275970Scy#endif 37275970Scy 38275970Scy/* 39275970Scy * Get the next line. 40275970Scy * A "current" position is passed and a "new" position is returned. 41275970Scy * The current position is the position of the first character of 42275970Scy * a line. The new position is the position of the first character 43275970Scy * of the NEXT line. The line obtained is the line starting at curr_pos. 44275970Scy */ 45275970Scy public POSITION 46275970Scyforw_line(curr_pos) 47275970Scy POSITION curr_pos; 48275970Scy{ 49275970Scy POSITION base_pos; 50275970Scy POSITION new_pos; 51275970Scy register int c; 52275970Scy int blankline; 53275970Scy int endline; 54275970Scy int backchars; 55275970Scy 56275970Scyget_forw_line: 57275970Scy if (curr_pos == NULL_POSITION) 58275970Scy { 59275970Scy null_line(); 60275970Scy return (NULL_POSITION); 61275970Scy } 62275970Scy#if HILITE_SEARCH 63275970Scy if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 64338531Sdelphij /* 65275970Scy * If we are ignoring EOI (command F), only prepare 66275970Scy * one line ahead, to avoid getting stuck waiting for 67275970Scy * slow data without displaying the data we already have. 68275970Scy * If we're not ignoring EOI, we *could* do the same, but 69275970Scy * for efficiency we prepare several lines ahead at once. 70275970Scy */ 71275970Scy prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 72275970Scy ignore_eoi ? 1 : -1); 73275970Scy#endif 74275970Scy if (ch_seek(curr_pos)) 75275970Scy { 76275970Scy null_line(); 77275970Scy return (NULL_POSITION); 78275970Scy } 79275970Scy 80275970Scy /* 81275970Scy * Step back to the beginning of the line. 82275970Scy */ 83275970Scy base_pos = curr_pos; 84275970Scy for (;;) 85275970Scy { 86275970Scy if (ABORT_SIGS()) 87275970Scy { 88275970Scy null_line(); 89275970Scy return (NULL_POSITION); 90275970Scy } 91275970Scy c = ch_back_get(); 92275970Scy if (c == EOI) 93275970Scy break; 94275970Scy if (c == '\n') 95275970Scy { 96275970Scy (void) ch_forw_get(); 97275970Scy break; 98275970Scy } 99275970Scy --base_pos; 100275970Scy } 101275970Scy 102275970Scy /* 103275970Scy * Read forward again to the position we should start at. 104275970Scy */ 105275970Scy prewind(); 106275970Scy plinenum(base_pos); 107275970Scy (void) ch_seek(base_pos); 108275970Scy new_pos = base_pos; 109275970Scy while (new_pos < curr_pos) 110275970Scy { 111275970Scy if (ABORT_SIGS()) 112275970Scy { 113275970Scy null_line(); 114275970Scy return (NULL_POSITION); 115 } 116 c = ch_forw_get(); 117 backchars = pappend(c, new_pos); 118 new_pos++; 119 if (backchars > 0) 120 { 121 pshift_all(); 122 new_pos -= backchars; 123 while (--backchars >= 0) 124 (void) ch_back_get(); 125 } 126 } 127 (void) pflushmbc(); 128 pshift_all(); 129 130 /* 131 * Read the first character to display. 132 */ 133 c = ch_forw_get(); 134 if (c == EOI) 135 { 136 null_line(); 137 return (NULL_POSITION); 138 } 139 blankline = (c == '\n' || c == '\r'); 140 141 /* 142 * Read each character in the line and append to the line buffer. 143 */ 144 for (;;) 145 { 146 if (ABORT_SIGS()) 147 { 148 null_line(); 149 return (NULL_POSITION); 150 } 151 if (c == '\n' || c == EOI) 152 { 153 /* 154 * End of the line. 155 */ 156 backchars = pflushmbc(); 157 new_pos = ch_tell(); 158 if (backchars > 0 && !chopline && hshift == 0) 159 { 160 new_pos -= backchars + 1; 161 endline = FALSE; 162 } else 163 endline = TRUE; 164 break; 165 } 166 if (c != '\r') 167 blankline = 0; 168 169 /* 170 * Append the char to the line and get the next char. 171 */ 172 backchars = pappend(c, ch_tell()-1); 173 if (backchars > 0) 174 { 175 /* 176 * The char won't fit in the line; the line 177 * is too long to print in the screen width. 178 * End the line here. 179 */ 180 if (chopline || hshift > 0) 181 { 182 do 183 { 184 if (ABORT_SIGS()) 185 { 186 null_line(); 187 return (NULL_POSITION); 188 } 189 c = ch_forw_get(); 190 } while (c != '\n' && c != EOI); 191 new_pos = ch_tell(); 192 endline = TRUE; 193 quit_if_one_screen = FALSE; 194 } else 195 { 196 new_pos = ch_tell() - backchars; 197 endline = FALSE; 198 } 199 break; 200 } 201 c = ch_forw_get(); 202 } 203 204 pdone(endline, 1); 205 206#if HILITE_SEARCH 207 if (is_filtered(base_pos)) 208 { 209 /* 210 * We don't want to display this line. 211 * Get the next line. 212 */ 213 curr_pos = new_pos; 214 goto get_forw_line; 215 } 216 217 if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL)) 218 set_status_col('*'); 219#endif 220 221 if (squeeze && blankline) 222 { 223 /* 224 * This line is blank. 225 * Skip down to the last contiguous blank line 226 * and pretend it is the one which we are returning. 227 */ 228 while ((c = ch_forw_get()) == '\n' || c == '\r') 229 if (ABORT_SIGS()) 230 { 231 null_line(); 232 return (NULL_POSITION); 233 } 234 if (c != EOI) 235 (void) ch_back_get(); 236 new_pos = ch_tell(); 237 } 238 239 return (new_pos); 240} 241 242/* 243 * Get the previous line. 244 * A "current" position is passed and a "new" position is returned. 245 * The current position is the position of the first character of 246 * a line. The new position is the position of the first character 247 * of the PREVIOUS line. The line obtained is the one starting at new_pos. 248 */ 249 public POSITION 250back_line(curr_pos) 251 POSITION curr_pos; 252{ 253 POSITION new_pos, begin_new_pos, base_pos; 254 int c; 255 int endline; 256 int backchars; 257 258get_back_line: 259 if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 260 { 261 null_line(); 262 return (NULL_POSITION); 263 } 264#if HILITE_SEARCH 265 if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 266 prep_hilite((curr_pos < 3*size_linebuf) ? 267 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 268#endif 269 if (ch_seek(curr_pos-1)) 270 { 271 null_line(); 272 return (NULL_POSITION); 273 } 274 275 if (squeeze) 276 { 277 /* 278 * Find out if the "current" line was blank. 279 */ 280 (void) ch_forw_get(); /* Skip the newline */ 281 c = ch_forw_get(); /* First char of "current" line */ 282 (void) ch_back_get(); /* Restore our position */ 283 (void) ch_back_get(); 284 285 if (c == '\n' || c == '\r') 286 { 287 /* 288 * The "current" line was blank. 289 * Skip over any preceding blank lines, 290 * since we skipped them in forw_line(). 291 */ 292 while ((c = ch_back_get()) == '\n' || c == '\r') 293 if (ABORT_SIGS()) 294 { 295 null_line(); 296 return (NULL_POSITION); 297 } 298 if (c == EOI) 299 { 300 null_line(); 301 return (NULL_POSITION); 302 } 303 (void) ch_forw_get(); 304 } 305 } 306 307 /* 308 * Scan backwards until we hit the beginning of the line. 309 */ 310 for (;;) 311 { 312 if (ABORT_SIGS()) 313 { 314 null_line(); 315 return (NULL_POSITION); 316 } 317 c = ch_back_get(); 318 if (c == '\n') 319 { 320 /* 321 * This is the newline ending the previous line. 322 * We have hit the beginning of the line. 323 */ 324 base_pos = ch_tell() + 1; 325 break; 326 } 327 if (c == EOI) 328 { 329 /* 330 * We have hit the beginning of the file. 331 * This must be the first line in the file. 332 * This must, of course, be the beginning of the line. 333 */ 334 base_pos = ch_tell(); 335 break; 336 } 337 } 338 339 /* 340 * Now scan forwards from the beginning of this line. 341 * We keep discarding "printable lines" (based on screen width) 342 * until we reach the curr_pos. 343 * 344 * {{ This algorithm is pretty inefficient if the lines 345 * are much longer than the screen width, 346 * but I don't know of any better way. }} 347 */ 348 new_pos = base_pos; 349 if (ch_seek(new_pos)) 350 { 351 null_line(); 352 return (NULL_POSITION); 353 } 354 endline = FALSE; 355 prewind(); 356 plinenum(new_pos); 357 loop: 358 begin_new_pos = new_pos; 359 (void) ch_seek(new_pos); 360 361 do 362 { 363 c = ch_forw_get(); 364 if (c == EOI || ABORT_SIGS()) 365 { 366 null_line(); 367 return (NULL_POSITION); 368 } 369 new_pos++; 370 if (c == '\n') 371 { 372 backchars = pflushmbc(); 373 if (backchars > 0 && !chopline && hshift == 0) 374 { 375 backchars++; 376 goto shift; 377 } 378 endline = TRUE; 379 break; 380 } 381 backchars = pappend(c, ch_tell()-1); 382 if (backchars > 0) 383 { 384 /* 385 * Got a full printable line, but we haven't 386 * reached our curr_pos yet. Discard the line 387 * and start a new one. 388 */ 389 if (chopline || hshift > 0) 390 { 391 endline = TRUE; 392 quit_if_one_screen = FALSE; 393 break; 394 } 395 shift: 396 pshift_all(); 397 while (backchars-- > 0) 398 { 399 (void) ch_back_get(); 400 new_pos--; 401 } 402 goto loop; 403 } 404 } while (new_pos < curr_pos); 405 406 pdone(endline, 0); 407 408#if HILITE_SEARCH 409 if (is_filtered(base_pos)) 410 { 411 /* 412 * We don't want to display this line. 413 * Get the previous line. 414 */ 415 curr_pos = begin_new_pos; 416 goto get_back_line; 417 } 418 419 if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL)) 420 set_status_col('*'); 421#endif 422 423 return (begin_new_pos); 424} 425 426/* 427 * Set attnpos. 428 */ 429 public void 430set_attnpos(pos) 431 POSITION pos; 432{ 433 int c; 434 435 if (pos != NULL_POSITION) 436 { 437 if (ch_seek(pos)) 438 return; 439 for (;;) 440 { 441 c = ch_forw_get(); 442 if (c == EOI) 443 return; 444 if (c != '\n' && c != '\r') 445 break; 446 pos++; 447 } 448 } 449 start_attnpos = pos; 450 for (;;) 451 { 452 c = ch_forw_get(); 453 pos++; 454 if (c == EOI || c == '\n' || c == '\r') 455 break; 456 } 457 end_attnpos = pos; 458} 459