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.

229 lines
7.3 KiB

  1. /***
  2. *ungetwc.c - unget a wide character from a stream
  3. *
  4. * Copyright (c) 1993-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines ungetwc() - pushes a wide character back onto an input stream
  8. *
  9. *Revision History:
  10. * 04-26-93 CFW Module created.
  11. * 04-30-93 CFW Bring wide char support from ungetc.c.
  12. * 05-10-93 CFW Optimize, fix error handling.
  13. * 06-02-93 CFW Wide get/put use wint_t.
  14. * 07-16-93 SRW ALPHA Merge
  15. * 09-15-93 CFW Use ANSI conformant "__" names.
  16. * 10-01-93 CFW Test only for TEXT, update comments.
  17. * 10-28-93 CFW Test for both IOSTRG and TEXT.
  18. * 11-10-93 GJF Merged in NT SDK version (picked up fix to a cast
  19. * expression). Also replaced MTHREAD with _MT.
  20. * 02-07-94 CFW POSIXify.
  21. * 08-31-94 CFW Fix for "C" locale, call wctomb().
  22. * 02-06-94 CFW assert -> _ASSERTE.
  23. * 03-07-95 GJF _[un]lock_str macros now take FILE * arg.
  24. * 06-12-95 GJF Replaced _osfile[] with _osfile() (macro referencing
  25. * field in ioinfo struct).
  26. * 07-28-95 GJF Replaced _osfile() with _osfile_safe().
  27. * 03-02-98 GJF Exception-safe locking.
  28. * 11-05-08 GJF Don't push back characters onto strings (i.e., when
  29. * called by swscanf).
  30. * 12-16-99 GB Modified for the case when return value from wctomb is
  31. * greater then 2.
  32. *
  33. *******************************************************************************/
  34. #ifndef _POSIX_
  35. #include <cruntime.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <file2.h>
  39. #include <dbgint.h>
  40. #include <internal.h>
  41. #include <mtdll.h>
  42. #include <msdos.h>
  43. #include <errno.h>
  44. #include <wchar.h>
  45. #include <setlocal.h>
  46. #ifdef _MT /* multi-thread; define both ungetwc and _lk_ungetwc */
  47. /***
  48. *wint_t ungetwc(ch, stream) - put a wide character back onto a stream
  49. *
  50. *Purpose:
  51. * Guaranteed one char pushback on a stream as long as open for reading.
  52. * More than one char pushback in a row is not guaranteed, and will fail
  53. * if it follows an ungetc which pushed the first char in buffer. Failure
  54. * causes return of WEOF.
  55. *
  56. *Entry:
  57. * wint_t ch - wide character to push back
  58. * FILE *stream - stream to push character onto
  59. *
  60. *Exit:
  61. * returns ch
  62. * returns WEOF if tried to push WEOF, stream not opened for reading or
  63. * or if we have already ungetc'd back to beginning of buffer.
  64. *
  65. *Exceptions:
  66. *
  67. *******************************************************************************/
  68. wint_t __cdecl ungetwc (
  69. REG2 wint_t ch,
  70. REG1 FILE *stream
  71. )
  72. {
  73. wint_t retval;
  74. _ASSERTE(stream != NULL);
  75. _lock_str(stream);
  76. __try {
  77. retval = _ungetwc_lk (ch, stream);
  78. }
  79. __finally {
  80. _unlock_str(stream);
  81. }
  82. return(retval);
  83. }
  84. /***
  85. *_ungetwc_lk() - Ungetwc() core routine (locked version)
  86. *
  87. *Purpose:
  88. * Core ungetwc() routine; assumes stream is already locked.
  89. *
  90. * [See ungetwc() above for more info.]
  91. *
  92. *Entry: [See ungetwc()]
  93. *
  94. *Exit: [See ungetwc()]
  95. *
  96. *Exceptions:
  97. *
  98. *******************************************************************************/
  99. wint_t __cdecl _ungetwc_lk (
  100. wint_t ch,
  101. FILE *str
  102. )
  103. {
  104. #else /* non multi-thread; just define ungetc */
  105. wint_t __cdecl ungetwc (
  106. wint_t ch,
  107. FILE *str
  108. )
  109. {
  110. #endif /* rejoin common code */
  111. _ASSERTE(str != NULL);
  112. /*
  113. * Requirements for success:
  114. *
  115. * 1. Character to be pushed back on the stream must not be WEOF.
  116. *
  117. * 2. The stream must currently be in read mode, or must be open for
  118. * update (i.e., read/write) and must NOT currently be in write
  119. * mode.
  120. */
  121. if ( (ch != WEOF) &&
  122. ( (str->_flag & _IOREAD) || ((str->_flag & _IORW) &&
  123. !(str->_flag & _IOWRT))
  124. )
  125. )
  126. {
  127. /* If stream is unbuffered, get one. */
  128. if (str->_base == NULL)
  129. _getbuf(str);
  130. #ifndef _NTSUBSET_
  131. if (!(str->_flag & _IOSTRG) && (_osfile_safe(_fileno(str)) &
  132. FTEXT))
  133. {
  134. /*
  135. * Text mode, sigh... Convert the wc to a mbc.
  136. */
  137. int size, i;
  138. char mbc[MB_LEN_MAX];
  139. if ((size = wctomb(mbc, ch)) == -1)
  140. {
  141. /*
  142. * Conversion failed! Set errno and return
  143. * failure.
  144. */
  145. errno = EILSEQ;
  146. return WEOF;
  147. }
  148. /* we know _base != NULL; since file is buffered */
  149. if (str->_ptr < str->_base + size)
  150. {
  151. if (str->_cnt)
  152. /* my back is against the wall; i've already done
  153. * ungetwc, and there's no room for this one
  154. */
  155. return WEOF;
  156. if (size > str->_bufsiz)
  157. return WEOF;
  158. str->_ptr = size + str->_base;
  159. }
  160. for ( i = size -1; i >= 0; i--)
  161. {
  162. *--str->_ptr = mbc[i];
  163. }
  164. str->_cnt += size;
  165. str->_flag &= ~_IOEOF;
  166. str->_flag |= _IOREAD; /* may already be set */
  167. return (wint_t) (0x0ffff & ch);
  168. }
  169. #endif
  170. /*
  171. * Binary mode or a string (from swscanf) - push back the wide
  172. * character
  173. */
  174. /* we know _base != NULL; since file is buffered */
  175. if (str->_ptr < str->_base + sizeof(wchar_t))
  176. {
  177. if (str->_cnt)
  178. /* my back is against the wall; i've already done
  179. * ungetc, and there's no room for this one
  180. */
  181. return WEOF;
  182. if (sizeof(wchar_t) > str->_bufsiz)
  183. return WEOF;
  184. str->_ptr = sizeof(wchar_t) + str->_base;
  185. }
  186. if (str->_flag & _IOSTRG) {
  187. /* If stream opened by swscanf do not modify buffer */
  188. if (*--((wchar_t *)(str->_ptr)) != (wchar_t)ch) {
  189. ++((wchar_t *)(str->_ptr));
  190. return WEOF;
  191. }
  192. } else
  193. *--((wchar_t *)(str->_ptr)) = (wchar_t)(ch & 0xffff);
  194. str->_cnt += sizeof(wchar_t);
  195. str->_flag &= ~_IOEOF;
  196. str->_flag |= _IOREAD; /* may already be set */
  197. return (wint_t)(ch & 0xffff);
  198. }
  199. return WEOF;
  200. }
  201. #endif /* _POSIX_ */