Subversion Repositories Kolibri OS

Rev

Rev 4874 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. /*
  19. FUNCTION
  20. <<fflush>>---flush buffered file output
  21.  
  22. INDEX
  23.         fflush
  24. INDEX
  25.         _fflush_r
  26.  
  27. ANSI_SYNOPSIS
  28.         #include <stdio.h>
  29.         int fflush(FILE *<[fp]>);
  30.  
  31.         int _fflush_r(struct _reent *<[reent]>, FILE *<[fp]>);
  32.  
  33. DESCRIPTION
  34. The <<stdio>> output functions can buffer output before delivering it
  35. to the host system, in order to minimize the overhead of system calls.
  36.  
  37. Use <<fflush>> to deliver any such pending output (for the file
  38. or stream identified by <[fp]>) to the host system.
  39.  
  40. If <[fp]> is <<NULL>>, <<fflush>> delivers pending output from all
  41. open files.
  42.  
  43. Additionally, if <[fp]> is a seekable input stream visiting a file
  44. descriptor, set the position of the file descriptor to match next
  45. unread byte, useful for obeying POSIX semantics when ending a process
  46. without consuming all input from the stream.
  47.  
  48. The alternate function <<_fflush_r>> is a reentrant version, where the
  49. extra argument <[reent]> is a pointer to a reentrancy structure, and
  50. <[fp]> must not be NULL.
  51.  
  52. RETURNS
  53. <<fflush>> returns <<0>> unless it encounters a write error; in that
  54. situation, it returns <<EOF>>.
  55.  
  56. PORTABILITY
  57. ANSI C requires <<fflush>>.  The behavior on input streams is only
  58. specified by POSIX, and not all implementations follow POSIX rules.
  59.  
  60. No supporting OS subroutines are required.
  61. */
  62.  
  63. #include <_ansi.h>
  64. #include <stdio.h>
  65. #include <errno.h>
  66. #include "local.h"
  67.  
  68. /* Flush a single file, or (if fp is NULL) all files.  */
  69.  
  70. /* Core function which does not lock file pointer.  This gets called
  71.    directly from __srefill. */
  72. int
  73. _DEFUN(__sflush_r, (ptr, fp),
  74.        struct _reent *ptr _AND
  75.        register FILE * fp)
  76. {
  77.   register unsigned char *p;
  78.   register _READ_WRITE_BUFSIZE_TYPE n;
  79.   register _READ_WRITE_RETURN_TYPE t;
  80.   short flags;
  81.  
  82.   flags = fp->_flags;
  83.   if ((flags & __SWR) == 0)
  84.     {
  85. #ifdef _FSEEK_OPTIMIZATION
  86.       /* For a read stream, an fflush causes the next seek to be
  87.          unoptimized (i.e. forces a system-level seek).  This conforms
  88.          to the POSIX and SUSv3 standards.  */
  89.       fp->_flags |= __SNPT;
  90. #endif
  91.  
  92.       /* For a seekable stream with buffered read characters, we will attempt
  93.          a seek to the current position now.  A subsequent read will then get
  94.          the next byte from the file rather than the buffer.  This conforms
  95.          to the POSIX and SUSv3 standards.  Note that the standards allow
  96.          this seek to be deferred until necessary, but we choose to do it here
  97.          to make the change simpler, more contained, and less likely
  98.          to miss a code scenario.  */
  99.       if ((fp->_r > 0 || fp->_ur > 0) && fp->_seek != NULL)
  100.         {
  101.           int tmp_errno;
  102. #ifdef __LARGE64_FILES
  103.           _fpos64_t curoff;
  104. #else
  105.           _fpos_t curoff;
  106. #endif
  107.  
  108.           /* Save last errno and set errno to 0, so we can check if a device
  109.              returns with a valid position -1.  We restore the last errno if
  110.              no other error condition has been encountered. */
  111.           tmp_errno = ptr->_errno;
  112.           ptr->_errno = 0;
  113.           /* Get the physical position we are at in the file.  */
  114.           if (fp->_flags & __SOFF)
  115.             curoff = fp->_offset;
  116.           else
  117.             {
  118.               /* We don't know current physical offset, so ask for it.
  119.                  Only ESPIPE and EINVAL are ignorable.  */
  120. #ifdef __LARGE64_FILES
  121.               if (fp->_flags & __SL64)
  122.                 curoff = fp->_seek64 (ptr, fp->_cookie, 0, SEEK_CUR);
  123.               else
  124. #endif
  125.                 curoff = fp->_seek (ptr, fp->_cookie, 0, SEEK_CUR);
  126.               if (curoff == -1L && ptr->_errno != 0)
  127.                 {
  128.                   int result = EOF;
  129.                   if (ptr->_errno == ESPIPE || ptr->_errno == EINVAL)
  130.                     {
  131.                       result = 0;
  132.                       ptr->_errno = tmp_errno;
  133.                     }
  134.                   else
  135.                     fp->_flags |= __SERR;
  136.                   return result;
  137.                 }
  138.             }
  139.           if (fp->_flags & __SRD)
  140.             {
  141.               /* Current offset is at end of buffer.  Compensate for
  142.                  characters not yet read.  */
  143.               curoff -= fp->_r;
  144.               if (HASUB (fp))
  145.                 curoff -= fp->_ur;
  146.             }
  147.           /* Now physically seek to after byte last read.  */
  148. #ifdef __LARGE64_FILES
  149.           if (fp->_flags & __SL64)
  150.             curoff = fp->_seek64 (ptr, fp->_cookie, curoff, SEEK_SET);
  151.           else
  152. #endif
  153.             curoff = fp->_seek (ptr, fp->_cookie, curoff, SEEK_SET);
  154.           if (curoff != -1 || ptr->_errno == 0
  155.               || ptr->_errno == ESPIPE || ptr->_errno == EINVAL)
  156.             {
  157.               /* Seek successful or ignorable error condition.
  158.                  We can clear read buffer now.  */
  159. #ifdef _FSEEK_OPTIMIZATION
  160.               fp->_flags &= ~__SNPT;
  161. #endif
  162.               fp->_r = 0;
  163.               fp->_p = fp->_bf._base;
  164.               if ((fp->_flags & __SOFF) && (curoff != -1 || ptr->_errno == 0))
  165.                 fp->_offset = curoff;
  166.               ptr->_errno = tmp_errno;
  167.               if (HASUB (fp))
  168.                 FREEUB (ptr, fp);
  169.             }
  170.           else
  171.             {
  172.               fp->_flags |= __SERR;
  173.               return EOF;
  174.             }
  175.         }
  176.       return 0;
  177.     }
  178.   if ((p = fp->_bf._base) == NULL)
  179.     {
  180.       /* Nothing to flush.  */
  181.       return 0;
  182.     }
  183.   n = fp->_p - p;               /* write this much */
  184.  
  185.   /*
  186.    * Set these immediately to avoid problems with longjmp
  187.    * and to allow exchange buffering (via setvbuf) in user
  188.    * write function.
  189.    */
  190.   fp->_p = p;
  191.   fp->_w = flags & (__SLBF | __SNBF) ? 0 : fp->_bf._size;
  192.  
  193.   while (n > 0)
  194.     {
  195.       t = fp->_write (ptr, fp->_cookie, (char *) p, n);
  196.       if (t <= 0)
  197.         {
  198.           fp->_flags |= __SERR;
  199.           return EOF;
  200.         }
  201.       p += t;
  202.       n -= t;
  203.     }
  204.   return 0;
  205. }
  206.  
  207. int
  208. _DEFUN(_fflush_r, (ptr, fp),
  209.        struct _reent *ptr _AND
  210.        register FILE * fp)
  211. {
  212.   int ret;
  213.  
  214. #ifdef _REENT_SMALL
  215.   /* For REENT_SMALL platforms, it is possible we are being
  216.      called for the first time on a std stream.  This std
  217.      stream can belong to a reentrant struct that is not
  218.      _REENT.  If CHECK_INIT gets called below based on _REENT,
  219.      we will end up changing said file pointers to the equivalent
  220.      std stream off of _REENT.  This causes unexpected behavior if
  221.      there is any data to flush on the _REENT std stream.  There
  222.      are two alternatives to fix this:  1) make a reentrant fflush
  223.      or 2) simply recognize that this file has nothing to flush
  224.      and return immediately before performing a CHECK_INIT.  Choice
  225.      2 is implemented here due to its simplicity.  */
  226.   if (fp->_bf._base == NULL)
  227.     return 0;
  228. #endif /* _REENT_SMALL  */
  229.  
  230.   CHECK_INIT (ptr, fp);
  231.  
  232.   if (!fp->_flags)
  233.     return 0;
  234.  
  235.   _newlib_flockfile_start (fp);
  236.   ret = __sflush_r (ptr, fp);
  237.   _newlib_flockfile_end (fp);
  238.   return ret;
  239. }
  240.  
  241. #ifndef _REENT_ONLY
  242.  
  243. int
  244. _DEFUN(fflush, (fp),
  245.        register FILE * fp)
  246. {
  247.   if (fp == NULL)
  248.     return _fwalk_reent (_GLOBAL_REENT, _fflush_r);
  249.  
  250.   return _fflush_r (_REENT, fp);
  251. }
  252.  
  253. #endif /* _REENT_ONLY */
  254.