xref: /csrg-svn/lib/libc/stdio/ungetc.c (revision 64810)
146108Sbostic /*-
261180Sbostic  * Copyright (c) 1990, 1993
361180Sbostic  *	The Regents of the University of California.  All rights reserved.
446108Sbostic  *
546108Sbostic  * This code is derived from software contributed to Berkeley by
646108Sbostic  * Chris Torek.
746108Sbostic  *
846108Sbostic  * %sccs.include.redist.c%
946108Sbostic  */
1046108Sbostic 
1126665Sdonn #if defined(LIBC_SCCS) && !defined(lint)
12*64810Storek static char sccsid[] = "@(#)ungetc.c	8.2 (Berkeley) 11/03/93";
1346108Sbostic #endif /* LIBC_SCCS and not lint */
1415084Ssam 
152037Swnj #include <stdio.h>
1646108Sbostic #include <stdlib.h>
1746108Sbostic #include <string.h>
1846108Sbostic #include "local.h"
192037Swnj 
2046108Sbostic /*
2146108Sbostic  * Expand the ungetc buffer `in place'.  That is, adjust fp->_p when
2246108Sbostic  * the buffer moves, so that it points the same distance from the end,
2346108Sbostic  * and move the bytes in the buffer around as necessary so that they
2446108Sbostic  * are all at the end (stack-style).
2546108Sbostic  */
2646108Sbostic static
__submore(fp)2746108Sbostic __submore(fp)
2846108Sbostic 	register FILE *fp;
292037Swnj {
3046108Sbostic 	register int i;
3146108Sbostic 	register unsigned char *p;
3246108Sbostic 
3346108Sbostic 	if (fp->_ub._base == fp->_ubuf) {
3446108Sbostic 		/*
3546108Sbostic 		 * Get a new buffer (rather than expanding the old one).
3646108Sbostic 		 */
3746108Sbostic 		if ((p = malloc((size_t)BUFSIZ)) == NULL)
3846108Sbostic 			return (EOF);
3946108Sbostic 		fp->_ub._base = p;
4046108Sbostic 		fp->_ub._size = BUFSIZ;
4146108Sbostic 		p += BUFSIZ - sizeof(fp->_ubuf);
4246108Sbostic 		for (i = sizeof(fp->_ubuf); --i >= 0;)
4346108Sbostic 			p[i] = fp->_ubuf[i];
4446108Sbostic 		fp->_p = p;
4546108Sbostic 		return (0);
4646108Sbostic 	}
4746108Sbostic 	i = fp->_ub._size;
4846108Sbostic 	p = realloc(fp->_ub._base, i << 1);
4946108Sbostic 	if (p == NULL)
5017951Sserge 		return (EOF);
5158451Storek 	/* no overlap (hence can use memcpy) because we doubled the size */
5258451Storek 	(void)memcpy((void *)(p + i), (void *)p, (size_t)i);
5346108Sbostic 	fp->_p = p + i;
5446108Sbostic 	fp->_ub._base = p;
5546108Sbostic 	fp->_ub._size = i << 1;
5646108Sbostic 	return (0);
5746108Sbostic }
5817951Sserge 
ungetc(c,fp)5946108Sbostic ungetc(c, fp)
6046108Sbostic 	int c;
6146108Sbostic 	register FILE *fp;
6246108Sbostic {
6346108Sbostic 	if (c == EOF)
6446108Sbostic 		return (EOF);
6546108Sbostic 	if (!__sdidinit)
6646108Sbostic 		__sinit();
6746108Sbostic 	if ((fp->_flags & __SRD) == 0) {
6846108Sbostic 		/*
6946108Sbostic 		 * Not already reading: no good unless reading-and-writing.
7046108Sbostic 		 * Otherwise, flush any current write stuff.
7146108Sbostic 		 */
7246108Sbostic 		if ((fp->_flags & __SRW) == 0)
7326938Sbloom 			return (EOF);
7446108Sbostic 		if (fp->_flags & __SWR) {
7546219Sbostic 			if (__sflush(fp))
7646108Sbostic 				return (EOF);
7746108Sbostic 			fp->_flags &= ~__SWR;
7846108Sbostic 			fp->_w = 0;
7946108Sbostic 			fp->_lbfsize = 0;
8046108Sbostic 		}
8146108Sbostic 		fp->_flags |= __SRD;
8246108Sbostic 	}
8346108Sbostic 	c = (unsigned char)c;
8417951Sserge 
8546108Sbostic 	/*
8646108Sbostic 	 * If we are in the middle of ungetc'ing, just continue.
8746108Sbostic 	 * This may require expanding the current ungetc buffer.
8846108Sbostic 	 */
8946108Sbostic 	if (HASUB(fp)) {
9046108Sbostic 		if (fp->_r >= fp->_ub._size && __submore(fp))
9146108Sbostic 			return (EOF);
9246108Sbostic 		*--fp->_p = c;
9346108Sbostic 		fp->_r++;
9446108Sbostic 		return (c);
9546108Sbostic 	}
96*64810Storek 	fp->_flags &= ~__SEOF;
9717951Sserge 
9846108Sbostic 	/*
9946108Sbostic 	 * If we can handle this by simply backing up, do so,
10046108Sbostic 	 * but never replace the original character.
10146108Sbostic 	 * (This makes sscanf() work when scanning `const' data.)
10246108Sbostic 	 */
10346108Sbostic 	if (fp->_bf._base != NULL && fp->_p > fp->_bf._base &&
10446108Sbostic 	    fp->_p[-1] == c) {
10546108Sbostic 		fp->_p--;
10646108Sbostic 		fp->_r++;
10746108Sbostic 		return (c);
10846108Sbostic 	}
10946108Sbostic 
11046108Sbostic 	/*
11146108Sbostic 	 * Create an ungetc buffer.
11246108Sbostic 	 * Initially, we will use the `reserve' buffer.
11346108Sbostic 	 */
11446108Sbostic 	fp->_ur = fp->_r;
11546108Sbostic 	fp->_up = fp->_p;
11646108Sbostic 	fp->_ub._base = fp->_ubuf;
11746108Sbostic 	fp->_ub._size = sizeof(fp->_ubuf);
11846108Sbostic 	fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
11946108Sbostic 	fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1];
12046108Sbostic 	fp->_r = 1;
12115084Ssam 	return (c);
1222037Swnj }
123