# 2.11BSD#431 - /usr/src/new/PORT/apl/src/ay.c

##### Functions

    bflush            X
    check             X
    closef            X
    creatf            X
    dupf              X
    empty             X
    fstatf            X
    initbuf           X
    lseekf            X
    newbuf            X
    openf             X
    openup            X
    readf             X
    realfd            X
    writef            X

##### Macros

    realfd            X

       1: static char Sccsid[] = "ay.c @(#)ay.c	1.1	10/1/82 Berkeley ";
       2: #
       3:
       4: /*
       5:  *      APL Buffered I/O routines
       6:  *
       7:  *
       8:  * The following routines perform all of the I/O required by APL.
       9:  * They are designed to maximize buffer utilization while maintaining
      10:  * reliable operation.  For a machine such as the PDP-11, the number
      11:  * of buffers, defined in apl.h, should be around 4 for best results.
      12:  * For a machine such as the VAX 11/780, a larger number may be desirable
      13:  * for better results.
      14:  *
      15:  */
      16:
      17: #include "apl.h"                /* Header definitions */
      18: #ifdef NBUF                     /* Don't do any of this unless buffering
      19: 				 * was requested by defining NBUF
      20: 				 */
      21:
      22: #define realfd(x)   files[x].fd_dup
      23:
      24: openf(fname, mode)
      25: char *fname;
      26: {
      27:
      28:     int fd;
      29:
      30:
      31:     /* The first order of business is to open the
      32: 	 * file.  If this fails, return -1.
      33: 	 */
      34:
      35:     if ((fd=open(fname,mode)) < 0) return(fd);
      36:
      37:
      38:     /* Now, perform all of the work necessary for setting
      39: 	 * up the file tables.  This code is shared by "openf"
      40: 	 * and "creatf" since both open files.
      41: 	 */
      42:
      43:     openup(fd);
      44:     return(fd);
      45: }
      46:
      47: creatf(fname, mode)
      48: char *fname;
      49: {
      50:
      51:     int fd;
      52:
      53:
      54:     /* The first order of business is to create the
      55: 	 * file.  If this fails, return -1.
      56: 	 */
      57:
      58:     if ((fd=creat(fname,mode)) < 0) return(fd);
      59:
      60:
      61:     /* Now, perform all of the work necessary for setting
      62: 	 * up the file tables.  This code is shared by "openf"
      63: 	 * and "creatf" since both open files.
      64: 	 */
      65:
      66:     openup(fd);
      67:     return(fd);
      68: }
      69:
      70: openup(fd)
      71: {
      72:     struct stat stat_buf;
      73:     register struct fds *p, *q;
      74:     register j;
      75:
      76:
      77:     /* Try to perform an "fstat" call on the file.  This
      78: 	 * information is required for all file descriptors
      79: 	 * to prevent reading from a file while data destined
      80: 	 * for that file is still buffered for output.  If for
      81: 	 * some reason the "fstat" fails, arbitrarily set
      82: 	 * the major/minor number and inode number to zero.
      83: 	 */
      84:
      85:     if (fstat(fd, &stat_buf) < 0){
      86:         write(2, "Can't \"stat\" new fd\n", 20);
      87:         stat_buf.st_dev = 0;
      88:         stat_buf.st_ino = 0;
      89:     }
      90:
      91:
      92:     /* Copy the information into the "files" structure, which
      93: 	 * maintains such data on all open files.
      94: 	 */
      95:
      96:     p = &files[fd];
      97:     p->fd_dev = stat_buf.st_dev;    /* Major/minor device numbers */
      98:     p->fd_ind = stat_buf.st_ino;    /* Inode number */
      99:     p->fd_open = 1;                 /* File is open */
     100:     p->fd_buf = -1;                 /* No buffer is currently assigned */
     101:     p->fd_dup = fd;                 /* All it duplicates is itself */
     102:     p->fd_lastop = 0;               /* Lastop was read (default) */
     103:     p->fd_pipe = !!lseek(fd, 0L, 1);    /* Seek will fail if a pipe */
     104:
     105:
     106:     /* Determine if the new fd is unique or not.  If not,
     107: 	 * make sure any matching fd's know that they no longer
     108: 	 * are either.
     109: 	 */
     110:
     111:     p->fd_uniq = 1;                 /* Assume uniqueness */
     112:     for(j=0; j<NFDS; j++){
     113:         if (!files[j].fd_open) continue;        /* File not open */
     114:
     115:         q = &files[realfd(j)];
     116:         if (p->fd_ind == q->fd_ind && p->fd_dev == q->fd_dev)
     117:             p->fd_uniq = q->fd_uniq = 0;
     118:     }
     119:     check();                                        /*DEBUG*/
     120: }
     121:
     122: dupf(fd)
     123: {
     124:
     125:     int fd2;
     126:     register struct fds *p, *q;
     127:
     128:
     129:     /* Duplicating a file descriptor does not require an "fstat"
     130: 	 * on the new file descriptor, because its device and inode
     131: 	 * are already recorded.  However, duplicate file descriptors
     132: 	 * complicate I/O because they MUST be linked to the same
     133: 	 * buffer.
     134: 	 */
     135:
     136:     if ((fd2=dup(fd)) < 0) return(fd2);     /* Get new fd */
     137:
     138:     /* Copy all of the information into the "files" for the new
     139: 	 * file descriptor.  The uniqueness of the original fd is copied
     140: 	 * to the new fd -- they both represent the same thing.
     141: 	 */
     142:
     143:     p = &files[fd];                 /* Point to appropriate places */
     144:     q = &files[fd2];
     145:
     146:     q->fd_dev = p->fd_dev;          /* Major/minor device number */
     147:     q->fd_ind = p->fd_ind;          /* Inode number */
     148:     q->fd_buf = -1;                 /* Buffer is assigned to princ. fd */
     149:     q->fd_uniq = p->fd_uniq;        /* Uniqueness of dev/inode */
     150:     q->fd_dup = p->fd_dup;          /* Point new entry to old one */
     151:     q->fd_open = 1;                 /* File is now open */
     152:     q->fd_lastop = p->fd_lastop;    /* Last operation is the same */
     153:
     154:     return(fd2);                    /* Return new fd */
     155: }
     156:
     157: closef(fd)
     158: {
     159:
     160:     register j;
     161:     register struct fds *p, *q;
     162:     int fd2, count;
     163:
     164:     /* Closing a file is easier than opening it, but some precautions
     165: 	 * are necessary.  For instance, if a "dup" was performed to
     166: 	 * obtain some new file descriptor and the original file is
     167: 	 * now being closed, the duplicated file must retain all
     168: 	 * pertinent information.  Thus, the first order of business
     169: 	 * is to scan the list of file descriptors for duplicates.
     170: 	 */
     171:
     172:     p = &files[fd];                 /* Entry for dying fd */
     173:
     174:     count = 0;                      /* Number of remaining dups */
     175:     fd2 = -1;                       /* New fd reference for dups */
     176:
     177:     if (p->fd_dup == fd) for (j=0; j<NFDS; j++){
     178:         if (j == fd) continue;          /* Don't look at fd */
     179:         q = &files[j];
     180:         if (!q->fd_open) continue;      /* Not open */
     181:         if (q->fd_dup != fd) continue;
     182:         if (fd2 == -1){
     183:             fd2 = j;                /* New reference */
     184:             q->fd_buf = p->fd_buf;  /* Vital data */
     185:             q->fd_open = 1;
     186:             q->fd_lastop = p->fd_lastop;
     187:         }
     188:         q->fd_dup = fd2;
     189:         count++;
     190:     }
     191:
     192:
     193:     /* Flush and release the buffer associated with this fd. */
     194:
     195:     newbuf(files[realfd(fd)].fd_buf, -1);
     196:
     197:
     198:     /* Mark the entry in the file descriptor table as "closed"
     199: 	 * and check the uniqueness of any remaining fd's pointing to
     200: 	 * the same area.  Be sure the buffer is released.
     201: 	 */
     202:
     203:     p->fd_open = 0;
     204:     p->fd_dup = fd;
     205:     p->fd_buf = -1;
     206:
     207:     for(j=0; j<NFDS; j++){
     208:         if (j == fd) continue;          /* Skip the same fd */
     209:         q = &files[fd];
     210:         if (!q->fd_open) continue;      /* Skip closed files */
     211:         if (p->fd_dev == q->fd_dev && p->fd_ind == q->fd_ind) break;
     212:     }
     213:
     214:     if (j<NFDS) q->fd_uniq = 1;             /* Assume new fd is unique */
     215:     while(++j < NFDS){                      /* Now check to be sure */
     216:         p = &files[j];
     217:         if (p->fd_dev == q->fd_dev && p->fd_ind == q->fd_ind)
     218:             p->fd_uniq = q->fd_uniq = 0;
     219:     }
     220:
     221:
     222:     /* Actually perform the close of the fd, and return the status
     223: 	 * of that system call.
     224: 	 */
     225:
     226:     return(close(fd));
     227: }
     228:
     229:
     230: initbuf()
     231: {
     232:
     233:     /* Initialize buffer structure, then use "openup" to set up
     234: 	 * file descriptors 0, and 1, which should already be
     235: 	 * open from parent process.  If 0 and 1 have the same inode
     236: 	 * and major/minor number they will be considered to be
     237: 	 * duplicates.  Fils descriptor 2 will be closed and set to
     238: 	 * duplicate file descriptor 1.
     239: 	 */
     240:
     241:     register j;
     242:     register struct fds *p, *q;
     243:
     244:
     245:     /* Initialize file descriptor table */
     246:
     247:     for(j=0; j<NFDS; j++){
     248:         files[j].fd_open = 0;           /* Closed */
     249:         files[j].fd_dup = j;            /* Dup = fd */
     250:         files[j].fd_buf = -1;           /* No buffer */
     251:         files[j].fd_pipe = 0;           /* Not pipe */
     252:     }
     253:
     254:
     255:     /* Initialize buffer table */
     256:
     257:     for(j=0; j<NBUF; j++) iobuf[j].b_fd = -1;       /* Available */
     258:
     259:
     260:     /* "Open" devices 0, and 1 */
     261:
     262:     openup(0);
     263:     openup(1);
     264:     p = &files[0];
     265:     q = &files[1];
     266:     if (p->fd_ind == q->fd_ind && p->fd_dev == q->fd_dev){
     267:         q->fd_dup = 0;
     268:         p->fd_uniq = q->fd_uniq = 1;
     269:     }
     270:
     271:
     272:     /* File descriptor 2 duplicates fd 1 */
     273:
     274:     close(2);
     275:     dupf(1);
     276: }
     277:
     278: newbuf(bufnum, fd)
     279: {
     280:
     281:     register struct iobuf *bp;
     282:     register struct fds *fp;
     283:     register j;
     284:     static int bufcnt = 0;
     285:
     286:
     287:     /* The two arguments for this routine specify a buffer to
     288: 	 * be operated upon and a file descriptor.  There are three
     289: 	 * legal cases:
     290: 	 *
     291: 	 * bufnum < 0,  fd >= 0 -- assign new buffer to file descriptor fd
     292: 	 * bufnum >= 0, fd >= 0 -- assign buffer "bufnum" to fd
     293: 	 * bufnum >= 0, fd < 0  -- de-assign buffer "bufnum"
     294: 	 */
     295:
     296:     if ((bufnum < 0 && fd < 0) || bufnum >= NBUF || fd >= NFDS)
     297:         return(-1);                             /* Invalid args */
     298:
     299:     fd = (fd < 0) ? fd : realfd(fd);                /* Handle dups */
     300:
     301:
     302:     /* Step one -- if a buffer was specified, flush it.  If the
     303: 	 * last operation was a write, then write out the rest of
     304: 	 * the buffer.  If the last operation was a read, then perform
     305: 	 * a seek backwards on the corresponding fd to reposition the
     306: 	 * next read.
     307: 	 */
     308:
     309:     if (bufnum >= 0){
     310:         bp = &iobuf[bufnum];
     311:         if (bp->b_len && (bp->b_fd >= 0))
     312:             if (files[bp->b_fd].fd_lastop)
     313:                 write(bp->b_fd, bp->b_buf, bp->b_len);
     314:             else
     315:                 lseek(bp->b_fd, (long)-bp->b_len, 1);
     316:
     317:         bp->b_len = 0;                  /* Reset length */
     318:         bp->b_next = 0;                 /* Reset next position */
     319:
     320:
     321:         /* Step one point five -- if a file descriptor was
     322: 		 * specified, check to insure that it is open.  Then,
     323: 		 * reassign the buffer to that fd.
     324: 		 */
     325:
     326:         if(bp->b_fd >= 0)               /* Drop old assignment */
     327:             files[bp->b_fd].fd_buf = -1;
     328:
     329:         bp->b_fd = fd;                  /* Give buffer new fd */
     330:         if (fd < 0) return(0);          /* If fd < 0, done */
     331:
     332:         fp = &files[fd];                /* Point to new structure */
     333:
     334:         if (!fp->fd_open){              /* New file is not open */
     335:             bp->b_fd = -1;          /* Drop assignment */
     336:             return(-1);
     337:         }
     338:
     339:         fp->fd_buf = bufnum;            /* New assignment */
     340:         return(0);
     341:
     342:     }
     343:
     344:
     345:     /* Step two -- if no buffer was specified, but a file descriptor
     346: 	 * was, then some existing buffer must be allocated to that fd.
     347: 	 */
     348:
     349:     fp = &files[fd];
     350:
     351:
     352:     /* First, check to see if a buffer is already assigned */
     353:
     354:     for (j=0; j<NBUF; j++)
     355:         if (iobuf[j].b_fd == fd){
     356:             bufcnt = j;
     357:             goto recursive;
     358:         }
     359:
     360:
     361:     /* Next, scan the table of buffers looking for one
     362: 	 * which is not assigned.
     363: 	 */
     364:
     365:     for (j=0; j<NBUF; j++) if (iobuf[j].b_fd < 0){
     366:         bufcnt = j;
     367:         goto recursive;
     368:     }
     369:
     370:
     371:     /* If no vacant buffer was found, then a buffer must
     372: 	 * be allocated arbitrarily.  The static local variable
     373: 	 * "bufcnt" is used for this purpose.  It contains the
     374: 	 * number of the last assigned buffer.  Buffers are
     375: 	 * switched in a sort-of "round robin" approach.
     376: 	 */
     377:
     378:     j = bufcnt;
     379:     do {
     380:         bp = &iobuf[j];
     381:         fp = &files[bp->b_fd];
     382:         if (fp->fd_pipe && (!fp->fd_lastop) && bp->b_len > 0)
     383:             continue;
     384:         bufcnt = j;
     385:         goto recursive;
     386:     } while((j = (j+1)%NBUF) != bufcnt);
     387:     return(-1);
     388:
     389:
     390:     /* Now, with a recursive call to this routine,
     391: 	 * switch to the new buffer.
     392: 	 */
     393:
     394: recursive: return(newbuf(bufcnt, fd));
     395:
     396: }
     397:
     398: #ifndef realfd
     399: realfd(fd)
     400: {
     401:
     402:     register struct fds *fp;
     403:
     404:
     405:     /* Process duplicate file descriptors.  If the main fd is
     406: 	 * nonnegative, use the value of the dup number for the true fd.
     407: 	 * No change is made if the file is closed.
     408: 	 */
     409:
     410:     fp = &files[fd];
     411:     if (!fp->fd_open) return(fd);
     412:     return(fp->fd_dup < 0 ? fd : fp->fd_dup);
     413: }
     414: #endif
     415:
     416:
     417: readf(fd, buffer, length)
     418: char *buffer;
     419: {
     420:
     421:     register struct fds *fp;
     422:     register struct iobuf *bp;
     423:     register j;
     424:     int change, trlog, again;
     425:
     426:
     427:     /* Handle duplicate files first.  If this file descriptor is
     428: 	 * a duplicate of another one, then the other's buffer and
     429: 	 * other information must be used.
     430: 	 */
     431:
     432:     fd = realfd(fd);
     433:
     434:
     435:     /* If a read is to be performed on a file, all output to that
     436: 	 * file must first be flushed.  If the file descriptor's last
     437: 	 * function was output, use "newbuf" to flush the output,
     438: 	 * retaining the buffer, and then set the mode to input.  This
     439: 	 * must be done for all entries in "files" which have the same
     440: 	 * major/minor number as the current file.
     441: 	 */
     442:
     443:
     444:
     445:     fp = &files[fd];
     446:     if (!fp->fd_open) return(-1);           /* File not open */
     447:     if (fp->fd_uniq){
     448:         if (fp->fd_lastop && fp->fd_buf >= 0)
     449:             newbuf(fp->fd_buf, fd);
     450:     } else for(j=0; j<NFDS; j++){
     451:         fp = &files[realfd(j)];
     452:         if (fp->fd_dev == files[fd].fd_dev
     453:             && fp->fd_ind == files[fd].fd_ind
     454:             && fp->fd_open
     455:             && fp->fd_lastop
     456:             && fp->fd_buf >= 0){
     457:                 newbuf(fp->fd_buf, j);
     458:         }
     459:     }
     460:
     461:
     462:     /* The above code nicely took care of any buffer associated
     463: 	 * with the current fd.  Now, set the last operation on this fd
     464: 	 * to read, and if no buffer is currently assigned, get one.
     465: 	 */
     466:
     467:     fp = &files[fd];
     468:     fp->fd_lastop = 0;
     469:
     470:     if (fp->fd_buf < 0)
     471:         if (newbuf(-1, fd) < 0) return(read(fd, buffer, length));
     472:
     473:
     474:     /* The flag "again" determines whether or not the read buffer
     475: 	 * should be refilled when the end of it is reached.  Basically,
     476: 	 * "again" is set to 0 when a read of less than one buffer length
     477: 	 * occurs.  This way, terminal reads can stop at the carriage
     478: 	 * return, but disc reads can still buffer in BLEN-byte chunks
     479: 	 */
     480:
     481:     again = 1;
     482:
     483:
     484:     /* The variable "trlog" keeps track of how many bytes have been
     485: 	 * transferred into the buffer supplied by the routine which
     486: 	 * called "readf".  Initially, this number is -1 (EOF).
     487: 	 */
     488:
     489:     trlog = -1;
     490:
     491:
     492:     /* The main loop is rather simple -- the buffer is continually
     493: 	 * emptied and refilled until all of the requested data has been
     494: 	 * transferred.
     495: 	 */
     496:
     497:     bp = &iobuf[fp->fd_buf];
     498:     while(1){
     499:         if (length <= 0) return(trlog);
     500:         if (bp->b_len == 0 && again){
     501:             again = (bp->b_len=read(fd,bp->b_buf,BLEN)) == BLEN;
     502:             bp->b_next = 0;
     503:         }
     504:         if (bp->b_len <= 0) return(trlog);
     505:         if (trlog < 0) trlog++;
     506:         change = (bp->b_len < length) ? bp->b_len : length;
     507:         for (j=0; j<change; j++)
     508:             buffer[trlog+j] = bp->b_buf[bp->b_next+j];
     509:         trlog += change;
     510:         bp->b_len -= change;
     511:         bp->b_next += change;
     512:         length -= change;
     513:     }
     514: }
     515:
     516:
     517: writef(fd, buffer, length)
     518: char *buffer;
     519: {
     520:
     521:     register struct fds *fp;
     522:     register struct iobuf *bp;
     523:     register j;
     524:     int change, trlog, again;
     525:
     526:
     527:     /* Handle duplicate files first.  If this file descriptor is
     528: 	 * a duplicate of another one, then the other's buffer and
     529: 	 * other information must be used.
     530: 	 */
     531:
     532:     fd = realfd(fd);
     533:
     534:
     535:     /* If a write is to be performed on a file, all input from that
     536: 	 * file must first be flushed.  If the file descriptor's last
     537: 	 * function was input, use "newbuf" to flush the input,
     538: 	 * retaining the buffer, and then set the mode to output.  This
     539: 	 * must be done for all entries in "files" which have the same
     540: 	 * major/minor number as the current file.
     541: 	 */
     542:
     543:     fp = &files[fd];
     544:     if (!fp->fd_open) return(-1);            /* File not open */
     545:     if (fp->fd_uniq){
     546:         if ((!fp->fd_lastop) && fp->fd_buf >= 0)
     547:             newbuf(fp->fd_buf, fd);
     548:
     549:     } else for(j=0; j<NFDS; j++){
     550:         fp = &files[realfd(j)];
     551:         if (fp->fd_dev == files[fd].fd_dev
     552:             && fp->fd_ind == files[fd].fd_ind
     553:             && fp->fd_open
     554:             && (!fp->fd_lastop)
     555:             && fp->fd_buf >= 0){
     556:                 newbuf(fp->fd_buf, j);
     557:         }
     558:     }
     559:
     560:
     561:     /* The above code nicely took care of any buffer associated
     562: 	 * with the current fd.  Now, set the last operation on this fd
     563: 	 * to write, and if no buffer is currently assigned, get one.
     564: 	 */
     565:
     566:     fp = &files[fd];
     567:     fp->fd_lastop = 1;
     568:
     569:     if (fp->fd_buf < 0)
     570:         if (newbuf(-1, fd) < 0) return(write(fd,buffer,length));
     571:
     572:
     573:     /* The main loop of output, like the main loop for input, is
     574: 	 * rather simple.  In fact, output is easier.  It is only
     575: 	 * necessary to check when the buffer is full and to flush it
     576: 	 * as necessary to the file.
     577: 	 */
     578:
     579:     bp = &iobuf[fp->fd_buf];
     580:     trlog = 0;
     581:     while(1){
     582:         if (!length) return(trlog);
     583:         if (bp->b_len >= BLEN){
     584:             write(fd, bp->b_buf, bp->b_len);
     585:             bp->b_next = bp->b_len = 0;
     586:         }
     587:
     588:         change = ((BLEN - bp->b_len) < length) ?
     589:             (BLEN - bp->b_len) : length;
     590:
     591:         for (j=0; j<change; j++)
     592:             bp->b_buf[j+bp->b_next] = buffer[j+trlog];
     593:
     594:         trlog += change;
     595:         bp->b_next = bp->b_len += change;
     596:         length -= change;
     597:     }
     598: }
     599:
     600: long lseekf(fd, p1, p2)
     601: int fd, p2;
     602: long p1;
     603: {
     604:
     605:     register struct fds *fp;
     606:     register j;
     607:     long lseek();
     608:
     609:
     610:     /* A seek on a file requires a flush of the buffer for that
     611: 	 * file and for any other file descriptors which are pointing
     612: 	 * to the same file.
     613: 	 */
     614:
     615:     fd = realfd(fd);                /* Take care of dups */
     616:     fp = &files[fd];
     617:
     618:     if (!fp->fd_open) return(-1);   /* not open */
     619:
     620:     if (fp->fd_uniq){
     621:         if (fp->fd_buf >= 0) newbuf(fp->fd_buf, fd);
     622:     } else for(j=0; j<NFDS; j++){
     623:         fp = &files[j];
     624:         if (fp->fd_dev == files[fd].fd_dev
     625:             && fp->fd_ind == files[fd].fd_ind
     626:             && fp->fd_open
     627:             && fp->fd_buf >= 0)
     628:                 newbuf(fp->fd_buf, j);
     629:     }
     630:
     631:
     632:     /* Now that all of the preliminaries are over, the actual
     633: 	 * seek can be performed.
     634: 	 */
     635:
     636:     return(lseek(fd, p1, p2));
     637: }
     638:
     639: fstatf(fd, stat_buf)
     640: struct stat *stat_buf;
     641: {
     642:
     643:     register fd2;
     644:
     645:     fd2 = realfd(fd);
     646:     newbuf(files[fd2].fd_buf, fd2);
     647:     return(fstat(fd, stat_buf));
     648:
     649: }
     650:
     651: bflush(){
     652:
     653:     register j;
     654:
     655:     /* Flush all buffers */
     656:
     657:     for(j=0; j<NBUF; j++) newbuf(j, -1);
     658: }
     659:
     660: check()
     661: {
     662:     register j, k;
     663:
     664:     for (j=0; j<NFDS; j++)
     665:         if ((k=files[j].fd_buf) >= 0)
     666:             if (iobuf[k].b_fd != j){
     667:                 write(2, "CONSISTENCY CHECK!\n", 19);
     668:                 if (files[j].fd_dup != j)
     669:                     write(2, "BAD DUP ENTRY\n", 14);
     670:             }
     671:
     672:
     673:     for (j=0; j<NBUF; j++)
     674:         if ((k=iobuf[j].b_fd) >= 0)
     675:             if (files[k].fd_buf != j)
     676:                 write(2, "CONSISTENCY CHECK2!\n", 20);
     677:
     678: }
     679:
     680: #endif
     681:
     682: empty(fd){
     683:
     684:     struct stat sbuf;
     685:     register struct fds *fp;
     686:
     687:     /* Simulate the Rand Corp.'s "empty" system call on a
     688: 	 * V7 system by seeing if the given fd is a pipe, and if
     689: 	 * so, whether or not it is empty.
     690: 	 */
     691:
     692: #ifdef NBUF
     693:     fp = &files[realfd(fd)];
     694:
     695:     if (!fp->fd_pipe || !fp->fd_open)
     696:         return(-1);     /* Not a pipe */
     697:
     698:     if (fp->fd_buf >= 0 && iobuf[fp->fd_buf].b_len > 0)
     699:         return(0);      /* Data pending in buffer */
     700: #endif
     701:
     702:     if (fstat(fd, &sbuf) < 0)
     703:         return(-1);     /* Can't "stat" it */
     704:
     705:     return(sbuf.st_size == 0);
     706: }

