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