ungetc.c revision 35129
1254885Sdumbbell/*- 2254885Sdumbbell * Copyright (c) 1990, 1993 3254885Sdumbbell * The Regents of the University of California. All rights reserved. 4254885Sdumbbell * 5254885Sdumbbell * This code is derived from software contributed to Berkeley by 6254885Sdumbbell * Chris Torek. 7254885Sdumbbell * 8254885Sdumbbell * Redistribution and use in source and binary forms, with or without 9254885Sdumbbell * modification, are permitted provided that the following conditions 10254885Sdumbbell * are met: 11254885Sdumbbell * 1. Redistributions of source code must retain the above copyright 12254885Sdumbbell * notice, this list of conditions and the following disclaimer. 13254885Sdumbbell * 2. Redistributions in binary form must reproduce the above copyright 14254885Sdumbbell * notice, this list of conditions and the following disclaimer in the 15254885Sdumbbell * documentation and/or other materials provided with the distribution. 16254885Sdumbbell * 3. All advertising materials mentioning features or use of this software 17254885Sdumbbell * must display the following acknowledgement: 18254885Sdumbbell * This product includes software developed by the University of 19254885Sdumbbell * California, Berkeley and its contributors. 20254885Sdumbbell * 4. Neither the name of the University nor the names of its contributors 21254885Sdumbbell * may be used to endorse or promote products derived from this software 22254885Sdumbbell * without specific prior written permission. 23254885Sdumbbell * 24254885Sdumbbell * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25254885Sdumbbell * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26254885Sdumbbell * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27254885Sdumbbell * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28254885Sdumbbell * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29254885Sdumbbell * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30254885Sdumbbell * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31254885Sdumbbell * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32254885Sdumbbell * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33254885Sdumbbell * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34254885Sdumbbell * SUCH DAMAGE. 35254885Sdumbbell */ 36254885Sdumbbell 37254885Sdumbbell#if defined(LIBC_SCCS) && !defined(lint) 38254885Sdumbbell#if 0 39254885Sdumbbellstatic char sccsid[] = "@(#)ungetc.c 8.2 (Berkeley) 11/3/93"; 40254885Sdumbbell#endif 41254885Sdumbbellstatic const char rcsid[] = 42254885Sdumbbell "$Id: ungetc.c,v 1.5 1997/02/22 15:02:38 peter Exp $"; 43254885Sdumbbell#endif /* LIBC_SCCS and not lint */ 44254885Sdumbbell 45254885Sdumbbell#include <stdio.h> 46254885Sdumbbell#include <stdlib.h> 47254885Sdumbbell#include <string.h> 48254885Sdumbbell#include "local.h" 49254885Sdumbbell#include "libc_private.h" 50254885Sdumbbell 51254885Sdumbbellstatic int __submore __P((FILE *)); 52254885Sdumbbell 53254885Sdumbbell/* 54254885Sdumbbell * Expand the ungetc buffer `in place'. That is, adjust fp->_p when 55254885Sdumbbell * the buffer moves, so that it points the same distance from the end, 56254885Sdumbbell * and move the bytes in the buffer around as necessary so that they 57254885Sdumbbell * are all at the end (stack-style). 58254885Sdumbbell */ 59254885Sdumbbellstatic int 60254885Sdumbbell__submore(fp) 61254885Sdumbbell register FILE *fp; 62254885Sdumbbell{ 63254885Sdumbbell register int i; 64254885Sdumbbell register unsigned char *p; 65254885Sdumbbell 66254885Sdumbbell if (fp->_ub._base == fp->_ubuf) { 67254885Sdumbbell /* 68254885Sdumbbell * Get a new buffer (rather than expanding the old one). 69254885Sdumbbell */ 70254885Sdumbbell if ((p = malloc((size_t)BUFSIZ)) == NULL) 71254885Sdumbbell return (EOF); 72254885Sdumbbell fp->_ub._base = p; 73254885Sdumbbell fp->_ub._size = BUFSIZ; 74254885Sdumbbell p += BUFSIZ - sizeof(fp->_ubuf); 75254885Sdumbbell for (i = sizeof(fp->_ubuf); --i >= 0;) 76254885Sdumbbell p[i] = fp->_ubuf[i]; 77254885Sdumbbell fp->_p = p; 78254885Sdumbbell return (0); 79254885Sdumbbell } 80254885Sdumbbell i = fp->_ub._size; 81254885Sdumbbell p = realloc(fp->_ub._base, (size_t)(i << 1)); 82254885Sdumbbell if (p == NULL) 83254885Sdumbbell return (EOF); 84254885Sdumbbell /* no overlap (hence can use memcpy) because we doubled the size */ 85254885Sdumbbell (void)memcpy((void *)(p + i), (void *)p, (size_t)i); 86254885Sdumbbell fp->_p = p + i; 87254885Sdumbbell fp->_ub._base = p; 88254885Sdumbbell fp->_ub._size = i << 1; 89254885Sdumbbell return (0); 90254885Sdumbbell} 91254885Sdumbbell 92254885Sdumbbellint 93254885Sdumbbellungetc(c, fp) 94254885Sdumbbell int c; 95254885Sdumbbell register FILE *fp; 96254885Sdumbbell{ 97254885Sdumbbell if (c == EOF) 98254885Sdumbbell return (EOF); 99254885Sdumbbell if (!__sdidinit) 100254885Sdumbbell __sinit(); 101254885Sdumbbell FLOCKFILE(fp); 102254885Sdumbbell if ((fp->_flags & __SRD) == 0) { 103254885Sdumbbell /* 104254885Sdumbbell * Not already reading: no good unless reading-and-writing. 105254885Sdumbbell * Otherwise, flush any current write stuff. 106254885Sdumbbell */ 107254885Sdumbbell if ((fp->_flags & __SRW) == 0) { 108254885Sdumbbell FUNLOCKFILE(fp); 109254885Sdumbbell return (EOF); 110254885Sdumbbell } 111254885Sdumbbell if (fp->_flags & __SWR) { 112254885Sdumbbell if (__sflush(fp)) { 113254885Sdumbbell FUNLOCKFILE(fp); 114254885Sdumbbell return (EOF); 115254885Sdumbbell } 116254885Sdumbbell fp->_flags &= ~__SWR; 117254885Sdumbbell fp->_w = 0; 118254885Sdumbbell fp->_lbfsize = 0; 119254885Sdumbbell } 120254885Sdumbbell fp->_flags |= __SRD; 121254885Sdumbbell } 122254885Sdumbbell c = (unsigned char)c; 123254885Sdumbbell 124254885Sdumbbell /* 125254885Sdumbbell * If we are in the middle of ungetc'ing, just continue. 126254885Sdumbbell * This may require expanding the current ungetc buffer. 127254885Sdumbbell */ 128254885Sdumbbell if (HASUB(fp)) { 129254885Sdumbbell if (fp->_r >= fp->_ub._size && __submore(fp)) { 130254885Sdumbbell FUNLOCKFILE(fp); 131254885Sdumbbell return (EOF); 132254885Sdumbbell } 133254885Sdumbbell *--fp->_p = c; 134254885Sdumbbell fp->_r++; 135254885Sdumbbell FUNLOCKFILE(fp); 136254885Sdumbbell return (c); 137254885Sdumbbell } 138254885Sdumbbell fp->_flags &= ~__SEOF; 139254885Sdumbbell 140254885Sdumbbell /* 141254885Sdumbbell * If we can handle this by simply backing up, do so, 142254885Sdumbbell * but never replace the original character. 143254885Sdumbbell * (This makes sscanf() work when scanning `const' data.) 144254885Sdumbbell */ 145254885Sdumbbell if (fp->_bf._base != NULL && fp->_p > fp->_bf._base && 146254885Sdumbbell fp->_p[-1] == c) { 147254885Sdumbbell fp->_p--; 148254885Sdumbbell fp->_r++; 149254885Sdumbbell FUNLOCKFILE(fp); 150254885Sdumbbell return (c); 151254885Sdumbbell } 152254885Sdumbbell 153254885Sdumbbell /* 154254885Sdumbbell * Create an ungetc buffer. 155254885Sdumbbell * Initially, we will use the `reserve' buffer. 156254885Sdumbbell */ 157254885Sdumbbell fp->_ur = fp->_r; 158254885Sdumbbell fp->_up = fp->_p; 159254885Sdumbbell fp->_ub._base = fp->_ubuf; 160254885Sdumbbell fp->_ub._size = sizeof(fp->_ubuf); 161254885Sdumbbell fp->_ubuf[sizeof(fp->_ubuf) - 1] = c; 162254885Sdumbbell fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1]; 163254885Sdumbbell fp->_r = 1; 164254885Sdumbbell FUNLOCKFILE(fp); 165254885Sdumbbell return (c); 166254885Sdumbbell} 167254885Sdumbbell