#### Defined functions

bflush defined in line 651; used 2 times

- in /usr/src/new/PORT/apl/src/apl.h line 549-551(2)

check defined in line 660; used 1 times

- in line 119

closef defined in line 157; never used
creatf defined in line 47; never used
dupf defined in line 122; used 1 times

- in line 275

empty defined in line 682; used 1 times

- in /usr/src/new/PORT/apl/src/a9.c line 53

fstatf defined in line 639; never used
initbuf defined in line 230; used 1 times

- in /usr/src/new/PORT/apl/src/a0.c line 25

lseekf defined in line 600; never used
newbuf defined in line 278; used 16 times

- in line 195, 394, 449, 457, 471, 547, 556, 570, 621, 628, 646, 657
- in /usr/src/new/PORT/apl/src/a2.c line 470
- in /usr/src/new/PORT/apl/src/a9.c line 68
- in /usr/src/new/PORT/apl/src/az.c line 116, 260

openf defined in line 24; never used
openup defined in line 70; used 6 times

- in line 43, 66, 262-263(2)
- in /usr/src/new/PORT/apl/src/az.c line 170-171(2)

readf defined in line 417; never used
realfd defined in line 399; never used
writef defined in line 517; never used

#### Defined variables

Sccsid defined in line 1; never used

#### Defined macros

realfd defined in line 22; used 11 times

- in line 115, 195, 299, 398, 432, 451, 532, 550, 615, 645, 693

Last modified: 1983-06-22 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1593 |