/* * Copyright (c) 1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* FUNCTION <>---push data back into a stream INDEX ungetc INDEX _ungetc_r SYNOPSIS #include int ungetc(int <[c]>, FILE *<[stream]>); int _ungetc_r(struct _reent *<[reent]>, int <[c]>, FILE *<[stream]>); DESCRIPTION <> is used to return bytes back to <[stream]> to be read again. If <[c]> is EOF, the stream is unchanged. Otherwise, the unsigned char <[c]> is put back on the stream, and subsequent reads will see the bytes pushed back in reverse order. Pushed byes are lost if the stream is repositioned, such as by <>, <>, or <>. The underlying file is not changed, but it is possible to push back something different than what was originally read. Ungetting a character will clear the end-of-stream marker, and decrement the file position indicator. Pushing back beyond the beginning of a file gives unspecified behavior. The alternate function <<_ungetc_r>> is a reentrant version. The extra argument <[reent]> is a pointer to a reentrancy structure. RETURNS The character pushed back, or <> on error. PORTABILITY ANSI C requires <>, but only requires a pushback buffer of one byte; although this implementation can handle multiple bytes, not all can. Pushing back a signed char is a common application bug. Supporting OS subroutines required: <>. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "%W% (Berkeley) %G%"; #endif /* LIBC_SCCS and not lint */ #include <_ansi.h> #include #include #include #include #include "local.h" /* * Expand the ungetc buffer `in place'. That is, adjust fp->_p when * the buffer moves, so that it points the same distance from the end, * and move the bytes in the buffer around as necessary so that they * are all at the end (stack-style). */ /*static*/ int _DEFUN(__submore, (rptr, fp), struct _reent *rptr _AND register FILE *fp) { register int i; register unsigned char *p; if (fp->_ub._base == fp->_ubuf) { /* * Get a new buffer (rather than expanding the old one). */ if ((p = (unsigned char *) _malloc_r (rptr, (size_t) BUFSIZ)) == NULL) return EOF; fp->_ub._base = p; fp->_ub._size = BUFSIZ; p += BUFSIZ - sizeof (fp->_ubuf); for (i = sizeof (fp->_ubuf); --i >= 0;) p[i] = fp->_ubuf[i]; fp->_p = p; return 0; } i = fp->_ub._size; p = (unsigned char *) _realloc_r (rptr, (_PTR) (fp->_ub._base), i << 1); if (p == NULL) return EOF; _CAST_VOID memcpy ((_PTR) (p + i), (_PTR) p, (size_t) i); fp->_p = p + i; fp->_ub._base = p; fp->_ub._size = i << 1; return 0; } int _DEFUN(_ungetc_r, (rptr, c, fp), struct _reent *rptr _AND int c _AND register FILE *fp) { if (c == EOF) return (EOF); /* Ensure stdio has been initialized. ??? Might be able to remove this as some other stdio routine should have already been called to get the char we are un-getting. */ CHECK_INIT (rptr, fp); _newlib_flockfile_start (fp); ORIENT (fp, -1); /* After ungetc, we won't be at eof anymore */ fp->_flags &= ~__SEOF; if ((fp->_flags & __SRD) == 0) { /* * Not already reading: no good unless reading-and-writing. * Otherwise, flush any current write stuff. */ if ((fp->_flags & __SRW) == 0) { _newlib_flockfile_exit (fp); return EOF; } if (fp->_flags & __SWR) { if (_fflush_r (rptr, fp)) { _newlib_flockfile_exit (fp); return EOF; } fp->_flags &= ~__SWR; fp->_w = 0; fp->_lbfsize = 0; } fp->_flags |= __SRD; } c = (unsigned char) c; /* * If we are in the middle of ungetc'ing, just continue. * This may require expanding the current ungetc buffer. */ if (HASUB (fp)) { if (fp->_r >= fp->_ub._size && __submore (rptr, fp)) { _newlib_flockfile_exit (fp); return EOF; } *--fp->_p = c; fp->_r++; _newlib_flockfile_exit (fp); return c; } /* * If we can handle this by simply backing up, do so, * but never replace the original character. * (This makes sscanf() work when scanning `const' data.) */ if (fp->_bf._base != NULL && fp->_p > fp->_bf._base && fp->_p[-1] == c) { fp->_p--; fp->_r++; _newlib_flockfile_exit (fp); return c; } /* * Create an ungetc buffer. * Initially, we will use the `reserve' buffer. */ fp->_ur = fp->_r; fp->_up = fp->_p; fp->_ub._base = fp->_ubuf; fp->_ub._size = sizeof (fp->_ubuf); fp->_ubuf[sizeof (fp->_ubuf) - 1] = c; fp->_p = &fp->_ubuf[sizeof (fp->_ubuf) - 1]; fp->_r = 1; _newlib_flockfile_end (fp); return c; } #ifndef _REENT_ONLY int _DEFUN(ungetc, (c, fp), int c _AND register FILE *fp) { return _ungetc_r (_REENT, c, fp); } #endif /* !_REENT_ONLY */