[BACK]Return to ch.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Annotation of src/usr.bin/less/ch.c, Revision 1.1.1.1

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