xref: /csrg-svn/lib/libc/stdio/ungetc.c (revision 46219)
146108Sbostic /*-
246108Sbostic  * Copyright (c) 1990 The Regents of the University of California.
346108Sbostic  * 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*46219Sbostic static char sccsid[] = "@(#)ungetc.c	5.5 (Berkeley) 02/01/91";
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
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);
5146108Sbostic 	(void) memcpy((void *)(p + i), (void *)p, (size_t)i);
5246108Sbostic 	fp->_p = p + i;
5346108Sbostic 	fp->_ub._base = p;
5446108Sbostic 	fp->_ub._size = i << 1;
5546108Sbostic 	return (0);
5646108Sbostic }
5717951Sserge 
5846108Sbostic ungetc(c, fp)
5946108Sbostic 	int c;
6046108Sbostic 	register FILE *fp;
6146108Sbostic {
6246108Sbostic 	if (c == EOF)
6346108Sbostic 		return (EOF);
6446108Sbostic 	if (!__sdidinit)
6546108Sbostic 		__sinit();
6646108Sbostic 	if ((fp->_flags & __SRD) == 0) {
6746108Sbostic 		/*
6846108Sbostic 		 * Not already reading: no good unless reading-and-writing.
6946108Sbostic 		 * Otherwise, flush any current write stuff.
7046108Sbostic 		 */
7146108Sbostic 		if ((fp->_flags & __SRW) == 0)
7226938Sbloom 			return (EOF);
7346108Sbostic 		if (fp->_flags & __SWR) {
74*46219Sbostic 			if (__sflush(fp))
7546108Sbostic 				return (EOF);
7646108Sbostic 			fp->_flags &= ~__SWR;
7746108Sbostic 			fp->_w = 0;
7846108Sbostic 			fp->_lbfsize = 0;
7946108Sbostic 		}
8046108Sbostic 		fp->_flags |= __SRD;
8146108Sbostic 	}
8246108Sbostic 	c = (unsigned char)c;
8317951Sserge 
8446108Sbostic 	/*
8546108Sbostic 	 * If we are in the middle of ungetc'ing, just continue.
8646108Sbostic 	 * This may require expanding the current ungetc buffer.
8746108Sbostic 	 */
8846108Sbostic 	if (HASUB(fp)) {
8946108Sbostic 		if (fp->_r >= fp->_ub._size && __submore(fp))
9046108Sbostic 			return (EOF);
9146108Sbostic 		*--fp->_p = c;
9246108Sbostic 		fp->_r++;
9346108Sbostic 		return (c);
9446108Sbostic 	}
9517951Sserge 
9646108Sbostic 	/*
9746108Sbostic 	 * If we can handle this by simply backing up, do so,
9846108Sbostic 	 * but never replace the original character.
9946108Sbostic 	 * (This makes sscanf() work when scanning `const' data.)
10046108Sbostic 	 */
10146108Sbostic 	if (fp->_bf._base != NULL && fp->_p > fp->_bf._base &&
10246108Sbostic 	    fp->_p[-1] == c) {
10346108Sbostic 		fp->_p--;
10446108Sbostic 		fp->_r++;
10546108Sbostic 		return (c);
10646108Sbostic 	}
10746108Sbostic 
10846108Sbostic 	/*
10946108Sbostic 	 * Create an ungetc buffer.
11046108Sbostic 	 * Initially, we will use the `reserve' buffer.
11146108Sbostic 	 */
11246108Sbostic 	fp->_ur = fp->_r;
11346108Sbostic 	fp->_up = fp->_p;
11446108Sbostic 	fp->_ub._base = fp->_ubuf;
11546108Sbostic 	fp->_ub._size = sizeof(fp->_ubuf);
11646108Sbostic 	fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
11746108Sbostic 	fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1];
11846108Sbostic 	fp->_r = 1;
11915084Ssam 	return (c);
1202037Swnj }
121