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