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