ungetc.c 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  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. /* Having ungotten characters implies the stream is reading.
  9. * The scheme used here treats the least significant 2 bits of
  10. * the stream's modeflags member as follows:
  11. * 0 0 Not currently reading.
  12. * 0 1 Reading, but no ungetc() or scanf() push back chars.
  13. * 1 0 Reading with one ungetc() char (ungot[1] is 1)
  14. * or one scanf() pushed back char (ungot[1] is 0).
  15. * 1 1 Reading with both an ungetc() char and a scanf()
  16. * pushed back char. Note that this must be the result
  17. * of a scanf() push back (in ungot[0]) _followed_ by
  18. * an ungetc() call (in ungot[1]).
  19. *
  20. * Notes:
  21. * scanf() can NOT use ungetc() to push back characters.
  22. * (See section 7.19.6.2 of the C9X rationale -- WG14/N897.)
  23. */
  24. int ungetc(int c, register FILE *stream)
  25. {
  26. __STDIO_AUTO_THREADLOCK_VAR;
  27. __STDIO_AUTO_THREADLOCK(stream);
  28. __STDIO_STREAM_VALIDATE(stream);
  29. #ifdef __UCLIBC_MJN3_ONLY__
  30. #warning CONSIDER: Make fast ungetc an option?
  31. #endif
  32. #ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__
  33. /* If buffered narrow reading with no ungot slots filled, and if not
  34. * ungetting a different char than the one last read from the buffer,
  35. * we can simply decrement the position and not worry about disabling
  36. * the getc macros. This will cut down on overhead in applications
  37. * that use getc/ungetc extensively (like gcc). */
  38. /* NOTE: If we can use getc, then we are buffered narrow reading with
  39. * no ungot slots filled. */
  40. if (__STDIO_STREAM_CAN_USE_BUFFER_GET(stream)
  41. && (c != EOF)
  42. && (stream->__bufpos > stream->__bufstart)
  43. && (stream->__bufpos[-1] == ((unsigned char)c))
  44. ) {
  45. --stream->__bufpos;
  46. __STDIO_STREAM_CLEAR_EOF(stream); /* Must clear end-of-file flag. */
  47. } else
  48. #endif
  49. /* Note: Even if c == EOF, we need to initialize/verify the
  50. * stream's orientation and ensure the stream is in reading
  51. * mode (if readable and properly oriented). */
  52. if ((!__STDIO_STREAM_IS_NARROW_READING(stream)
  53. && __STDIO_STREAM_TRANS_TO_READ(stream, __FLAG_NARROW))
  54. || ((stream->__modeflags & __FLAG_UNGOT)
  55. && ((stream->__modeflags & 1) || stream->__ungot[1]))
  56. ) {
  57. c = EOF;
  58. } else if (c != EOF) {
  59. __STDIO_STREAM_DISABLE_GETC(stream);
  60. /* Flag this as a user ungot, as scanf does the necessary fixup. */
  61. stream->__ungot[1] = 1;
  62. stream->__ungot[(++stream->__modeflags) & 1] = c;
  63. __STDIO_STREAM_CLEAR_EOF(stream); /* Must clear end-of-file flag. */
  64. }
  65. __STDIO_STREAM_VALIDATE(stream);
  66. __STDIO_AUTO_THREADUNLOCK(stream);
  67. return c;
  68. }
  69. libc_hidden_def(ungetc)