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 | FUNCTION |
---|
19 | <<ungetc>>---push data back into a stream |
---|
20 | |
---|
21 | INDEX |
---|
22 | ungetc |
---|
23 | INDEX |
---|
24 | _ungetc_r |
---|
25 | |
---|
26 | SYNOPSIS |
---|
27 | #include <stdio.h> |
---|
28 | int ungetc(int <[c]>, FILE *<[stream]>); |
---|
29 | |
---|
30 | int _ungetc_r(struct _reent *<[reent]>, int <[c]>, FILE *<[stream]>); |
---|
31 | |
---|
32 | DESCRIPTION |
---|
33 | <<ungetc>> is used to return bytes back to <[stream]> to be read again. |
---|
34 | If <[c]> is EOF, the stream is unchanged. Otherwise, the unsigned |
---|
35 | char <[c]> is put back on the stream, and subsequent reads will see |
---|
36 | the bytes pushed back in reverse order. Pushed byes are lost if the |
---|
37 | stream is repositioned, such as by <<fseek>>, <<fsetpos>>, or |
---|
38 | <<rewind>>. |
---|
39 | |
---|
40 | The underlying file is not changed, but it is possible to push back |
---|
41 | something different than what was originally read. Ungetting a |
---|
42 | character will clear the end-of-stream marker, and decrement the file |
---|
43 | position indicator. Pushing back beyond the beginning of a file gives |
---|
44 | unspecified behavior. |
---|
45 | |
---|
46 | The alternate function <<_ungetc_r>> is a reentrant version. The |
---|
47 | extra argument <[reent]> is a pointer to a reentrancy structure. |
---|
48 | |
---|
49 | RETURNS |
---|
50 | The character pushed back, or <<EOF>> on error. |
---|
51 | |
---|
52 | PORTABILITY |
---|
53 | ANSI C requires <<ungetc>>, but only requires a pushback buffer of one |
---|
54 | byte; although this implementation can handle multiple bytes, not all |
---|
55 | can. Pushing back a signed char is a common application bug. |
---|
56 | |
---|
57 | Supporting OS subroutines required: <<sbrk>>. |
---|
58 | */ |
---|
59 | |
---|
60 | #if defined(LIBC_SCCS) && !defined(lint) |
---|
61 | static char sccsid[] = "%W% (Berkeley) %G%"; |
---|
62 | #endif /* LIBC_SCCS and not lint */ |
---|
63 | |
---|
64 | #include <_ansi.h> |
---|
65 | #include <reent.h> |
---|
66 | #include <stdio.h> |
---|
67 | #include <stdlib.h> |
---|
68 | #include <string.h> |
---|
69 | #include "local.h" |
---|
70 | |
---|
71 | /* |
---|
72 | * Expand the ungetc buffer `in place'. That is, adjust fp->_p when |
---|
73 | * the buffer moves, so that it points the same distance from the end, |
---|
74 | * and move the bytes in the buffer around as necessary so that they |
---|
75 | * are all at the end (stack-style). |
---|
76 | */ |
---|
77 | |
---|
78 | /*static*/ |
---|
79 | int |
---|
80 | __submore (struct _reent *rptr, |
---|
81 | register FILE *fp) |
---|
82 | { |
---|
83 | register int i; |
---|
84 | register unsigned char *p; |
---|
85 | |
---|
86 | if (fp->_ub._base == fp->_ubuf) |
---|
87 | { |
---|
88 | /* |
---|
89 | * Get a new buffer (rather than expanding the old one). |
---|
90 | */ |
---|
91 | if ((p = (unsigned char *) _malloc_r (rptr, (size_t) BUFSIZ)) == NULL) |
---|
92 | return EOF; |
---|
93 | fp->_ub._base = p; |
---|
94 | fp->_ub._size = BUFSIZ; |
---|
95 | p += BUFSIZ - sizeof (fp->_ubuf); |
---|
96 | for (i = sizeof (fp->_ubuf); --i >= 0;) |
---|
97 | p[i] = fp->_ubuf[i]; |
---|
98 | fp->_p = p; |
---|
99 | return 0; |
---|
100 | } |
---|
101 | i = fp->_ub._size; |
---|
102 | p = (unsigned char *) _realloc_r (rptr, (void *) (fp->_ub._base), i << 1); |
---|
103 | if (p == NULL) |
---|
104 | return EOF; |
---|
105 | (void) memcpy ((void *) (p + i), (void *) p, (size_t) i); |
---|
106 | fp->_p = p + i; |
---|
107 | fp->_ub._base = p; |
---|
108 | fp->_ub._size = i << 1; |
---|
109 | return 0; |
---|
110 | } |
---|
111 | |
---|
112 | int |
---|
113 | _ungetc_r (struct _reent *rptr, |
---|
114 | int c, |
---|
115 | register FILE *fp) |
---|
116 | { |
---|
117 | if (c == EOF) |
---|
118 | return (EOF); |
---|
119 | |
---|
120 | /* Ensure stdio has been initialized. |
---|
121 | ??? Might be able to remove this as some other stdio routine should |
---|
122 | have already been called to get the char we are un-getting. */ |
---|
123 | |
---|
124 | CHECK_INIT (rptr, fp); |
---|
125 | |
---|
126 | _newlib_flockfile_start (fp); |
---|
127 | |
---|
128 | ORIENT (fp, -1); |
---|
129 | |
---|
130 | /* After ungetc, we won't be at eof anymore */ |
---|
131 | fp->_flags &= ~__SEOF; |
---|
132 | |
---|
133 | if ((fp->_flags & __SRD) == 0) |
---|
134 | { |
---|
135 | /* |
---|
136 | * Not already reading: no good unless reading-and-writing. |
---|
137 | * Otherwise, flush any current write stuff. |
---|
138 | */ |
---|
139 | if ((fp->_flags & __SRW) == 0) |
---|
140 | { |
---|
141 | _newlib_flockfile_exit (fp); |
---|
142 | return EOF; |
---|
143 | } |
---|
144 | if (fp->_flags & __SWR) |
---|
145 | { |
---|
146 | if (_fflush_r (rptr, fp)) |
---|
147 | { |
---|
148 | _newlib_flockfile_exit (fp); |
---|
149 | return EOF; |
---|
150 | } |
---|
151 | fp->_flags &= ~__SWR; |
---|
152 | fp->_w = 0; |
---|
153 | fp->_lbfsize = 0; |
---|
154 | } |
---|
155 | fp->_flags |= __SRD; |
---|
156 | } |
---|
157 | c = (unsigned char) c; |
---|
158 | |
---|
159 | /* |
---|
160 | * If we are in the middle of ungetc'ing, just continue. |
---|
161 | * This may require expanding the current ungetc buffer. |
---|
162 | */ |
---|
163 | |
---|
164 | if (HASUB (fp)) |
---|
165 | { |
---|
166 | if (fp->_r >= fp->_ub._size && __submore (rptr, fp)) |
---|
167 | { |
---|
168 | _newlib_flockfile_exit (fp); |
---|
169 | return EOF; |
---|
170 | } |
---|
171 | *--fp->_p = c; |
---|
172 | fp->_r++; |
---|
173 | _newlib_flockfile_exit (fp); |
---|
174 | return c; |
---|
175 | } |
---|
176 | |
---|
177 | /* |
---|
178 | * If we can handle this by simply backing up, do so, |
---|
179 | * but never replace the original character. |
---|
180 | * (This makes sscanf() work when scanning `const' data.) |
---|
181 | */ |
---|
182 | |
---|
183 | if (fp->_bf._base != NULL && fp->_p > fp->_bf._base && fp->_p[-1] == c) |
---|
184 | { |
---|
185 | fp->_p--; |
---|
186 | fp->_r++; |
---|
187 | _newlib_flockfile_exit (fp); |
---|
188 | return c; |
---|
189 | } |
---|
190 | |
---|
191 | /* |
---|
192 | * Create an ungetc buffer. |
---|
193 | * Initially, we will use the `reserve' buffer. |
---|
194 | */ |
---|
195 | |
---|
196 | fp->_ur = fp->_r; |
---|
197 | fp->_up = fp->_p; |
---|
198 | fp->_ub._base = fp->_ubuf; |
---|
199 | fp->_ub._size = sizeof (fp->_ubuf); |
---|
200 | fp->_ubuf[sizeof (fp->_ubuf) - 1] = c; |
---|
201 | fp->_p = &fp->_ubuf[sizeof (fp->_ubuf) - 1]; |
---|
202 | fp->_r = 1; |
---|
203 | _newlib_flockfile_end (fp); |
---|
204 | return c; |
---|
205 | } |
---|
206 | |
---|
207 | #ifndef _REENT_ONLY |
---|
208 | int |
---|
209 | ungetc (int c, |
---|
210 | register FILE *fp) |
---|
211 | { |
---|
212 | return _ungetc_r (_REENT, c, fp); |
---|
213 | } |
---|
214 | #endif /* !_REENT_ONLY */ |
---|