summaryrefslogtreecommitdiffstats
path: root/private/crt32/stdio/_flsbuf.c
blob: 564f58625b270cce13dc4e229da39bb9becaf995 (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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/***
*_flsbuf.c - flush buffer and output character.
*
*	Copyright (c) 1985-1993, Microsoft Corporation. All rights reserved.
*
*Purpose:
*	defines _flsbuf() - flush a file buffer and output a character.
*	defines _flswbuf() - flush a file buffer and output a wide character.
*	If no buffer, make one.
*
*Revision History:
*	09-01-83  RN	initial version
*	06-26-85  TC	added code to handle variable length buffers
*	06-08-87  JCR	When buffer is allocated or when first write to buffer
*			occurs, if stream is in append mode, then position file
*			pointer to end.
*	07-20-87  SKS	Change first parameter "ch" from (char) to (int)
*	09-28-87  JCR	Corrected _iob2 indexing (now uses _iob_index() macro).
*	11-05-87  JCR	Re-wrote for simplicity and for new stderr/stdout
*			handling
*	12-11-87  JCR	Added "_LOAD_DS" to declaration
*	01-11-88  JCR	Merged mthread version into normal code
*	01-13-88  SKS	Changed bogus "_fileno_lk" to "fileno"
*	06-06-88  JCR	Optimized _iob2 references
*	06-13-88  JCR	Use near pointer to reference _iob[] entries
*	06-28-88  JCR	Support for dynamic buffer allocation for stdout/stderr
*	07-28-88  GJF	Set stream->_cnt to 0 if _IOREAD is set.
*	08-25-88  GJF	Added checked that OS2 is defined whenever M_I386 is.
*	06-20-89  PHG	Removed FP_OFF macro call.
*	08-28-89  JCR	Removed _NEAR_ for 386
*	02-15-90  GJF	_iob[], _iob2[] merge. Also, fixed copyright and
*			indents.
*	03-16-90  GJF	Replaced cdecl _LOAD_DS with _CALLTYPE1, added #include
*			<cruntime.h> and removed #include <register.h>. Also,
*			removed some leftover 16-bit support.
*	03-27-90  GJF	Added #include <io.h>.
*	07-23-90  SBM	Replaced <assertm.h> by <assert.h>
*	08-07-90  SBM	Restored descriptive text in assertion
*	08-14-90  SBM	Compiles cleanly with -W3
*	10-03-90  GJF	New-style function declarator.
*	01-22-91  GJF	ANSI naming.
*	03-25-91  DJM	POSIX support
*	08-26-92  GJF	Include unistd.h for POSIX build.
*	04-26-93  CFW	Wide char enable.
*	05-06-93  CFW	Optimize wide char conversion.
*
*******************************************************************************/

#include <cruntime.h>
#include <stdio.h>
#include <file2.h>
#include <io.h>
#include <assert.h>
#include <malloc.h>
#ifdef _POSIX_
#include <unistd.h>
#include <errno.h>
#else
#include <msdos.h>
#endif
#include <internal.h>
#ifdef MTHREAD
#include <os2dll.h>
#endif
#include <wchar.h>
#include <tchar.h>

#ifndef _UNICODE

/***
*int _flsbuf(ch, stream) - flush buffer and output character.
*
*Purpose:
*	flush a buffer if this stream has one. if not, try to get one. put the
*	next output char (ch) into the buffer (or output it immediately if this
*	stream can't have a buffer). called only from putc. intended for use
*	only within library.
*
*	[NOTE: Multi-thread - It is assumed that the caller has aquired
*	the stream lock.]
*
*Entry:
*	FILE *stream - stream to flish and write on
*	int ch - character to output.
*
*Exit:
*	returns -1 if FILE is actually a string, or if can't write ch to
*	unbuffered file, or if we flush a buffer but the number of chars
*	written doesn't agree with buffer size.  Otherwise returns ch.
*	all fields in FILE struct can be affected except _file.
*
*Exceptions:
*
*******************************************************************************/

int _CRTAPI1 _flsbuf (
	int ch,
	FILE *str
	)

#else /* _UNICODE */

/***
*int _flswbuf(ch, stream) - flush buffer and output wide character.
*
*Purpose:
*	flush a buffer if this stream has one. if not, try to get one. put the
*	next output wide char (ch) into the buffer (or output it immediately if this
*	stream can't have a buffer). called only from putwc. intended for use
*	only within library.
*
*	[NOTE: Multi-thread - It is assumed that the caller has aquired
*	the stream lock.]
*
*Entry:
*	FILE *stream - stream to flish and write on
*	int ch - wide character to output.
*
*Exit:
*	returns -1 if FILE is actually a string, or if can't write ch to
*	unbuffered file, or if we flush a buffer but the number of wide chars
*	written doesn't agree with buffer size.  Otherwise returns ch.
*	all fields in FILE struct can be affected except _file.
*
*Exceptions:
*
*******************************************************************************/

int _CRTAPI1 _flswbuf (
	int ch,
	FILE *str
	)

#endif /* _UNICODE */

{
#if defined _NTSUBSET_ && !defined _POSIX_
        str->_flag |= _IOERR;
        return(_TEOF);
#else
	REG1 FILE *stream;
	REG2 int charcount;
	REG3 int written;
	int fh;

	assert(str != NULL);

	/* Init file handle and pointers */
	stream = str;
#ifdef _POSIX_
	fh = fileno(stream);
#else
	fh = _fileno(stream);
#endif

	if (!(stream->_flag & (_IOWRT|_IORW)) || (stream->_flag & _IOSTRG)) {
#ifdef _POSIX_
		errno = EBADF;
#endif
		stream->_flag |= _IOERR;
		return(_TEOF);
	}

	/* Check that _IOREAD is not set or, if it is, then so is _IOEOF. Note
	   that _IOREAD and IOEOF both being set implies switching from read to
	   write at end-of-file, which is allowed by ANSI. Note that resetting
	   the _cnt and _ptr fields amounts to doing an fflush() on the stream
	   in this case. Note also that the _cnt field has to be reset to 0 for
	   the error path as well (i.e., _IOREAD set but _IOEOF not set) as
	   well as the non-error path. */

	if (stream->_flag & _IOREAD) {
		stream->_cnt = 0;
		if (stream->_flag & _IOEOF) {
			stream->_ptr = stream->_base;
			stream->_flag &= ~_IOREAD;
		}
		else {
			stream->_flag |= _IOERR;
			return(_TEOF);
		}
	}

	stream->_flag |= _IOWRT;
	stream->_flag &= ~_IOEOF;
	written = charcount = stream->_cnt = 0;

	/* Get a buffer for this stream, if necessary. */
	if (!anybuf(stream)) {

		/* Do NOT get a buffer if (1) stream is stdout/stderr, and
		   (2) stream is NOT a tty.
		   [If stdout/stderr is a tty, we do NOT set up single char
		   buffering. This is so that later temporary buffering will
		   not be thwarted by the _IONBF bit being set (see
		   _stbuf/_ftbuf usage).]
		*/
		if (!( ((stream==stdout) || (stream==stderr))
#ifdef _POSIX_
		&& (isatty(fh)) ))
#else
		&& (_isatty(fh)) ))
#endif

			_getbuf(stream);

	} /* end !anybuf() */

	/* If big buffer is assigned to stream... */
	if (bigbuf(stream)) {

		assert(("inconsistent IOB fields", stream->_ptr - stream->_base >= 0));

		charcount = stream->_ptr - stream->_base;
		stream->_ptr = stream->_base + sizeof(TCHAR);
		stream->_cnt = stream->_bufsiz - sizeof(TCHAR);

		if (charcount > 0)
#ifdef _POSIX_
			written = write(fh, stream->_base, charcount);
#else
			written = _write(fh, stream->_base, charcount);
#endif
		else
#ifdef _POSIX_
			if (stream->_flag & _IOAPPEND)
			    lseek(fh,0l,SEEK_END);
#else
			if (_osfile[fh] & FAPPEND)
				_lseek(fh,0L,SEEK_END);
#endif

#ifndef _UNICODE
		*stream->_base = (char)ch;
#else /* _UNICODE */
		*(wchar_t *)(stream->_base) = (wchar_t)(ch & 0xffff);
#endif /* _UNICODE */
	}

    /* Perform single character output (either _IONBF or no buffering) */
	else {
		charcount = sizeof(TCHAR);
#ifndef _UNICODE
#ifdef _POSIX_
		written = write(fh, &ch, charcount);
#else
		written = _write(fh, &ch, charcount);
#endif
#else /* _UNICODE */
		{
			char mbc[4];

			*(wchar_t *)mbc = (wchar_t)(ch & 0xffff);
#ifdef _POSIX_
			written = write(fh, mbc, charcount);
#else
			written = _write(fh, mbc, charcount);
#endif
		}
#endif /* _UNICODE */
	}

	/* See if the _write() was successful. */
	if (written != charcount) {
		stream->_flag |= _IOERR;
		return(_TEOF);
	}

#ifndef _UNICODE
	return(ch & 0xff);
#else /* _UNICODE */
	return(ch & 0xffff);
#endif /* _UNICODE */
#endif /* _NTSUBSET */
}