Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | 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 int n, t;
  79.  
  80.   t = fp->_flags;
  81.   if ((t & __SWR) == 0)
  82.     {
  83.       /* For a read stream, an fflush causes the next seek to be
  84.          unoptimized (i.e. forces a system-level seek).  This conforms
  85.          to the POSIX and SUSv3 standards.  */
  86.       fp->_flags |= __SNPT;
  87.  
  88.       /* For a seekable stream with buffered read characters, we will attempt
  89.          a seek to the current position now.  A subsequent read will then get
  90.          the next byte from the file rather than the buffer.  This conforms
  91.          to the POSIX and SUSv3 standards.  Note that the standards allow
  92.          this seek to be deferred until necessary, but we choose to do it here
  93.          to make the change simpler, more contained, and less likely
  94.          to miss a code scenario.  */
  95.       if ((fp->_r > 0 || fp->_ur > 0) && fp->_seek != NULL)
  96.         {
  97.           int tmp_errno;
  98. #ifdef __LARGE64_FILES
  99.           _fpos64_t curoff;
  100. #else
  101.           _fpos_t curoff;
  102. #endif
  103.  
  104.           /* Save last errno and set errno to 0, so we can check if a device
  105.              returns with a valid position -1.  We restore the last errno if
  106.              no other error condition has been encountered. */
  107.           tmp_errno = ptr->_errno;
  108.           ptr->_errno = 0;
  109.           /* Get the physical position we are at in the file.  */
  110.           if (fp->_flags & __SOFF)
  111.             curoff = fp->_offset;
  112.           else
  113.             {
  114.               /* We don't know current physical offset, so ask for it.
  115.                  Only ESPIPE and EINVAL are ignorable.  */
  116. #ifdef __LARGE64_FILES
  117.               if (fp->_flags & __SL64)
  118.                 curoff = fp->_seek64 (ptr, fp->_cookie, 0, SEEK_CUR);
  119.               else
  120. #endif
  121.                 curoff = fp->_seek (ptr, fp->_cookie, 0, SEEK_CUR);
  122.               if (curoff == -1L && ptr->_errno != 0)
  123.                 {
  124.                   int result = EOF;
  125.                   if (ptr->_errno == ESPIPE || ptr->_errno == EINVAL)
  126.                     {
  127.                       result = 0;
  128.                       ptr->_errno = tmp_errno;
  129.                     }
  130.                   else
  131.                     fp->_flags |= __SERR;
  132.                   return result;
  133.                 }
  134.             }
  135.           if (fp->_flags & __SRD)
  136.             {
  137.               /* Current offset is at end of buffer.  Compensate for
  138.                  characters not yet read.  */
  139.               curoff -= fp->_r;
  140.               if (HASUB (fp))
  141.                 curoff -= fp->_ur;
  142.             }
  143.           /* Now physically seek to after byte last read.  */
  144. #ifdef __LARGE64_FILES
  145.           if (fp->_flags & __SL64)
  146.             curoff = fp->_seek64 (ptr, fp->_cookie, curoff, SEEK_SET);
  147.           else
  148. #endif
  149.             curoff = fp->_seek (ptr, fp->_cookie, curoff, SEEK_SET);
  150.           if (curoff != -1 || ptr->_errno == 0
  151.               || ptr->_errno == ESPIPE || ptr->_errno == EINVAL)
  152.             {
  153.               /* Seek successful or ignorable error condition.
  154.                  We can clear read buffer now.  */
  155.               fp->_flags &= ~__SNPT;
  156.               fp->_r = 0;
  157.               fp->_p = fp->_bf._base;
  158.               if ((fp->_flags & __SOFF) && (curoff != -1 || ptr->_errno == 0))
  159.                 fp->_offset = curoff;
  160.               ptr->_errno = tmp_errno;
  161.               if (HASUB (fp))
  162.                 FREEUB (ptr, fp);
  163.             }
  164.           else
  165.             {
  166.               fp->_flags |= __SERR;
  167.               return EOF;
  168.             }
  169.         }
  170.       return 0;
  171.     }
  172.   if ((p = fp->_bf._base) == NULL)
  173.     {
  174.       /* Nothing to flush.  */
  175.       return 0;
  176.     }
  177.   n = fp->_p - p;               /* write this much */
  178.  
  179.   /*
  180.    * Set these immediately to avoid problems with longjmp
  181.    * and to allow exchange buffering (via setvbuf) in user
  182.    * write function.
  183.    */
  184.   fp->_p = p;
  185.   fp->_w = t & (__SLBF | __SNBF) ? 0 : fp->_bf._size;
  186.  
  187.   while (n > 0)
  188.     {
  189.       t = fp->_write (ptr, fp->_cookie, (char *) p, n);
  190.       if (t <= 0)
  191.         {
  192.           fp->_flags |= __SERR;
  193.           return EOF;
  194.         }
  195.       p += t;
  196.       n -= t;
  197.     }
  198.   return 0;
  199. }
  200.  
  201. int
  202. _DEFUN(_fflush_r, (ptr, fp),
  203.        struct _reent *ptr _AND
  204.        register FILE * fp)
  205. {
  206.   int ret;
  207.  
  208. #ifdef _REENT_SMALL
  209.   /* For REENT_SMALL platforms, it is possible we are being
  210.      called for the first time on a std stream.  This std
  211.      stream can belong to a reentrant struct that is not
  212.      _REENT.  If CHECK_INIT gets called below based on _REENT,
  213.      we will end up changing said file pointers to the equivalent
  214.      std stream off of _REENT.  This causes unexpected behavior if
  215.      there is any data to flush on the _REENT std stream.  There
  216.      are two alternatives to fix this:  1) make a reentrant fflush
  217.      or 2) simply recognize that this file has nothing to flush
  218.      and return immediately before performing a CHECK_INIT.  Choice
  219.      2 is implemented here due to its simplicity.  */
  220.   if (fp->_bf._base == NULL)
  221.     return 0;
  222. #endif /* _REENT_SMALL  */
  223.  
  224.   CHECK_INIT (ptr, fp);
  225.  
  226.   if (!fp->_flags)
  227.     return 0;
  228.  
  229.   _flockfile (fp);
  230.   ret = __sflush_r (ptr, fp);
  231.   _funlockfile (fp);
  232.   return ret;
  233. }
  234.  
  235. #ifndef _REENT_ONLY
  236.  
  237. int
  238. _DEFUN(fflush, (fp),
  239.        register FILE * fp)
  240. {
  241.   if (fp == NULL)
  242.     return _fwalk_reent (_GLOBAL_REENT, _fflush_r);
  243.  
  244.   return _fflush_r (_REENT, fp);
  245. }
  246.  
  247. #endif /* _REENT_ONLY */
  248.