Annotation of 43BSD/contrib/mh/miscellany/less/ch.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Low level character input from the input file.
        !             3:  * We use these special purpose routines which optimize moving
        !             4:  * both forward and backward from the current read pointer.
        !             5:  */
        !             6: 
        !             7: #include "less.h"
        !             8: 
        !             9: public int file = -1;  /* File descriptor of the input file */
        !            10: 
        !            11: /*
        !            12:  * Pool of buffers holding the most recently used blocks of the input file.
        !            13:  */
        !            14: #define BUFSIZ 1024
        !            15: static struct buf {
        !            16:        struct buf *next, *prev;
        !            17:        long block;
        !            18:        char data[BUFSIZ];
        !            19: };
        !            20: static struct buf *bufs = NULL;
        !            21: public int nbufs;
        !            22: 
        !            23: /*
        !            24:  * The buffer pool is kept as a doubly-linked circular list,
        !            25:  * in order from most- to least-recently used.
        !            26:  * The circular list is anchored by buf_anchor.
        !            27:  */
        !            28: static struct {
        !            29:        struct buf *next, *prev;
        !            30: } buf_anchor;
        !            31: #define        END_OF_CHAIN    ((struct buf *)&buf_anchor)
        !            32: #define        buf_head        buf_anchor.next
        !            33: #define        buf_tail        buf_anchor.prev
        !            34: 
        !            35: /*
        !            36:  * If we fail to allocate enough memory for buffers, we try to limp
        !            37:  * along with a minimum number of buffers.  
        !            38:  */
        !            39: #define        DEF_NBUFS       2       /* Minimum number of buffers */
        !            40: 
        !            41: extern int clean_data;
        !            42: extern int ispipe;
        !            43: 
        !            44: /*
        !            45:  * Current position in file.
        !            46:  * Stored as a block number and an offset into the block.
        !            47:  */
        !            48: static long ch_block;
        !            49: static int ch_offset;
        !            50: 
        !            51: /* 
        !            52:  * Length of file, needed if input is a pipe.
        !            53:  */
        !            54: static POSITION ch_fsize;
        !            55: 
        !            56: /*
        !            57:  * Largest block number read if input is standard input (a pipe).
        !            58:  */
        !            59: static long last_piped_block;
        !            60: 
        !            61: /*
        !            62:  * Get the character pointed to by the read pointer.
        !            63:  * ch_get() is a macro which is more efficient to call
        !            64:  * than fch_get (the function), in the usual case 
        !            65:  * that the block desired is at the head of the chain.
        !            66:  */
        !            67: #define        ch_get()   ((buf_head->block == ch_block) ? \
        !            68:                        buf_head->data[ch_offset] : fch_get())
        !            69:        static int
        !            70: fch_get()
        !            71: {
        !            72:        register struct buf *bp;
        !            73:        register int n;
        !            74:        register int end;
        !            75:        POSITION pos;
        !            76: 
        !            77:        /*
        !            78:         * Look for a buffer holding the desired block.
        !            79:         */
        !            80:        for (bp = buf_head;  bp != END_OF_CHAIN;  bp = bp->next)
        !            81:                if (bp->block == ch_block)
        !            82:                        goto found;
        !            83:        /*
        !            84:         * Block is not in a buffer.  
        !            85:         * Take the least recently used buffer 
        !            86:         * and read the desired block into it.
        !            87:         */
        !            88:        bp = buf_tail;
        !            89:        bp->block = ch_block;
        !            90:        pos = ch_block * BUFSIZ;
        !            91:        if (ispipe)
        !            92:        {
        !            93:                /*
        !            94:                 * The block requested should be one more than
        !            95:                 * the last block read.
        !            96:                 */
        !            97:                if (ch_block != ++last_piped_block)
        !            98:                {
        !            99:                        /* This "should not happen". */
        !           100:                        char message[80];
        !           101:                        sprintf(message, "Pipe error: last %ld, want %ld\n",
        !           102:                                last_piped_block-1, ch_block);
        !           103:                        error(message);
        !           104:                        quit();
        !           105:                }
        !           106:        } else
        !           107:                lseek(file, pos, 0);
        !           108: 
        !           109:        /*
        !           110:         * Read the block.  This may take several reads if the input
        !           111:         * is coming from standard input, due to the nature of pipes.
        !           112:         */
        !           113:        end = 0;
        !           114:        while ((n = read(file, &bp->data[end], BUFSIZ-end)) > 0)
        !           115:                if ((end += n) >= BUFSIZ)
        !           116:                        break;
        !           117: 
        !           118:        if (n < 0)
        !           119:        {
        !           120:                error("read error");
        !           121:                quit();
        !           122:        }
        !           123: 
        !           124:        /*
        !           125:         * Set an EOF marker in the buffered data itself.
        !           126:         * Then ensure the data is "clean": there are no 
        !           127:         * extra EOF chars in the data and that the "meta"
        !           128:         * bit (the 0200 bit) is reset in each char.
        !           129:         */
        !           130:        if (end < BUFSIZ)
        !           131:        {
        !           132:                ch_fsize = pos + end;
        !           133:                bp->data[end] = EOF;
        !           134:        }
        !           135: 
        !           136:        if (!clean_data)
        !           137:                while (--end >= 0)
        !           138:                {
        !           139:                        bp->data[end] &= 0177;
        !           140:                        if (bp->data[end] == EOF)
        !           141:                                bp->data[end] = '@';
        !           142:                }
        !           143: 
        !           144:     found:
        !           145:        /* if (buf_head != bp) {this is guaranteed by the ch_get macro} */
        !           146:        {
        !           147:                /*
        !           148:                 * Move the buffer to the head of the buffer chain.
        !           149:                 * This orders the buffer chain, most- to least-recently used.
        !           150:                 */
        !           151:                bp->next->prev = bp->prev;
        !           152:                bp->prev->next = bp->next;
        !           153: 
        !           154:                bp->next = buf_head;
        !           155:                bp->prev = END_OF_CHAIN;
        !           156:                buf_head->prev = bp;
        !           157:                buf_head = bp;
        !           158:        }
        !           159:        return (bp->data[ch_offset]);
        !           160: }
        !           161: 
        !           162: /*
        !           163:  * Determine if a specific block is currently in one of the buffers.
        !           164:  */
        !           165:        static int
        !           166: buffered(block)
        !           167:        long block;
        !           168: {
        !           169:        register struct buf *bp;
        !           170: 
        !           171:        for (bp = buf_head;  bp != END_OF_CHAIN;  bp = bp->next)
        !           172:                if (bp->block == block)
        !           173:                        return (1);
        !           174:        return (0);
        !           175: }
        !           176: 
        !           177: /*
        !           178:  * Seek to a specified position in the file.
        !           179:  * Return 0 if successful, non-zero if can't seek there.
        !           180:  */
        !           181:        public int
        !           182: ch_seek(pos)
        !           183:        register POSITION pos;
        !           184: {
        !           185:        long new_block;
        !           186: 
        !           187:        new_block = pos / BUFSIZ;
        !           188:        if (!ispipe || new_block == last_piped_block + 1 || buffered(new_block))
        !           189:        {
        !           190:                /*
        !           191:                 * Set read pointer.
        !           192:                 */
        !           193:                ch_block = new_block;
        !           194:                ch_offset = pos % BUFSIZ;
        !           195:                return (0);
        !           196:        }
        !           197:        return (1);
        !           198: }
        !           199: 
        !           200: /*
        !           201:  * Seek to the end of the file.
        !           202:  */
        !           203:        public int
        !           204: ch_end_seek()
        !           205: {
        !           206:        if (ispipe)
        !           207:        {
        !           208:                /*
        !           209:                 * Do it the slow way: read till end of data.
        !           210:                 */
        !           211:                while (ch_forw_get() != EOF)
        !           212:                        ;
        !           213:        } else
        !           214:        {
        !           215:                (void) ch_seek((POSITION)(lseek(file, (off_t)0, 2)));
        !           216:        }
        !           217:        return (0);
        !           218: }
        !           219: 
        !           220: /*
        !           221:  * Return the length of the file, if known.
        !           222:  */
        !           223:        public POSITION
        !           224: ch_length()
        !           225: {
        !           226:        if (ispipe)
        !           227:                return (ch_fsize);
        !           228:        return ((POSITION)(lseek(file, (off_t)0, 2)));
        !           229: }
        !           230: 
        !           231: /*
        !           232:  * Return the current position in the file.
        !           233:  */
        !           234:        public POSITION
        !           235: ch_tell()
        !           236: {
        !           237:        return (ch_block * BUFSIZ + ch_offset);
        !           238: }
        !           239: 
        !           240: /*
        !           241:  * Get the current char and post-increment the read pointer.
        !           242:  */
        !           243:        public int
        !           244: ch_forw_get()
        !           245: {
        !           246:        register int c;
        !           247: 
        !           248:        c = ch_get();
        !           249:        if (c != EOF && ++ch_offset >= BUFSIZ)
        !           250:        {
        !           251:                ch_offset = 0;
        !           252:                ch_block ++;
        !           253:        }
        !           254:        return (c);
        !           255: }
        !           256: 
        !           257: /*
        !           258:  * Pre-decrement the read pointer and get the new current char.
        !           259:  */
        !           260:        public int
        !           261: ch_back_get()
        !           262: {
        !           263:        register int c;
        !           264: 
        !           265:        if (--ch_offset < 0)
        !           266:        {
        !           267:                if (ch_block <= 0 || (ispipe && !buffered(ch_block-1)))
        !           268:                {
        !           269:                        ch_offset = 0;
        !           270:                        return (EOF);
        !           271:                }
        !           272:                ch_offset = BUFSIZ - 1;
        !           273:                ch_block--;
        !           274:        }
        !           275:        c = ch_get();
        !           276:        return (c);
        !           277: }
        !           278: 
        !           279: /*
        !           280:  * Initialize the buffer pool to all empty.
        !           281:  * Caller suggests that we use want_nbufs buffers.
        !           282:  */
        !           283:        public void
        !           284: ch_init(want_nbufs)
        !           285:        int want_nbufs;
        !           286: {
        !           287:        register struct buf *bp;
        !           288:        char *calloc();
        !           289: 
        !           290:        if (nbufs < want_nbufs)
        !           291:        {
        !           292:                /*
        !           293:                 * We don't have enough buffers.  
        !           294:                 * Free what we have (if any) and allocate some new ones.
        !           295:                 */
        !           296:                if (bufs != NULL)
        !           297:                        free((char *)bufs);
        !           298:                bufs = (struct buf *) calloc(want_nbufs, sizeof(struct buf));
        !           299:                nbufs = want_nbufs;
        !           300:                if (bufs == NULL)
        !           301:                {
        !           302:                        /*
        !           303:                         * Couldn't get that many.
        !           304:                         * Try for a small default number of buffers.
        !           305:                         */
        !           306:                        char message[80];
        !           307:                        sprintf(message,
        !           308:                          "Cannot allocate %d buffers.  Using %d buffers.", 
        !           309:                          nbufs, DEF_NBUFS);
        !           310:                        error(message);
        !           311:                        bufs = (struct buf *) calloc(DEF_NBUFS, sizeof(struct buf));
        !           312:                        nbufs = DEF_NBUFS;
        !           313:                        if (bufs == NULL)
        !           314:                        {
        !           315:                                /*
        !           316:                                 * Couldn't even get the smaller number of bufs.
        !           317:                                 * Something is wrong here, don't continue.
        !           318:                                 */
        !           319:                                sprintf(message, 
        !           320:                                "Cannot even allocate %d buffers!  Quitting.\n",
        !           321:                                  DEF_NBUFS);
        !           322:                                error(message);
        !           323:                                quit();
        !           324:                                /*NOTREACHED*/
        !           325:                        }
        !           326:                }
        !           327:        }
        !           328: 
        !           329:        /*
        !           330:         * Initialize the buffers to empty.
        !           331:         * Set up the circular list.
        !           332:         */
        !           333:        for (bp = &bufs[0];  bp < &bufs[nbufs];  bp++)
        !           334:        {
        !           335:                bp->next = bp + 1;
        !           336:                bp->prev = bp - 1;
        !           337:                bp->block = (long)(-1);
        !           338:        }
        !           339:        bufs[0].prev = bufs[nbufs-1].next = END_OF_CHAIN;
        !           340:        buf_head = &bufs[0];
        !           341:        buf_tail = &bufs[nbufs-1];
        !           342:        last_piped_block = -1;
        !           343:        ch_fsize = NULL_POSITION;
        !           344:        (void) ch_seek((POSITION)0);
        !           345: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.