Subversion Repositories Kolibri OS

Rev

Rev 4874 | Go to most recent revision | 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
20
<>---flush buffered file output
21
 
22
INDEX
23
	fflush
24
INDEX
25
	_fflush_r
26
 
27
ANSI_SYNOPSIS
28
	#include 
29
	int fflush(FILE *<[fp]>);
30
 
31
	int _fflush_r(struct _reent *<[reent]>, FILE *<[fp]>);
32
 
33
DESCRIPTION
34
The <> 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 <> to deliver any such pending output (for the file
38
or stream identified by <[fp]>) to the host system.
39
 
40
If <[fp]> is <>, <> 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
<> returns <<0>> unless it encounters a write error; in that
54
situation, it returns <>.
55
 
56
PORTABILITY
57
ANSI C requires <>.  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 
65
#include 
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;
4921 Serge 78
  register _READ_WRITE_BUFSIZE_TYPE n;
79
  register _READ_WRITE_RETURN_TYPE t;
80
  short flags;
4349 Serge 81
 
4921 Serge 82
  flags = fp->_flags;
83
  if ((flags & __SWR) == 0)
4349 Serge 84
    {
4921 Serge 85
#ifdef _FSEEK_OPTIMIZATION
4349 Serge 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;
4921 Serge 90
#endif
4349 Serge 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.  */
4921 Serge 159
#ifdef _FSEEK_OPTIMIZATION
4349 Serge 160
	      fp->_flags &= ~__SNPT;
4921 Serge 161
#endif
4349 Serge 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;
4921 Serge 191
  fp->_w = flags & (__SLBF | __SNBF) ? 0 : fp->_bf._size;
4349 Serge 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
 
4921 Serge 235
  _newlib_flockfile_start (fp);
4349 Serge 236
  ret = __sflush_r (ptr, fp);
4921 Serge 237
  _newlib_flockfile_end (fp);
4349 Serge 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 */