diff options
Diffstat (limited to 'libc/src/yscanf.c')
-rw-r--r-- | libc/src/yscanf.c | 55 |
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); +} |