1 1.17 christos /* $NetBSD: ungetc.c,v 1.17 2012/03/15 18:22:30 christos Exp $ */ 2 1.4 jtc 3 1.1 cgd /*- 4 1.17 christos * Copyright c 1990, 1993 5 1.4 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Chris Torek. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.14 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.6 christos #include <sys/cdefs.h> 36 1.1 cgd #if defined(LIBC_SCCS) && !defined(lint) 37 1.4 jtc #if 0 38 1.4 jtc static char sccsid[] = "@(#)ungetc.c 8.2 (Berkeley) 11/3/93"; 39 1.6 christos #else 40 1.17 christos __RCSID("$NetBSD: ungetc.c,v 1.17 2012/03/15 18:22:30 christos Exp $"); 41 1.4 jtc #endif 42 1.1 cgd #endif /* LIBC_SCCS and not lint */ 43 1.1 cgd 44 1.10 lukem #include <assert.h> 45 1.10 lukem #include <errno.h> 46 1.1 cgd #include <stdio.h> 47 1.1 cgd #include <stdlib.h> 48 1.1 cgd #include <string.h> 49 1.13 thorpej #include "reentrant.h" 50 1.1 cgd #include "local.h" 51 1.1 cgd 52 1.1 cgd /* 53 1.1 cgd * Expand the ungetc buffer `in place'. That is, adjust fp->_p when 54 1.1 cgd * the buffer moves, so that it points the same distance from the end, 55 1.1 cgd * and move the bytes in the buffer around as necessary so that they 56 1.1 cgd * are all at the end (stack-style). 57 1.1 cgd */ 58 1.5 jtc static int 59 1.17 christos __submore(FILE *fp) 60 1.1 cgd { 61 1.7 perry int i; 62 1.7 perry unsigned char *p; 63 1.1 cgd 64 1.10 lukem _DIAGASSERT(fp != NULL); 65 1.10 lukem 66 1.12 yamt if (_UB(fp)._base == fp->_ubuf) { 67 1.1 cgd /* 68 1.1 cgd * Get a new buffer (rather than expanding the old one). 69 1.1 cgd */ 70 1.16 christos if ((p = malloc((size_t)BUFSIZ)) == NULL) 71 1.17 christos return EOF; 72 1.12 yamt _UB(fp)._base = p; 73 1.12 yamt _UB(fp)._size = BUFSIZ; 74 1.1 cgd p += BUFSIZ - sizeof(fp->_ubuf); 75 1.1 cgd for (i = sizeof(fp->_ubuf); --i >= 0;) 76 1.1 cgd p[i] = fp->_ubuf[i]; 77 1.1 cgd fp->_p = p; 78 1.17 christos return 0; 79 1.1 cgd } 80 1.12 yamt i = _UB(fp)._size; 81 1.16 christos p = realloc(_UB(fp)._base, (size_t)(i << 1)); 82 1.1 cgd if (p == NULL) 83 1.17 christos return EOF; 84 1.4 jtc /* no overlap (hence can use memcpy) because we doubled the size */ 85 1.16 christos (void)memcpy((p + i), p, (size_t)i); 86 1.1 cgd fp->_p = p + i; 87 1.12 yamt _UB(fp)._base = p; 88 1.12 yamt _UB(fp)._size = i << 1; 89 1.17 christos return 0; 90 1.1 cgd } 91 1.1 cgd 92 1.5 jtc int 93 1.17 christos ungetc(int c, FILE *fp) 94 1.1 cgd { 95 1.10 lukem 96 1.10 lukem _DIAGASSERT(fp != NULL); 97 1.10 lukem 98 1.1 cgd if (c == EOF) 99 1.17 christos return EOF; 100 1.1 cgd if (!__sdidinit) 101 1.1 cgd __sinit(); 102 1.8 kleink FLOCKFILE(fp); 103 1.12 yamt _SET_ORIENTATION(fp, -1); 104 1.1 cgd if ((fp->_flags & __SRD) == 0) { 105 1.1 cgd /* 106 1.1 cgd * Not already reading: no good unless reading-and-writing. 107 1.1 cgd * Otherwise, flush any current write stuff. 108 1.1 cgd */ 109 1.8 kleink if ((fp->_flags & __SRW) == 0) { 110 1.8 kleink FUNLOCKFILE(fp); 111 1.17 christos return EOF; 112 1.8 kleink } 113 1.1 cgd if (fp->_flags & __SWR) { 114 1.8 kleink if (__sflush(fp)) { 115 1.8 kleink FUNLOCKFILE(fp); 116 1.17 christos return EOF; 117 1.8 kleink } 118 1.1 cgd fp->_flags &= ~__SWR; 119 1.1 cgd fp->_w = 0; 120 1.1 cgd fp->_lbfsize = 0; 121 1.1 cgd } 122 1.1 cgd fp->_flags |= __SRD; 123 1.1 cgd } 124 1.1 cgd c = (unsigned char)c; 125 1.1 cgd 126 1.1 cgd /* 127 1.1 cgd * If we are in the middle of ungetc'ing, just continue. 128 1.1 cgd * This may require expanding the current ungetc buffer. 129 1.1 cgd */ 130 1.1 cgd if (HASUB(fp)) { 131 1.12 yamt if (fp->_r >= _UB(fp)._size && __submore(fp)) { 132 1.8 kleink FUNLOCKFILE(fp); 133 1.17 christos return EOF; 134 1.8 kleink } 135 1.1 cgd *--fp->_p = c; 136 1.1 cgd fp->_r++; 137 1.8 kleink FUNLOCKFILE(fp); 138 1.17 christos return c; 139 1.1 cgd } 140 1.4 jtc fp->_flags &= ~__SEOF; 141 1.1 cgd 142 1.1 cgd /* 143 1.1 cgd * If we can handle this by simply backing up, do so, 144 1.1 cgd * but never replace the original character. 145 1.1 cgd * (This makes sscanf() work when scanning `const' data.) 146 1.1 cgd */ 147 1.1 cgd if (fp->_bf._base != NULL && fp->_p > fp->_bf._base && 148 1.1 cgd fp->_p[-1] == c) { 149 1.1 cgd fp->_p--; 150 1.1 cgd fp->_r++; 151 1.8 kleink FUNLOCKFILE(fp); 152 1.17 christos return c; 153 1.1 cgd } 154 1.1 cgd 155 1.1 cgd /* 156 1.1 cgd * Create an ungetc buffer. 157 1.1 cgd * Initially, we will use the `reserve' buffer. 158 1.1 cgd */ 159 1.1 cgd fp->_ur = fp->_r; 160 1.1 cgd fp->_up = fp->_p; 161 1.12 yamt _UB(fp)._base = fp->_ubuf; 162 1.12 yamt _UB(fp)._size = sizeof(fp->_ubuf); 163 1.1 cgd fp->_ubuf[sizeof(fp->_ubuf) - 1] = c; 164 1.1 cgd fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1]; 165 1.1 cgd fp->_r = 1; 166 1.8 kleink FUNLOCKFILE(fp); 167 1.17 christos return c; 168 1.1 cgd } 169