Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

293 lines
9.8 KiB

  1. /***
  2. *_flsbuf.c - flush buffer and output character.
  3. *
  4. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines _flsbuf() - flush a file buffer and output a character.
  8. * defines _flswbuf() - flush a file buffer and output a wide character.
  9. * If no buffer, make one.
  10. *
  11. *Revision History:
  12. * 09-01-83 RN initial version
  13. * 06-26-85 TC added code to handle variable length buffers
  14. * 06-08-87 JCR When buffer is allocated or when first write to buffer
  15. * occurs, if stream is in append mode, then position file
  16. * pointer to end.
  17. * 07-20-87 SKS Change first parameter "ch" from (char) to (int)
  18. * 09-28-87 JCR Corrected _iob2 indexing (now uses _iob_index() macro).
  19. * 11-05-87 JCR Re-wrote for simplicity and for new stderr/stdout
  20. * handling
  21. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  22. * 01-11-88 JCR Merged mthread version into normal code
  23. * 01-13-88 SKS Changed bogus "_fileno_lk" to "fileno"
  24. * 06-06-88 JCR Optimized _iob2 references
  25. * 06-13-88 JCR Use near pointer to reference _iob[] entries
  26. * 06-28-88 JCR Support for dynamic buffer allocation for stdout/stderr
  27. * 07-28-88 GJF Set stream->_cnt to 0 if _IOREAD is set.
  28. * 08-25-88 GJF Added checked that OS2 is defined whenever M_I386 is.
  29. * 06-20-89 PHG Removed FP_OFF macro call.
  30. * 08-28-89 JCR Removed _NEAR_ for 386
  31. * 02-15-90 GJF _iob[], _iob2[] merge. Also, fixed copyright and
  32. * indents.
  33. * 03-16-90 GJF Replaced cdecl _LOAD_DS with _CALLTYPE1, added #include
  34. * <cruntime.h> and removed #include <register.h>. Also,
  35. * removed some leftover 16-bit support.
  36. * 03-27-90 GJF Added #include <io.h>.
  37. * 07-23-90 SBM Replaced <assertm.h> by <assert.h>
  38. * 08-07-90 SBM Restored descriptive text in assertion
  39. * 08-14-90 SBM Compiles cleanly with -W3
  40. * 10-03-90 GJF New-style function declarator.
  41. * 01-22-91 GJF ANSI naming.
  42. * 03-25-91 DJM POSIX support
  43. * 08-26-92 GJF Include unistd.h for POSIX build.
  44. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  45. * 04-26-93 CFW Wide char enable.
  46. * 05-06-93 CFW Optimize wide char conversion.
  47. * 11-05-93 GJF Merged with NT SDK version (picked up _NTSUBSET_
  48. * stuff).
  49. * 10-17-94 BWT Move wchar.h to non-POSIX build (ino_t definitions conflict)
  50. * 02-06-94 CFW assert -> _ASSERTE.
  51. * 02-16-95 GJF Appended Mac version of source file (somewhat cleaned
  52. * up), with appropriate #ifdef-s.
  53. * 06-12-95 GJF Replaced _osfile[] with _osfile() (macro referencing
  54. * field in ioinfo struct).
  55. * 07-25-95 GJF Replaced _osfile()with _osfile_safe().
  56. * 12-07-95 SKS Fix misspelling of _NTSUBSET_ (final _ was missing)
  57. * 02-27-98 RKP Added 64 bit support.
  58. * 01-04-99 GJF Changes for 64-bit size_t.
  59. * 05-17-99 PML Remove all Macintosh support.
  60. *
  61. *******************************************************************************/
  62. #include <cruntime.h>
  63. #include <stdio.h>
  64. #include <file2.h>
  65. #include <io.h>
  66. #include <dbgint.h>
  67. #include <malloc.h>
  68. #ifdef _POSIX_
  69. #include <unistd.h>
  70. #include <errno.h>
  71. #else
  72. #include <msdos.h>
  73. #include <wchar.h>
  74. #endif
  75. #include <internal.h>
  76. #ifdef _MT
  77. #include <mtdll.h>
  78. #endif
  79. #include <tchar.h>
  80. #ifndef _UNICODE
  81. /***
  82. *int _flsbuf(ch, stream) - flush buffer and output character.
  83. *
  84. *Purpose:
  85. * flush a buffer if this stream has one. if not, try to get one. put the
  86. * next output char (ch) into the buffer (or output it immediately if this
  87. * stream can't have a buffer). called only from putc. intended for use
  88. * only within library.
  89. *
  90. * [NOTE: Multi-thread - It is assumed that the caller has aquired
  91. * the stream lock.]
  92. *
  93. *Entry:
  94. * FILE *stream - stream to flish and write on
  95. * int ch - character to output.
  96. *
  97. *Exit:
  98. * returns -1 if FILE is actually a string, or if can't write ch to
  99. * unbuffered file, or if we flush a buffer but the number of chars
  100. * written doesn't agree with buffer size. Otherwise returns ch.
  101. * all fields in FILE struct can be affected except _file.
  102. *
  103. *Exceptions:
  104. *
  105. *******************************************************************************/
  106. int __cdecl _flsbuf (
  107. int ch,
  108. FILE *str
  109. )
  110. #else /* _UNICODE */
  111. /***
  112. *int _flswbuf(ch, stream) - flush buffer and output wide character.
  113. *
  114. *Purpose:
  115. * flush a buffer if this stream has one. if not, try to get one. put the
  116. * next output wide char (ch) into the buffer (or output it immediately if this
  117. * stream can't have a buffer). called only from putwc. intended for use
  118. * only within library.
  119. *
  120. * [NOTE: Multi-thread - It is assumed that the caller has aquired
  121. * the stream lock.]
  122. *
  123. *Entry:
  124. * FILE *stream - stream to flish and write on
  125. * int ch - wide character to output.
  126. *
  127. *Exit:
  128. * returns -1 if FILE is actually a string, or if can't write ch to
  129. * unbuffered file, or if we flush a buffer but the number of wide chars
  130. * written doesn't agree with buffer size. Otherwise returns ch.
  131. * all fields in FILE struct can be affected except _file.
  132. *
  133. *Exceptions:
  134. *
  135. *******************************************************************************/
  136. int __cdecl _flswbuf (
  137. int ch,
  138. FILE *str
  139. )
  140. #endif /* _UNICODE */
  141. {
  142. #ifdef _NTSUBSET_
  143. str->_flag |= _IOERR;
  144. return(_TEOF);
  145. #else /* ndef _NTSUBSET_ */
  146. REG1 FILE *stream;
  147. REG2 int charcount;
  148. REG3 int written;
  149. int fh;
  150. _ASSERTE(str != NULL);
  151. /* Init file handle and pointers */
  152. stream = str;
  153. #ifdef _POSIX_
  154. fh = fileno(stream);
  155. #else
  156. fh = _fileno(stream);
  157. #endif
  158. if (!(stream->_flag & (_IOWRT|_IORW)) || (stream->_flag & _IOSTRG)) {
  159. #ifdef _POSIX_
  160. errno = EBADF;
  161. #endif
  162. stream->_flag |= _IOERR;
  163. return(_TEOF);
  164. }
  165. /* Check that _IOREAD is not set or, if it is, then so is _IOEOF. Note
  166. that _IOREAD and IOEOF both being set implies switching from read to
  167. write at end-of-file, which is allowed by ANSI. Note that resetting
  168. the _cnt and _ptr fields amounts to doing an fflush() on the stream
  169. in this case. Note also that the _cnt field has to be reset to 0 for
  170. the error path as well (i.e., _IOREAD set but _IOEOF not set) as
  171. well as the non-error path. */
  172. if (stream->_flag & _IOREAD) {
  173. stream->_cnt = 0;
  174. if (stream->_flag & _IOEOF) {
  175. stream->_ptr = stream->_base;
  176. stream->_flag &= ~_IOREAD;
  177. }
  178. else {
  179. stream->_flag |= _IOERR;
  180. return(_TEOF);
  181. }
  182. }
  183. stream->_flag |= _IOWRT;
  184. stream->_flag &= ~_IOEOF;
  185. written = charcount = stream->_cnt = 0;
  186. /* Get a buffer for this stream, if necessary. */
  187. if (!anybuf(stream)) {
  188. /* Do NOT get a buffer if (1) stream is stdout/stderr, and
  189. (2) stream is NOT a tty.
  190. [If stdout/stderr is a tty, we do NOT set up single char
  191. buffering. This is so that later temporary buffering will
  192. not be thwarted by the _IONBF bit being set (see
  193. _stbuf/_ftbuf usage).]
  194. */
  195. if (!( ((stream==stdout) || (stream==stderr))
  196. #ifdef _POSIX_
  197. && (isatty(fh)) ))
  198. #else
  199. && (_isatty(fh)) ))
  200. #endif
  201. _getbuf(stream);
  202. } /* end !anybuf() */
  203. /* If big buffer is assigned to stream... */
  204. if (bigbuf(stream)) {
  205. _ASSERTE(("inconsistent IOB fields", stream->_ptr - stream->_base >= 0));
  206. charcount = (int)(stream->_ptr - stream->_base);
  207. stream->_ptr = stream->_base + sizeof(TCHAR);
  208. stream->_cnt = stream->_bufsiz - (int)sizeof(TCHAR);
  209. if (charcount > 0)
  210. #ifdef _POSIX_
  211. written = write(fh, stream->_base, charcount);
  212. #else
  213. written = _write(fh, stream->_base, charcount);
  214. #endif
  215. else
  216. #ifdef _POSIX_
  217. if (stream->_flag & _IOAPPEND)
  218. lseek(fh,0l,SEEK_END);
  219. #else
  220. if (_osfile_safe(fh) & FAPPEND)
  221. _lseek(fh,0L,SEEK_END);
  222. #endif
  223. #ifndef _UNICODE
  224. *stream->_base = (char)ch;
  225. #else /* _UNICODE */
  226. *(wchar_t *)(stream->_base) = (wchar_t)(ch & 0xffff);
  227. #endif /* _UNICODE */
  228. }
  229. /* Perform single character output (either _IONBF or no buffering) */
  230. else {
  231. charcount = sizeof(TCHAR);
  232. #ifndef _UNICODE
  233. #ifdef _POSIX_
  234. written = write(fh, &ch, charcount);
  235. #else
  236. written = _write(fh, &ch, charcount);
  237. #endif
  238. #else /* _UNICODE */
  239. {
  240. char mbc[4];
  241. *(wchar_t *)mbc = (wchar_t)(ch & 0xffff);
  242. #ifdef _POSIX_
  243. written = write(fh, mbc, charcount);
  244. #else
  245. written = _write(fh, mbc, charcount);
  246. #endif
  247. }
  248. #endif /* _UNICODE */
  249. }
  250. /* See if the _write() was successful. */
  251. if (written != charcount) {
  252. stream->_flag |= _IOERR;
  253. return(_TEOF);
  254. }
  255. #ifndef _UNICODE
  256. return(ch & 0xff);
  257. #else /* _UNICODE */
  258. return(ch & 0xffff);
  259. #endif /* _UNICODE */
  260. #endif /* _NTSUBSET_ */
  261. }