stdio.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:24k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

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