summaryrefslogtreecommitdiffstats
path: root/private/crt32/stdio/ungetc.c
blob: e8b912ffee34cf8ab04adf894a6909862a2ec3a8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/***
*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
*			<cruntime.h> and removed #include <register.h>.
*	07-23-90  SBM	Replaced <assertm.h> by <assert.h>
*	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 <cruntime.h>
#include <stdio.h>
#include <file2.h>
#include <assert.h>
#include <internal.h>
#include <os2dll.h>

#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);
}