commit 567ff7edd184b1e0d3d3988f73860068a194ae91
parent ce905e8370025cc5fd2f22a518d58df17c0dda5b
Author: Michael Forney <mforney@mforney.org>
Date: Mon, 4 Oct 2021 00:24:29 -0700
libc: Add implementation of ungetc
Co-authored-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
Diffstat:
3 files changed, 37 insertions(+), 0 deletions(-)
diff --git a/src/libc/objs/common-objs.mk b/src/libc/objs/common-objs.mk
@@ -57,6 +57,7 @@ COMMON_OBJS =\
stdio/snprintf.$O\
stdio/sprintf.$O\
stdio/tmpnam.$O\
+ stdio/ungetc.$O\
stdio/vfprintf.$O\
stdio/vprintf.$O\
stdio/vsnprintf.$O\
diff --git a/src/libc/stdio/Makefile b/src/libc/stdio/Makefile
@@ -40,6 +40,7 @@ OBJS =\
sprintf.$O\
__iob.$O\
tmpnam.$O\
+ ungetc.$O\
vfprintf.$O\
vsnprintf.$O\
vsprintf.$O\
diff --git a/src/libc/stdio/ungetc.c b/src/libc/stdio/ungetc.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+
+/**
+ * ungetc() - push back one character to a input stream
+ *
+ * Context: A stream just opened has rp, wp, lp and buf pointing to NULL,
+ * in the same way that a closed stream. In both cases we have to
+ * return EOF, so the check fp->rp == fp->buf detects both cases.
+ * An input stream can be either a read only input or a read and
+ * write input in read state, and we can detect the write state
+ * when wp does not point to the beginning of buf. _IOSTRG is used
+ * in sprintf/sscanf functions, where it is possible rp points to
+ * a constant string, so we cannot write back c, but it is safe
+ * because in those functions we are going to push back always
+ * the same character that the one contained in the string.
+ */
+int
+ungetc(int c, FILE *fp)
+{
+ if (c == EOF)
+ return EOF;
+
+ if ((fp->flags & _IOWRITE) != 0)
+ return EOF;
+
+ if (fp->rp == fp->buf || fp->wp != fp->buf)
+ return EOF;
+
+ --fp->rp;
+ if ((fp->flags & _IOSTRG) == 0)
+ *fp->rp = c;
+ fp->flags &= ~_IOEOF;
+
+ return c;
+}