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: }

Defined functions

buffered defined in line 165; used 2 times
fch_get defined in line 69; used 1 times
  • in line 68

Defined variables

bufs defined in line 20; used 12 times
ch_block defined in line 48; used 12 times
ch_fsize defined in line 54; used 3 times
ch_offset defined in line 49; used 9 times
file defined in line 9; used 10 times
last_piped_block defined in line 59; used 4 times
nbufs defined in line 21; used 9 times
public defined in line 283; never used

Defined struct's

buf defined in line 15; used 20 times

Defined macros

BUFSIZ defined in line 14; used 10 times
DEF_NBUFS defined in line 39; used 4 times
END_OF_CHAIN defined in line 31; used 4 times
buf_head defined in line 32; used 8 times
buf_tail defined in line 33; used 2 times
ch_get defined in line 67; used 2 times
Last modified: 1986-04-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1588
Valid CSS Valid XHTML 1.0 Strict