Subversion Repositories Kolibri OS

Rev

Rev 4921 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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
6099 serge 20
<>, <>---flush buffered file output
4349 Serge 21
 
22
INDEX
23
	fflush
24
INDEX
6099 serge 25
	fflush_unlocked
26
INDEX
4349 Serge 27
	_fflush_r
6099 serge 28
INDEX
29
	_fflush_unlocked_r
4349 Serge 30
 
31
ANSI_SYNOPSIS
32
	#include 
33
	int fflush(FILE *<[fp]>);
34
 
6099 serge 35
	#define _BSD_SOURCE
36
	#include 
37
	int fflush_unlocked(FILE *<[fp]>);
38
 
39
	#include 
4349 Serge 40
	int _fflush_r(struct _reent *<[reent]>, FILE *<[fp]>);
41
 
6099 serge 42
	#define _BSD_SOURCE
43
	#include 
44
	int _fflush_unlocked_r(struct _reent *<[reent]>, FILE *<[fp]>);
45
 
4349 Serge 46
DESCRIPTION
47
The <> output functions can buffer output before delivering it
48
to the host system, in order to minimize the overhead of system calls.
49
 
50
Use <> to deliver any such pending output (for the file
51
or stream identified by <[fp]>) to the host system.
52
 
53
If <[fp]> is <>, <> delivers pending output from all
54
open files.
55
 
56
Additionally, if <[fp]> is a seekable input stream visiting a file
57
descriptor, set the position of the file descriptor to match next
58
unread byte, useful for obeying POSIX semantics when ending a process
59
without consuming all input from the stream.
60
 
6099 serge 61
<> is a non-thread-safe version of <>.
62
<> may only safely be used within a scope
63
protected by flockfile() (or ftrylockfile()) and funlockfile().  This
64
function may safely be used in a multi-threaded program if and only
65
if they are called while the invoking thread owns the (FILE *)
66
object, as is the case after a successful call to the flockfile() or
67
ftrylockfile() functions.  If threads are disabled, then
68
<> is equivalent to <>.
4349 Serge 69
 
6099 serge 70
The alternate functions <<_fflush_r>> and <<_fflush_unlocked_r>> are
71
reentrant versions, where the extra argument <[reent]> is a pointer to
72
a reentrancy structure, and <[fp]> must not be NULL.
73
 
4349 Serge 74
RETURNS
75
<> returns <<0>> unless it encounters a write error; in that
76
situation, it returns <>.
77
 
78
PORTABILITY
79
ANSI C requires <>.  The behavior on input streams is only
80
specified by POSIX, and not all implementations follow POSIX rules.
81
 
6099 serge 82
<> is a BSD extension also provided by GNU libc.
83
 
4349 Serge 84
No supporting OS subroutines are required.
85
*/
86
 
87
#include <_ansi.h>
88
#include 
89
#include 
90
#include "local.h"
91
 
6099 serge 92
#ifdef __IMPL_UNLOCKED__
93
#define _fflush_r _fflush_unlocked_r
94
#define fflush fflush_unlocked
95
#endif
96
 
97
#ifndef __IMPL_UNLOCKED__
4349 Serge 98
/* Flush a single file, or (if fp is NULL) all files.  */
99
 
100
/* Core function which does not lock file pointer.  This gets called
101
   directly from __srefill. */
102
int
103
_DEFUN(__sflush_r, (ptr, fp),
104
       struct _reent *ptr _AND
105
       register FILE * fp)
