|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.