ref: 81fbf1e91adceadae1bafa06682a7f47ca28fce2
parent: 68fc5b73b8cc4ba666d8d30d74762c71a0653a9d
author: Michael Forney <mforney@mforney.org>
date: Sun Oct 3 20:24:29 EDT 2021
libc: Add implementation of ungetc Co-authored-by: Roberto E. Vargas Caballero <k0ga@shike2.com>
--- a/src/libc/objs/common-objs.mk
+++ b/src/libc/objs/common-objs.mk
@@ -57,6 +57,7 @@
stdio/snprintf.$O\
stdio/sprintf.$O\
stdio/tmpnam.$O\
+ stdio/ungetc.$O\
stdio/vfprintf.$O\
stdio/vprintf.$O\
stdio/vsnprintf.$O\
--- a/src/libc/stdio/Makefile
+++ b/src/libc/stdio/Makefile
@@ -40,6 +40,7 @@
sprintf.$O\
__iob.$O\
tmpnam.$O\
+ ungetc.$O\
vfprintf.$O\
vsnprintf.$O\
vsprintf.$O\
--- /dev/null
+++ b/src/libc/stdio/ungetc.c
@@ -1,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;
+}