106
{
107
  register unsigned char *p;
4921 Serge 108
  register _READ_WRITE_BUFSIZE_TYPE n;
109
  register _READ_WRITE_RETURN_TYPE t;
110
  short flags;
4349 Serge 111
 
4921 Serge 112
  flags = fp->_flags;
113
  if ((flags & __SWR) == 0)
4349 Serge 114
    {
4921 Serge 115
#ifdef _FSEEK_OPTIMIZATION
4349 Serge 116
      /* For a read stream, an fflush causes the next seek to be
117
         unoptimized (i.e. forces a system-level seek).  This conforms
118
         to the POSIX and SUSv3 standards.  */
119
      fp->_flags |= __SNPT;
4921 Serge 120
#endif
4349 Serge 121
 
122
      /* For a seekable stream with buffered read characters, we will attempt
123
         a seek to the current position now.  A subsequent read will then get
124
         the next byte from the file rather than the buffer.  This conforms
125
         to the POSIX and SUSv3 standards.  Note that the standards allow
126
         this seek to be deferred until necessary, but we choose to do it here
127
         to make the change simpler, more contained, and less likely
128
         to miss a code scenario.  */
129
      if ((fp->_r > 0 || fp->_ur > 0) && fp->_seek != NULL)
130
	{
131
	  int tmp_errno;
132
#ifdef __LARGE64_FILES
133
	  _fpos64_t curoff;
134
#else
135
	  _fpos_t curoff;
136
#endif
137
 
138
	  /* Save last errno and set errno to 0, so we can check if a device
139
	     returns with a valid position -1.  We restore the last errno if
140
	     no other error condition has been encountered. */
141
	  tmp_errno = ptr->_errno;
142
	  ptr->_errno = 0;
143
	  /* Get the physical position we are at in the file.  */
144
	  if (fp->_flags & __SOFF)
145
	    curoff = fp->_offset;
146
	  else
147
	    {
148
	      /* We don't know current physical offset, so ask for it.
149
		 Only ESPIPE and EINVAL are ignorable.  */
150
#ifdef __LARGE64_FILES
151
	      if (fp->_flags & __SL64)
152
		curoff = fp->_seek64 (ptr, fp->_cookie, 0, SEEK_CUR);
153
	      else
154
#endif
155
		curoff = fp->_seek (ptr, fp->_cookie, 0, SEEK_CUR);
156
	      if (curoff == -1L && ptr->_errno != 0)
157
		{
158
		  int result = EOF;
159
		  if (ptr->_errno == ESPIPE || ptr->_errno == EINVAL)
160
		    {
161
		      result = 0;
162
		      ptr->_errno = tmp_errno;
163
		    }
164
		  else
165
		    fp->_flags |= __SERR;
166
		  return result;
167
		}
168
            }
169
          if (fp->_flags & __SRD)
170
            {
171
              /* Current offset is at end of buffer.  Compensate for
172
                 characters not yet read.  */
173
              curoff -= fp->_r;
174
              if (HASUB (fp))
175
                curoff -= fp->_ur;
176
            }
177
	  /* Now physically seek to after byte last read.  */
178
#ifdef __LARGE64_FILES
179
	  if (fp->_flags & __SL64)
180
	    curoff = fp->_seek64 (ptr, fp->_cookie, curoff, SEEK_SET);
181
	  else
182
#endif
183
	    curoff = fp->_seek (ptr, fp->_cookie, curoff, SEEK_SET);
184
	  if (curoff != -1 || ptr->_errno == 0
185
	      || ptr->_errno == ESPIPE || ptr->_errno == EINVAL)
186
	    {
187
	      /* Seek successful or ignorable error condition.
188
		 We can clear read buffer now.  */
4921 Serge 189
#ifdef _FSEEK_OPTIMIZATION
4349 Serge 190
	      fp->_flags &= ~__SNPT;
4921 Serge 191
#endif
4349 Serge 192
	      fp->_r = 0;
193
	      fp->_p = fp->_bf._base;
194
	      if ((fp->_flags & __SOFF) && (curoff != -1 || ptr->_errno == 0))
195
		fp->_offset = curoff;
196
	      ptr->_errno = tmp_errno;
197
	      if (HASUB (fp))
198
		FREEUB (ptr, fp);
199
	    }
200
	  else
201
	    {
202
	      fp->_flags |= __SERR;
203
	      return EOF;
204
	    }
205
	}
206
      return 0;
207
    }
208
  if ((p = fp->_bf._base) == NULL)
209
    {
210
      /* Nothing to flush.  */
211
      return 0;
212
    }
213
  n = fp->_p - p;		/* write this much */
214
 
215
  /*
216
   * Set these immediately to avoid problems with longjmp
217
   * and to allow exchange buffering (via setvbuf) in user
218
   * write function.
219
   */
220
  fp->_p = p;
4921 Serge 221
  fp->_w = flags & (__SLBF | __SNBF) ? 0 : fp->_bf._size;
4349 Serge 222
 
223
  while (n > 0)
224
    {
225
      t = fp->_write (ptr, fp->_cookie, (char *) p, n);
226
      if (t <= 0)
227
	{
228
          fp->_flags |= __SERR;
229
          return EOF;
230
	}
231
      p += t;
232
      n -= t;
233
    }
234
  return 0;
235
}
236
 
6099 serge 237
#ifdef _STDIO_BSD_SEMANTICS
238
/* Called from _cleanup_r.  At exit time, we don't need file locking,
239
   and we don't want to move the underlying file pointer unless we're
240
   writing. */
4349 Serge 241
int
6099 serge 242
_DEFUN(__sflushw_r, (ptr, fp),
243
       struct _reent *ptr _AND
244
       register FILE *fp)
245
{
246
  return (fp->_flags & __SWR) ?  __sflush_r (ptr, fp) : 0;
247
}
248
#endif
249
 
250
#endif /* __IMPL_UNLOCKED__ */
251
 
252
int
4349 Serge 253
_DEFUN(_fflush_r, (ptr, fp),
254
       struct _reent *ptr _AND
255
       register FILE * fp)
256
{
257
  int ret;
258
 
259
#ifdef _REENT_SMALL
260
  /* For REENT_SMALL platforms, it is possible we are being
261
     called for the first time on a std stream.  This std
262
     stream can belong to a reentrant struct that is not
263
     _REENT.  If CHECK_INIT gets called below based on _REENT,
264
     we will end up changing said file pointers to the equivalent
265
     std stream off of _REENT.  This causes unexpected behavior if
266
     there is any data to flush on the _REENT std stream.  There
267
     are two alternatives to fix this:  1) make a reentrant fflush
268
     or 2) simply recognize that this file has nothing to flush
269
     and return immediately before performing a CHECK_INIT.  Choice
270
     2 is implemented here due to its simplicity.  */
271
  if (fp->_bf._base == NULL)
272
    return 0;
273
#endif /* _REENT_SMALL  */
274
 
275
  CHECK_INIT (ptr, fp);
276
 
277
  if (!fp->_flags)
278
    return 0;
279
 
4921 Serge 280
  _newlib_flockfile_start (fp);
4349 Serge 281
  ret = __sflush_r (ptr, fp);
4921 Serge 282
  _newlib_flockfile_end (fp);
4349 Serge 283
  return ret;
284
}
285
 
286
#ifndef _REENT_ONLY
287
 
288
int
289
_DEFUN(fflush, (fp),
290
       register FILE * fp)
291
{
292
  if (fp == NULL)
293
    return _fwalk_reent (_GLOBAL_REENT, _fflush_r);
294
 
295
  return _fflush_r (_REENT, fp);
296
}
297
 
298
#endif /* _REENT_ONLY */