]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/stdio/refill.c
Merge llvm trunk r351319, resolve conflicts, and update FREEBSD-Xlist.
[FreeBSD/FreeBSD.git] / lib / libc / stdio / refill.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1990, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Chris Torek.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34
35 #if defined(LIBC_SCCS) && !defined(lint)
36 static char sccsid[] = "@(#)refill.c    8.1 (Berkeley) 6/4/93";
37 #endif /* LIBC_SCCS and not lint */
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD$");
40
41 #include "namespace.h"
42 #include <errno.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include "un-namespace.h"
46
47 #include "libc_private.h"
48 #include "local.h"
49
50 static int lflush(FILE *);
51
52 static int
53 lflush(FILE *fp)
54 {
55         int     ret = 0;
56
57         if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) {
58                 FLOCKFILE_CANCELSAFE(fp);
59                 ret = __sflush(fp);
60                 FUNLOCKFILE_CANCELSAFE();
61         }
62         return (ret);
63 }
64
65 /*
66  * Refill a stdio buffer.
67  * Return EOF on eof or error, 0 otherwise.
68  */
69 int
70 __srefill(FILE *fp)
71 {
72
73         /* make sure stdio is set up */
74         if (!__sdidinit)
75                 __sinit();
76
77         ORIENT(fp, -1);
78
79         fp->_r = 0;             /* largely a convenience for callers */
80
81         /* SysV does not make this test; take it out for compatibility */
82         if (fp->_flags & __SEOF)
83                 return (EOF);
84
85         /* if not already reading, have to be reading and writing */
86         if ((fp->_flags & __SRD) == 0) {
87                 if ((fp->_flags & __SRW) == 0) {
88                         errno = EBADF;
89                         fp->_flags |= __SERR;
90                         return (EOF);
91                 }
92                 /* switch to reading */
93                 if (fp->_flags & __SWR) {
94                         if (__sflush(fp))
95                                 return (EOF);
96                         fp->_flags &= ~__SWR;
97                         fp->_w = 0;
98                         fp->_lbfsize = 0;
99                 }
100                 fp->_flags |= __SRD;
101         } else {
102                 /*
103                  * We were reading.  If there is an ungetc buffer,
104                  * we must have been reading from that.  Drop it,
105                  * restoring the previous buffer (if any).  If there
106                  * is anything in that buffer, return.
107                  */
108                 if (HASUB(fp)) {
109                         FREEUB(fp);
110                         if ((fp->_r = fp->_ur) != 0) {
111                                 fp->_p = fp->_up;
112                                 return (0);
113                         }
114                 }
115         }
116
117         if (fp->_bf._base == NULL)
118                 __smakebuf(fp);
119
120         /*
121          * Before reading from a line buffered or unbuffered file,
122          * flush all line buffered output files, per the ANSI C
123          * standard.
124          */
125         if (fp->_flags & (__SLBF|__SNBF)) {
126                 /* Ignore this file in _fwalk to avoid potential deadlock. */
127                 fp->_flags |= __SIGN;
128                 (void) _fwalk(lflush);
129                 fp->_flags &= ~__SIGN;
130
131                 /* Now flush this file without locking it. */
132                 if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR))
133                         __sflush(fp);
134         }
135         fp->_p = fp->_bf._base;
136         fp->_r = _sread(fp, (char *)fp->_p, fp->_bf._size);
137         fp->_flags &= ~__SMOD;  /* buffer contents are again pristine */
138         if (fp->_r <= 0) {
139                 if (fp->_r == 0)
140                         fp->_flags |= __SEOF;
141                 else {
142                         fp->_r = 0;
143                         fp->_flags |= __SERR;
144                 }
145                 return (EOF);
146         }
147         return (0);
148 }