fgetwc.c 3.4 KB

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