fgetwc.c 3.3 KB

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