1 /* 2 * Copyright (C) 1984-2021 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 * Low level character input from the input file. 13 * We use these special purpose routines which optimize moving 14 * both forward and backward from the current read pointer. 15 */ 16 17 #include "less.h" 18 #if MSDOS_COMPILER==WIN32C 19 #include <errno.h> 20 #include <windows.h> 21 #endif 22 23 #if HAVE_STAT_INO 24 #include <sys/stat.h> 25 extern dev_t curr_dev; 26 extern ino_t curr_ino; 27 #endif 28 29 typedef POSITION BLOCKNUM; 30 31 public int ignore_eoi; 32 33 /* 34 * Pool of buffers holding the most recently used blocks of the input file. 35 * The buffer pool is kept as a doubly-linked circular list, 36 * in order from most- to least-recently used. 37 * The circular list is anchored by the file state "thisfile". 38 */ 39 struct bufnode { 40 struct bufnode *next, *prev; 41 struct bufnode *hnext, *hprev; 42 }; 43 44 #define LBUFSIZE 8192 45 struct buf { 46 struct bufnode node; 47 BLOCKNUM block; 48 unsigned int datasize; 49 unsigned char data[LBUFSIZE]; 50 }; 51 #define bufnode_buf(bn) ((struct buf *) bn) 52 53 /* 54 * The file state is maintained in a filestate structure. 55 * A pointer to the filestate is kept in the ifile structure. 56 */ 57 #define BUFHASH_SIZE 1024 58 struct filestate { 59 struct bufnode buflist; 60 struct bufnode hashtbl[BUFHASH_SIZE]; 61 int file; 62 int flags; 63 POSITION fpos; 64 int nbufs; 65 BLOCKNUM block; 66 unsigned int offset; 67 POSITION fsize; 68 }; 69 70 #define ch_bufhead thisfile->buflist.next 71 #define ch_buftail thisfile->buflist.prev 72 #define ch_nbufs thisfile->nbufs 73 #define ch_block thisfile->block 74 #define ch_offset thisfile->offset 75 #define ch_fpos thisfile->fpos 76 #define ch_fsize thisfile->fsize 77 #define ch_flags thisfile->flags 78 #define ch_file thisfile->file 79 80 #define END_OF_CHAIN (&thisfile->buflist) 81 #define END_OF_HCHAIN(h) (&thisfile->hashtbl[h]) 82 #define BUFHASH(blk) ((blk) & (BUFHASH_SIZE-1)) 83 84 /* 85 * Macros to manipulate the list of buffers in thisfile->buflist. 86 */ 87 #define FOR_BUFS(bn) \ 88 for (bn = ch_bufhead; bn != END_OF_CHAIN; bn = bn->next) 89 90 #define BUF_RM(bn) \ 91 (bn)->next->prev = (bn)->prev; \ 92 (bn)->prev->next = (bn)->next; 93 94 #define BUF_INS_HEAD(bn) \ 95 (bn)->next = ch_bufhead; \ 96 (bn)->prev = END_OF_CHAIN; \ 97 ch_bufhead->prev = (bn); \ 98 ch_bufhead = (bn); 99 100 #define BUF_INS_TAIL(bn) \ 101 (bn)->next = END_OF_CHAIN; \ 102 (bn)->prev = ch_buftail; \ 103 ch_buftail->next = (bn); \ 104 ch_buftail = (bn); 105 106 /* 107 * Macros to manipulate the list of buffers in thisfile->hashtbl[n]. 108 */ 109 #define FOR_BUFS_IN_CHAIN(h,bn) \ 110 for (bn = thisfile->hashtbl[h].hnext; \ 111 bn != END_OF_HCHAIN(h); bn = bn->hnext) 112 113 #define BUF_HASH_RM(bn) \ 114 (bn)->hnext->hprev = (bn)->hprev; \ 115 (bn)->hprev->hnext = (bn)->hnext; 116 117 #define BUF_HASH_INS(bn,h) \ 118 (bn)->hnext = thisfile->hashtbl[h].hnext; \ 119 (bn)->hprev = END_OF_HCHAIN(h); \ 120 thisfile->hashtbl[h].hnext->hprev = (bn); \ 121 thisfile->hashtbl[h].hnext = (bn); 122 123 static struct filestate *thisfile; 124 static int ch_ungotchar = -1; 125 static int maxbufs = -1; 126 127 extern int autobuf; 128 extern int sigs; 129 extern int secure; 130 extern int screen_trashed; 131 extern int follow_mode; 132 extern constant char helpdata[]; 133 extern constant int size_helpdata; 134 extern IFILE curr_ifile; 135 #if LOGFILE 136 extern int logfile; 137 extern char *namelogfile; 138 #endif 139 140 static int ch_addbuf(); 141 142 143 /* 144 * Get the character pointed to by the read pointer. 145 */ 146 int 147 ch_get(VOID_PARAM) 148 { 149 struct buf *bp; 150 struct bufnode *bn; 151 int n; 152 int slept; 153 int h; 154 POSITION pos; 155 POSITION len; 156 157 if (thisfile == NULL) 158 return (EOI); 159 160 /* 161 * Quick check for the common case where 162 * the desired char is in the head buffer. 163 */ 164 if (ch_bufhead != END_OF_CHAIN) 165 { 166 bp = bufnode_buf(ch_bufhead); 167 if (ch_block == bp->block && ch_offset < bp->datasize) 168 return bp->data[ch_offset]; 169 } 170 171 slept = FALSE; 172 173 /* 174 * Look for a buffer holding the desired block. 175 */ 176 h = BUFHASH(ch_block); 177 FOR_BUFS_IN_CHAIN(h, bn) 178 { 179 bp = bufnode_buf(bn); 180 if (bp->block == ch_block) 181 { 182 if (ch_offset >= bp->datasize) 183 /* 184 * Need more data in this buffer. 185 */ 186 break; 187 goto found; 188 } 189 } 190 if (bn == END_OF_HCHAIN(h)) 191 { 192 /* 193 * Block is not in a buffer. 194 * Take the least recently used buffer 195 * and read the desired block into it. 196 * If the LRU buffer has data in it, 197 * then maybe allocate a new buffer. 198 */ 199 if (ch_buftail == END_OF_CHAIN || 200 bufnode_buf(ch_buftail)->block != -1) 201 { 202 /* 203 * There is no empty buffer to use. 204 * Allocate a new buffer if: 205 * 1. We can't seek on this file and -b is not in effect; or 206 * 2. We haven't allocated the max buffers for this file yet. 207 */ 208 if ((autobuf && !(ch_flags & CH_CANSEEK)) || 209 (maxbufs < 0 || ch_nbufs < maxbufs)) 210 if (ch_addbuf()) 211 /* 212 * Allocation failed: turn off autobuf. 213 */ 214 autobuf = OPT_OFF; 215 } 216 bn = ch_buftail; 217 bp = bufnode_buf(bn); 218 BUF_HASH_RM(bn); /* Remove from old hash chain. */ 219 bp->block = ch_block; 220 bp->datasize = 0; 221 BUF_HASH_INS(bn, h); /* Insert into new hash chain. */ 222 } 223 224 read_more: 225 pos = (ch_block * LBUFSIZE) + bp->datasize; 226 if ((len = ch_length()) != NULL_POSITION && pos >= len) 227 /* 228 * At end of file. 229 */ 230 return (EOI); 231 232 if (pos != ch_fpos) 233 { 234 /* 235 * Not at the correct position: must seek. 236 * If input is a pipe, we're in trouble (can't seek on a pipe). 237 * Some data has been lost: just return "?". 238 */ 239 if (!(ch_flags & CH_CANSEEK)) 240 return ('?'); 241 if (lseek(ch_file, (off_t)pos, SEEK_SET) == BAD_LSEEK) 242 { 243 error("seek error", NULL_PARG); 244 clear_eol(); 245 return (EOI); 246 } 247 ch_fpos = pos; 248 } 249 250 /* 251 * Read the block. 252 * If we read less than a full block, that's ok. 253 * We use partial block and pick up the rest next time. 254 */ 255 if (ch_ungotchar != -1) 256 { 257 bp->data[bp->datasize] = ch_ungotchar; 258 n = 1; 259 ch_ungotchar = -1; 260 } else if (ch_flags & CH_HELPFILE) 261 { 262 bp->data[bp->datasize] = helpdata[ch_fpos]; 263 n = 1; 264 } else 265 { 266 n = iread(ch_file, &bp->data[bp->datasize], 267 (unsigned int)(LBUFSIZE - bp->datasize)); 268 } 269 270 if (n == READ_INTR) 271 return (EOI); 272 if (n < 0) 273 { 274 #if MSDOS_COMPILER==WIN32C 275 if (errno != EPIPE) 276 #endif 277 { 278 error("read error", NULL_PARG); 279 clear_eol(); 280 } 281 n = 0; 282 } 283 284 #if LOGFILE 285 /* 286 * If we have a log file, write the new data to it. 287 */ 288 if (!secure && logfile >= 0 && n > 0) 289 write(logfile, (char *) &bp->data[bp->datasize], n); 290 #endif 291 292 ch_fpos += n; 293 bp->datasize += n; 294 295 /* 296 * If we have read to end of file, set ch_fsize to indicate 297 * the position of the end of file. 298 */ 299 if (n == 0) 300 { 301 ch_fsize = pos; 302 if (ignore_eoi) 303 { 304 /* 305 * We are ignoring EOF. 306 * Wait a while, then try again. 307 */ 308 if (!slept) 309 { 310 PARG parg; 311 parg.p_string = wait_message(); 312 ierror("%s", &parg); 313 } 314 sleep_ms(2); /* Reduce system load */ 315 slept = TRUE; 316 317 #if HAVE_STAT_INO 318 if (follow_mode == FOLLOW_NAME) 319 { 320 /* See whether the file's i-number has changed, 321 * or the file has shrunk. 322 * If so, force the file to be closed and 323 * reopened. */ 324 struct stat st; 325 POSITION curr_pos = ch_tell(); 326 int r = stat(get_filename(curr_ifile), &st); 327 if (r == 0 && (st.st_ino != curr_ino || 328 st.st_dev != curr_dev || 329 (curr_pos != NULL_POSITION && st.st_size < curr_pos))) 330 { 331 /* screen_trashed=2 causes 332 * make_display to reopen the file. */ 333 screen_trashed = 2; 334 return (EOI); 335 } 336 } 337 #endif 338 } 339 if (sigs) 340 return (EOI); 341 } 342 343 found: 344 if (ch_bufhead != bn) 345 { 346 /* 347 * Move the buffer to the head of the buffer chain. 348 * This orders the buffer chain, most- to least-recently used. 349 */ 350 BUF_RM(bn); 351 BUF_INS_HEAD(bn); 352 353 /* 354 * Move to head of hash chain too. 355 */ 356 BUF_HASH_RM(bn); 357 BUF_HASH_INS(bn, h); 358 } 359 360 if (ch_offset >= bp->datasize) 361 /* 362 * After all that, we still don't have enough data. 363 * Go back and try again. 364 */ 365 goto read_more; 366 367 return (bp->data[ch_offset]); 368 } 369 370 /* 371 * ch_ungetchar is a rather kludgy and limited way to push 372 * a single char onto an input file descriptor. 373 */ 374 public void 375 ch_ungetchar(c) 376 int c; 377 { 378 if (c != -1 && ch_ungotchar != -1) 379 error("ch_ungetchar overrun", NULL_PARG); 380 ch_ungotchar = c; 381 } 382 383 #if LOGFILE 384 /* 385 * Close the logfile. 386 * If we haven't read all of standard input into it, do that now. 387 */ 388 public void 389 end_logfile(VOID_PARAM) 390 { 391 static int tried = FALSE; 392 393 if (logfile < 0) 394 return; 395 if (!tried && ch_fsize == NULL_POSITION) 396 { 397 tried = TRUE; 398 ierror("Finishing logfile", NULL_PARG); 399 while (ch_forw_get() != EOI) 400 if (ABORT_SIGS()) 401 break; 402 } 403 close(logfile); 404 logfile = -1; 405 free(namelogfile); 406 namelogfile = NULL; 407 } 408 409 /* 410 * Start a log file AFTER less has already been running. 411 * Invoked from the - command; see toggle_option(). 412 * Write all the existing buffered data to the log file. 413 */ 414 public void 415 sync_logfile(VOID_PARAM) 416 { 417 struct buf *bp; 418 struct bufnode *bn; 419 int warned = FALSE; 420 BLOCKNUM block; 421 BLOCKNUM nblocks; 422 423 nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE; 424 for (block = 0; block < nblocks; block++) 425 { 426 int wrote = FALSE; 427 FOR_BUFS(bn) 428 { 429 bp = bufnode_buf(bn); 430 if (bp->block == block) 431 { 432 write(logfile, (char *) bp->data, bp->datasize); 433 wrote = TRUE; 434 break; 435 } 436 } 437 if (!wrote && !warned) 438 { 439 error("Warning: log file is incomplete", 440 NULL_PARG); 441 warned = TRUE; 442 } 443 } 444 } 445 446 #endif 447 448 /* 449 * Determine if a specific block is currently in one of the buffers. 450 */ 451 static int 452 buffered(block) 453 BLOCKNUM block; 454 { 455 struct buf *bp; 456 struct bufnode *bn; 457 int h; 458 459 h = BUFHASH(block); 460 FOR_BUFS_IN_CHAIN(h, bn) 461 { 462 bp = bufnode_buf(bn); 463 if (bp->block == block) 464 return (TRUE); 465 } 466 return (FALSE); 467 } 468 469 /* 470 * Seek to a specified position in the file. 471 * Return 0 if successful, non-zero if can't seek there. 472 */ 473 public int 474 ch_seek(pos) 475 POSITION pos; 476 { 477 BLOCKNUM new_block; 478 POSITION len; 479 480 if (thisfile == NULL) 481 return (0); 482 483 len = ch_length(); 484 if (pos < ch_zero() || (len != NULL_POSITION && pos > len)) 485 return (1); 486 487 new_block = pos / LBUFSIZE; 488 if (!(ch_flags & CH_CANSEEK) && pos != ch_fpos && !buffered(new_block)) 489 { 490 if (ch_fpos > pos) 491 return (1); 492 while (ch_fpos < pos) 493 { 494 if (ch_forw_get() == EOI) 495 return (1); 496 if (ABORT_SIGS()) 497 return (1); 498 } 499 return (0); 500 } 501 /* 502 * Set read pointer. 503 */ 504 ch_block = new_block; 505 ch_offset = pos % LBUFSIZE; 506 return (0); 507 } 508 509 /* 510 * Seek to the end of the file. 511 */ 512 public int 513 ch_end_seek(VOID_PARAM) 514 { 515 POSITION len; 516 517 if (thisfile == NULL) 518 return (0); 519 520 if (ch_flags & CH_CANSEEK) 521 ch_fsize = filesize(ch_file); 522 523 len = ch_length(); 524 if (len != NULL_POSITION) 525 return (ch_seek(len)); 526 527 /* 528 * Do it the slow way: read till end of data. 529 */ 530 while (ch_forw_get() != EOI) 531 if (ABORT_SIGS()) 532 return (1); 533 return (0); 534 } 535 536 /* 537 * Seek to the last position in the file that is currently buffered. 538 */ 539 public int 540 ch_end_buffer_seek(VOID_PARAM) 541 { 542 struct buf *bp; 543 struct bufnode *bn; 544 POSITION buf_pos; 545 POSITION end_pos; 546 547 if (thisfile == NULL || (ch_flags & CH_CANSEEK)) 548 return (ch_end_seek()); 549 550 end_pos = 0; 551 FOR_BUFS(bn) 552 { 553 bp = bufnode_buf(bn); 554 buf_pos = (bp->block * LBUFSIZE) + bp->datasize; 555 if (buf_pos > end_pos) 556 end_pos = buf_pos; 557 } 558 559 return (ch_seek(end_pos)); 560 } 561 562 /* 563 * Seek to the beginning of the file, or as close to it as we can get. 564 * We may not be able to seek there if input is a pipe and the 565 * beginning of the pipe is no longer buffered. 566 */ 567 public int 568 ch_beg_seek(VOID_PARAM) 569 { 570 struct bufnode *bn; 571 struct bufnode *firstbn; 572 573 /* 574 * Try a plain ch_seek first. 575 */ 576 if (ch_seek(ch_zero()) == 0) 577 return (0); 578 579 /* 580 * Can't get to position 0. 581 * Look thru the buffers for the one closest to position 0. 582 */ 583 firstbn = ch_bufhead; 584 if (firstbn == END_OF_CHAIN) 585 return (1); 586 FOR_BUFS(bn) 587 { 588 if (bufnode_buf(bn)->block < bufnode_buf(firstbn)->block) 589 firstbn = bn; 590 } 591 ch_block = bufnode_buf(firstbn)->block; 592 ch_offset = 0; 593 return (0); 594 } 595 596 /* 597 * Return the length of the file, if known. 598 */ 599 public POSITION 600 ch_length(VOID_PARAM) 601 { 602 if (thisfile == NULL) 603 return (NULL_POSITION); 604 if (ignore_eoi) 605 return (NULL_POSITION); 606 if (ch_flags & CH_HELPFILE) 607 return (size_helpdata); 608 if (ch_flags & CH_NODATA) 609 return (0); 610 return (ch_fsize); 611 } 612 613 /* 614 * Return the current position in the file. 615 */ 616 public POSITION 617 ch_tell(VOID_PARAM) 618 { 619 if (thisfile == NULL) 620 return (NULL_POSITION); 621 return (ch_block * LBUFSIZE) + ch_offset; 622 } 623 624 /* 625 * Get the current char and post-increment the read pointer. 626 */ 627 public int 628 ch_forw_get(VOID_PARAM) 629 { 630 int c; 631 632 if (thisfile == NULL) 633 return (EOI); 634 c = ch_get(); 635 if (c == EOI) 636 return (EOI); 637 if (ch_offset < LBUFSIZE-1) 638 ch_offset++; 639 else 640 { 641 ch_block ++; 642 ch_offset = 0; 643 } 644 return (c); 645 } 646 647 /* 648 * Pre-decrement the read pointer and get the new current char. 649 */ 650 public int 651 ch_back_get(VOID_PARAM) 652 { 653 if (thisfile == NULL) 654 return (EOI); 655 if (ch_offset > 0) 656 ch_offset --; 657 else 658 { 659 if (ch_block <= 0) 660 return (EOI); 661 if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1)) 662 return (EOI); 663 ch_block--; 664 ch_offset = LBUFSIZE-1; 665 } 666 return (ch_get()); 667 } 668 669 /* 670 * Set max amount of buffer space. 671 * bufspace is in units of 1024 bytes. -1 mean no limit. 672 */ 673 public void 674 ch_setbufspace(bufspace) 675 int bufspace; 676 { 677 if (bufspace < 0) 678 maxbufs = -1; 679 else 680 { 681 maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE; 682 if (maxbufs < 1) 683 maxbufs = 1; 684 } 685 } 686 687 /* 688 * Flush (discard) any saved file state, including buffer contents. 689 */ 690 public void 691 ch_flush(VOID_PARAM) 692 { 693 struct bufnode *bn; 694 695 if (thisfile == NULL) 696 return; 697 698 if (!(ch_flags & CH_CANSEEK)) 699 { 700 /* 701 * If input is a pipe, we don't flush buffer contents, 702 * since the contents can't be recovered. 703 */ 704 ch_fsize = NULL_POSITION; 705 return; 706 } 707 708 /* 709 * Initialize all the buffers. 710 */ 711 FOR_BUFS(bn) 712 { 713 bufnode_buf(bn)->block = -1; 714 } 715 716 /* 717 * Figure out the size of the file, if we can. 718 */ 719 ch_fsize = filesize(ch_file); 720 721 /* 722 * Seek to a known position: the beginning of the file. 723 */ 724 ch_fpos = 0; 725 ch_block = 0; /* ch_fpos / LBUFSIZE; */ 726 ch_offset = 0; /* ch_fpos % LBUFSIZE; */ 727 728 #if 1 729 /* 730 * This is a kludge to workaround a Linux kernel bug: files in 731 * /proc have a size of 0 according to fstat() but have readable 732 * data. They are sometimes, but not always, seekable. 733 * Force them to be non-seekable here. 734 */ 735 if (ch_fsize == 0) 736 { 737 ch_fsize = NULL_POSITION; 738 ch_flags &= ~CH_CANSEEK; 739 } 740 #endif 741 742 if (lseek(ch_file, (off_t)0, SEEK_SET) == BAD_LSEEK) 743 { 744 /* 745 * Warning only; even if the seek fails for some reason, 746 * there's a good chance we're at the beginning anyway. 747 * {{ I think this is bogus reasoning. }} 748 */ 749 error("seek error to 0", NULL_PARG); 750 } 751 } 752 753 /* 754 * Allocate a new buffer. 755 * The buffer is added to the tail of the buffer chain. 756 */ 757 static int 758 ch_addbuf(VOID_PARAM) 759 { 760 struct buf *bp; 761 struct bufnode *bn; 762 763 /* 764 * Allocate and initialize a new buffer and link it 765 * onto the tail of the buffer list. 766 */ 767 bp = (struct buf *) calloc(1, sizeof(struct buf)); 768 if (bp == NULL) 769 return (1); 770 ch_nbufs++; 771 bp->block = -1; 772 bn = &bp->node; 773 774 BUF_INS_TAIL(bn); 775 BUF_HASH_INS(bn, 0); 776 return (0); 777 } 778 779 /* 780 * 781 */ 782 static void 783 init_hashtbl(VOID_PARAM) 784 { 785 int h; 786 787 for (h = 0; h < BUFHASH_SIZE; h++) 788 { 789 thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h); 790 thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h); 791 } 792 } 793 794 /* 795 * Delete all buffers for this file. 796 */ 797 static void 798 ch_delbufs(VOID_PARAM) 799 { 800 struct bufnode *bn; 801 802 while (ch_bufhead != END_OF_CHAIN) 803 { 804 bn = ch_bufhead; 805 BUF_RM(bn); 806 free(bufnode_buf(bn)); 807 } 808 ch_nbufs = 0; 809 init_hashtbl(); 810 } 811 812 /* 813 * Is it possible to seek on a file descriptor? 814 */ 815 public int 816 seekable(f) 817 int f; 818 { 819 #if MSDOS_COMPILER 820 extern int fd0; 821 if (f == fd0 && !isatty(fd0)) 822 { 823 /* 824 * In MS-DOS, pipes are seekable. Check for 825 * standard input, and pretend it is not seekable. 826 */ 827 return (0); 828 } 829 #endif 830 return (lseek(f, (off_t)1, SEEK_SET) != BAD_LSEEK); 831 } 832 833 /* 834 * Force EOF to be at the current read position. 835 * This is used after an ignore_eof read, during which the EOF may change. 836 */ 837 public void 838 ch_set_eof(VOID_PARAM) 839 { 840 if (ch_fsize != NULL_POSITION && ch_fsize < ch_fpos) 841 ch_fsize = ch_fpos; 842 } 843 844 845 /* 846 * Initialize file state for a new file. 847 */ 848 public void 849 ch_init(f, flags) 850 int f; 851 int flags; 852 { 853 /* 854 * See if we already have a filestate for this file. 855 */ 856 thisfile = (struct filestate *) get_filestate(curr_ifile); 857 if (thisfile == NULL) 858 { 859 /* 860 * Allocate and initialize a new filestate. 861 */ 862 thisfile = (struct filestate *) 863 ecalloc(1, sizeof(struct filestate)); 864 thisfile->buflist.next = thisfile->buflist.prev = END_OF_CHAIN; 865 thisfile->nbufs = 0; 866 thisfile->flags = flags; 867 thisfile->fpos = 0; 868 thisfile->block = 0; 869 thisfile->offset = 0; 870 thisfile->file = -1; 871 thisfile->fsize = NULL_POSITION; 872 init_hashtbl(); 873 /* 874 * Try to seek; set CH_CANSEEK if it works. 875 */ 876 if ((flags & CH_CANSEEK) && !seekable(f)) 877 ch_flags &= ~CH_CANSEEK; 878 set_filestate(curr_ifile, (void *) thisfile); 879 } 880 if (thisfile->file == -1) 881 thisfile->file = f; 882 ch_flush(); 883 } 884 885 /* 886 * Close a filestate. 887 */ 888 public void 889 ch_close(VOID_PARAM) 890 { 891 int keepstate = FALSE; 892 893 if (thisfile == NULL) 894 return; 895 896 if ((ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE)) && !(ch_flags & CH_KEEPOPEN)) 897 { 898 /* 899 * We can seek or re-open, so we don't need to keep buffers. 900 */ 901 ch_delbufs(); 902 } else 903 keepstate = TRUE; 904 if (!(ch_flags & CH_KEEPOPEN)) 905 { 906 /* 907 * We don't need to keep the file descriptor open 908 * (because we can re-open it.) 909 * But don't really close it if it was opened via popen(), 910 * because pclose() wants to close it. 911 */ 912 if (!(ch_flags & (CH_POPENED|CH_HELPFILE))) 913 close(ch_file); 914 ch_file = -1; 915 } else 916 keepstate = TRUE; 917 if (!keepstate) 918 { 919 /* 920 * We don't even need to keep the filestate structure. 921 */ 922 free(thisfile); 923 thisfile = NULL; 924 set_filestate(curr_ifile, (void *) NULL); 925 } 926 } 927 928 /* 929 * Return ch_flags for the current file. 930 */ 931 public int 932 ch_getflags(VOID_PARAM) 933 { 934 if (thisfile == NULL) 935 return (0); 936 return (ch_flags); 937 } 938 939 #if 0 940 public void 941 ch_dump(struct filestate *fs) 942 { 943 struct buf *bp; 944 struct bufnode *bn; 945 unsigned char *s; 946 947 if (fs == NULL) 948 { 949 printf(" --no filestate\n"); 950 return; 951 } 952 printf(" file %d, flags %x, fpos %x, fsize %x, blk/off %x/%x\n", 953 fs->file, fs->flags, fs->fpos, 954 fs->fsize, fs->block, fs->offset); 955 printf(" %d bufs:\n", fs->nbufs); 956 for (bn = fs->next; bn != &fs->buflist; bn = bn->next) 957 { 958 bp = bufnode_buf(bn); 959 printf("%x: blk %x, size %x \"", 960 bp, bp->block, bp->datasize); 961 for (s = bp->data; s < bp->data + 30; s++) 962 if (*s >= ' ' && *s < 0x7F) 963 printf("%c", *s); 964 else 965 printf("."); 966 printf("\"\n"); 967 } 968 } 969 #endif 970