1 1.4 simonb /* $NetBSD: input.c,v 1.4 2023/10/06 05:49:49 simonb Exp $ */ 2 1.1 tron 3 1.1 tron /* 4 1.4 simonb * Copyright (C) 1984-2023 Mark Nudelman 5 1.1 tron * 6 1.1 tron * You may distribute under the terms of either the GNU General Public 7 1.1 tron * License or the Less License, as specified in the README file. 8 1.1 tron * 9 1.3 tron * For more information, see the README file. 10 1.1 tron */ 11 1.1 tron 12 1.1 tron /* 13 1.1 tron * High level routines dealing with getting lines of input 14 1.1 tron * from the file being viewed. 15 1.1 tron * 16 1.1 tron * When we speak of "lines" here, we mean PRINTABLE lines; 17 1.1 tron * lines processed with respect to the screen width. 18 1.1 tron * We use the term "raw line" to refer to lines simply 19 1.1 tron * delimited by newlines; not processed with respect to screen width. 20 1.1 tron */ 21 1.1 tron 22 1.1 tron #include "less.h" 23 1.1 tron 24 1.1 tron extern int squeeze; 25 1.1 tron extern int hshift; 26 1.1 tron extern int quit_if_one_screen; 27 1.1 tron extern int sigs; 28 1.1 tron extern int ignore_eoi; 29 1.1 tron extern int status_col; 30 1.4 simonb extern int wordwrap; 31 1.1 tron extern POSITION start_attnpos; 32 1.1 tron extern POSITION end_attnpos; 33 1.1 tron #if HILITE_SEARCH 34 1.1 tron extern int hilite_search; 35 1.1 tron extern int size_linebuf; 36 1.4 simonb extern int show_attn; 37 1.1 tron #endif 38 1.1 tron 39 1.1 tron /* 40 1.4 simonb * Set the status column. 41 1.4 simonb * base Position of first char in line. 42 1.4 simonb * disp First visible char. 43 1.4 simonb * Different than base_pos if line is shifted. 44 1.4 simonb * edisp Last visible char. 45 1.4 simonb * eol End of line. Normally the newline. 46 1.4 simonb * Different than edisp if line is chopped. 47 1.4 simonb */ 48 1.4 simonb static void init_status_col(POSITION base_pos, POSITION disp_pos, POSITION edisp_pos, POSITION eol_pos) 49 1.4 simonb { 50 1.4 simonb int hl_before = (chop_line() && disp_pos != NULL_POSITION) ? 51 1.4 simonb is_hilited_attr(base_pos, disp_pos, TRUE, NULL) : 0; 52 1.4 simonb int hl_after = (chop_line()) ? 53 1.4 simonb is_hilited_attr(edisp_pos, eol_pos, TRUE, NULL) : 0; 54 1.4 simonb int attr; 55 1.4 simonb char ch; 56 1.4 simonb 57 1.4 simonb if (hl_before && hl_after) 58 1.4 simonb { 59 1.4 simonb attr = hl_after; 60 1.4 simonb ch = '='; 61 1.4 simonb } else if (hl_before) 62 1.4 simonb { 63 1.4 simonb attr = hl_before; 64 1.4 simonb ch = '<'; 65 1.4 simonb } else if (hl_after) 66 1.4 simonb { 67 1.4 simonb attr = hl_after; 68 1.4 simonb ch = '>'; 69 1.4 simonb } else 70 1.4 simonb { 71 1.4 simonb attr = is_hilited_attr(base_pos, eol_pos, TRUE, NULL); 72 1.4 simonb ch = '*'; 73 1.4 simonb } 74 1.4 simonb if (attr) 75 1.4 simonb set_status_col(ch, attr); 76 1.4 simonb } 77 1.4 simonb 78 1.4 simonb /* 79 1.1 tron * Get the next line. 80 1.1 tron * A "current" position is passed and a "new" position is returned. 81 1.1 tron * The current position is the position of the first character of 82 1.1 tron * a line. The new position is the position of the first character 83 1.1 tron * of the NEXT line. The line obtained is the line starting at curr_pos. 84 1.1 tron */ 85 1.4 simonb public POSITION forw_line_seg(POSITION curr_pos, int skipeol, int rscroll, int nochop) 86 1.1 tron { 87 1.1 tron POSITION base_pos; 88 1.1 tron POSITION new_pos; 89 1.4 simonb POSITION edisp_pos; 90 1.4 simonb int c; 91 1.1 tron int blankline; 92 1.1 tron int endline; 93 1.4 simonb int chopped; 94 1.1 tron int backchars; 95 1.4 simonb POSITION wrap_pos; 96 1.4 simonb int skipped_leading; 97 1.1 tron 98 1.1 tron get_forw_line: 99 1.1 tron if (curr_pos == NULL_POSITION) 100 1.1 tron { 101 1.1 tron null_line(); 102 1.1 tron return (NULL_POSITION); 103 1.1 tron } 104 1.1 tron #if HILITE_SEARCH 105 1.1 tron if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 106 1.4 simonb { 107 1.1 tron /* 108 1.1 tron * If we are ignoring EOI (command F), only prepare 109 1.1 tron * one line ahead, to avoid getting stuck waiting for 110 1.1 tron * slow data without displaying the data we already have. 111 1.1 tron * If we're not ignoring EOI, we *could* do the same, but 112 1.1 tron * for efficiency we prepare several lines ahead at once. 113 1.1 tron */ 114 1.1 tron prep_hilite(curr_pos, curr_pos + 3*size_linebuf, 115 1.1 tron ignore_eoi ? 1 : -1); 116 1.4 simonb curr_pos = next_unfiltered(curr_pos); 117 1.4 simonb } 118 1.1 tron #endif 119 1.1 tron if (ch_seek(curr_pos)) 120 1.1 tron { 121 1.1 tron null_line(); 122 1.1 tron return (NULL_POSITION); 123 1.1 tron } 124 1.1 tron 125 1.1 tron /* 126 1.1 tron * Step back to the beginning of the line. 127 1.1 tron */ 128 1.1 tron base_pos = curr_pos; 129 1.1 tron for (;;) 130 1.1 tron { 131 1.1 tron if (ABORT_SIGS()) 132 1.1 tron { 133 1.1 tron null_line(); 134 1.1 tron return (NULL_POSITION); 135 1.1 tron } 136 1.1 tron c = ch_back_get(); 137 1.1 tron if (c == EOI) 138 1.1 tron break; 139 1.1 tron if (c == '\n') 140 1.1 tron { 141 1.1 tron (void) ch_forw_get(); 142 1.1 tron break; 143 1.1 tron } 144 1.1 tron --base_pos; 145 1.1 tron } 146 1.1 tron 147 1.1 tron /* 148 1.1 tron * Read forward again to the position we should start at. 149 1.1 tron */ 150 1.4 simonb prewind(); 151 1.4 simonb plinestart(base_pos); 152 1.1 tron (void) ch_seek(base_pos); 153 1.1 tron new_pos = base_pos; 154 1.1 tron while (new_pos < curr_pos) 155 1.1 tron { 156 1.1 tron if (ABORT_SIGS()) 157 1.1 tron { 158 1.1 tron null_line(); 159 1.1 tron return (NULL_POSITION); 160 1.1 tron } 161 1.1 tron c = ch_forw_get(); 162 1.1 tron backchars = pappend(c, new_pos); 163 1.1 tron new_pos++; 164 1.1 tron if (backchars > 0) 165 1.1 tron { 166 1.1 tron pshift_all(); 167 1.4 simonb if (wordwrap && (c == ' ' || c == '\t')) 168 1.4 simonb { 169 1.4 simonb do 170 1.4 simonb { 171 1.4 simonb new_pos++; 172 1.4 simonb c = ch_forw_get(); 173 1.4 simonb } while (c == ' ' || c == '\t'); 174 1.4 simonb backchars = 1; 175 1.4 simonb } 176 1.1 tron new_pos -= backchars; 177 1.1 tron while (--backchars >= 0) 178 1.1 tron (void) ch_back_get(); 179 1.1 tron } 180 1.1 tron } 181 1.1 tron (void) pflushmbc(); 182 1.1 tron pshift_all(); 183 1.1 tron 184 1.1 tron /* 185 1.1 tron * Read the first character to display. 186 1.1 tron */ 187 1.1 tron c = ch_forw_get(); 188 1.1 tron if (c == EOI) 189 1.1 tron { 190 1.1 tron null_line(); 191 1.1 tron return (NULL_POSITION); 192 1.1 tron } 193 1.1 tron blankline = (c == '\n' || c == '\r'); 194 1.4 simonb wrap_pos = NULL_POSITION; 195 1.4 simonb skipped_leading = FALSE; 196 1.1 tron 197 1.1 tron /* 198 1.1 tron * Read each character in the line and append to the line buffer. 199 1.1 tron */ 200 1.4 simonb chopped = FALSE; 201 1.1 tron for (;;) 202 1.1 tron { 203 1.1 tron if (ABORT_SIGS()) 204 1.1 tron { 205 1.1 tron null_line(); 206 1.1 tron return (NULL_POSITION); 207 1.1 tron } 208 1.1 tron if (c == '\n' || c == EOI) 209 1.1 tron { 210 1.1 tron /* 211 1.1 tron * End of the line. 212 1.1 tron */ 213 1.1 tron backchars = pflushmbc(); 214 1.1 tron new_pos = ch_tell(); 215 1.4 simonb if (backchars > 0 && (nochop || !chop_line()) && hshift == 0) 216 1.1 tron { 217 1.1 tron new_pos -= backchars + 1; 218 1.1 tron endline = FALSE; 219 1.1 tron } else 220 1.1 tron endline = TRUE; 221 1.4 simonb edisp_pos = new_pos; 222 1.1 tron break; 223 1.1 tron } 224 1.1 tron if (c != '\r') 225 1.1 tron blankline = 0; 226 1.1 tron 227 1.1 tron /* 228 1.1 tron * Append the char to the line and get the next char. 229 1.1 tron */ 230 1.1 tron backchars = pappend(c, ch_tell()-1); 231 1.1 tron if (backchars > 0) 232 1.1 tron { 233 1.1 tron /* 234 1.1 tron * The char won't fit in the line; the line 235 1.1 tron * is too long to print in the screen width. 236 1.1 tron * End the line here. 237 1.1 tron */ 238 1.4 simonb if (skipeol) 239 1.1 tron { 240 1.4 simonb /* Read to end of line. */ 241 1.4 simonb edisp_pos = ch_tell(); 242 1.1 tron do 243 1.1 tron { 244 1.1 tron if (ABORT_SIGS()) 245 1.1 tron { 246 1.1 tron null_line(); 247 1.1 tron return (NULL_POSITION); 248 1.1 tron } 249 1.1 tron c = ch_forw_get(); 250 1.1 tron } while (c != '\n' && c != EOI); 251 1.1 tron new_pos = ch_tell(); 252 1.1 tron endline = TRUE; 253 1.1 tron quit_if_one_screen = FALSE; 254 1.4 simonb chopped = TRUE; 255 1.1 tron } else 256 1.1 tron { 257 1.4 simonb if (!wordwrap) 258 1.4 simonb new_pos = ch_tell() - backchars; 259 1.4 simonb else 260 1.4 simonb { 261 1.4 simonb /* 262 1.4 simonb * We're word-wrapping, so go back to the last space. 263 1.4 simonb * However, if it's the space itself that couldn't fit, 264 1.4 simonb * simply ignore it and any subsequent spaces. 265 1.4 simonb */ 266 1.4 simonb if (c == ' ' || c == '\t') 267 1.4 simonb { 268 1.4 simonb do 269 1.4 simonb { 270 1.4 simonb new_pos = ch_tell(); 271 1.4 simonb c = ch_forw_get(); 272 1.4 simonb } while (c == ' ' || c == '\t'); 273 1.4 simonb if (c == '\r') 274 1.4 simonb c = ch_forw_get(); 275 1.4 simonb if (c == '\n') 276 1.4 simonb new_pos = ch_tell(); 277 1.4 simonb } else if (wrap_pos == NULL_POSITION) 278 1.4 simonb new_pos = ch_tell() - backchars; 279 1.4 simonb else 280 1.4 simonb { 281 1.4 simonb new_pos = wrap_pos; 282 1.4 simonb loadc(); 283 1.4 simonb } 284 1.4 simonb } 285 1.1 tron endline = FALSE; 286 1.1 tron } 287 1.1 tron break; 288 1.1 tron } 289 1.4 simonb if (wordwrap) 290 1.4 simonb { 291 1.4 simonb if (c == ' ' || c == '\t') 292 1.4 simonb { 293 1.4 simonb if (skipped_leading) 294 1.4 simonb { 295 1.4 simonb wrap_pos = ch_tell(); 296 1.4 simonb savec(); 297 1.4 simonb } 298 1.4 simonb } else 299 1.4 simonb skipped_leading = TRUE; 300 1.4 simonb } 301 1.1 tron c = ch_forw_get(); 302 1.1 tron } 303 1.1 tron 304 1.4 simonb #if HILITE_SEARCH 305 1.4 simonb if (blankline && show_attn) 306 1.4 simonb { 307 1.4 simonb /* Add spurious space to carry possible attn hilite. */ 308 1.4 simonb pappend(' ', ch_tell()-1); 309 1.4 simonb } 310 1.4 simonb #endif 311 1.4 simonb pdone(endline, rscroll && chopped, 1); 312 1.1 tron 313 1.1 tron #if HILITE_SEARCH 314 1.1 tron if (is_filtered(base_pos)) 315 1.1 tron { 316 1.1 tron /* 317 1.1 tron * We don't want to display this line. 318 1.1 tron * Get the next line. 319 1.1 tron */ 320 1.1 tron curr_pos = new_pos; 321 1.1 tron goto get_forw_line; 322 1.1 tron } 323 1.4 simonb if (status_col) 324 1.4 simonb init_status_col(base_pos, line_position(), edisp_pos, new_pos); 325 1.1 tron #endif 326 1.1 tron 327 1.1 tron if (squeeze && blankline) 328 1.1 tron { 329 1.1 tron /* 330 1.1 tron * This line is blank. 331 1.1 tron * Skip down to the last contiguous blank line 332 1.1 tron * and pretend it is the one which we are returning. 333 1.1 tron */ 334 1.1 tron while ((c = ch_forw_get()) == '\n' || c == '\r') 335 1.1 tron if (ABORT_SIGS()) 336 1.1 tron { 337 1.1 tron null_line(); 338 1.1 tron return (NULL_POSITION); 339 1.1 tron } 340 1.1 tron if (c != EOI) 341 1.1 tron (void) ch_back_get(); 342 1.1 tron new_pos = ch_tell(); 343 1.1 tron } 344 1.1 tron 345 1.1 tron return (new_pos); 346 1.1 tron } 347 1.1 tron 348 1.4 simonb public POSITION forw_line(POSITION curr_pos) 349 1.4 simonb { 350 1.4 simonb 351 1.4 simonb return forw_line_seg(curr_pos, (chop_line() || hshift > 0), TRUE, FALSE); 352 1.4 simonb } 353 1.4 simonb 354 1.1 tron /* 355 1.1 tron * Get the previous line. 356 1.1 tron * A "current" position is passed and a "new" position is returned. 357 1.1 tron * The current position is the position of the first character of 358 1.1 tron * a line. The new position is the position of the first character 359 1.1 tron * of the PREVIOUS line. The line obtained is the one starting at new_pos. 360 1.1 tron */ 361 1.4 simonb public POSITION back_line(POSITION curr_pos) 362 1.1 tron { 363 1.4 simonb POSITION base_pos; 364 1.4 simonb POSITION new_pos; 365 1.4 simonb POSITION edisp_pos; 366 1.4 simonb POSITION begin_new_pos; 367 1.1 tron int c; 368 1.1 tron int endline; 369 1.4 simonb int chopped; 370 1.1 tron int backchars; 371 1.4 simonb POSITION wrap_pos; 372 1.4 simonb int skipped_leading; 373 1.1 tron 374 1.1 tron get_back_line: 375 1.1 tron if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) 376 1.1 tron { 377 1.1 tron null_line(); 378 1.1 tron return (NULL_POSITION); 379 1.1 tron } 380 1.1 tron #if HILITE_SEARCH 381 1.1 tron if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) 382 1.1 tron prep_hilite((curr_pos < 3*size_linebuf) ? 383 1.1 tron 0 : curr_pos - 3*size_linebuf, curr_pos, -1); 384 1.1 tron #endif 385 1.1 tron if (ch_seek(curr_pos-1)) 386 1.1 tron { 387 1.1 tron null_line(); 388 1.1 tron return (NULL_POSITION); 389 1.1 tron } 390 1.1 tron 391 1.1 tron if (squeeze) 392 1.1 tron { 393 1.1 tron /* 394 1.1 tron * Find out if the "current" line was blank. 395 1.1 tron */ 396 1.1 tron (void) ch_forw_get(); /* Skip the newline */ 397 1.1 tron c = ch_forw_get(); /* First char of "current" line */ 398 1.1 tron (void) ch_back_get(); /* Restore our position */ 399 1.1 tron (void) ch_back_get(); 400 1.1 tron 401 1.1 tron if (c == '\n' || c == '\r') 402 1.1 tron { 403 1.1 tron /* 404 1.1 tron * The "current" line was blank. 405 1.1 tron * Skip over any preceding blank lines, 406 1.1 tron * since we skipped them in forw_line(). 407 1.1 tron */ 408 1.1 tron while ((c = ch_back_get()) == '\n' || c == '\r') 409 1.1 tron if (ABORT_SIGS()) 410 1.1 tron { 411 1.1 tron null_line(); 412 1.1 tron return (NULL_POSITION); 413 1.1 tron } 414 1.1 tron if (c == EOI) 415 1.1 tron { 416 1.1 tron null_line(); 417 1.1 tron return (NULL_POSITION); 418 1.1 tron } 419 1.1 tron (void) ch_forw_get(); 420 1.1 tron } 421 1.1 tron } 422 1.1 tron 423 1.1 tron /* 424 1.1 tron * Scan backwards until we hit the beginning of the line. 425 1.1 tron */ 426 1.1 tron for (;;) 427 1.1 tron { 428 1.1 tron if (ABORT_SIGS()) 429 1.1 tron { 430 1.1 tron null_line(); 431 1.1 tron return (NULL_POSITION); 432 1.1 tron } 433 1.1 tron c = ch_back_get(); 434 1.1 tron if (c == '\n') 435 1.1 tron { 436 1.1 tron /* 437 1.1 tron * This is the newline ending the previous line. 438 1.1 tron * We have hit the beginning of the line. 439 1.1 tron */ 440 1.1 tron base_pos = ch_tell() + 1; 441 1.1 tron break; 442 1.1 tron } 443 1.1 tron if (c == EOI) 444 1.1 tron { 445 1.1 tron /* 446 1.1 tron * We have hit the beginning of the file. 447 1.1 tron * This must be the first line in the file. 448 1.1 tron * This must, of course, be the beginning of the line. 449 1.1 tron */ 450 1.1 tron base_pos = ch_tell(); 451 1.1 tron break; 452 1.1 tron } 453 1.1 tron } 454 1.1 tron 455 1.1 tron /* 456 1.1 tron * Now scan forwards from the beginning of this line. 457 1.1 tron * We keep discarding "printable lines" (based on screen width) 458 1.1 tron * until we reach the curr_pos. 459 1.1 tron * 460 1.1 tron * {{ This algorithm is pretty inefficient if the lines 461 1.1 tron * are much longer than the screen width, 462 1.1 tron * but I don't know of any better way. }} 463 1.1 tron */ 464 1.1 tron new_pos = base_pos; 465 1.1 tron if (ch_seek(new_pos)) 466 1.1 tron { 467 1.1 tron null_line(); 468 1.1 tron return (NULL_POSITION); 469 1.1 tron } 470 1.1 tron endline = FALSE; 471 1.1 tron prewind(); 472 1.4 simonb plinestart(new_pos); 473 1.1 tron loop: 474 1.4 simonb wrap_pos = NULL_POSITION; 475 1.4 simonb skipped_leading = FALSE; 476 1.1 tron begin_new_pos = new_pos; 477 1.1 tron (void) ch_seek(new_pos); 478 1.4 simonb chopped = FALSE; 479 1.1 tron 480 1.4 simonb for (;;) 481 1.1 tron { 482 1.1 tron c = ch_forw_get(); 483 1.1 tron if (c == EOI || ABORT_SIGS()) 484 1.1 tron { 485 1.1 tron null_line(); 486 1.1 tron return (NULL_POSITION); 487 1.1 tron } 488 1.1 tron new_pos++; 489 1.1 tron if (c == '\n') 490 1.1 tron { 491 1.1 tron backchars = pflushmbc(); 492 1.4 simonb if (backchars > 0 && !chop_line() && hshift == 0) 493 1.1 tron { 494 1.1 tron backchars++; 495 1.1 tron goto shift; 496 1.1 tron } 497 1.1 tron endline = TRUE; 498 1.4 simonb edisp_pos = new_pos; 499 1.1 tron break; 500 1.1 tron } 501 1.1 tron backchars = pappend(c, ch_tell()-1); 502 1.1 tron if (backchars > 0) 503 1.1 tron { 504 1.1 tron /* 505 1.1 tron * Got a full printable line, but we haven't 506 1.1 tron * reached our curr_pos yet. Discard the line 507 1.1 tron * and start a new one. 508 1.1 tron */ 509 1.4 simonb if (chop_line() || hshift > 0) 510 1.1 tron { 511 1.1 tron endline = TRUE; 512 1.4 simonb chopped = TRUE; 513 1.1 tron quit_if_one_screen = FALSE; 514 1.4 simonb edisp_pos = new_pos; 515 1.1 tron break; 516 1.1 tron } 517 1.1 tron shift: 518 1.4 simonb if (!wordwrap) 519 1.4 simonb { 520 1.4 simonb pshift_all(); 521 1.4 simonb new_pos -= backchars; 522 1.4 simonb } else 523 1.1 tron { 524 1.4 simonb if (c == ' ' || c == '\t') 525 1.4 simonb { 526 1.4 simonb for (;;) 527 1.4 simonb { 528 1.4 simonb c = ch_forw_get(); 529 1.4 simonb if (c == ' ' || c == '\t') 530 1.4 simonb new_pos++; 531 1.4 simonb else 532 1.4 simonb { 533 1.4 simonb if (c == '\r') 534 1.4 simonb { 535 1.4 simonb c = ch_forw_get(); 536 1.4 simonb if (c == '\n') 537 1.4 simonb new_pos++; 538 1.4 simonb } 539 1.4 simonb if (c == '\n') 540 1.4 simonb new_pos++; 541 1.4 simonb break; 542 1.4 simonb } 543 1.4 simonb } 544 1.4 simonb if (new_pos >= curr_pos) 545 1.4 simonb break; 546 1.4 simonb pshift_all(); 547 1.4 simonb } else 548 1.4 simonb { 549 1.4 simonb pshift_all(); 550 1.4 simonb if (wrap_pos == NULL_POSITION) 551 1.4 simonb new_pos -= backchars; 552 1.4 simonb else 553 1.4 simonb new_pos = wrap_pos; 554 1.4 simonb } 555 1.1 tron } 556 1.1 tron goto loop; 557 1.1 tron } 558 1.4 simonb if (wordwrap) 559 1.4 simonb { 560 1.4 simonb if (c == ' ' || c == '\t') 561 1.4 simonb { 562 1.4 simonb if (skipped_leading) 563 1.4 simonb wrap_pos = new_pos; 564 1.4 simonb } else 565 1.4 simonb skipped_leading = TRUE; 566 1.4 simonb } 567 1.4 simonb if (new_pos >= curr_pos) 568 1.4 simonb { 569 1.4 simonb edisp_pos = new_pos; 570 1.4 simonb break; 571 1.4 simonb } 572 1.4 simonb } 573 1.1 tron 574 1.4 simonb pdone(endline, chopped, 0); 575 1.1 tron 576 1.1 tron #if HILITE_SEARCH 577 1.1 tron if (is_filtered(base_pos)) 578 1.1 tron { 579 1.1 tron /* 580 1.1 tron * We don't want to display this line. 581 1.1 tron * Get the previous line. 582 1.1 tron */ 583 1.1 tron curr_pos = begin_new_pos; 584 1.1 tron goto get_back_line; 585 1.1 tron } 586 1.4 simonb if (status_col) 587 1.4 simonb init_status_col(base_pos, line_position(), edisp_pos, new_pos); 588 1.1 tron #endif 589 1.1 tron 590 1.1 tron return (begin_new_pos); 591 1.1 tron } 592 1.1 tron 593 1.1 tron /* 594 1.1 tron * Set attnpos. 595 1.1 tron */ 596 1.4 simonb public void set_attnpos(POSITION pos) 597 1.1 tron { 598 1.1 tron int c; 599 1.1 tron 600 1.1 tron if (pos != NULL_POSITION) 601 1.1 tron { 602 1.1 tron if (ch_seek(pos)) 603 1.1 tron return; 604 1.1 tron for (;;) 605 1.1 tron { 606 1.1 tron c = ch_forw_get(); 607 1.1 tron if (c == EOI) 608 1.1 tron break; 609 1.4 simonb if (c == '\n' || c == '\r') 610 1.4 simonb { 611 1.4 simonb (void) ch_back_get(); 612 1.4 simonb break; 613 1.4 simonb } 614 1.1 tron pos++; 615 1.1 tron } 616 1.4 simonb end_attnpos = pos; 617 1.4 simonb for (;;) 618 1.4 simonb { 619 1.4 simonb c = ch_back_get(); 620 1.4 simonb if (c == EOI || c == '\n' || c == '\r') 621 1.4 simonb break; 622 1.4 simonb pos--; 623 1.4 simonb } 624 1.1 tron } 625 1.1 tron start_attnpos = pos; 626 1.1 tron } 627