home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / pc / files / amiga / rhinosrc.lha / stdio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-19  |  21.9 KB  |  1,162 lines

  1. /* Standard I/O routines with socket support
  2.  * Replaces those in Borland C++ library
  3.  * Copyright 1992 Phil Karn, KA9Q
  4.  */
  5. #include <string.h>
  6. #include <stdarg.h>
  7. #ifdef MSDOS
  8. #include <mem.h>
  9. #include <io.h>
  10. #endif
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13. #include <errno.h>
  14. #include "global.h"
  15. #include "stdio.h"
  16. #include "mbuf.h"
  17. #include "proc.h"
  18. #include "usock.h"
  19. #include "socket.h"
  20. #include "display.h"
  21. #include "hardware.h"
  22.  
  23. #ifndef _CREAT
  24. #define _CREAT(a,b)     _creat((a),(b))
  25. #define _OPEN(a,b)      _open((a),(b))
  26. #define _CLOSE(a)       _close((a))
  27. #define _READ(a,b,c)    _read((a),(b),(c))
  28. #define _WRITE(a,b,c)   _write((a),(b),(c))
  29. #define _LSEEK(a,b,c)   _lseek((a),(b),(c))
  30. #define _DUP(a)         dup((a))
  31. #endif
  32.  
  33. long _lseek __ARGS((int fd,long offset,int whence));
  34.  
  35. static void _fclose __ARGS((FILE *fp));
  36. static struct mbuf *_fillbuf __ARGS((FILE *fp,int cnt));
  37. static FILE *_fcreat __ARGS((void));
  38. int breakpipe __ARGS((FILE *p));
  39. int dofiles(int argc, char *argv[], void *p);
  40.  
  41. FILE *_Files;
  42. extern unsigned *Refcnt;
  43.  
  44. /* Open a file and associate it with a (possibly specified) stream */
  45. FILE *
  46. freopen(filename,mode,fp)
  47. char *filename;
  48. char *mode;
  49. FILE *fp;
  50. {
  51.     int modef;
  52.     int textmode = 0;
  53.     int create = 0;
  54.     int append = 0;
  55.     int fd;
  56.     struct stat statbuf;
  57.  
  58.     if(strchr(mode,'r') != NULLCHAR){
  59.         modef = O_RDONLY;
  60.     } else if(strchr(mode,'w') != NULLCHAR){
  61.         create = 1;
  62.         modef = O_WRONLY;
  63.     } else if(strchr(mode,'a') != NULLCHAR){
  64.         modef = O_WRONLY;
  65.         append = 1;
  66.         if(stat(filename,&statbuf) == -1 && errno == ENOENT)
  67.             create = 1;    /* Doesn't exist, so create */
  68.     } else
  69.         return NULLFILE;    /* No recognizable mode! */
  70.  
  71.     if(strchr(mode,'+') != NULLCHAR)
  72.         modef = O_RDWR; /* Update implies R/W */
  73.  
  74.     if(strchr(mode,'t') != NULLCHAR)
  75.         textmode = 1;
  76.  
  77.     if(create)
  78.         fd = _CREAT(filename,S_IREAD|S_IWRITE);
  79.     else
  80.         fd = _OPEN(filename,modef);
  81.     if(fd == -1)
  82.         return NULLFILE;
  83.  
  84.     if(fp != NULLFILE){
  85.         _fclose(fp);
  86.     } else {
  87.         if((fp = _fcreat()) == NULLFILE){
  88.             _CLOSE(fd);
  89.             if(create)
  90.                 remove(filename);
  91.             return NULLFILE;
  92.         }
  93.     }
  94.     fp->fd = fd;
  95.     fp->offset = 0;
  96.     fp->type = _FL_FILE;
  97.     fp->bufmode = _IOFBF;
  98.     fp->ptr = strdup(filename);
  99.     if(textmode)
  100.         fp->flags |= _FL_ASCII;
  101.     if(append)
  102.         fp->flags |= _FL_APPEND;
  103.     fp->bufsize = BUFSIZ;
  104.     seteol(fp,Eol);
  105.     return fp;
  106. }
  107. /* Associate a file or socket descripter (small integer) with a stream */
  108. FILE *
  109. fdopen(handle,mode)
  110. int handle;
  111. char *mode;
  112. {
  113.     FILE *fp;
  114.     int textmode = 0;
  115.     int append = 0;
  116.  
  117.     if(handle == -1)
  118.         return NULLFILE;
  119.  
  120.     if(strchr(mode,'a') != NULLCHAR)
  121.         append = 1;
  122.  
  123.     if(strchr(mode,'t') != NULLCHAR)
  124.         textmode = 1;
  125.  
  126.     if((fp = _fcreat()) == NULLFILE)
  127.         return NULLFILE;
  128.  
  129.     fp->fd = handle;
  130.     fp->bufmode = _IOFBF;
  131.     if(handle >= Nfiles)
  132.         fp->type = _FL_SOCK;
  133.     else
  134.         fp->type = _FL_FILE;
  135.     if(textmode)
  136.         fp->flags |= _FL_ASCII;
  137.     if(append)
  138.         fp->flags |= _FL_APPEND;
  139.  
  140.     fp->bufsize = BUFSIZ;
  141.     /* set default eol sequence, can be overridden by user */
  142.     switch(fp->type){
  143.     case _FL_SOCK:
  144.         seteol(fp,eolseq(handle));      /* Socket eol seq */
  145.         break;
  146.     case _FL_FILE:
  147.         seteol(fp,Eol); /* System end-of-line sequence */
  148.         break;
  149.     }
  150.     fp->refcnt = 1;
  151.  
  152.     return fp;
  153. }
  154. /* Create a stream in pipe mode (whatever is written can be
  155.  * read back). These always work in binary mode.
  156.  */
  157. FILE *
  158. pipeopen()
  159. {
  160.     FILE *fp;
  161.  
  162.     if((fp = _fcreat()) == NULLFILE)
  163.         return NULLFILE;
  164.  
  165.     fp->fd = -1;
  166.     fp->type = _FL_PIPE;
  167.     fp->bufmode = _IOFBF;
  168.     fp->bufsize = BUFSIZ;
  169.  
  170.     strcpy(fp->eol,"\r\n");
  171.     return fp;
  172. }
  173.  
  174. #ifdef notdef
  175. /* Abort read on a pipe. May not work!
  176.  */
  177. int
  178. breakpipe(fp)
  179. FILE *fp;
  180. {
  181.     struct mbuf *m;
  182.  
  183.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  184.         return EOF;
  185.     if(fp->type != _FL_PIPE)
  186.         return EOF;
  187.     m = ambufw(0);        /* empty buffer causes PULLCHAR to -1 */
  188.     append(&fp->ibuf,m);
  189.     psignal(&fp->ibuf,0);
  190.     return 0;
  191. }
  192. #endif
  193.  
  194. /* Create a new display screen and associate it with a stream. */
  195. FILE *
  196. displayopen(mode,noscrol)
  197. char *mode;
  198. int noscrol;
  199. {
  200.     FILE *fp;
  201.     int textmode = 0;
  202.  
  203.     if(strchr(mode,'t') != NULLCHAR)
  204.         textmode = 1;
  205.  
  206.     if((fp = _fcreat()) == NULLFILE)
  207.         return NULLFILE;
  208.  
  209.     fp->fd = -1;
  210.     fp->type = _FL_DISPLAY;
  211.     fp->bufmode = _IOFBF;
  212.     if(textmode)
  213.         fp->flags |= _FL_ASCII;
  214.  
  215.     fp->ptr = newdisplay(NROWS,NCOLS,noscrol);
  216.     fp->bufsize = BUFSIZ;
  217.     strcpy(fp->eol,"\r\n");
  218.     return fp;
  219. }
  220.  
  221.  
  222. /* Read string from stdin into buf until newline, which is not retained */
  223. char *
  224. gets(s)
  225. char *s;
  226. {
  227.     int c;
  228.     char *cp;
  229.  
  230.     cp = s;
  231.     for(;;){
  232.         if((c = getc(stdin)) == EOF)
  233.             return NULLCHAR;
  234.  
  235.         if(uchar(c) == '\n')
  236.             break;
  237.  
  238.         if(s != NULLCHAR)
  239.             *cp++ = c;
  240.     }
  241.     if(s != NULLCHAR)
  242.         *cp = '\0';
  243.     return s;
  244. }
  245.  
  246. /* Read a line from a stream into a buffer, retaining newline */
  247. char *
  248. fgets(buf,len,fp)
  249. char *buf;    /* User buffer */
  250. int len;    /* Length of buffer */
  251. FILE *fp;    /* Input stream */
  252. {
  253.     int c;
  254.     char *cp;
  255.  
  256.     cp = buf;
  257.     while(len-- > 1){       /* Allow room for the terminal null */
  258.         if((c = getc(fp)) == EOF){
  259.             return NULLCHAR;
  260.         }
  261.         if(buf != NULLCHAR)
  262.             *cp++ = c;
  263.         if(uchar(c) == '\n')
  264.             break;
  265.     }
  266.     if(buf != NULLCHAR)
  267.         *cp = '\0';
  268.     return buf;
  269. }
  270.  
  271. /* Do printf on a stream */
  272. int
  273. fprintf(FILE *fp,char *fmt,...)
  274. {
  275.     va_list args;
  276.     int len;
  277.  
  278.     va_start(args,fmt);
  279.     len = vfprintf(fp,fmt,args);
  280.     va_end(args);
  281.     return len;
  282. }
  283. /* Printf on standard output stream */
  284. int
  285. printf(char *fmt,...)
  286. {
  287.     va_list args;
  288.     int len;
  289.  
  290.     va_start(args,fmt);
  291.     len = vfprintf(stdout,fmt,args);
  292.     va_end(args);
  293.     return len;
  294. }
  295. /* The guts of printf, uses variable arg version of sprintf */
  296. int
  297. vprintf(char *fmt, va_list args)
  298. {
  299.     return vfprintf(stdout,fmt,args);
  300. }
  301.  
  302. /* The guts of printf, uses variable arg version of sprintf */
  303. int
  304. vfprintf(FILE *fp,char *fmt, va_list args)
  305. {
  306.     int len,cnt,withargs;
  307.     char *buf;
  308.  
  309.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  310.         return -1;
  311.     if(strchr(fmt,'%') == NULLCHAR){
  312.         /* Common case optimization: no args, so we don't
  313.          * need vsprintf()
  314.          */
  315.         withargs = 0;
  316.         buf = fmt;
  317.     } else {
  318.         /* Use a default value that is hopefully longer than the
  319.          * biggest output string we'll ever print (!)
  320.          */
  321.         withargs = 1;
  322.         buf = mallocw(BUFSIZ);
  323.         vsprintf(buf,fmt,args);
  324.     }
  325.     len = strlen(buf);
  326.     cnt = fwrite(buf,1,len,fp);
  327.     if(cnt != len)
  328.         cnt = -1;
  329.     if(withargs)
  330.         free(buf);
  331.     return cnt;
  332. }
  333. /* put a char to a stream */
  334. int
  335. fputc(c,fp)
  336. int c;
  337. FILE *fp;
  338. {
  339.     int nbytes;
  340.     struct mbuf *bp;
  341.     int eol;
  342.  
  343.     if(c == '\n' && (fp->flags & _FL_ASCII)){
  344.         nbytes = strlen(fp->eol);
  345.         eol = 1;
  346.     } else {
  347.         nbytes = 1;
  348.         eol = 0;
  349.     }
  350.     bp = fp->obuf;
  351.     if(bp != NULLBUF && bp->size - bp->cnt < nbytes && fflush(fp) == EOF)
  352.         return EOF;
  353.     if(fp->obuf == NULLBUF)
  354.         fp->obuf = ambufw(max(nbytes,fp->bufsize));
  355.  
  356.     bp = fp->obuf;
  357.     if(eol)
  358.         strcpy(&bp->data[bp->cnt],fp->eol);
  359.     else
  360.         bp->data[bp->cnt] = c;
  361.     bp->cnt += nbytes;
  362.  
  363.     if(bp->cnt == bp->size || (fp->bufmode == _IONBF)
  364.      || ((fp->bufmode == _IOLBF) && eol)){
  365.         if(fflush(fp) == EOF)
  366.             return EOF;
  367.     }
  368.     return c;
  369. }
  370. /* put a string to a stream */
  371. int
  372. fputs(buf,fp)
  373. char *buf;
  374. FILE *fp;
  375. {
  376.     int cnt,len;
  377.  
  378.     len = strlen(buf);
  379.     cnt = fwrite(buf,1,len,fp);
  380.     if(cnt != len)
  381.         return EOF;
  382.     return uchar(buf[len-1]);
  383. }
  384.  
  385. /* Put a string to standard output */
  386. int
  387. puts(s)
  388. char *s;
  389. {
  390.     if(fputs(s,stdout) == EOF)
  391.         return EOF;
  392.     putchar('\n');
  393.     return 1;
  394. }
  395.  
  396. /* Read a character from the stream */
  397. int
  398. fgetc(fp)
  399. FILE *fp;
  400. {
  401.     int c;
  402.  
  403.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  404.         return EOF;
  405.     c = _fgetc(fp);
  406.     if(c == EOF || !(fp->flags & _FL_ASCII) || c != fp->eol[0])
  407.         return c;
  408.     /* First char of newline sequence encountered */
  409.     if(fp->eol[1] == '\0')
  410.         return '\n';    /* Translate 1-char eol sequence */
  411.     /* Try to read next input character */
  412.     if((c = _fgetc(fp)) == EOF)
  413.         return fp->eol[0];    /* Got a better idea? */
  414.     if(c == fp->eol[1]){
  415.         /* Translate two-character eol sequence into newline */
  416.         return '\n';
  417.     } else {
  418.         /* CR-NUL sequence on Internet -> bare CR (kludge?) */
  419.         if(c != '\0')
  420.             ungetc(c,fp);
  421.         /* Otherwise return first char unchanged */
  422.         return fp->eol[0];
  423.     }
  424. }
  425. /* Read a character from a stream without newline processing */
  426. int
  427. _fgetc(fp)
  428. FILE *fp;
  429. {
  430.     struct mbuf *bp;
  431.  
  432.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  433.         return EOF;
  434.     fflush(fp);
  435.     if((bp = fp->ibuf) == NULLBUF || bp->cnt == 0)
  436.         if(_fillbuf(fp,1) == NULLBUF)
  437.             return EOF;
  438.     return PULLCHAR(&fp->ibuf);
  439. }
  440.  
  441. /* Flush output on a stream. All actual output is done here. */
  442. int
  443. fflush(fp)
  444. FILE *fp;
  445. {
  446.     struct mbuf *bp;
  447.     int cnt;
  448.  
  449.     if(fp == NULLFILE || fp->cookie != _COOKIE){
  450.         flushall();
  451.         return 0;
  452.     }
  453.     if(fp->obuf == NULLBUF)
  454.         return 0;    /* Nothing to do */
  455.  
  456.     bp = fp->obuf;
  457.     fp->obuf = NULLBUF;
  458.     switch(fp->type){
  459.     case _FL_PIPE:
  460.         append(&fp->ibuf,bp);
  461.         psignal(&fp->ibuf,1);
  462.         while(len_p(fp->ibuf) >= BUFSIZ)
  463.             pwait(&fp->obuf);       /* Hold at hiwat mark */
  464.         return 0;
  465.     case _FL_SOCK:
  466.         return send_mbuf(fp->fd,bp,0,NULLCHAR,0);
  467.     case _FL_FILE:
  468.         do {
  469.             if(fp->flags & _FL_APPEND)
  470.                 _LSEEK(fp->fd,0L,SEEK_END);
  471.             else
  472.                 _LSEEK(fp->fd,fp->offset,SEEK_SET);
  473.             cnt = _WRITE(fp->fd,bp->data,bp->cnt);
  474.             if(cnt > 0)
  475.                 fp->offset += cnt;
  476.             if(cnt != bp->cnt){
  477.                 fp->flags |= _FL_ERR;
  478.                 free_p(bp);
  479.                 return EOF;
  480.             }
  481.             bp = free_mbuf(bp);
  482.         } while(bp != NULLBUF);
  483.         return 0;
  484.     case _FL_DISPLAY:
  485.         do {
  486.             displaywrite(fp->ptr,bp->data,bp->cnt);
  487.             bp = free_mbuf(bp);
  488.         } while(bp != NULLBUF);
  489.         return 0;
  490.     }
  491.     return 0;    /* Can't happen */
  492. }
  493.  
  494. /* Set the end-of-line sequence on a stream */
  495. int
  496. seteol(fp,seq)
  497. FILE *fp;
  498. char *seq;
  499. {
  500.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  501.         return -1;
  502.     if(seq != NULLCHAR)
  503.         strncpy(fp->eol,seq,sizeof(fp->eol));
  504.     else
  505.         *fp->eol = '\0';
  506.     return 0;
  507. }
  508. /* Enable/disable eol translation, return previous state */
  509. int
  510. fmode(fp,mode)
  511. FILE *fp;
  512. int mode;
  513. {
  514.     int prev;
  515.  
  516.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  517.         return -1;
  518.     fflush(fp);
  519.     prev = (fp->flags & _FL_ASCII) ? STREAM_ASCII : STREAM_BINARY;
  520.     switch(mode){
  521.     case STREAM_ASCII:    /* Turn on ascii translation */
  522.         fp->flags |= _FL_ASCII;
  523.         break;
  524.     case STREAM_BINARY:    /* Turn it off */
  525.         fp->flags &= ~_FL_ASCII;
  526.         break;
  527.     default:
  528.         break;
  529.     }
  530.     return prev;
  531. }
  532. int
  533. fclose(fp)
  534. FILE *fp;
  535. {
  536.     if(fp == NULLFILE || fp->cookie != _COOKIE){
  537.         return -1;
  538.     }
  539.     if(--fp->refcnt != 0)
  540.         return 0;    /* Others are still using it */
  541.     _fclose(fp);
  542.     if(fp->prev != NULLFILE)
  543.         fp->prev->next = fp->next;
  544.     else
  545.         _Files = fp->next;
  546.  
  547.     if(fp->next != NULLFILE)
  548.         fp->next->prev = fp->prev;
  549.     free(fp);
  550.     return 0;
  551. }
  552. int
  553. fseek(fp,offset,whence)
  554. FILE *fp;
  555. long offset;
  556. int whence;
  557. {
  558.     struct stat statbuf;
  559.  
  560.     if(fp == NULLFILE || fp->cookie != _COOKIE || fp->type != _FL_FILE){
  561.         errno = EINVAL;
  562.         return -1;
  563.     }
  564.     fflush(fp);     /* Flush output buffer */
  565.     /* On relative seeks, adjust for data in input buffer */
  566.     switch(whence){
  567.     case SEEK_SET:
  568.         fp->offset = offset;    /* Absolute seek */
  569.         break;
  570.     case SEEK_CUR:
  571.         /* Relative seek, adjusting for buffered data */
  572.         fp->offset += offset - len_p(fp->ibuf);
  573.         break;
  574.     case SEEK_END:
  575.         /* Find out how big the file currently is */
  576. #ifdef notdef
  577.         if(fstat(fp->fd,&statbuf) == -1)
  578.             return -1;    /* "Can't happen" */
  579.         fp->offset = statbuf.st_size + offset;
  580. #else
  581.         fp->offset = _LSEEK(fp->fd,0,SEEK_END) + offset;
  582. #endif
  583.         break;
  584.     }
  585.     /* Toss input buffer */
  586.     free_p(fp->ibuf);
  587.     fp->ibuf = NULLBUF;
  588.     fp->flags &= ~_FL_EOF;
  589.     return 0;
  590. }
  591. long
  592. ftell(fp)
  593. FILE *fp;
  594. {
  595.     if(fp == NULLFILE || fp->cookie != _COOKIE || fp->type != _FL_FILE)
  596.         return -1;
  597.     fflush(fp);
  598.     return fp->offset - len_p(fp->ibuf);
  599. }
  600.  
  601. int
  602. ungetc(c,fp)
  603. int c;
  604. FILE *fp;
  605. {
  606.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  607.         return -1;
  608.  
  609.     if(c == '\n' && (fp->flags & _FL_ASCII)){
  610.         fp->ibuf = pushdown(fp->ibuf,strlen(fp->eol));
  611.         strcpy(fp->ibuf->data,fp->eol);
  612.     } else {
  613.         fp->ibuf = pushdown(fp->ibuf,1);
  614.         *fp->ibuf->data = c;
  615.     }
  616.     return c;
  617. }
  618. size_t
  619. fwrite(ptr,size,n,fp)
  620. void *ptr;
  621. size_t size;
  622. size_t n;
  623. FILE *fp;
  624. {
  625.     struct mbuf *bp;
  626.     char *icp,*ocp;
  627.     size_t bytes;
  628.     size_t cnt;
  629.     size_t asize;
  630.     int room;
  631.     int newlines = 0;
  632.     int eollen = 1;
  633.     int doflush = 0;
  634.  
  635.     if(fp == NULLFILE || fp->cookie != _COOKIE || size == 0)
  636.         return 0;
  637.     icp = (char *)ptr;
  638.     bytes = size*n;
  639.  
  640.     /* Optimization for large binary file writes */
  641.     if(fp->type == _FL_FILE && !(fp->flags & _FL_ASCII) && bytes >= fp->bufsize){
  642.         fflush(fp);
  643.         if(fp->flags & _FL_APPEND)
  644.             _LSEEK(fp->fd,0L,SEEK_END);
  645.         else
  646.             _LSEEK(fp->fd,fp->offset,SEEK_SET);
  647.         cnt = _WRITE(fp->fd,icp,bytes);
  648.         if(cnt > 0)
  649.             fp->offset += cnt;
  650.         if(cnt != bytes)
  651.             return cnt/size;
  652.         return n;
  653.     }
  654.     if(fp->flags & _FL_ASCII){
  655.         /* Count the newlines in the input buffer */
  656.         newlines = memcnt((char *)ptr,'\n',bytes);
  657.         if(newlines != 0){
  658.             eollen = strlen(fp->eol);
  659.             if(fp->flags & _IOLBF)
  660.                 doflush = 1;
  661.         }
  662.     }
  663.     while(bytes != 0){
  664.         bp = fp->obuf;
  665.         if(bp != NULLBUF && bp->cnt + eollen > bp->size){
  666.             /* Current obuf is full; flush it */
  667.             if(fflush(fp) == EOF)
  668.                 return (bytes - n*size)/size;
  669.         }
  670.         if((bp = fp->obuf) == NULLBUF){
  671.             /* Allocate a new output buffer. The size is the
  672.              * larger of the buffer size or the amount of data
  673.              * we have to write (including any expanded newlines)
  674.              */
  675.             asize = bytes+(eollen-1)*newlines;
  676.             asize = max(fp->bufsize,asize);
  677.             bp = fp->obuf = ambufw(asize);
  678.         }
  679.         if((fp->flags & _FL_ASCII) && newlines != 0){
  680.             /* Copy text to buffer, expanding newlines */
  681.             ocp = bp->data + bp->cnt;
  682.             room = bp->size - bp->cnt;
  683.             for(;room >= eollen && bytes != 0;icp++,bytes--){
  684.                 if(*icp == '\n'){
  685.                     strcpy(ocp,fp->eol);
  686.                     ocp += eollen;
  687.                     room -= eollen;
  688.                     newlines--;
  689.                 } else {
  690.                     *ocp++ = *icp;
  691.                     room--;
  692.                 }
  693.             }
  694.             bp->cnt = ocp - bp->data;
  695.         } else {
  696.             /* Simply copy binary data to buffer */
  697.             cnt = min(bp->size - bp->cnt,bytes);
  698.             memcpy(bp->data+bp->cnt,icp,cnt);
  699.             bp->cnt += cnt;
  700.             icp += cnt;
  701.             bytes -= cnt;
  702.         }
  703.     }
  704.     /* The final flush. Flush if the stream is unbuffered,
  705.      * the output buffer is full, or the stream is line buffered
  706.      * and we've written at least one newline (not necessarily the
  707.      * last character)
  708.      */
  709.     if(fp->bufmode == _IONBF || bp->cnt == bp->size || doflush){
  710.         if(fflush(fp) == EOF)
  711.             return (bytes - n*size)/size;
  712.     }
  713.     return n;
  714. }
  715. static struct mbuf *
  716. _fillbuf(fp,cnt)
  717. FILE *fp;
  718. int cnt;
  719. {
  720.     struct mbuf *bp;
  721.  
  722.     if(fp->ibuf != NULLBUF)
  723.         return fp->ibuf;    /* Stuff already in the input buffer */
  724.  
  725.     switch(fp->type){
  726.     case _FL_PIPE:
  727.         while(fp->ibuf == NULLBUF)
  728.             if((errno = pwait(&fp->ibuf)) != 0)     /* Wait for something */
  729.                 return NULLBUF;
  730.         psignal(&fp->obuf,1);   /* Reawaken writer, if any */
  731.         return fp->ibuf;
  732.     case _FL_SOCK:
  733.         /* Always grab everything available from a socket */
  734.         if(recv_mbuf(fp->fd,&fp->ibuf,0,NULLCHAR,0) <= 0
  735.          && errno != EALARM){
  736.             fp->flags |= _FL_EOF;
  737.         }
  738.         return fp->ibuf;
  739.     case _FL_FILE:
  740.         /* Read from file */
  741.         cnt = max(fp->bufsize,cnt);
  742.         bp = ambufw(cnt);
  743.         _LSEEK(fp->fd,fp->offset,SEEK_SET);
  744.         cnt = _READ(fp->fd,bp->data,cnt);
  745.         if(cnt < 0)
  746.             fp->flags |= _FL_ERR;
  747.         if(cnt == 0)
  748.             fp->flags |= _FL_EOF;
  749.         if(cnt <= 0){
  750.             free_p(bp);     /* Nothing successfully read */
  751.             return NULLBUF;
  752.         }
  753.         fp->offset += cnt;    /* Update pointer */
  754.         /* Buffer successfully read, store it */
  755.         bp->cnt = cnt;
  756.         fp->ibuf = bp;
  757.         return bp;
  758.     case _FL_DISPLAY:    /* Displays are write-only */
  759.         return NULLBUF;
  760.     }
  761.     return NULLBUF; /* Can't happen */
  762. }
  763. size_t
  764. fread(ptr,size,n,fp)
  765. void *ptr;
  766. size_t size,n;
  767. FILE *fp;
  768. {
  769.     struct mbuf *bp;
  770.     size_t bytes;
  771.     size_t cnt;
  772.     int c;
  773.     size_t tot = 0;
  774.     char *ocp;
  775.     char *cp;
  776.  
  777.     if(fp == NULLFILE || fp->cookie != _COOKIE || size == 0)
  778.         return 0;
  779.     fflush(fp);
  780.     bytes = n*size;
  781.  
  782.     ocp = (char *)ptr;
  783.     while(bytes != 0){
  784.         /* Optimization for large binary file reads */
  785.         if(fp->ibuf == NULLBUF
  786.          && fp->type == _FL_FILE && !(fp->flags & _FL_ASCII)
  787.          && bytes >= BUFSIZ){
  788.             _LSEEK(fp->fd,fp->offset,SEEK_SET);
  789.             tot = _READ(fp->fd,ocp,bytes);
  790.             if(tot > 0)
  791.                 fp->offset += tot;
  792.             if(tot != bytes)
  793.                 return tot/size;
  794.             return n;
  795.         }
  796.         /* Replenish input buffer if necessary */
  797.         if(fp->ibuf == NULLBUF && _fillbuf(fp,bytes) == NULLBUF){
  798.             /* Must have hit eof or had error */
  799.             return tot/size;
  800.         }
  801.         /* In this pass, read the lesser of the buffer size,
  802.          * the requested amount, or the amount up to the next
  803.          * eol sequence (if ascii mode)
  804.          */
  805.         bp = fp->ibuf;
  806.         cnt = min(bp->cnt,bytes);
  807.         if((fp->flags & _FL_ASCII)
  808.          && (cp = memchr(bp->data,fp->eol[0],cnt)) != NULLCHAR)
  809.             cnt = min(cnt,cp - bp->data);
  810.         if(cnt != 0){
  811.             cnt = pullup(&fp->ibuf,ocp,cnt);
  812.             ocp += cnt;
  813.             tot += cnt;
  814.             bytes -= cnt;
  815.         } else {
  816.             /* Hit a eol sequence, use fgetc to translate */
  817.             if((c = fgetc(fp)) == EOF)
  818.                 return tot/size;
  819.  
  820.             *ocp++ = c;
  821.             tot++;
  822.             bytes--;
  823.         }
  824.     }
  825.     return n;
  826. }
  827. void
  828. perror(s)
  829. char *s;
  830. {
  831.     if(errno < sys_nerr)
  832.         fprintf(stderr,"%s: %s\n",s,sys_errlist[errno]);
  833.     else if(errno <= EMAX)
  834.         fprintf(stderr,"%s: %s\n",s,Sock_errlist[errno-36]);
  835.     else
  836.         fprintf(stderr,"%s: errno %d\n",s,errno);
  837. }
  838. int
  839. setvbuf(fp,buf,type,size)
  840. FILE *fp;
  841. char *buf;    /* Ignored; we alloc our own */
  842. int type;
  843. int size;
  844. {
  845.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  846.         return -1;
  847.     if(size == 0)
  848.         type = _IONBF;
  849.     switch(type){
  850.     case _IOFBF:
  851.         fp->bufsize = size;
  852.         break;
  853.     case _IOLBF:
  854.         fp->bufsize = size;
  855.         break;
  856.     case _IONBF:
  857.         fp->bufsize = 1;
  858.         break;
  859.     default:
  860.         return -1;    /* Invalid */
  861.     }
  862.     fp->bufmode = type;
  863.     fflush(fp);
  864.     return 0;
  865. }
  866. void
  867. setbuf(fp,buf)
  868. FILE *fp;
  869. char *buf;
  870. {
  871.     if(buf == NULLCHAR)
  872.         setvbuf(fp,NULLCHAR,_IONBF,0);
  873.     else
  874.         setvbuf(fp,buf,_IOFBF,BUFSIZ);
  875. }
  876. FILE *
  877. tmpfile()
  878. {
  879.     static int num;
  880.     struct stat statbuf;
  881.     FILE *fp;
  882.     char *fname;
  883.     char *tmpdir;
  884.     char *cp;
  885.  
  886.     /* Determine directory to use. First look for $TMP environment
  887.      * variable, then use the compiled-in-default, then use the
  888.      * current directory.
  889.      */
  890.     if((cp = getenv("TMP")) != NULLCHAR
  891.      && stat(cp,&statbuf) == 0 && (statbuf.st_mode & S_IFDIR)){
  892.         fname = malloc(strlen(cp) + 11);
  893.         tmpdir = malloc(strlen(cp) + 2);
  894.         strcpy(tmpdir,cp);
  895.         strcat(tmpdir,"/");
  896.     } else if(stat(Tmpdir,&statbuf) == 0 && (statbuf.st_mode & S_IFDIR)){
  897.         fname = malloc(strlen(Tmpdir) + 11);
  898.         tmpdir = malloc(strlen(Tmpdir) + 2);
  899.         strcpy(tmpdir,Tmpdir);
  900.         strcat(tmpdir,"/");
  901.     } else {
  902.         fname = malloc(10);
  903.         tmpdir = strdup("");
  904.     }
  905.     for(;;){
  906.         sprintf(fname,"%stemp.%03d",tmpdir,num);
  907.         if(stat(fname,&statbuf) == -1 && errno == ENOENT)
  908.             break;
  909.         num++;
  910.     }
  911.     free(tmpdir);
  912.     fp = fopen(fname,"w+b");
  913.     free(fname);
  914.     if(fp != NULLFILE)
  915.         fp->flags |= _FL_TMP;
  916.     return fp;
  917. }
  918. /* Do everything to close a stream except freeing the descriptor
  919.  * The reference count is left unchanged, and the descriptor is still
  920.  * on the list
  921.  */
  922. static void
  923. _fclose(fp)
  924. FILE *fp;
  925. {
  926.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  927.         return;
  928.     fflush(fp);
  929.     switch(fp->type){
  930.     case _FL_SOCK:
  931.         close_s(fp->fd);
  932.         break;
  933.     case _FL_FILE:
  934.         _CLOSE(fp->fd);
  935.         fp->offset = 0;
  936.         break;
  937.     case _FL_DISPLAY:
  938.         closedisplay(fp->ptr);
  939.         fp->ptr = NULL;
  940.         break;
  941.     }
  942.     free_p(fp->obuf);       /* Should be NULLBUF anyway */
  943.     fp->obuf = NULLBUF;
  944.     free_p(fp->ibuf);
  945.     fp->ibuf = NULLBUF;
  946.     if((fp->flags & _FL_TMP) && Refcnt[fp->fd] == 0)
  947.         remove(fp->ptr);
  948.     free(fp->ptr);
  949.     fp->ptr = NULLCHAR;
  950.     fp->flags = 0;
  951.     fp->fd = -1;
  952.     fp->cookie = ~_COOKIE;
  953. }
  954. /* allocate a new file pointer structure, init a few fields and put on list */
  955. static FILE *
  956. _fcreat()
  957. {
  958.     FILE *fp;
  959.  
  960.     if((fp = (FILE *)calloc(1,sizeof(FILE))) == NULLFILE)
  961.         return NULLFILE;
  962.  
  963.     fp->cookie = _COOKIE;
  964.     fp->refcnt = 1;
  965.     fp->next = _Files;
  966.     _Files = fp;
  967.     if(fp->next != NULLFILE)
  968.         fp->next->prev = fp;
  969.     return fp;
  970. }
  971.  
  972. int
  973. read(fd,buf,cnt)
  974. int fd;
  975. void *buf;
  976. unsigned cnt;
  977. {
  978.     if(fd < 0 || fd >= Nfiles+Nsock){
  979.         errno = EINVAL;
  980.         return -1;
  981.     } else if(fd < Nfiles)
  982.         return _READ(fd,buf,cnt);
  983.     else
  984.         return recv(fd,buf,cnt,0);
  985. }
  986. int
  987. write(fd,buf,cnt)
  988. int fd;
  989. void *buf;
  990. unsigned cnt;
  991. {
  992.     if(fd < 0 || fd >= Nfiles+Nsock){
  993.         errno = EINVAL;
  994.         return -1;
  995.     } else if(fd < Nfiles)
  996.         return _WRITE(fd,buf,cnt);
  997.     else
  998.         return send(fd,buf,cnt,0);
  999. }
  1000.  
  1001. int
  1002. open(file,mode,perm)
  1003. char *file;
  1004. int mode;
  1005. int perm;
  1006. {
  1007.     return _open(file,mode,perm);
  1008. }
  1009.  
  1010. int
  1011. close(fd)
  1012. int fd;
  1013. {
  1014.     if(fd < 0 || fd >= Nfiles+Nsock){
  1015.         errno = EINVAL;
  1016.         return -1;
  1017.     } else if(fd < Nfiles)
  1018.         return _CLOSE(fd);
  1019.     else
  1020.         return close_s(fd);
  1021. }
  1022.  
  1023. void
  1024. fcloseall()
  1025. {
  1026.     FILE *fp,*fpnext;
  1027.  
  1028.     flushall();
  1029.     for(fp = _Files;fp != NULLFILE;fp=fpnext){
  1030.         fpnext = fp->next;
  1031.         fp->refcnt = 1;
  1032.         if((unsigned)fp->fd > 2)
  1033.             fclose(fp);
  1034.     }
  1035. }
  1036. void
  1037. flushall()
  1038. {
  1039.     FILE *fp;
  1040.  
  1041.     for(fp = _Files;fp != NULLFILE;fp=fp->next){
  1042.         fflush(fp);
  1043.     }
  1044. }
  1045. FILE *
  1046. fdup(fp)
  1047. FILE *fp;
  1048. {
  1049.     FILE *nfp;
  1050.  
  1051.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  1052.         return NULLFILE;    /* Invalid arg */
  1053.     switch(fp->type){
  1054.     case _FL_FILE:
  1055.         /* Allocate new file pointer structure so each can
  1056.          * have its own read/write pointer and buffering
  1057.          */
  1058.         if((nfp = _fcreat()) == NULLFILE)
  1059.             return NULLFILE;
  1060.         nfp->fd = _DUP(fp->fd);
  1061.         nfp->offset = fp->offset;
  1062.         nfp->type = fp->type;
  1063.         nfp->bufmode = fp->bufmode;
  1064.         nfp->flags = fp->flags;
  1065.         strcpy(nfp->eol,fp->eol);
  1066.         nfp->bufsize = fp->bufsize;
  1067.         nfp->ptr = strdup(fp->ptr);
  1068.         fp = nfp;
  1069.         break;
  1070.     case _FL_SOCK:    /* These just share the same file pointer */
  1071.     case _FL_DISPLAY:
  1072.     case _FL_PIPE:
  1073.         fp->refcnt++;
  1074.         break;
  1075.     }
  1076.     return fp;
  1077. }
  1078. char *
  1079. fpname(fp)
  1080. FILE *fp;
  1081. {
  1082.     if(fp == NULLFILE || fp->cookie != _COOKIE)
  1083.         return NULLCHAR;
  1084.     if(fp->type == _FL_FILE)
  1085.         return fp->ptr;
  1086.     return NULLCHAR;
  1087. }
  1088.  
  1089. void
  1090. exit(n)
  1091. int n;
  1092. {
  1093.     fcloseall();
  1094.     _exit(n);
  1095. }
  1096.  
  1097. int
  1098. dofiles(argc,argv,p)
  1099. int argc;
  1100. char *argv[];
  1101. void *p;
  1102. {
  1103.     FILE *fp;
  1104.     int i;
  1105.     int flags;
  1106.  
  1107.     printf("fp       fd  ref  eol   type mod buf  flags\n");
  1108.     for(fp = _Files;fp != NULLFILE;fp = fp->next){
  1109.         printf("%8lx ",ptol(fp));
  1110.         if(fp->fd != -1)
  1111.             printf("%-3d",fp->fd);
  1112.         else
  1113.             printf("   ");
  1114.         printf(" %-3d ",fp->refcnt);
  1115.         for(i=0;i<EOL_LEN-1;i++){
  1116.             if(fp->eol[i] != '\0')
  1117.                 printf(" %02x",fp->eol[i]);
  1118.             else
  1119.                 printf("   ");
  1120.         }
  1121.         flags = fp->flags;
  1122.         switch(fp->type){
  1123.         case _FL_SOCK:
  1124.             printf(" sock");
  1125.             break;
  1126.         case _FL_FILE:
  1127.             printf(" file");
  1128.             break;
  1129.         case _FL_DISPLAY:
  1130.             printf(" disp");
  1131.             break;
  1132.         case _FL_PIPE:
  1133.             printf(" pipe");
  1134.             break;
  1135.         }
  1136.         printf("%4s",(flags & _FL_ASCII) ? " txt" : " bin");
  1137.         switch(fp->bufmode){
  1138.         case _IONBF:
  1139.             printf(" none");
  1140.             break;
  1141.         case _IOLBF:
  1142.             printf(" line");
  1143.             break;
  1144.         case _IOFBF:
  1145.             printf(" full");
  1146.             break;
  1147.         }
  1148.         if(flags & _FL_EOF)
  1149.             printf(" EOF");
  1150.         if(flags & _FL_ERR)
  1151.             printf(" ERR");
  1152.         if(flags & _FL_APPEND)
  1153.             printf(" APND");
  1154.         if(flags & _FL_TMP)
  1155.             printf(" TMP");
  1156.         if(fp->type == _FL_FILE && fp->ptr != NULLCHAR)
  1157.             printf(" (%s seek=%lu)",(char *)fp->ptr,ftell(fp));
  1158.         putchar('\n');
  1159.     }
  1160.     return 0;
  1161. }
  1162.