[444] | 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 */ |
---|