home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / fflush.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  15KB  |  567 lines

  1. /***
  2. *fflush.c - flush a stream buffer
  3. *
  4. *       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines fflush() - flush the buffer on a stream
  8. *               _flushall() - flush all stream buffers
  9. *
  10. *******************************************************************************/
  11.  
  12. #ifdef _WIN32
  13.  
  14.  
  15. #include <cruntime.h>
  16. #include <stdio.h>
  17. #include <file2.h>
  18. #include <io.h>
  19. #include <mtdll.h>
  20. #include <internal.h>
  21.  
  22.  
  23. /* Values passed to flsall() to distinguish between _flushall() and
  24.  * fflush(NULL) behavior
  25.  */
  26. #define FLUSHALL        1
  27. #define FFLUSHNULL      0
  28.  
  29. /* Core routine for fflush(NULL) and flushall()
  30.  */
  31. static int __cdecl flsall(int);
  32.  
  33.  
  34. /***
  35. *int fflush(stream) - flush the buffer on a stream
  36. *
  37. *Purpose:
  38. *       if file open for writing and buffered, flush the buffer. if problems
  39. *       flushing the buffer, set the stream flag to error
  40. *       Always flushes the stdio stream and forces a commit to disk if file
  41. *       was opened in commit mode.
  42. *
  43. *Entry:
  44. *       FILE *stream - stream to flush
  45. *
  46. *Exit:
  47. *       returns 0 if flushed successfully, or no buffer to flush
  48. *       returns EOF and sets file error flag if fails.
  49. *       FILE struct entries affected: _ptr, _cnt, _flag.
  50. *
  51. *Exceptions:
  52. *
  53. *******************************************************************************/
  54.  
  55. #ifdef _MT
  56.  
  57. int __cdecl fflush (
  58.         REG1 FILE *stream
  59.         )
  60. {
  61.         int rc;
  62.  
  63.         /* if stream is NULL, flush all streams
  64.          */
  65.         if ( stream == NULL )
  66.                 return(flsall(FFLUSHNULL));
  67.  
  68.         _lock_str(stream);
  69.  
  70.         rc = _fflush_lk(stream);
  71.  
  72.         _unlock_str(stream);
  73.  
  74.         return(rc);
  75. }
  76.  
  77.  
  78. /***
  79. *_fflush_lk() - Flush the buffer on a stream (stream is already locked)
  80. *
  81. *Purpose:
  82. *       Core flush routine; assumes stream lock is held by caller.
  83. *
  84. *       [See fflush() above for more information.]
  85. *
  86. *Entry:
  87. *       [See fflush()]
  88. *Exit:
  89. *       [See fflush()]
  90. *
  91. *Exceptions:
  92. *
  93. *******************************************************************************/
  94.  
  95. int __cdecl _fflush_lk (
  96.         REG1 FILE *str
  97.         )
  98. {
  99.  
  100. #else  /* _MT */
  101.  
  102. int __cdecl fflush (
  103.         REG1 FILE *str
  104.         )
  105. {
  106.  
  107.         /* if stream is NULL, flush all streams */
  108.         if ( str == NULL ) {
  109.                 return(flsall(FFLUSHNULL));
  110.         }
  111.  
  112. #endif  /* _MT */
  113.  
  114.         if (_flush(str) != 0) {
  115.                 /* _flush failed, don't attempt to commit */
  116.                 return(EOF);
  117.         }
  118.  
  119.         /* lowio commit to ensure data is written to disk */
  120.         if (str->_flag & _IOCOMMIT) {
  121.                 return (_commit(_fileno(str)) ? EOF : 0);
  122.         }
  123.         return 0;
  124. }
  125.  
  126.  
  127. /***
  128. *int _flush(stream) - flush the buffer on a single stream
  129. *
  130. *Purpose:
  131. *       If file open for writing and buffered, flush the buffer.  If
  132. *       problems flushing the buffer, set the stream flag to error.
  133. *       Multi-thread version assumes stream lock is held by caller.
  134. *
  135. *Entry:
  136. *       FILE* stream - stream to flush
  137. *
  138. *Exit:
  139. *       Returns 0 if flushed successfully, or if no buffer to flush.,
  140. *       Returns EOF and sets file error flag if fails.
  141. *       File struct entries affected: _ptr, _cnt, _flag.
  142. *
  143. *Exceptions:
  144. *
  145. *******************************************************************************/
  146.  
  147. int __cdecl _flush (
  148.         FILE *str
  149.         )
  150. {
  151.         REG1 FILE *stream;
  152.         REG2 int rc = 0; /* assume good return */
  153.         REG3 int nchar;
  154.  
  155.         /* Init pointer to stream */
  156.         stream = str;
  157.  
  158.  
  159.         if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT && bigbuf(stream)
  160.                 && (nchar = stream->_ptr - stream->_base) > 0)
  161.         {
  162.                 if ( _write(_fileno(stream), stream->_base, nchar) == nchar ) {
  163.                         /* if this is a read/write file, clear _IOWRT so that
  164.                          * next operation can be a read
  165.                          */
  166.                         if ( _IORW & stream->_flag )
  167.                                 stream->_flag &= ~_IOWRT;
  168.                 }
  169.                 else {
  170.                         stream->_flag |= _IOERR;
  171.                         rc = EOF;
  172.                 }
  173.         }
  174.  
  175.         stream->_ptr = stream->_base;
  176.         stream->_cnt = 0;
  177.  
  178.         return(rc);
  179. }
  180.  
  181.  
  182. /***
  183. *int _flushall() - flush all output buffers
  184. *
  185. *Purpose:
  186. *       flushes all the output buffers to the file, clears all input buffers.
  187. *
  188. *Entry:
  189. *       None.
  190. *
  191. *Exit:
  192. *       returns number of open streams
  193. *
  194. *Exceptions:
  195. *
  196. *******************************************************************************/
  197.  
  198. int __cdecl _flushall (
  199.         void
  200.         )
  201. {
  202.         return(flsall(FLUSHALL));
  203. }
  204.  
  205.  
  206. /***
  207. *static int flsall(flushflag) - flush all output buffers
  208. *
  209. *Purpose:
  210. *       Flushes all the output buffers to the file and, if FLUSHALL is passed,
  211. *       clears all input buffers. Core routine for both fflush(NULL) and
  212. *       flushall().
  213. *
  214. *       MTHREAD Note: All the locking/unlocking required for both fflush(NULL)
  215. *       and flushall() is performed in this routine.
  216. *
  217. *Entry:
  218. *       int flushflag - flag indicating the exact semantics, there are two
  219. *                       legal values: FLUSHALL and FFLUSHNULL
  220. *
  221. *Exit:
  222. *       if flushflag == FFLUSHNULL then flsbuf returns:
  223.                 0, if successful
  224. *               EOF, if an error occurs while flushing one of the streams
  225. *
  226. *       if flushflag == FLUSHALL then flsbuf returns the number of streams
  227. *       successfully flushed
  228. *
  229. *Exceptions:
  230. *
  231. *******************************************************************************/
  232.  
  233. static int __cdecl flsall (
  234.         int flushflag
  235.         )
  236. {
  237.         REG1 int i;
  238.         int count = 0;
  239.         int errcode = 0;
  240.  
  241.         _mlock(_IOB_SCAN_LOCK);
  242.  
  243.         for ( i = 0 ; i < _nstream ; i++ ) {
  244.  
  245.                 if ( (__piob[i] != NULL) && (inuse((FILE *)__piob[i])) ) {
  246.  
  247. #ifdef _MT
  248.                         /*
  249.                          * lock the stream. this is not done until testing
  250.                          * the stream is in use to avoid unnecessarily creating
  251.                          * a lock for every stream. the price is having to
  252.                          * retest the stream after the lock has been asserted.
  253.                          */
  254.                         _lock_str2(i, __piob[i]);
  255.  
  256.                         /*
  257.                          * if the stream is STILL in use (it may have been
  258.                          * closed before the lock was asserted), see about
  259.                          * flushing it.
  260.                          */
  261.                         if ( inuse((FILE *)__piob[i]) ) {
  262. #endif  /* _MT */
  263.  
  264.                         if ( flushflag == FLUSHALL ) {
  265.                                 /*
  266.                                  * FLUSHALL functionality: fflush the read or
  267.                                  * write stream and, if successful, update the
  268.                                  * count of flushed streams
  269.                                  */
  270.                                 if ( _fflush_lk(__piob[i]) != EOF )
  271.                                         /* update count of successfully flushed
  272.                                          * streams
  273.                                          */
  274.                                         count++;
  275.                         }
  276.                         else if ( (flushflag == FFLUSHNULL) &&
  277.                                   (((FILE *)__piob[i])->_flag & _IOWRT) ) {
  278.                                 /*
  279.                                  * FFLUSHNULL functionality: fflush the write
  280.                                  * stream and kept track of the error, if one
  281.                                  * occurs
  282.                                  */
  283.                                 if ( _fflush_lk(__piob[i]) == EOF )
  284.                                         errcode = EOF;
  285.                         }
  286.  
  287. #ifdef _MT
  288.                         }
  289.                         _unlock_str2(i, __piob[i]);
  290. #endif  /* _MT */
  291.                 }
  292.         }
  293.  
  294.         _munlock(_IOB_SCAN_LOCK);
  295.  
  296.         if ( flushflag == FLUSHALL )
  297.                 return(count);
  298.         else
  299.                 return(errcode);
  300. }
  301.  
  302.  
  303. #else  /* _WIN32 */
  304.  
  305. #if defined (_M_MPPC) || defined (_M_M68K)
  306.  
  307.  
  308. #include <cruntime.h>
  309. #include <stdio.h>
  310. #include <file2.h>
  311. #include <io.h>
  312. #include <internal.h>
  313.  
  314. /* define the entry in pre-terminator table */
  315.  
  316. #pragma data_seg(".CRT$XPX")
  317.  
  318. static _PVFV __pendstdio = _endstdio;
  319.  
  320. #pragma data_seg()
  321.  
  322. #ifndef CRTDLL
  323. /*
  324.  * _cflush is a dummy variable used to pull in _endstdio() when any STDIO
  325.  * routine is included in the user program.
  326.  */
  327. int _cflush = 1;
  328. #endif  /* CRTDLL */
  329.  
  330.  
  331. /* Values passed to flsall() to distinguish between _flushall() and
  332.  * fflush(NULL) behavior
  333.  */
  334. #define FLUSHALL        1
  335. #define FFLUSHNULL      0
  336.  
  337. /* Core routine for fflush(NULL) and flushall()
  338.  */
  339. static int __cdecl flsall(int);
  340.  
  341. /***
  342. *int fflush(stream) - flush the buffer on a stream
  343. *
  344. *Purpose:
  345. *       if file open for writing and buffered, flush the buffer. if problems
  346. *       flushing the buffer, set the stream flag to error
  347. *       Always flushes the stdio stream and forces a commit to disk if file
  348. *       was opened in commit mode.
  349. *
  350. *Entry:
  351. *       FILE *stream - stream to flush
  352. *
  353. *Exit:
  354. *       returns 0 if flushed successfully, or no buffer to flush
  355. *       returns EOF and sets file error flag if fails.
  356. *       FILE struct entries affected: _ptr, _cnt, _flag.
  357. *
  358. *Exceptions:
  359. *
  360. *******************************************************************************/
  361.  
  362. int __cdecl fflush (
  363.         REG1 FILE *str
  364.         )
  365. {
  366.  
  367.         /* if stream is NULL, flush all streams */
  368.         if ( str == NULL ) {
  369.                 return(flsall(FFLUSHNULL));
  370.         }
  371.  
  372.         if (_flush(str) != 0) {
  373.                 /* _flush failed, don't attempt to commit */
  374.                 return(EOF);
  375.         }
  376.  
  377.         /* lowio commit to ensure data is written to disk */
  378.         if (str->_flag & _IOCOMMIT) {
  379.                 return (_commit(_fileno(str)) ? EOF : 0);
  380.         }
  381.         return (0);
  382. }
  383.  
  384.  
  385. /***
  386. *int _flush(stream) - flush the buffer on a single stream
  387. *
  388. *Purpose:
  389. *       If file open for writing and buffered, flush the buffer.  If
  390. *       problems flushing the buffer, set the stream flag to error.
  391. *       Multi-thread version assumes stream lock is held by caller.
  392. *
  393. *Entry:
  394. *       FILE* stream - stream to flush
  395. *
  396. *Exit:
  397. *       Returns 0 if flushed successfully, or if no buffer to flush.,
  398. *       Returns EOF and sets file error flag if fails.
  399. *       File struct entries affected: _ptr, _cnt, _flag.
  400. *
  401. *Exceptions:
  402. *
  403. *******************************************************************************/
  404.  
  405. int __cdecl _flush (
  406.         FILE *str
  407.         )
  408. {
  409.         REG1 FILE *stream;
  410.         REG2 int rc = 0; /* assume good return */
  411.         REG3 int nchar;
  412.  
  413.         /* Init pointer to stream */
  414.         stream = str;
  415.  
  416.         if ((stream->_flag & (_IOREAD | _IOWRT)) == _IOWRT && bigbuf(stream)
  417.                 && (nchar = stream->_ptr - stream->_base) > 0)
  418.         {
  419.                 if ( _write(_fileno(stream), stream->_base, nchar) == nchar ) {
  420.                         /* if this is a read/write file, clear _IOWRT so that
  421.                          * next operation can be a read
  422.                          */
  423.                         if ( _IORW & stream->_flag )
  424.                                 stream->_flag &= ~_IOWRT;
  425.                 }
  426.                 else {
  427.                         stream->_flag |= _IOERR;
  428.                         rc = EOF;
  429.                 }
  430.         }
  431.  
  432.         stream->_ptr = stream->_base;
  433.         stream->_cnt = 0;
  434.  
  435.         return(rc);
  436. }
  437.  
  438.  
  439. /***
  440. *int _flushall() - flush all output buffers
  441. *
  442. *Purpose:
  443. *       flushes all the output buffers to the file, clears all input buffers.
  444. *
  445. *Entry:
  446. *       None.
  447. *
  448. *Exit:
  449. *       returns number of open streams
  450. *
  451. *Exceptions:
  452. *
  453. *******************************************************************************/
  454.  
  455. int __cdecl _flushall (
  456.         void
  457.         )
  458. {
  459.         return(flsall(FLUSHALL));
  460. }
  461.  
  462.  
  463. /***
  464. *static int flsall(flushflag) - flush all output buffers
  465. *
  466. *Purpose:
  467. *       Flushes all the output buffers to the file and, if FLUSHALL is passed,
  468. *       clears all input buffers. Core routine for both fflush(NULL) and
  469. *       flushall().
  470. *
  471. *Entry:
  472. *       int flushflag - flag indicating the exact semantics, there are two
  473. *                       legal values: FLUSHALL and FFLUSHNULL
  474. *
  475. *Exit:
  476. *       if flushflag == FFLUSHNULL then flsbuf returns:
  477. *               0, if successful
  478. *               EOF, if an error occurs while flushing one of the streams
  479. *
  480. *       if flushflag == FLUSHALL then flsbuf returns the number of streams
  481. *       successfully flushed
  482. *
  483. *Exceptions:
  484. *
  485. *******************************************************************************/
  486.  
  487. static int __cdecl flsall (
  488.         int flushflag
  489.         )
  490. {
  491.         REG1 FILE *stream = _iob;
  492.         REG2 int count = 0;
  493.         int errcode = 0;
  494.  
  495.         for (; stream <= _lastiob; stream++) {
  496.  
  497.                 if ( (flushflag == FLUSHALL) && inuse(stream) ) {
  498.                         /* FLUSHALL functionality: fflush the read or write
  499.                          * stream and, if successful, update the count of
  500.                          * flushed streams
  501.                          */
  502.                         if ( fflush(stream) != EOF )
  503.                                 /* update count of successfully flushed
  504.                                  * streams
  505.                                  */
  506.                                 count++;
  507.                 }
  508.                 else if ( (flushflag == FFLUSHNULL) &&
  509.                 (stream->_flag & _IOWRT) ) {
  510.                         /* FFLUSHNULL functionality: fflush the write stream
  511.                          * and kept track of the error, if one occurs
  512.                          */
  513.                         if ( fflush(stream) == EOF )
  514.                                 errcode = EOF;
  515.                 }
  516.  
  517.         }
  518.  
  519.         if ( flushflag == FLUSHALL )
  520.                 return(count);
  521.         else
  522.                 return(errcode);
  523. }
  524.  
  525.  
  526. /***
  527. * _endstdio - Terminate the stdio system
  528. *
  529. *Purpose:
  530. *       Terminate the stdio system
  531. *
  532. *       (1) Flush all streams.  (Do this even if we're going to
  533. *       call fcloseall since that routine won't do anything to the
  534. *       std streams.)
  535. *
  536. *       (2) If returning to caller, close all streams.  This is
  537. *       not necessary if the exe is terminating because the OS will
  538. *       close the files for us (much more efficiently, too).
  539. *
  540. *Entry: <void>
  541. *
  542. *Exit:  <void>
  543. *
  544. *Uses:
  545. *
  546. *Exceptions:
  547. *
  548. *******************************************************************************/
  549.  
  550. void _endstdio(void)
  551.  
  552. {
  553.  
  554.         /* flush all streams */
  555.         _flushall();
  556.  
  557.         /* if in callable exit, close all streams */
  558.         if (_exitflag)
  559.                 _fcloseall();
  560.  
  561. }
  562.  
  563.  
  564. #endif  /* defined (_M_MPPC) || defined (_M_M68K) */
  565.  
  566. #endif  /* _WIN32 */
  567.