1 /*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #if defined(LIBC_SCCS) && !defined(lint)
12 static char sccsid[] = "@(#)ungetc.c 8.2 (Berkeley) 11/03/93";
13 #endif /* LIBC_SCCS and not lint */
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include "local.h"
19
20 /*
21 * Expand the ungetc buffer `in place'. That is, adjust fp->_p when
22 * the buffer moves, so that it points the same distance from the end,
23 * and move the bytes in the buffer around as necessary so that they
24 * are all at the end (stack-style).
25 */
26 static
__submore(fp)27 __submore(fp)
28 register FILE *fp;
29 {
30 register int i;
31 register unsigned char *p;
32
33 if (fp->_ub._base == fp->_ubuf) {
34 /*
35 * Get a new buffer (rather than expanding the old one).
36 */
37 if ((p = malloc((size_t)BUFSIZ)) == NULL)
38 return (EOF);
39 fp->_ub._base = p;
40 fp->_ub._size = BUFSIZ;
41 p += BUFSIZ - sizeof(fp->_ubuf);
42 for (i = sizeof(fp->_ubuf); --i >= 0;)
43 p[i] = fp->_ubuf[i];
44 fp->_p = p;
45 return (0);
46 }
47 i = fp->_ub._size;
48 p = realloc(fp->_ub._base, i << 1);
49 if (p == NULL)
50 return (EOF);
51 /* no overlap (hence can use memcpy) because we doubled the size */
52 (void)memcpy((void *)(p + i), (void *)p, (size_t)i);
53 fp->_p = p + i;
54 fp->_ub._base = p;
55 fp->_ub._size = i << 1;
56 return (0);
57 }
58
ungetc(c,fp)59 ungetc(c, fp)
60 int c;
61 register FILE *fp;
62 {
63 if (c == EOF)
64 return (EOF);
65 if (!__sdidinit)
66 __sinit();
67 if ((fp->_flags & __SRD) == 0) {
68 /*
69 * Not already reading: no good unless reading-and-writing.
70 * Otherwise, flush any current write stuff.
71 */
72 if ((fp->_flags & __SRW) == 0)
73 return (EOF);
74 if (fp->_flags & __SWR) {
75 if (__sflush(fp))
76 return (EOF);
77 fp->_flags &= ~__SWR;
78 fp->_w = 0;
79 fp->_lbfsize = 0;
80 }
81 fp->_flags |= __SRD;
82 }
83 c = (unsigned char)c;
84
85 /*
86 * If we are in the middle of ungetc'ing, just continue.
87 * This may require expanding the current ungetc buffer.
88 */
89 if (HASUB(fp)) {
90 if (fp->_r >= fp->_ub._size && __submore(fp))
91 return (EOF);
92 *--fp->_p = c;
93 fp->_r++;
94 return (c);
95 }
96 fp->_flags &= ~__SEOF;
97
98 /*
99 * If we can handle this by simply backing up, do so,
100 * but never replace the original character.
101 * (This makes sscanf() work when scanning `const' data.)
102 */
103 if (fp->_bf._base != NULL && fp->_p > fp->_bf._base &&
104 fp->_p[-1] == c) {
105 fp->_p--;
106 fp->_r++;
107 return (c);
108 }
109
110 /*
111 * Create an ungetc buffer.
112 * Initially, we will use the `reserve' buffer.
113 */
114 fp->_ur = fp->_r;
115 fp->_up = fp->_p;
116 fp->_ub._base = fp->_ubuf;
117 fp->_ub._size = sizeof(fp->_ubuf);
118 fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
119 fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1];
120 fp->_r = 1;
121 return (c);
122 }
123