ungetc.c revision 71579
1353095Skevans/*-
2353095Skevans * Copyright (c) 1990, 1993
3353095Skevans *	The Regents of the University of California.  All rights reserved.
4353095Skevans *
5353095Skevans * This code is derived from software contributed to Berkeley by
6353095Skevans * Chris Torek.
7353095Skevans *
8353095Skevans * Redistribution and use in source and binary forms, with or without
9353095Skevans * modification, are permitted provided that the following conditions
10353095Skevans * are met:
11353095Skevans * 1. Redistributions of source code must retain the above copyright
12353095Skevans *    notice, this list of conditions and the following disclaimer.
13353095Skevans * 2. Redistributions in binary form must reproduce the above copyright
14353095Skevans *    notice, this list of conditions and the following disclaimer in the
15353095Skevans *    documentation and/or other materials provided with the distribution.
16353095Skevans * 3. All advertising materials mentioning features or use of this software
17353095Skevans *    must display the following acknowledgement:
18353095Skevans *	This product includes software developed by the University of
19353095Skevans *	California, Berkeley and its contributors.
20353095Skevans * 4. Neither the name of the University nor the names of its contributors
21353095Skevans *    may be used to endorse or promote products derived from this software
22353095Skevans *    without specific prior written permission.
23353095Skevans *
24353095Skevans * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25353095Skevans * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26353095Skevans * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27353095Skevans * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28353095Skevans * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29353095Skevans * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30353095Skevans * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31353095Skevans * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32353095Skevans * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33353095Skevans * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34353095Skevans * SUCH DAMAGE.
35353095Skevans */
36353095Skevans
37353095Skevans#if defined(LIBC_SCCS) && !defined(lint)
38353095Skevans#if 0
39353095Skevansstatic char sccsid[] = "@(#)ungetc.c	8.2 (Berkeley) 11/3/93";
40353095Skevans#endif
41353095Skevansstatic const char rcsid[] =
42353095Skevans  "$FreeBSD: head/lib/libc/stdio/ungetc.c 71579 2001-01-24 13:01:12Z deischen $";
43353095Skevans#endif /* LIBC_SCCS and not lint */
44353095Skevans
45353095Skevans#include "namespace.h"
46353095Skevans#include <stdio.h>
47353095Skevans#include <stdlib.h>
48353095Skevans#include <string.h>
49353095Skevans#include "un-namespace.h"
50353095Skevans#include "local.h"
51353095Skevans#include "libc_private.h"
52353095Skevans
53353095Skevansstatic int __submore __P((FILE *));
54353095Skevans
55353095Skevans/*
56353095Skevans * Expand the ungetc buffer `in place'.  That is, adjust fp->_p when
57353095Skevans * the buffer moves, so that it points the same distance from the end,
58353095Skevans * and move the bytes in the buffer around as necessary so that they
59353095Skevans * are all at the end (stack-style).
60353095Skevans */
61353095Skevansstatic int
62353095Skevans__submore(FILE *fp)
63353095Skevans{
64353095Skevans	int i;
65353095Skevans	unsigned char *p;
66353095Skevans
67353095Skevans	if (fp->_ub._base == fp->_ubuf) {
68353095Skevans		/*
69353095Skevans		 * Get a new buffer (rather than expanding the old one).
70353095Skevans		 */
71353095Skevans		if ((p = malloc((size_t)BUFSIZ)) == NULL)
72353095Skevans			return (EOF);
73353095Skevans		fp->_ub._base = p;
74353095Skevans		fp->_ub._size = BUFSIZ;
75353095Skevans		p += BUFSIZ - sizeof(fp->_ubuf);
76353095Skevans		for (i = sizeof(fp->_ubuf); --i >= 0;)
77353095Skevans			p[i] = fp->_ubuf[i];
78353095Skevans		fp->_p = p;
79353095Skevans		return (0);
80353095Skevans	}
81353095Skevans	i = fp->_ub._size;
82353095Skevans	p = realloc(fp->_ub._base, (size_t)(i << 1));
83353095Skevans	if (p == NULL)
84353095Skevans		return (EOF);
85353095Skevans	/* no overlap (hence can use memcpy) because we doubled the size */
86353095Skevans	(void)memcpy((void *)(p + i), (void *)p, (size_t)i);
87353095Skevans	fp->_p = p + i;
88353095Skevans	fp->_ub._base = p;
89353095Skevans	fp->_ub._size = i << 1;
90353095Skevans	return (0);
91353095Skevans}
92353095Skevans
93353095Skevans/*
94353095Skevans * MT-safe version
95353095Skevans */
96353095Skevansint
97353095Skevansungetc(int c, FILE *fp)
98353095Skevans{
99353095Skevans	int ret;
100353095Skevans
101353095Skevans	if (c == EOF)
102353095Skevans		return (EOF);
103353095Skevans	if (!__sdidinit)
104353095Skevans		__sinit();
105353095Skevans	FLOCKFILE(fp);
106353095Skevans	ret = __ungetc(c, fp);
107353095Skevans	FUNLOCKFILE(fp);
108353095Skevans	return (ret);
109353095Skevans}
110353095Skevans
111353095Skevans/*
112353095Skevans * Non-MT-safe version
113353095Skevans */
114353095Skevansint
115353095Skevans__ungetc(int c, FILE *fp)
116353095Skevans{
117353095Skevans	if (c == EOF)
118353095Skevans		return (EOF);
119353095Skevans	if ((fp->_flags & __SRD) == 0) {
120353095Skevans		/*
121353095Skevans		 * Not already reading: no good unless reading-and-writing.
122353095Skevans		 * Otherwise, flush any current write stuff.
123353095Skevans		 */
124353095Skevans		if ((fp->_flags & __SRW) == 0)
125353095Skevans			return (EOF);
126353095Skevans		if (fp->_flags & __SWR) {
127353095Skevans			if (__sflush(fp))
128353095Skevans				return (EOF);
129353095Skevans			fp->_flags &= ~__SWR;
130353095Skevans			fp->_w = 0;
131353095Skevans			fp->_lbfsize = 0;
132353095Skevans		}
133353095Skevans		fp->_flags |= __SRD;
134353095Skevans	}
135353095Skevans	c = (unsigned char)c;
136353095Skevans
137353095Skevans	/*
138353095Skevans	 * If we are in the middle of ungetc'ing, just continue.
139353095Skevans	 * This may require expanding the current ungetc buffer.
140353095Skevans	 */
141353095Skevans	if (HASUB(fp)) {
142		if (fp->_r >= fp->_ub._size && __submore(fp))
143			return (EOF);
144		*--fp->_p = c;
145		fp->_r++;
146		return (c);
147	}
148	fp->_flags &= ~__SEOF;
149
150	/*
151	 * If we can handle this by simply backing up, do so,
152	 * but never replace the original character.
153	 * (This makes sscanf() work when scanning `const' data.)
154	 */
155	if (fp->_bf._base != NULL && fp->_p > fp->_bf._base &&
156	    fp->_p[-1] == c) {
157		fp->_p--;
158		fp->_r++;
159		return (c);
160	}
161
162	/*
163	 * Create an ungetc buffer.
164	 * Initially, we will use the `reserve' buffer.
165	 */
166	fp->_ur = fp->_r;
167	fp->_up = fp->_p;
168	fp->_ub._base = fp->_ubuf;
169	fp->_ub._size = sizeof(fp->_ubuf);
170	fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
171	fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1];
172	fp->_r = 1;
173	return (c);
174}
175