summaryrefslogtreecommitdiff
path: root/libc/stdio/scanf.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/stdio/scanf.c')
-rw-r--r--libc/stdio/scanf.c96
1 files changed, 83 insertions, 13 deletions
diff --git a/libc/stdio/scanf.c b/libc/stdio/scanf.c
index 11deea38c..9f811968a 100644
--- a/libc/stdio/scanf.c
+++ b/libc/stdio/scanf.c
@@ -25,6 +25,10 @@
* Bug fix: scanf %lc,%ls,%l[ would always set mb_fail on eof or error,
* even when just starting a new mb char.
* Bug fix: wscanf would incorrectly unget in certain situations.
+ *
+ * Sep 5, 2003
+ * Bug fix: store flag wasn't respected if no positional args.
+ * Implement vs{n}scanf for the non-buffered stdio no-wchar case.
*/
@@ -72,6 +76,20 @@
#undef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__
#endif
+#undef __STDIO_HAS_VSSCANF
+#if defined(__STDIO_BUFFERS) || !defined(__UCLIBC_HAS_WCHAR__) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
+#define __STDIO_HAS_VSSCANF 1
+
+#if !defined(__STDIO_BUFFERS) && !defined(__UCLIBC_HAS_WCHAR__)
+typedef struct {
+ FILE f;
+ unsigned char *bufread; /* pointer to 1 past end of buffer */
+ unsigned char *bufpos;
+} __FILE_vsscanf;
+#endif
+
+#endif
+
extern void _store_inttype(void *dest, int desttype, uintmax_t val);
#ifdef LLONG_MAX
@@ -143,7 +161,7 @@ int scanf(const char * __restrict format, ...)
/**********************************************************************/
#ifdef L_sscanf
-#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
+#ifdef __STDIO_HAS_VSSCANF
int sscanf(const char * __restrict str, const char * __restrict format, ...)
{
@@ -157,9 +175,9 @@ int sscanf(const char * __restrict str, const char * __restrict format, ...)
return rv;
}
-#else /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
-#warning Skipping sscanf since no buffering and no custom streams!
-#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
+#else /* __STDIO_HAS_VSSCANF */
+#warning Skipping sscanf since no vsscanf!
+#endif /* __STDIO_HAS_VSSCANF */
#endif
/**********************************************************************/
@@ -179,6 +197,7 @@ int vscanf(const char * __restrict format, va_list arg)
#endif /* __UCLIBC_MJN3_ONLY__ */
#ifdef __STDIO_BUFFERS
+
int vsscanf(__const char *sp, __const char *fmt, va_list ap)
{
FILE string[1];
@@ -202,8 +221,32 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap)
return vfscanf(string, fmt, ap);
}
-#else /* __STDIO_BUFFERS */
-#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
+
+#elif !defined(__UCLIBC_HAS_WCHAR__)
+
+int vsscanf(__const char *sp, __const char *fmt, va_list ap)
+{
+ __FILE_vsscanf string[1];
+
+ string->f.filedes = -2;
+ string->f.modeflags = (__FLAG_NARROW|__FLAG_READONLY);
+ string->bufpos = (unsigned char *) ((void *) sp);
+ string->bufread = string->bufpos + strlen(sp);
+
+#ifdef __STDIO_MBSTATE
+#error __STDIO_MBSTATE is defined!
+#endif /* __STDIO_MBSTATE */
+
+#ifdef __STDIO_THREADSAFE
+ string->user_locking = 0;
+ __stdio_init_mutex(&string->f.lock);
+#endif
+
+ return vfscanf(&string->f, fmt, ap);
+}
+
+#elif defined(__STDIO_GLIBC_CUSTOM_STREAMS)
+
int vsscanf(__const char *sp, __const char *fmt, va_list ap)
{
FILE *f;
@@ -217,10 +260,13 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap)
return rv;
}
-#else /* __STDIO_GLIBC_CUSTOM_STREAMS */
-#warning Skipping vsscanf since no buffering and no custom streams!
-#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
-#endif /* __STDIO_BUFFERS */
+
+#else
+#warning Skipping vsscanf since no buffering, no custom streams, and wchar enabled!
+#ifdef __STDIO_HAS_VSSCANF
+#error WHOA! __STDIO_HAS_VSSCANF is defined!
+#endif
+#endif
#endif
/**********************************************************************/
@@ -617,10 +663,28 @@ int __scan_getc(register struct scan_cookie *sc)
}
if (sc->ungot_flag == 0) {
+#if !defined(__STDIO_BUFFERS) && !defined(__UCLIBC_HAS_WCHAR__)
+ if (sc->fp->filedes != -2) {
+ c = GETC(sc);
+ } else {
+ __FILE_vsscanf *fv = (__FILE_vsscanf *)(sc->fp);
+ if (fv->bufpos < fv->bufread) {
+ c = *fv->bufpos++;
+ } else {
+ c = EOF;
+ sc->fp->modeflags |= __FLAG_EOF;
+ }
+ }
+ if (c == EOF) {
+ sc->ungot_flag |= 2;
+ return -1;
+ }
+#else
if ((c = GETC(sc)) == EOF) {
sc->ungot_flag |= 2;
return -1;
}
+#endif
sc->ungot_char = c;
} else {
assert(sc->ungot_flag == 1);
@@ -962,7 +1026,13 @@ static __inline void kill_scan_cookie(register struct scan_cookie *sc)
#ifdef L_vfscanf
if (sc->ungot_flag & 1) {
+#if !defined(__STDIO_BUFFERS) && !defined(__UCLIBC_HAS_WCHAR__)
+ if (sc->fp->filedes != -2) {
+ ungetc(sc->ungot_char, sc->fp);
+ }
+#else
ungetc(sc->ungot_char, sc->fp);
+#endif
/* Deal with distiction between user and scanf ungots. */
if (sc->nread == 0) { /* Only one char was read... app ungot? */
sc->fp->ungot[1] = sc->app_ungot; /* restore ungot state. */
@@ -1146,8 +1216,8 @@ int VFSCANF (FILE *__restrict fp, const Wchar *__restrict format, va_list arg)
}
fmt += i;
-#if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
if (psfs.store) {
+#if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
if (psfs.num_pos_args == -2) {
psfs.cur_ptr = va_arg(arg, void *);
} else {
@@ -1156,10 +1226,10 @@ int VFSCANF (FILE *__restrict fp, const Wchar *__restrict format, va_list arg)
}
psfs.cur_ptr = psfs.pos_args[psfs.cur_pos_arg];
}
- }
#else /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
- psfs.cur_ptr = va_arg(arg, void *);
+ psfs.cur_ptr = va_arg(arg, void *);
#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
+ }
DO_CONVERSION:
/* First, consume white-space if not n, c, [, C, or l[. */