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: 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: extern int sigs;
  44: 
  45: #if LOGFILE
  46: extern int logfile;
  47: #endif
  48: 
  49: /*
  50:  * Current position in file.
  51:  * Stored as a block number and an offset into the block.
  52:  */
  53: static long ch_block;
  54: static int ch_offset;
  55: 
  56: /*
  57:  * Length of file, needed if input is a pipe.
  58:  */
  59: static POSITION ch_fsize;
  60: 
  61: /*
  62:  * Largest block number read if input is standard input (a pipe).
  63:  */
  64: static long last_piped_block;
  65: 
  66: /*
  67:  * Get the character pointed to by the read pointer.
  68:  * ch_get() is a macro which is more efficient to call
  69:  * than fch_get (the function), in the usual case
  70:  * that the block desired is at the head of the chain.
  71:  */
  72: #define ch_get()   ((buf_head->block == ch_block) ? \
  73:             buf_head->data[ch_offset] : fch_get())
  74:     static int
  75: fch_get()
  76: {
  77:     register struct buf *bp;
  78:     register int n;
  79:     register int end;
  80:     POSITION pos;
  81: 
  82:     /*
  83: 	 * Look for a buffer holding the desired block.
  84: 	 */
  85:     for (bp = buf_head;  bp != END_OF_CHAIN;  bp = bp->next)
  86:         if (bp->block == ch_block)
  87:             goto found;
  88:     /*
  89: 	 * Block is not in a buffer.
  90: 	 * Take the least recently used buffer
  91: 	 * and read the desired block into it.
  92: 	 */
  93:     bp = buf_tail;
  94:     bp->block = ch_block;
  95:     pos = ch_block * BUFSIZ;
  96:     if (ispipe)
  97:     {
  98:         /*
  99: 		 * The block requested should be one more than
 100: 		 * the last block read.
 101: 		 */
 102:         if (ch_block != ++last_piped_block)
 103:         {
 104:             /* This "should not happen". */
 105:             char message[80];
 106:             sprintf(message, "Pipe error: last %ld, want %ld\n",
 107:                 (long)last_piped_block-1, (long)ch_block);
 108:             error(message);
 109:             quit();
 110:         }
 111:     } else
 112:         lseek(file, pos, 0);
 113: 
 114:     /*
 115: 	 * Read the block.  This may take several reads if the input
 116: 	 * is coming from standard input, due to the nature of pipes.
 117: 	 */
 118:     end = 0;
 119:     while ((n = read(file, &bp->data[end], BUFSIZ-end)) > 0)
 120:         if ((end += n) >= BUFSIZ)
 121:             break;
 122: 
 123:     if (n < 0)
 124:     {
 125:         error("read error");
 126:         quit();
 127:     }
 128: 
 129: #if LOGFILE
 130:     /*
 131: 	 * If we have a log file, write this block to it.
 132: 	 */
 133:     if (logfile >= 0 && end > 0)
 134:         write(logfile, bp->data, end);
 135: #endif
 136: 
 137:     /*
 138: 	 * Set an EOF marker in the buffered data itself.
 139: 	 * Then ensure the data is "clean": there are no
 140: 	 * extra EOF chars in the data and that the "meta"
 141: 	 * bit (the 0200 bit) is reset in each char.
 142: 	 */
 143:     if (end < BUFSIZ)
 144:     {
 145:         ch_fsize = pos + end;
 146:         bp->data[end] = EOF;
 147:     }
 148: 
 149:     if (!clean_data)
 150:         while (--end >= 0)
 151:         {
 152:             bp->data[end] &= 0177;
 153:             if (bp->data[end] == EOF)
 154:                 bp->data[end] = '@';
 155:         }
 156: 
 157:     found:
 158:     /* if (buf_head != bp) {this is guaranteed by the ch_get macro} */
 159:     {
 160:         /*
 161: 		 * Move the buffer to the head of the buffer chain.
 162: 		 * This orders the buffer chain, most- to least-recently used.
 163: 		 */
 164:         bp->next->prev = bp->prev;
 165:         bp->prev->next = bp->next;
 166: 
 167:         bp->next = buf_head;
 168:         bp->prev = END_OF_CHAIN;
 169:         buf_head->prev = bp;
 170:         buf_head = bp;
 171:     }
 172:     return (bp->data[ch_offset]);
 173: }
 174: 
 175: #if LOGFILE
 176: /*
 177:  * Close the logfile.
 178:  * If we haven't read all of standard input into it, do that now.
 179:  */
 180:     public void
 181: end_logfile()
 182: {
 183:     static int tried;
 184: 
 185:     if (logfile < 0)
 186:         return;
 187:     if (!tried && ch_fsize == NULL_POSITION)
 188:     {
 189:         tried = 1;
 190:         lower_left();
 191:         clear_eol();
 192:         so_enter();
 193:         puts("finishing logfile... (interrupt to abort)");
 194:         so_exit();
 195:         flush();
 196:         while (sigs == 0 && ch_forw_get() != EOF)
 197:             ;
 198:     }
 199:     close(logfile);
 200:     logfile = -1;
 201: }
 202: #endif
 203: 
 204: /*
 205:  * Determine if a specific block is currently in one of the buffers.
 206:  */
 207:     static int
 208: buffered(block)
 209:     long block;
 210: {
 211:     register struct buf *bp;
 212: 
 213:     for (bp = buf_head;  bp != END_OF_CHAIN;  bp = bp->next)
 214:         if (bp->block == block)
 215:             return (1);
 216:     return (0);
 217: }
 218: 
 219: /*
 220:  * Seek to a specified position in the file.
 221:  * Return 0 if successful, non-zero if can't seek there.
 222:  */
 223:     public int
 224: ch_seek(pos)
 225:     register POSITION pos;
 226: {
 227:     long new_block;
 228: 
 229:     new_block = pos / BUFSIZ;
 230:     if (!ispipe || new_block == last_piped_block + 1 || buffered(new_block))
 231:     {
 232:         /*
 233: 		 * Set read pointer.
 234: 		 */
 235:         ch_block = new_block;
 236:         ch_offset = pos % BUFSIZ;
 237:         return (0);
 238:     }
 239:     return (1);
 240: }
 241: 
 242: /*
 243:  * Seek to the end of the file.
 244:  */
 245:     public int
 246: ch_end_seek()
 247: {
 248:     if (ispipe)
 249:     {
 250:         /*
 251: 		 * Do it the slow way: read till end of data.
 252: 		 */
 253:         while (ch_forw_get() != EOF)
 254:             ;
 255:     } else
 256:     {
 257:         (void) ch_seek((POSITION)(lseek(file, (off_t)0, 2)));
 258:     }
 259:     return (0);
 260: }
 261: 
 262: /*
 263:  * Seek to the beginning of the file, or as close to it as we can get.
 264:  * We may not be able to seek there if input is a pipe and the
 265:  * beginning of the pipe is no longer buffered.
 266:  */
 267:     public int
 268: ch_beg_seek()
 269: {
 270:     register struct buf *bp, *firstbp;
 271: 
 272:     /*
 273: 	 * Try a plain ch_seek first.
 274: 	 */
 275:     if (ch_seek((POSITION)0) == 0)
 276:         return (0);
 277: 
 278:     /*
 279: 	 * Can't get to position 0.
 280: 	 * Look thru the buffers for the one closest to position 0.
 281: 	 */
 282:     firstbp = bp = buf_head;
 283:     if (bp == END_OF_CHAIN)
 284:         return (1);
 285:     while ((bp = bp->next) != END_OF_CHAIN)
 286:         if (bp->block < firstbp->block)
 287:             firstbp = bp;
 288:     ch_block = firstbp->block;
 289:     ch_offset = 0;
 290:     return (0);
 291: }
 292: 
 293: /*
 294:  * Return the length of the file, if known.
 295:  */
 296:     public POSITION
 297: ch_length()
 298: {
 299:     if (ispipe)
 300:         return (ch_fsize);
 301:     return ((POSITION)(lseek(file, (off_t)0, 2)));
 302: }
 303: 
 304: /*
 305:  * Return the current position in the file.
 306:  */
 307:     public POSITION
 308: ch_tell()
 309: {
 310:     return (ch_block * BUFSIZ + ch_offset);
 311: }
 312: 
 313: /*
 314:  * Get the current char and post-increment the read pointer.
 315:  */
 316:     public int
 317: ch_forw_get()
 318: {
 319:     register int c;
 320: 
 321:     c = ch_get();
 322:     if (c != EOF && ++ch_offset >= BUFSIZ)
 323:     {
 324:         ch_offset = 0;
 325:         ch_block ++;
 326:     }
 327:     return (c);
 328: }
 329: 
 330: /*
 331:  * Pre-decrement the read pointer and get the new current char.
 332:  */
 333:     public int
 334: ch_back_get()
 335: {
 336:     register int c;
 337: 
 338:     if (--ch_offset < 0)
 339:     {
 340:         if (ch_block <= 0 || (ispipe && !buffered(ch_block-1)))
 341:         {
 342:             ch_offset = 0;
 343:             return (EOF);
 344:         }
 345:         ch_offset = BUFSIZ - 1;
 346:         ch_block--;
 347:     }
 348:     c = ch_get();
 349:     return (c);
 350: }
 351: 
 352: /*
 353:  * Initialize the buffer pool to all empty.
 354:  * Caller suggests that we use want_nbufs buffers.
 355:  */
 356:     public void
 357: ch_init(want_nbufs)
 358:     int want_nbufs;
 359: {
 360:     register struct buf *bp;
 361:     char *calloc();
 362: 
 363:     if (nbufs < want_nbufs)
 364:     {
 365:         /*
 366: 		 * We don't have enough buffers.
 367: 		 * Free what we have (if any) and allocate some new ones.
 368: 		 */
 369:         if (bufs != NULL)
 370:             free((char *)bufs);
 371:         bufs = (struct buf *) calloc(want_nbufs, sizeof(struct buf));
 372:         nbufs = want_nbufs;
 373:         if (bufs == NULL)
 374:         {
 375:             /*
 376: 			 * Couldn't get that many.
 377: 			 * Try for a small default number of buffers.
 378: 			 */
 379:             char message[80];
 380:             sprintf(message,
 381:               "Cannot allocate %d buffers.  Using %d buffers.",
 382:               nbufs, DEF_NBUFS);
 383:             error(message);
 384:             bufs = (struct buf *) calloc(DEF_NBUFS, sizeof(struct buf));
 385:             nbufs = DEF_NBUFS;
 386:             if (bufs == NULL)
 387:             {
 388:                 /*
 389: 				 * Couldn't even get the smaller number of bufs.
 390: 				 * Something is wrong here, don't continue.
 391: 				 */
 392:                 sprintf(message,
 393:                 "Cannot even allocate %d buffers!  Quitting.",
 394:                   DEF_NBUFS);
 395:                 error(message);
 396:                 quit();
 397:                 /*NOTREACHED*/
 398:             }
 399:         }
 400:     }
 401: 
 402:     /*
 403: 	 * Initialize the buffers to empty.
 404: 	 * Set up the circular list.
 405: 	 */
 406:     for (bp = &bufs[0];  bp < &bufs[nbufs];  bp++)
 407:     {
 408:         bp->next = bp + 1;
 409:         bp->prev = bp - 1;
 410:         bp->block = (long)(-1);
 411:     }
 412:     bufs[0].prev = bufs[nbufs-1].next = END_OF_CHAIN;
 413:     buf_head = &bufs[0];
 414:     buf_tail = &bufs[nbufs-1];
 415:     last_piped_block = -1;
 416:     ch_fsize = NULL_POSITION;
 417:     (void) ch_seek((POSITION)0);
 418: }

Defined functions

buffered defined in line 207; used 2 times
ch_beg_seek defined in line 267; used 2 times
ch_end_seek defined in line 245; used 2 times
end_logfile defined in line 180; used 3 times
fch_get defined in line 74; used 1 times
  • in line 73

Defined variables

bufs defined in line 20; used 12 times
ch_block defined in line 53; used 13 times
ch_fsize defined in line 59; used 4 times
ch_offset defined in line 54; used 10 times
file defined in line 9; used 10 times
last_piped_block defined in line 64; used 4 times
nbufs defined in line 21; used 8 times
public defined in line 356; never used

Defined struct's

buf defined in line 15; used 22 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 6 times
buf_head defined in line 32; used 9 times
buf_tail defined in line 33; used 2 times
ch_get defined in line 72; used 2 times
Last modified: 1990-07-10
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3244
Valid CSS Valid XHTML 1.0 Strict