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