# 2.11BSD#431 - /usr/src/local/less/ch.c

##### Functions

    ch_back_get       X
    ch_beg_seek       X
    ch_end_seek       X
    ch_forw_get       X
    ch_init           X
    ch_length         X
    ch_seek           X
    ch_tell           X
    end_logfile       X

##### Variables

    file              X
    nbufs             X
    public            X

##### Macros

    BUFSIZ            X
    DEF_NBUFS         X
    END_OF_CHAIN      X
    buf_head          X
    buf_tail          X
    ch_get            X

##### struct's

    buf               X

       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

- in line 230, 340

ch_back_get defined in line 333; used 9 times

- in /usr/src/local/less/funcs.h line 28
- in /usr/src/local/less/input.c line 76, 108-109(2), 118, 131, 182
- in /usr/src/local/less/line.c line 455
- in /usr/src/local/less/prim.c line 370

ch_beg_seek defined in line 267; used 2 times

- in /usr/src/local/less/funcs.h line 24
- in /usr/src/local/less/prim.c line 317

ch_end_seek defined in line 245; used 2 times

- in /usr/src/local/less/funcs.h line 23
- in /usr/src/local/less/prim.c line 283

ch_forw_get defined in line 316; used 15 times

- in line 196, 253
- in /usr/src/local/less/funcs.h line 27
- in /usr/src/local/less/input.c line 33, 62, 73, 106-107(2), 122, 170
- in /usr/src/local/less/line.c line 403, 427
- in /usr/src/local/less/main.c line 239
- in /usr/src/local/less/prim.c line 328, 373

ch_init defined in line 356; used 4 times

- in /usr/src/local/less/command.c line 423, 566
- in /usr/src/local/less/funcs.h line 29
- in /usr/src/local/less/main.c line 174

ch_length defined in line 296; used 6 times

- in /usr/src/local/less/funcs.h line 25
- in /usr/src/local/less/prim.c line 45, 358
- in /usr/src/local/less/prompt.c line 76-81(2), 101

ch_seek defined in line 223; used 12 times

- in line 257, 275, 417
- in /usr/src/local/less/funcs.h line 22
- in /usr/src/local/less/input.c line 30, 98, 162
- in /usr/src/local/less/line.c line 402, 447
- in /usr/src/local/less/prim.c line 310, 368, 426

ch_tell defined in line 307; used 14 times

- in /usr/src/local/less/funcs.h line 26
- in /usr/src/local/less/input.c line 45, 59, 77, 138, 148
- in /usr/src/local/less/line.c line 412, 423, 462, 481
- in /usr/src/local/less/prim.c line 289, 318, 339, 374

end_logfile defined in line 180; used 3 times

- in /usr/src/local/less/funcs.h line 21
- in /usr/src/local/less/main.c line 102, 361

fch_get defined in line 74; used 1 times

- in line 73

#### Defined variables

bufs defined in line 20; used 12 times

- in line 369-373(4), 384-386(2), 406(2), 412-414(4)

ch_block defined in line 53; used 13 times

- in line 72, 86, 94-95(2), 102-107(2), 235, 288, 310, 325, 340(2), 346

ch_fsize defined in line 59; used 4 times

- in line 145, 187, 300, 416

ch_offset defined in line 54; used 10 times

- in line 73, 172, 236, 289, 310, 322-324(2), 338-345(3)

file defined in line 9; used 10 times

- in line 112, 119, 257, 301
- in /usr/src/local/less/main.c line 166-167(2), 173, 298, 329-332(2)

last_piped_block defined in line 64; used 4 times

- in line 102-107(2), 230, 415

nbufs defined in line 21; used 8 times

- in line 363, 372, 382-385(2), 406, 412-414(2)
- in /usr/src/local/less/option.c line 194

public defined in line 356; never used

#### Defined struct's

buf defined in line 15; used 22 times

- in line 16-20(4), 29(2), 77(2), 211(2), 270(2), 360(2), 371(4), 384(4)

#### Defined macros

BUFSIZ defined in line 14; used 10 times

- in line 18, 95, 119-120(2), 143, 229, 236, 310, 322, 345

DEF_NBUFS defined in line 39; used 4 times

- in line 382-385(3), 394

END_OF_CHAIN defined in line 31; used 6 times

- in line 85, 168, 213, 283-285(2), 412

buf_head defined in line 32; used 9 times

- in line 72-73(2), 85, 167-170(3), 213, 282, 413

buf_tail defined in line 33; used 2 times

- in line 93, 414

ch_get defined in line 72; used 2 times

- in line 321, 348

Last modified: 1990-07-10 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1072 |