Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1693 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
 
3065 serge 70
/* Core function which does not lock file pointer.  This gets called
71
   directly from __srefill. */
1693 serge 72
int
3065 serge 73
_DEFUN(__sflush_r, (ptr, fp),
1693 serge 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
 
3065 serge 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
 
1693 serge 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 */