fgetwc.c 3.4 KB

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