shithub: scc

Download patch

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;
+}