/*** *ungetc.c - unget a character from a stream * * Copyright (c) 1985-1993, Microsoft Corporation. All rights reserved. * *Purpose: * defines ungetc() - pushes a character back onto an input stream * *Revision History: * 09-02-83 RN initial version * 04-16-87 JCR added support for _IOUNGETC flag * 08-04-87 JCR (1) Added _IOSTRG check before setting _IOUNGETC flag. * (2) Allow an ugnetc() before a read has occurred (get a * buffer (ANSI). [MSC only] * 09-28-87 JCR Corrected _iob2 indexing (now uses _iob_index() macro). * 11-04-87 JCR Multi-thread support * 12-11-87 JCR Added "_LOAD_DS" to declaration * 05-25-88 JCR Allow an ungetc() before read for file opened "r+". * 05-31-88 PHG Merged DLL and normal versions * 06-06-88 JCR Optimized _iob2 references * 06-15-88 JCR Near reference to _iob[] entries; improve REG variables * 08-25-88 GJF Don't use FP_OFF() macro for the 386 * 04-11-89 JCR Removed _IOUNGETC flag, fseek() no longer needs it * 08-17-89 GJF Clean up, now specific to OS/2 2.0 (i.e., 386 flat * model). Also fixed copyright and indents. * 02-16-90 GJF Fixed copyright * 03-20-90 GJF Made calling type _CALLTYPE1, added #include * and removed #include . * 07-23-90 SBM Replaced by * 08-13-90 SBM Compiles cleanly with -W3 * 10-03-90 GJF New-style function declarators. * 11-07-92 SRW Dont modify buffer if stream opened by sscanf * 04-26-93 CFW Wide char enable. * 04-30-93 CFW Remove wide char support to ungetwc.c. * *******************************************************************************/ #include #include #include #include #include #include #ifdef MTHREAD /* multi-thread; define both ungetc and _lk_ungetc */ /*** *int ungetc(ch, stream) - put a character back onto a stream * *Purpose: * Guaranteed one char pushback on a stream as long as open for reading. * More than one char pushback in a row is not guaranteed, and will fail * if it follows an ungetc which pushed the first char in buffer. Failure * causes return of EOF. * *Entry: * char ch - character to push back * FILE *stream - stream to push character onto * *Exit: * returns ch * returns EOF if tried to push EOF, stream not opened for reading or * or if we have already ungetc'd back to beginning of buffer. * *Exceptions: * *******************************************************************************/ int _CRTAPI1 ungetc ( REG2 int ch, REG1 FILE *stream ) { int retval; int index; assert(stream != NULL); index = _iob_index(stream); _lock_str(index); retval = _ungetc_lk (ch, stream); _unlock_str(index); return(retval); } /*** *_ungetc_lk() - Ungetc() core routine (locked version) * *Purpose: * Core ungetc() routine; assumes stream is already locked. * * [See ungetc() above for more info.] * *Entry: [See ungetc()] * *Exit: [See ungetc()] * *Exceptions: * *******************************************************************************/ int _CRTAPI1 _ungetc_lk ( REG2 int ch, FILE *str ) { #else /* non multi-thread; just define ungetc */ int _CRTAPI1 ungetc ( REG2 int ch, FILE *str ) { #endif /* rejoin common code */ REG1 FILE *stream; assert(str != NULL); /* Init stream pointer and file descriptor */ stream = str; /* Stream must be open for read and can NOT be currently in write mode. Also, ungetc() character cannot be EOF. */ if ( (ch == EOF) || !( (stream->_flag & _IOREAD) || ((stream->_flag & _IORW) && !(stream->_flag & _IOWRT)) ) ) return(EOF); /* If stream is unbuffered, get one. */ if (stream->_base == NULL) _getbuf(stream); /* now we know _base != NULL; since file must be buffered */ if (stream->_ptr == stream->_base) { if (stream->_cnt) /* my back is against the wall; i've already done * ungetc, and there's no room for this one */ return(EOF); stream->_ptr++; } if (stream->_flag & _IOSTRG) { /* If stream opened by sscanf do not modify buffer */ if (*--stream->_ptr != (char)ch) { ++stream->_ptr; return(EOF); } } else *--stream->_ptr = (char)ch; stream->_cnt++; stream->_flag &= ~_IOEOF; stream->_flag |= _IOREAD; /* may already be set */ return(0xff & ch); }