home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / less3292.zip / ch.c < prev    next >
C/C++ Source or Header  |  1996-10-19  |  17KB  |  808 lines

  1. /*
  2.  * Copyright (c) 1984,1985,1989,1994,1995,1996  Mark Nudelman
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice in the documentation and/or other materials provided with 
  12.  *    the distribution.
  13.  *
  14.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
  15.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  17.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
  18.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  19.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
  20.  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
  21.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
  22.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
  23.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 
  24.  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25.  */
  26.  
  27.  
  28. /*
  29.  * Low level character input from the input file.
  30.  * We use these special purpose routines which optimize moving
  31.  * both forward and backward from the current read pointer.
  32.  */
  33.  
  34. #include "less.h"
  35. #if MSDOS_COMPILER==WIN32C
  36. #include <errno.h>
  37. #endif
  38.  
  39. public int ignore_eoi;
  40.  
  41. /*
  42.  * Pool of buffers holding the most recently used blocks of the input file.
  43.  * The buffer pool is kept as a doubly-linked circular list,
  44.  * in order from most- to least-recently used.
  45.  * The circular list is anchored by the file state "thisfile".
  46.  */
  47. #define LBUFSIZE    1024
  48. struct buf {
  49.     struct buf *next, *prev;  /* Must be first to match struct filestate */
  50.     long block;
  51.     unsigned int datasize;
  52.     unsigned char data[LBUFSIZE];
  53. };
  54.  
  55. /*
  56.  * The file state is maintained in a filestate structure.
  57.  * A pointer to the filestate is kept in the ifile structure.
  58.  */
  59. struct filestate {
  60.     /* -- Following members must match struct buf */
  61.     struct buf *buf_next, *buf_prev;
  62.     long buf_block;
  63.     /* -- End of struct buf copy */
  64.     int file;
  65.     int flags;
  66.     POSITION fpos;
  67.     int nbufs;
  68.     long block;
  69.     int offset;
  70.     POSITION fsize;
  71. };
  72.  
  73.  
  74. #define    END_OF_CHAIN    ((struct buf *)thisfile)
  75. #define    ch_bufhead    thisfile->buf_next
  76. #define    ch_buftail    thisfile->buf_prev
  77. #define    ch_nbufs    thisfile->nbufs
  78. #define    ch_block    thisfile->block
  79. #define    ch_offset    thisfile->offset
  80. #define    ch_fpos        thisfile->fpos
  81. #define    ch_fsize    thisfile->fsize
  82. #define    ch_flags    thisfile->flags
  83. #define    ch_file        thisfile->file
  84.  
  85. static struct filestate *thisfile;
  86. static int ch_ungotchar = -1;
  87.  
  88. extern int autobuf;
  89. extern int sigs;
  90. extern int cbufs;
  91. extern int secure;
  92. extern constant char helpdata[];
  93. extern constant int size_helpdata;
  94. extern IFILE curr_ifile;
  95. #if LOGFILE
  96. extern int logfile;
  97. extern char *namelogfile;
  98. #endif
  99.  
  100. static int ch_addbuf();
  101.  
  102.  
  103. /*
  104.  * Get the character pointed to by the read pointer.
  105.  * ch_get() is a macro which is more efficient to call
  106.  * than fch_get (the function), in the usual case 
  107.  * that the block desired is at the head of the chain.
  108.  */
  109. #define    ch_get()   ((ch_block == ch_bufhead->block && \
  110.              ch_offset < ch_bufhead->datasize) ? \
  111.             ch_bufhead->data[ch_offset] : fch_get())
  112.     int
  113. fch_get()
  114. {
  115.     register struct buf *bp;
  116.     register int n;
  117.     register int slept;
  118.     POSITION pos;
  119.     POSITION len;
  120.  
  121.     slept = FALSE;
  122.  
  123.     /*
  124.      * Look for a buffer holding the desired block.
  125.      */
  126.     for (bp = ch_bufhead;  bp != END_OF_CHAIN;  bp = bp->next)
  127.         if (bp->block == ch_block)
  128.         {
  129.             if (ch_offset >= bp->datasize)
  130.                 /*
  131.                  * Need more data in this buffer.
  132.                  */
  133.                 goto read_more;
  134.             goto found;
  135.         }
  136.     /*
  137.      * Block is not in a buffer.  
  138.      * Take the least recently used buffer 
  139.      * and read the desired block into it.
  140.      * If the LRU buffer has data in it, 
  141.      * then maybe allocate a new buffer.
  142.      */
  143.     if (ch_buftail == END_OF_CHAIN || ch_buftail->block != (long)(-1))
  144.     {
  145.         /*
  146.          * There is no empty buffer to use.
  147.          * Allocate a new buffer if:
  148.          * 1. We can't seek on this file and -b is not in effect; or
  149.          * 2. We haven't allocated the max buffers for this file yet.
  150.          */
  151.         if ((autobuf && !(ch_flags & CH_CANSEEK)) ||
  152.             (cbufs == -1 || ch_nbufs < cbufs))
  153.             if (ch_addbuf())
  154.                 /*
  155.                  * Allocation failed: turn off autobuf.
  156.                  */
  157.                 autobuf = OPT_OFF;
  158.     }
  159.     bp = ch_buftail;
  160.     bp->block = ch_block;
  161.     bp->datasize = 0;
  162.  
  163.     read_more:
  164.     pos = (ch_block * LBUFSIZE) + bp->datasize;
  165.     if ((len = ch_length()) != NULL_POSITION && pos >= len)
  166.         /*
  167.          * At end of file.
  168.          */
  169.         return (EOI);
  170.  
  171.     if (pos != ch_fpos)
  172.     {
  173.         /*
  174.          * Not at the correct position: must seek.
  175.          * If input is a pipe, we're in trouble (can't seek on a pipe).
  176.          * Some data has been lost: just return "?".
  177.          */
  178.         if (!(ch_flags & CH_CANSEEK))
  179.             return ('?');
  180.         if (lseek(ch_file, (off_t)pos, 0) == BAD_LSEEK)
  181.         {
  182.              error("seek error", NULL_PARG);
  183.             clear_eol();
  184.             return (EOI);
  185.          }
  186.          ch_fpos = pos;
  187.      }
  188.  
  189.     /*
  190.      * Read the block.
  191.      * If we read less than a full block, that's ok.
  192.      * We use partial block and pick up the rest next time.
  193.      */
  194.     if (ch_ungotchar != -1)
  195.     {
  196.         bp->data[bp->datasize] = ch_ungotchar;
  197.         n = 1;
  198.         ch_ungotchar = -1;
  199.     } else if (ch_flags & CH_HELPFILE)
  200.     {
  201.         bp->data[bp->datasize] = helpdata[ch_fpos];
  202.         n = 1;
  203.     } else
  204.     {
  205.         n = iread(ch_file, &bp->data[bp->datasize], 
  206.             (unsigned int)(LBUFSIZE - bp->datasize));
  207.     }
  208.  
  209.     if (n == READ_INTR)
  210.         return (EOI);
  211.     if (n < 0)
  212.     {
  213. #if MSDOS_COMPILER==WIN32C
  214.         if (errno != EPIPE)
  215. #endif
  216.         {
  217.             error("read error", NULL_PARG);
  218.             clear_eol();
  219.         }
  220.         n = 0;
  221.     }
  222.  
  223. #if LOGFILE
  224.     /*
  225.      * If we have a log file, write the new data to it.
  226.      */
  227.     if (!secure && logfile >= 0 && n > 0)
  228.         write(logfile, (char *) &bp->data[bp->datasize], n);
  229. #endif
  230.  
  231.     ch_fpos += n;
  232.     bp->datasize += n;
  233.  
  234.     /*
  235.      * If we have read to end of file, set ch_fsize to indicate
  236.      * the position of the end of file.
  237.      */
  238.     if (n == 0)
  239.     {
  240.         ch_fsize = pos;
  241.         if (ignore_eoi)
  242.         {
  243.             /*
  244.              * We are ignoring EOF.
  245.              * Wait a while, then try again.
  246.              */
  247.             if (!slept)
  248.                 ierror("Waiting for data", NULL_PARG);
  249. #if !MSDOS_COMPILER
  250.              sleep(1);
  251. #endif
  252.             slept = TRUE;
  253.         }
  254.         if (sigs)
  255.             return (EOI);
  256.     }
  257.  
  258.     found:
  259.     if (ch_bufhead != bp)
  260.     {
  261.         /*
  262.          * Move the buffer to the head of the buffer chain.
  263.          * This orders the buffer chain, most- to least-recently used.
  264.          */
  265.         bp->next->prev = bp->prev;
  266.         bp->prev->next = bp->next;
  267.  
  268.         bp->next = ch_bufhead;
  269.         bp->prev = END_OF_CHAIN;
  270.         ch_bufhead->prev = bp;
  271.         ch_bufhead = bp;
  272.     }
  273.  
  274.     if (ch_offset >= bp->datasize)
  275.         /*
  276.          * After all that, we still don't have enough data.
  277.          * Go back and try again.
  278.          */
  279.         goto read_more;
  280.  
  281.     return (bp->data[ch_offset]);
  282. }
  283.  
  284. /*
  285.  * ch_ungetchar is a rather kludgy and limited way to push 
  286.  * a single char onto an input file descriptor.
  287.  */
  288.     public void
  289. ch_ungetchar(c)
  290.     int c;
  291. {
  292.     if (c != -1 && ch_ungotchar != -1)
  293.         error("ch_ungetchar overrun", NULL_PARG);
  294.     ch_ungotchar = c;
  295. }
  296.  
  297. #if LOGFILE
  298. /*
  299.  * Close the logfile.
  300.  * If we haven't read all of standard input into it, do that now.
  301.  */
  302.     public void
  303. end_logfile()
  304. {
  305.     static int tried = FALSE;
  306.  
  307.     if (logfile < 0)
  308.         return;
  309.     if (!tried && ch_fsize == NULL_POSITION)
  310.     {
  311.         tried = TRUE;
  312.         ierror("Finishing logfile", NULL_PARG);
  313.         while (ch_forw_get() != EOI)
  314.             if (ABORT_SIGS())
  315.                 break;
  316.     }
  317.     close(logfile);
  318.     logfile = -1;
  319.     namelogfile = NULL;
  320. }
  321.  
  322. /*
  323.  * Start a log file AFTER less has already been running.
  324.  * Invoked from the - command; see toggle_option().
  325.  * Write all the existing buffered data to the log file.
  326.  */
  327.     public void
  328. sync_logfile()
  329. {
  330.     register struct buf *bp;
  331.     int warned = FALSE;
  332.     long block;
  333.     long nblocks;
  334.  
  335.     nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;
  336.     for (block = 0;  block < nblocks;  block++)
  337.     {
  338.         for (bp = ch_bufhead;  ;  bp = bp->next)
  339.         {
  340.             if (bp == END_OF_CHAIN)
  341.             {
  342.                 if (!warned)
  343.                 {
  344.                     error("Warning: log file is incomplete",
  345.                         NULL_PARG);
  346.                     warned = TRUE;
  347.                 }
  348.                 break;
  349.             }
  350.             if (bp->block == block)
  351.             {
  352.                 write(logfile, (char *) bp->data, bp->datasize);
  353.                 break;
  354.             }
  355.         }
  356.     }
  357. }
  358.  
  359. #endif
  360.  
  361. /*
  362.  * Determine if a specific block is currently in one of the buffers.
  363.  */
  364.     static int
  365. buffered(block)
  366.     long block;
  367. {
  368.     register struct buf *bp;
  369.  
  370.     for (bp = ch_bufhead;  bp != END_OF_CHAIN;  bp = bp->next)
  371.         if (bp->block == block)
  372.             return (TRUE);
  373.     return (FALSE);
  374. }
  375.  
  376. /*
  377.  * Seek to a specified position in the file.
  378.  * Return 0 if successful, non-zero if can't seek there.
  379.  */
  380.     public int
  381. ch_seek(pos)
  382.     register POSITION pos;
  383. {
  384.     long new_block;
  385.     POSITION len;
  386.  
  387.     len = ch_length();
  388.     if (pos < ch_zero() || (len != NULL_POSITION && pos > len))
  389.         return (1);
  390.  
  391.     new_block = pos / LBUFSIZE;
  392.     if (!(ch_flags & CH_CANSEEK) && pos != ch_fpos && !buffered(new_block))
  393.     {
  394.         if (ch_fpos > pos)
  395.             return (1);
  396.         while (ch_fpos < pos)
  397.         {
  398.             if (ch_forw_get() == EOI)
  399.                 return (1);
  400.             if (ABORT_SIGS())
  401.                 return (1);
  402.         }
  403.         return (0);
  404.     }
  405.     /*
  406.      * Set read pointer.
  407.      */
  408.     ch_block = new_block;
  409.     ch_offset = pos % LBUFSIZE;
  410.     return (0);
  411. }
  412.  
  413. /*
  414.  * Seek to the end of the file.
  415.  */
  416.     public int
  417. ch_end_seek()
  418. {
  419.     POSITION len;
  420.  
  421.     if (ch_flags & CH_CANSEEK)
  422.         ch_fsize = filesize(ch_file);
  423.  
  424.     len = ch_length();
  425.     if (len != NULL_POSITION)
  426.         return (ch_seek(len));
  427.  
  428.     /*
  429.      * Do it the slow way: read till end of data.
  430.      */
  431.     while (ch_forw_get() != EOI)
  432.         if (ABORT_SIGS())
  433.             return (1);
  434.     return (0);
  435. }
  436.  
  437. /*
  438.  * Seek to the beginning of the file, or as close to it as we can get.
  439.  * We may not be able to seek there if input is a pipe and the
  440.  * beginning of the pipe is no longer buffered.
  441.  */
  442.     public int
  443. ch_beg_seek()
  444. {
  445.     register struct buf *bp, *firstbp;
  446.  
  447.     /*
  448.      * Try a plain ch_seek first.
  449.      */
  450.     if (ch_seek(ch_zero()) == 0)
  451.         return (0);
  452.  
  453.     /*
  454.      * Can't get to position 0.
  455.      * Look thru the buffers for the one closest to position 0.
  456.      */
  457.     firstbp = bp = ch_bufhead;
  458.     if (bp == END_OF_CHAIN)
  459.         return (1);
  460.     while ((bp = bp->next) != END_OF_CHAIN)
  461.         if (bp->block < firstbp->block)
  462.             firstbp = bp;
  463.     ch_block = firstbp->block;
  464.     ch_offset = 0;
  465.     return (0);
  466. }
  467.  
  468. /*
  469.  * Return the length of the file, if known.
  470.  */
  471.     public POSITION
  472. ch_length()
  473. {
  474.     if (ignore_eoi)
  475.         return (NULL_POSITION);
  476.     if (ch_flags & CH_HELPFILE)
  477.         return (size_helpdata);
  478.     return (ch_fsize);
  479. }
  480.  
  481. /*
  482.  * Return the current position in the file.
  483.  */
  484. #define    tellpos(blk,off)   ((POSITION)((((long)(blk)) * LBUFSIZE) + (off)))
  485.  
  486.     public POSITION
  487. ch_tell()
  488. {
  489.     return (tellpos(ch_block, ch_offset));
  490. }
  491.  
  492. /*
  493.  * Get the current char and post-increment the read pointer.
  494.  */
  495.     public int
  496. ch_forw_get()
  497. {
  498.     register int c;
  499.  
  500.     c = ch_get();
  501.     if (c == EOI)
  502.         return (EOI);
  503.     if (ch_offset < LBUFSIZE-1)
  504.         ch_offset++;
  505.     else
  506.     {
  507.         ch_block ++;
  508.         ch_offset = 0;
  509.     }
  510.     return (c);
  511. }
  512.  
  513. /*
  514.  * Pre-decrement the read pointer and get the new current char.
  515.  */
  516.     public int
  517. ch_back_get()
  518. {
  519.     if (ch_offset > 0)
  520.         ch_offset --;
  521.     else
  522.     {
  523.         if (ch_block <= 0)
  524.             return (EOI);
  525.         if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1))
  526.             return (EOI);
  527.         ch_block--;
  528.         ch_offset = LBUFSIZE-1;
  529.     }
  530.     return (ch_get());
  531. }
  532.  
  533. /*
  534.  * Allocate buffers.
  535.  * Caller wants us to have a total of at least want_nbufs buffers.
  536.  */
  537.     public int
  538. ch_nbuf(want_nbufs)
  539.     int want_nbufs;
  540. {
  541.     PARG parg;
  542.  
  543.     while (ch_nbufs < want_nbufs)
  544.     {
  545.         if (ch_addbuf())
  546.         {
  547.             /*
  548.              * Cannot allocate enough buffers.
  549.              * If we don't have ANY, then quit.
  550.              * Otherwise, just report the error and return.
  551.              */
  552.             parg.p_int = want_nbufs - ch_nbufs;
  553.             error("Cannot allocate %d buffers", &parg);
  554.             if (ch_nbufs == 0)
  555.                 quit(QUIT_ERROR);
  556.             break;
  557.         }
  558.     }
  559.     return (ch_nbufs);
  560. }
  561.  
  562. /*
  563.  * Flush (discard) any saved file state, including buffer contents.
  564.  */
  565.     public void
  566. ch_flush()
  567. {
  568.     register struct buf *bp;
  569.  
  570.     if (!(ch_flags & CH_CANSEEK))
  571.     {
  572.         /*
  573.          * If input is a pipe, we don't flush buffer contents,
  574.          * since the contents can't be recovered.
  575.          */
  576.         ch_fsize = NULL_POSITION;
  577.         return;
  578.     }
  579.  
  580.     /*
  581.      * Initialize all the buffers.
  582.      */
  583.     for (bp = ch_bufhead;  bp != END_OF_CHAIN;  bp = bp->next)
  584.         bp->block = (long)(-1);
  585.  
  586.     /*
  587.      * Figure out the size of the file, if we can.
  588.      */
  589.     ch_fsize = filesize(ch_file);
  590.  
  591.     /*
  592.      * Seek to a known position: the beginning of the file.
  593.      */
  594.     ch_fpos = 0;
  595.     ch_block = 0; /* ch_fpos / LBUFSIZE; */
  596.     ch_offset = 0; /* ch_fpos % LBUFSIZE; */
  597.  
  598. #if 1
  599.     /*
  600.      * This is a kludge to workaround a Linux kernel bug: files in
  601.      * /proc have a size of 0 according to fstat() but have readable 
  602.      * data.  They are sometimes, but not always, seekable.
  603.      * Force them to be non-seekable here.
  604.      */
  605.     if (ch_fsize == 0)
  606.     {
  607.         ch_fsize = NULL_POSITION;
  608.         ch_flags &= ~CH_CANSEEK;
  609.     }
  610. #endif
  611.  
  612.     if (lseek(ch_file, (off_t)0, 0) == BAD_LSEEK)
  613.     {
  614.         /*
  615.          * Warning only; even if the seek fails for some reason,
  616.          * there's a good chance we're at the beginning anyway.
  617.          * {{ I think this is bogus reasoning. }}
  618.          */
  619.         error("seek error to 0", NULL_PARG);
  620.     }
  621. }
  622.  
  623. /*
  624.  * Allocate a new buffer.
  625.  * The buffer is added to the tail of the buffer chain.
  626.  */
  627.     static int
  628. ch_addbuf()
  629. {
  630.     register struct buf *bp;
  631.  
  632.     /*
  633.      * Allocate and initialize a new buffer and link it 
  634.      * onto the tail of the buffer list.
  635.      */
  636.     bp = (struct buf *) calloc(1, sizeof(struct buf));
  637.     if (bp == NULL)
  638.         return (1);
  639.     ch_nbufs++;
  640.     bp->block = (long)(-1);
  641.     bp->next = END_OF_CHAIN;
  642.     bp->prev = ch_buftail;
  643.     ch_buftail->next = bp;
  644.     ch_buftail = bp;
  645.     return (0);
  646. }
  647.  
  648. /*
  649.  * Delete all buffers for this file.
  650.  */
  651.     static void
  652. ch_delbufs()
  653. {
  654.     register struct buf *bp;
  655.  
  656.     while (ch_bufhead != END_OF_CHAIN)
  657.     {
  658.         bp = ch_bufhead;
  659.         bp->next->prev = bp->prev;;
  660.         bp->prev->next = bp->next;
  661.         free(bp);
  662.     }
  663.     ch_nbufs = 0;
  664. }
  665.  
  666. /*
  667.  * Is it possible to seek on a file descriptor?
  668.  */
  669.     public int
  670. seekable(f)
  671.     int f;
  672. {
  673. #if MSDOS_COMPILER
  674.     extern int fd0;
  675.     if (f == fd0 && !isatty(fd0))
  676.     {
  677.         /*
  678.          * In MS-DOS, pipes are seekable.  Check for
  679.          * standard input, and pretend it is not seekable.
  680.          */
  681.         return (0);
  682.     }
  683. #endif
  684.     return (lseek(f, (off_t)1, 0) != BAD_LSEEK);
  685. }
  686.  
  687. /*
  688.  * Initialize file state for a new file.
  689.  */
  690.     public void
  691. ch_init(f, flags)
  692.     int f;
  693.     int flags;
  694. {
  695.     /*
  696.      * See if we already have a filestate for this file.
  697.      */
  698.     thisfile = (struct filestate *) get_filestate(curr_ifile);
  699.     if (thisfile == NULL)
  700.     {
  701.         /*
  702.          * Allocate and initialize a new filestate.
  703.          */
  704.         thisfile = (struct filestate *) 
  705.                 calloc(1, sizeof(struct filestate));
  706.         thisfile->buf_next = thisfile->buf_prev = END_OF_CHAIN;
  707.         thisfile->buf_block = (long)(-1);
  708.         thisfile->nbufs = 0;
  709.         thisfile->flags = 0;
  710.         thisfile->fpos = 0;
  711.         thisfile->block = 0;
  712.         thisfile->offset = 0;
  713.         thisfile->file = -1;
  714.         thisfile->fsize = NULL_POSITION;
  715.         ch_flags = flags;
  716.         /*
  717.          * Try to seek; set CH_CANSEEK if it works.
  718.          */
  719.         if (!(flags & CH_HELPFILE) && seekable(f))
  720.             ch_flags |= CH_CANSEEK;
  721.         set_filestate(curr_ifile, (void *) thisfile);
  722.     }
  723.     if (thisfile->file == -1)
  724.         thisfile->file = f;
  725.     ch_flush();
  726. }
  727.  
  728. /*
  729.  * Close a filestate.
  730.  */
  731.     public void
  732. ch_close()
  733. {
  734.     int keepstate = FALSE;
  735.  
  736.     if (ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE))
  737.     {
  738.         /*
  739.          * We can seek or re-open, so we don't need to keep buffers.
  740.          */
  741.         ch_delbufs();
  742.     } else
  743.         keepstate = TRUE;
  744.     if (!(ch_flags & CH_KEEPOPEN))
  745.     {
  746.         /*
  747.          * We don't need to keep the file descriptor open
  748.          * (because we can re-open it.)
  749.          * But don't really close it if it was opened via popen(),
  750.          * because pclose() wants to close it.
  751.          */
  752.             if (ch_flags & CH_COMPRESSED)
  753.               Zclose(ch_file);
  754.         else if (!(ch_flags & (CH_POPENED|CH_HELPFILE)))
  755.             close(ch_file);
  756.         ch_file = -1;
  757.     } else
  758.         keepstate = TRUE;
  759.     if (!keepstate)
  760.     {
  761.         /*
  762.          * We don't even need to keep the filestate structure.
  763.          */
  764.         free(thisfile);
  765.         thisfile = NULL;
  766.         set_filestate(curr_ifile, (void *) NULL);
  767.     }
  768. }
  769.  
  770. /*
  771.  * Return ch_flags for the current file.
  772.  */
  773.     public int
  774. ch_getflags()
  775. {
  776.     return (ch_flags);
  777. }
  778.  
  779. #if 0
  780.     public void
  781. ch_dump(struct filestate *fs)
  782. {
  783.     struct buf *bp;
  784.     unsigned char *s;
  785.  
  786.     if (fs == NULL)
  787.     {
  788.         printf(" --no filestate\n");
  789.         return;
  790.     }
  791.     printf(" file %d, flags %x, fpos %x, fsize %x, blk/off %x/%x\n",
  792.         fs->file, fs->flags, fs->fpos, 
  793.         fs->fsize, fs->block, fs->offset);
  794.     printf(" %d bufs:\n", fs->nbufs);
  795.     for (bp = fs->buf_next; bp != (struct buf *)fs;  bp = bp->next)
  796.     {
  797.         printf("%x: blk %x, size %x \"",
  798.             bp, bp->block, bp->datasize);
  799.         for (s = bp->data;  s < bp->data + 30;  s++)
  800.             if (*s >= ' ' && *s < 0x7F)
  801.                 printf("%c", *s);
  802.             else
  803.                 printf(".");
  804.         printf("\"\n");
  805.     }
  806. }
  807. #endif
  808.