Subversion Repositories Kolibri OS

Rev

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