fgetwc.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
  2. *
  3. * GNU Library General Public License (LGPL) version 2 or later.
  4. *
  5. * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
  6. */
  7. #include "_stdio.h"
  8. libc_hidden_proto(fgetwc_unlocked)
  9. libc_hidden_proto(mbrtowc)
  10. #ifdef __DO_UNLOCKED
  11. static void munge_stream(register FILE *stream, unsigned char *buf)
  12. {
  13. stream->__bufend = stream->__bufstart = buf;
  14. __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream);
  15. __STDIO_STREAM_DISABLE_GETC(stream);
  16. __STDIO_STREAM_DISABLE_PUTC(stream);
  17. }
  18. wint_t fgetwc_unlocked(register FILE *stream)
  19. {
  20. wint_t wi;
  21. wchar_t wc[1];
  22. int n;
  23. size_t r;
  24. unsigned char sbuf[1];
  25. __STDIO_STREAM_VALIDATE(stream);
  26. wi = WEOF; /* Prepare for failure. */
  27. if (__STDIO_STREAM_IS_WIDE_READING(stream)
  28. || !__STDIO_STREAM_TRANS_TO_READ(stream, __FLAG_WIDE)
  29. ) {
  30. if (stream->__modeflags & __FLAG_UNGOT) { /* Any ungetwc()s? */
  31. if (((stream->__modeflags & 1) || stream->__ungot[1])) {
  32. stream->__ungot_width[0] = 0; /* Application ungot... */
  33. } else { /* scanf ungot */
  34. stream->__ungot_width[0] = stream->__ungot_width[1];
  35. }
  36. wi = stream->__ungot[(stream->__modeflags--) & 1];
  37. stream->__ungot[1] = 0;
  38. goto DONE;
  39. }
  40. if (!stream->__bufstart) { /* Ugh... stream isn't buffered! */
  41. /* Munge the stream temporarily to use a 1-byte buffer. */
  42. munge_stream(stream, sbuf);
  43. ++stream->__bufend;
  44. }
  45. if (stream->__state.__mask == 0) { /* If last was a complete char */
  46. stream->__ungot_width[0] = 0; /* then reset the width. */
  47. }
  48. LOOP:
  49. if ((n = __STDIO_STREAM_BUFFER_RAVAIL(stream)) == 0) {
  50. goto FILL_BUFFER;
  51. }
  52. r = mbrtowc(wc, stream->__bufpos, n, &stream->__state);
  53. if (((ssize_t) r) >= 0) { /* Success... */
  54. if (r == 0) { /* Nul wide char... means 0 byte for us so */
  55. ++r; /* increment r and handle below as single. */
  56. }
  57. stream->__bufpos += r;
  58. stream->__ungot_width[0] += r;
  59. wi = *wc;
  60. goto DONE;
  61. }
  62. if (r == ((size_t) -2)) {
  63. /* Potentially valid but incomplete and no more buffered. */
  64. stream->__bufpos += n; /* Update bufpos for stream. */
  65. stream->__ungot_width[0] += n;
  66. FILL_BUFFER:
  67. if(__STDIO_FILL_READ_BUFFER(stream)) { /* Refill succeeded? */
  68. goto LOOP;
  69. }
  70. if (!__FERROR_UNLOCKED(stream)) { /* EOF with no error. */
  71. if (!stream->__state.__mask) { /* No partial wchar. */
  72. goto DONE;
  73. }
  74. /* EOF but partially complete wchar. */
  75. /* TODO: should EILSEQ be set? */
  76. __set_errno(EILSEQ);
  77. }
  78. }
  79. /* If we reach here, either r == ((size_t)-1) and mbrtowc set errno
  80. * to EILSEQ, or r == ((size_t)-2) and stream is in an error state
  81. * or at EOF with a partially complete wchar. Make sure stream's
  82. * error indicator is set. */
  83. stream->__modeflags |= __FLAG_ERROR;
  84. DONE:
  85. if (stream->__bufstart == sbuf) { /* Need to un-munge the stream. */
  86. munge_stream(stream, NULL);
  87. }
  88. }
  89. __STDIO_STREAM_VALIDATE(stream);
  90. return wi;
  91. }
  92. libc_hidden_def(fgetwc_unlocked)
  93. strong_alias(fgetwc_unlocked,getwc_unlocked)
  94. #ifndef __UCLIBC_HAS_THREADS__
  95. libc_hidden_proto(fgetwc)
  96. strong_alias(fgetwc_unlocked,fgetwc)
  97. libc_hidden_def(fgetwc)
  98. strong_alias(fgetwc_unlocked,getwc)
  99. #endif
  100. #elif defined __UCLIBC_HAS_THREADS__
  101. libc_hidden_proto(fgetwc)
  102. wint_t fgetwc(register FILE *stream)
  103. {
  104. wint_t retval;
  105. __STDIO_AUTO_THREADLOCK_VAR;
  106. __STDIO_AUTO_THREADLOCK(stream);
  107. retval = fgetwc_unlocked(stream);
  108. __STDIO_AUTO_THREADUNLOCK(stream);
  109. return retval;
  110. }
  111. libc_hidden_def(fgetwc)
  112. strong_alias(fgetwc,getwc)
  113. #endif