summaryrefslogtreecommitdiff
path: root/libc/src/yscanf.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/src/yscanf.c')
-rw-r--r--libc/src/yscanf.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/libc/src/yscanf.c b/libc/src/yscanf.c
new file mode 100644
index 0000000..3d2a488
--- /dev/null
+++ b/libc/src/yscanf.c
@@ -0,0 +1,55 @@
+#include "stdio.h"
+
+struct opaque_t {
+ union {
+ const char * p;
+ int fd;
+ };
+ uint8_t bsize;
+ char backbuffer[3];
+};
+
+static int str_getc(void * _opaque) {
+ struct opaque_t * opaque = (struct opaque_t *) _opaque;
+ int r;
+
+ if (opaque->bsize)
+ return opaque->backbuffer[--(opaque->bsize)];
+
+ r = *(opaque->p++);
+
+ return r ? r : EOF;
+}
+
+static int file_getc(void * _opaque) {
+ struct opaque_t * opaque = (struct opaque_t *) _opaque;
+ uint8_t v;
+
+ if (opaque->bsize)
+ return opaque->backbuffer[--(opaque->bsize)];
+
+ if (read(opaque->fd, &v, 1) != 1)
+ return EOF;
+ return v;
+}
+
+static void scanf_ungetc(void * _opaque, int c) {
+ struct opaque_t * opaque = (struct opaque_t *) _opaque;
+
+ if (opaque->bsize < sizeof(opaque->backbuffer))
+ opaque->backbuffer[opaque->bsize++] = c;
+}
+
+int vsscanf(const char * str, const char * format, va_list ap) {
+ struct opaque_t opaque;
+ opaque.p = str;
+ opaque.bsize = 0;
+ return vxscanf(str_getc, scanf_ungetc, &opaque, format, ap);
+}
+
+int vdscanf(int fd, const char * format, va_list ap) {
+ struct opaque_t opaque;
+ opaque.fd = fd;
+ opaque.bsize = 0;
+ return vxscanf(file_getc, scanf_ungetc, &opaque, format, ap);
+}