diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2011-10-16 13:20:52 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2011-10-16 13:20:52 +0000 |
commit | f30a2a52ed0b737d6beb7b1c5c4f411bea21bae4 (patch) | |
tree | 6b84a1bbf783aeb9b4591abafb4c394349f199e6 /lib/libc/stdio | |
parent | 70a92ca001f3c5ac3ad8aaaa1d08cbe3848aa2e4 (diff) |
Add wscanf(3) and friends. Based on our scanf(3) implementation, with wide
character support changes based on code from FreeBSD.
ok espie guenther; man page help from schwarze
Diffstat (limited to 'lib/libc/stdio')
-rw-r--r-- | lib/libc/stdio/Makefile.inc | 9 | ||||
-rw-r--r-- | lib/libc/stdio/fwscanf.c | 45 | ||||
-rw-r--r-- | lib/libc/stdio/local.h | 4 | ||||
-rw-r--r-- | lib/libc/stdio/swscanf.c | 45 | ||||
-rw-r--r-- | lib/libc/stdio/ungetwc.c | 19 | ||||
-rw-r--r-- | lib/libc/stdio/vfwscanf.c | 798 | ||||
-rw-r--r-- | lib/libc/stdio/vswscanf.c | 89 | ||||
-rw-r--r-- | lib/libc/stdio/vwscanf.c | 40 | ||||
-rw-r--r-- | lib/libc/stdio/wscanf.3 | 447 | ||||
-rw-r--r-- | lib/libc/stdio/wscanf.c | 45 |
10 files changed, 1531 insertions, 10 deletions
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc index 411e38b6164..7496f06b579 100644 --- a/lib/libc/stdio/Makefile.inc +++ b/lib/libc/stdio/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.18 2011/07/06 19:53:52 stsp Exp $ +# $OpenBSD: Makefile.inc,v 1.19 2011/10/16 13:20:51 stsp Exp $ # stdio sources .PATH: ${LIBCSRCDIR}/stdio @@ -17,12 +17,13 @@ SRCS+= asprintf.c clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c fgetc.c \ wbuf.c wsetup.c flockfile.c __svfscanf.c \ fgetwc.c fgetws.c fputwc.c fputws.c fwide.c getwc.c getwchar.c \ putwc.c putwchar.c ungetwc.c \ - fwprintf.c swprintf.c vfwprintf.c vswprintf.c vwprintf.c wprintf.c + fwprintf.c swprintf.c vfwprintf.c vswprintf.c vwprintf.c wprintf.c \ + fwscanf.c swscanf.c vfwscanf.c vswscanf.c vwscanf.c wscanf.c MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fopen.3 fputs.3 \ fread.3 fseek.3 funopen.3 getc.3 mktemp.3 perror.3 printf.3 putc.3 \ remove.3 scanf.3 setbuf.3 stdio.3 tmpnam.3 ungetc.3 \ - fgetws.3 fputws.3 fwide.3 getwc.3 putwc.3 ungetwc.3 wprintf.3 + fgetws.3 fputws.3 fwide.3 getwc.3 putwc.3 ungetwc.3 wprintf.3 wscanf.3 MLINKS+=ferror.3 clearerr.3 ferror.3 feof.3 ferror.3 fileno.3 MLINKS+=fflush.3 fpurge.3 @@ -47,6 +48,8 @@ MLINKS+=setbuf.3 setbuffer.3 setbuf.3 setlinebuf.3 setbuf.3 setvbuf.3 MLINKS+=tmpnam.3 tempnam.3 tmpnam.3 tmpfile.3 MLINKS+=wprintf.3 fwprintf.3 wprintf.3 swprintf.3 wprintf.3 vwprintf.3 \ wprintf.3 vfwprintf.3 wprintf.3 vswprintf.3 +MLINKS+=wscanf.3 fwscanf.3 wscanf.3 swscanf.3 wscanf.3 vfwscanf.3 wscanf.3 \ + vswscanf.3 wscanf.3 vwscanf.3 MLINKS+=getwc.3 fgetwc.3 getwc.3 getwchar.3 MLINKS+=putwc.3 fputwc.3 putwc.3 putwchar.3 diff --git a/lib/libc/stdio/fwscanf.c b/lib/libc/stdio/fwscanf.c new file mode 100644 index 00000000000..dd8da0a8023 --- /dev/null +++ b/lib/libc/stdio/fwscanf.c @@ -0,0 +1,45 @@ +/* $OpenBSD: fwscanf.c,v 1.1 2011/10/16 13:20:51 stsp Exp $ */ + +/*- + * Copyright (c) 2002 Tim J. Robbins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <stdarg.h> +#include <stdio.h> +#include <wchar.h> + +int +fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = vfwscanf(fp, fmt, ap); + va_end(ap); + + return (r); +} diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h index 7680abefc36..21190207538 100644 --- a/lib/libc/stdio/local.h +++ b/lib/libc/stdio/local.h @@ -1,4 +1,4 @@ -/* $OpenBSD: local.h,v 1.18 2011/04/28 17:38:46 stsp Exp $ */ +/* $OpenBSD: local.h,v 1.19 2011/10/16 13:20:51 stsp Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -57,8 +57,10 @@ int _fwalk(int (*)(FILE *)); int __swsetup(FILE *); int __sflags(const char *, int *); wint_t __fgetwc_unlock(FILE *); +wint_t __ungetwc(wint_t, FILE *); int __vfprintf(FILE *, const char *, __va_list); int __vfwprintf(FILE * __restrict, const wchar_t * __restrict, __va_list); +int __vfwscanf(FILE * __restrict, const wchar_t * __restrict, __va_list); extern void __atexit_register_cleanup(void (*)(void)); extern int __sdidinit; diff --git a/lib/libc/stdio/swscanf.c b/lib/libc/stdio/swscanf.c new file mode 100644 index 00000000000..fc7e21b06cf --- /dev/null +++ b/lib/libc/stdio/swscanf.c @@ -0,0 +1,45 @@ +/* $OpenBSD: swscanf.c,v 1.1 2011/10/16 13:20:51 stsp Exp $ */ + +/*- + * Copyright (c) 2002 Tim J. Robbins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <stdarg.h> +#include <stdio.h> +#include <wchar.h> + +int +swscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = vswscanf(str, fmt, ap); + va_end(ap); + + return (r); +} diff --git a/lib/libc/stdio/ungetwc.c b/lib/libc/stdio/ungetwc.c index 60bee069f52..c0321e9e1e5 100644 --- a/lib/libc/stdio/ungetwc.c +++ b/lib/libc/stdio/ungetwc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ungetwc.c,v 1.4 2009/11/09 00:18:27 kurt Exp $ */ +/* $OpenBSD: ungetwc.c,v 1.5 2011/10/16 13:20:51 stsp Exp $ */ /* $NetBSD: ungetwc.c,v 1.2 2003/01/18 11:29:59 thorpej Exp $ */ /*- @@ -35,14 +35,13 @@ #include "local.h" wint_t -ungetwc(wint_t wc, FILE *fp) +__ungetwc(wint_t wc, FILE *fp) { struct wchar_io_data *wcio; if (wc == WEOF) return WEOF; - FLOCKFILE(fp); _SET_ORIENTATION(fp, 1); /* * XXX since we have no way to transform a wchar string to @@ -52,19 +51,27 @@ ungetwc(wint_t wc, FILE *fp) wcio = WCIO_GET(fp); if (wcio == 0) { - FUNLOCKFILE(fp); errno = ENOMEM; /* XXX */ return WEOF; } if (wcio->wcio_ungetwc_inbuf >= WCIO_UNGETWC_BUFSIZE) { - FUNLOCKFILE(fp); return WEOF; } wcio->wcio_ungetwc_buf[wcio->wcio_ungetwc_inbuf++] = wc; __sclearerr(fp); - FUNLOCKFILE(fp); return wc; } + +wint_t +ungetwc(wint_t wc, FILE *fp) +{ + wint_t r; + + FLOCKFILE(fp); + r = __ungetwc(wc, fp); + FUNLOCKFILE(fp); + return (r); +} diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c new file mode 100644 index 00000000000..942ede0fe97 --- /dev/null +++ b/lib/libc/stdio/vfwscanf.c @@ -0,0 +1,798 @@ +/* $OpenBSD: vfwscanf.c,v 1.1 2011/10/16 13:20:51 stsp Exp $ */ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <ctype.h> +#include <inttypes.h> +#include <limits.h> +#include <locale.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "local.h" + +#ifdef FLOATING_POINT +#include "floatio.h" +#endif + +#define BUF 513 /* Maximum length of numeric string. */ + +/* + * Flags used during conversion. + */ +#define LONG 0x00001 /* l: long or double */ +#define LONGDBL 0x00002 /* L: long double */ +#define SHORT 0x00004 /* h: short */ +#define SHORTSHORT 0x00008 /* hh: 8 bit integer */ +#define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */ +#define POINTER 0x00020 /* p: void * (as hex) */ +#define SIZEINT 0x00040 /* z: (signed) size_t */ +#define MAXINT 0x00080 /* j: intmax_t */ +#define PTRINT 0x00100 /* t: ptrdiff_t */ +#define NOSKIP 0x00200 /* [ or c: do not skip blanks */ +#define SUPPRESS 0x00400 /* *: suppress assignment */ +#define UNSIGNED 0x00800 /* %[oupxX] conversions */ + +/* + * The following are used in numeric conversions only: + * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point; + * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral. + */ +#define SIGNOK 0x01000 /* +/- is (still) legal */ +#define HAVESIGN 0x02000 /* sign detected */ +#define NDIGITS 0x04000 /* no digits detected */ + +#define DPTOK 0x08000 /* (float) decimal point is still legal */ +#define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */ + +#define PFXOK 0x08000 /* 0x prefix is (still) legal */ +#define NZDIGITS 0x10000 /* no zero digits detected */ + +/* + * Conversion types. + */ +#define CT_CHAR 0 /* %c conversion */ +#define CT_CCL 1 /* %[...] conversion */ +#define CT_STRING 2 /* %s conversion */ +#define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */ +#define CT_FLOAT 4 /* floating, i.e., strtod */ + +#define u_char unsigned char +#define u_long unsigned long + +#define INCCL(_c) \ + (cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \ + (wmemchr(ccls, (_c), ccle - ccls) != NULL)) + +/* + * vfwscanf + */ +int +__vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, __va_list ap) +{ + wint_t c; /* character from format, or conversion */ + size_t width; /* field width, or 0 */ + wchar_t *p; /* points into all kinds of strings */ + int n; /* handy integer */ + int flags; /* flags as defined above */ + wchar_t *p0; /* saves original value of p when necessary */ + int nassigned; /* number of fields assigned */ + int nconversions; /* number of conversions */ + int nread; /* number of characters consumed from fp */ + int base; /* base argument to strtoimax/strtouimax */ + wchar_t buf[BUF]; /* buffer for numeric conversions */ + const wchar_t *ccls; /* character class start */ + const wchar_t *ccle; /* character class end */ + int cclcompl; /* ccl is complemented? */ + wint_t wi; /* handy wint_t */ + char *mbp; /* multibyte string pointer for %c %s %[ */ + size_t nconv; /* number of bytes in mb. conversion */ + char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */ + mbstate_t mbs; +#ifdef FLOATING_POINT + wchar_t decimal_point = 0; +#endif + + /* `basefix' is used to avoid `if' tests in the integer scanner */ + static short basefix[17] = + { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + + _SET_ORIENTATION(fp, 1); + + nassigned = 0; + nconversions = 0; + nread = 0; + base = 0; /* XXX just to keep gcc happy */ + ccls = ccle = NULL; + for (;;) { + c = *fmt++; + if (c == 0) { + return (nassigned); + } + if (iswspace(c)) { + while ((c = __fgetwc_unlock(fp)) != WEOF && + iswspace(c)) + ; + if (c != WEOF) + __ungetwc(c, fp); + continue; + } + if (c != '%') + goto literal; + width = 0; + flags = 0; + /* + * switch on the format. continue if done; + * break once format type is derived. + */ +again: c = *fmt++; + switch (c) { + case '%': +literal: + if ((wi = __fgetwc_unlock(fp)) == WEOF) + goto input_failure; + if (wi != c) { + __ungetwc(wi, fp); + goto input_failure; + } + nread++; + continue; + + case '*': + flags |= SUPPRESS; + goto again; + case 'j': + flags |= MAXINT; + goto again; + case 'L': + flags |= LONGDBL; + goto again; + case 'h': + if (*fmt == 'h') { + fmt++; + flags |= SHORTSHORT; + } else { + flags |= SHORT; + } + goto again; + case 'l': + if (*fmt == 'l') { + fmt++; + flags |= LLONG; + } else { + flags |= LONG; + } + goto again; + case 'q': + flags |= LLONG; /* deprecated */ + goto again; + case 't': + flags |= PTRINT; + goto again; + case 'z': + flags |= SIZEINT; + goto again; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + width = width * 10 + c - '0'; + goto again; + + /* + * Conversions. + * Those marked `compat' are for 4.[123]BSD compatibility. + * + * (According to ANSI, E and X formats are supposed + * to the same as e and x. Sorry about that.) + */ + case 'D': /* compat */ + flags |= LONG; + /* FALLTHROUGH */ + case 'd': + c = CT_INT; + base = 10; + break; + + case 'i': + c = CT_INT; + base = 0; + break; + + case 'O': /* compat */ + flags |= LONG; + /* FALLTHROUGH */ + case 'o': + c = CT_INT; + flags |= UNSIGNED; + base = 8; + break; + + case 'u': + c = CT_INT; + flags |= UNSIGNED; + base = 10; + break; + + case 'X': + case 'x': + flags |= PFXOK; /* enable 0x prefixing */ + c = CT_INT; + flags |= UNSIGNED; + base = 16; + break; + +#ifdef FLOATING_POINT + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + case 'a': case 'A': + c = CT_FLOAT; + break; +#endif + + case 's': + c = CT_STRING; + break; + + case '[': + ccls = fmt; + if (*fmt == '^') { + cclcompl = 1; + fmt++; + } else + cclcompl = 0; + if (*fmt == ']') + fmt++; + while (*fmt != '\0' && *fmt != ']') + fmt++; + ccle = fmt; + fmt++; + flags |= NOSKIP; + c = CT_CCL; + break; + + case 'c': + flags |= NOSKIP; + c = CT_CHAR; + break; + + case 'p': /* pointer format is like hex */ + flags |= POINTER | PFXOK; + c = CT_INT; + flags |= UNSIGNED; + base = 16; + break; + + case 'n': + nconversions++; + if (flags & SUPPRESS) + continue; + if (flags & SHORTSHORT) + *va_arg(ap, __signed char *) = nread; + else if (flags & SHORT) + *va_arg(ap, short *) = nread; + else if (flags & LONG) + *va_arg(ap, long *) = nread; + else if (flags & SIZEINT) + *va_arg(ap, ssize_t *) = nread; + else if (flags & PTRINT) + *va_arg(ap, ptrdiff_t *) = nread; + else if (flags & LLONG) + *va_arg(ap, long long *) = nread; + else if (flags & MAXINT) + *va_arg(ap, intmax_t *) = nread; + else + *va_arg(ap, int *) = nread; + continue; + + /* + * Disgusting backwards compatibility hacks. XXX + */ + case '\0': /* compat */ + return (EOF); + + default: /* compat */ + if (isupper(c)) + flags |= LONG; + c = CT_INT; + base = 10; + break; + } + + /* + * Consume leading white space, except for formats + * that suppress this. + */ + if ((flags & NOSKIP) == 0) { + while ((wi = __fgetwc_unlock(fp)) != WEOF && + iswspace(wi)) + nread++; + if (wi == WEOF) + goto input_failure; + __ungetwc(wi, fp); + } + + /* + * Do the conversion. + */ + switch (c) { + + case CT_CHAR: + /* scan arbitrary characters (sets NOSKIP) */ + if (width == 0) + width = 1; + if (flags & LONG) { + if (!(flags & SUPPRESS)) + p = va_arg(ap, wchar_t *); + n = 0; + while (width-- != 0 && + (wi = __fgetwc_unlock(fp)) != WEOF) { + if (!(flags & SUPPRESS)) + *p++ = (wchar_t)wi; + n++; + } + if (n == 0) + goto input_failure; + nread += n; + if (!(flags & SUPPRESS)) + nassigned++; + } else { + if (!(flags & SUPPRESS)) + mbp = va_arg(ap, char *); + n = 0; + bzero(&mbs, sizeof(mbs)); + while (width != 0 && + (wi = __fgetwc_unlock(fp)) != WEOF) { + if (width >= MB_CUR_MAX && + !(flags & SUPPRESS)) { + nconv = wcrtomb(mbp, wi, &mbs); + if (nconv == (size_t)-1) + goto input_failure; + } else { + nconv = wcrtomb(mbbuf, wi, + &mbs); + if (nconv == (size_t)-1) + goto input_failure; + if (nconv > width) { + __ungetwc(wi, fp); + break; + } + if (!(flags & SUPPRESS)) + memcpy(mbp, mbbuf, + nconv); + } + if (!(flags & SUPPRESS)) + mbp += nconv; + width -= nconv; + n++; + } + if (n == 0) + goto input_failure; + nread += n; + if (!(flags & SUPPRESS)) + nassigned++; + } + nconversions++; + break; + + case CT_CCL: + /* scan a (nonempty) character class (sets NOSKIP) */ + if (width == 0) + width = (size_t)~0; /* `infinity' */ + /* take only those things in the class */ + if ((flags & SUPPRESS) && (flags & LONG)) { + n = 0; + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width-- != 0 && INCCL(wi)) + n++; + if (wi != WEOF) + __ungetwc(wi, fp); + if (n == 0) + goto match_failure; + } else if (flags & LONG) { + p0 = p = va_arg(ap, wchar_t *); + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width-- != 0 && INCCL(wi)) + *p++ = (wchar_t)wi; + if (wi != WEOF) + __ungetwc(wi, fp); + n = p - p0; + if (n == 0) + goto match_failure; + *p = 0; + nassigned++; + } else { + if (!(flags & SUPPRESS)) + mbp = va_arg(ap, char *); + n = 0; + bzero(&mbs, sizeof(mbs)); + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width != 0 && INCCL(wi)) { + if (width >= MB_CUR_MAX && + !(flags & SUPPRESS)) { + nconv = wcrtomb(mbp, wi, &mbs); + if (nconv == (size_t)-1) + goto input_failure; + } else { + nconv = wcrtomb(mbbuf, wi, + &mbs); + if (nconv == (size_t)-1) + goto input_failure; + if (nconv > width) + break; + if (!(flags & SUPPRESS)) + memcpy(mbp, mbbuf, + nconv); + } + if (!(flags & SUPPRESS)) + mbp += nconv; + width -= nconv; + n++; + } + if (wi != WEOF) + __ungetwc(wi, fp); + if (!(flags & SUPPRESS)) { + *mbp = 0; + nassigned++; + } + } + nread += n; + nconversions++; + break; + + case CT_STRING: + /* like CCL, but zero-length string OK, & no NOSKIP */ + if (width == 0) + width = (size_t)~0; + if ((flags & SUPPRESS) && (flags & LONG)) { + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width-- != 0 && + !iswspace(wi)) + nread++; + if (wi != WEOF) + __ungetwc(wi, fp); + } else if (flags & LONG) { + p0 = p = va_arg(ap, wchar_t *); + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width-- != 0 && + !iswspace(wi)) { + *p++ = (wchar_t)wi; + nread++; + } + if (wi != WEOF) + __ungetwc(wi, fp); + *p = 0; + nassigned++; + } else { + if (!(flags & SUPPRESS)) + mbp = va_arg(ap, char *); + bzero(&mbs, sizeof(mbs)); + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width != 0 && + !iswspace(wi)) { + if (width >= MB_CUR_MAX && + !(flags & SUPPRESS)) { + nconv = wcrtomb(mbp, wi, &mbs); + if (nconv == (size_t)-1) + goto input_failure; + } else { + nconv = wcrtomb(mbbuf, wi, + &mbs); + if (nconv == (size_t)-1) + goto input_failure; + if (nconv > width) + break; + if (!(flags & SUPPRESS)) + memcpy(mbp, mbbuf, + nconv); + } + if (!(flags & SUPPRESS)) + mbp += nconv; + width -= nconv; + nread++; + } + if (wi != WEOF) + __ungetwc(wi, fp); + if (!(flags & SUPPRESS)) { + *mbp = 0; + nassigned++; + } + } + nconversions++; + continue; + + case CT_INT: + /* scan an integer as if by strtoimax/strtoumax */ + if (width == 0 || width > sizeof(buf) / + sizeof(*buf) - 1) + width = sizeof(buf) / sizeof(*buf) - 1; + flags |= SIGNOK | NDIGITS | NZDIGITS; + for (p = buf; width; width--) { + c = __fgetwc_unlock(fp); + /* + * Switch on the character; `goto ok' + * if we accept it as a part of number. + */ + switch (c) { + + /* + * The digit 0 is always legal, but is + * special. For %i conversions, if no + * digits (zero or nonzero) have been + * scanned (only signs), we will have + * base==0. In that case, we should set + * it to 8 and enable 0x prefixing. + * Also, if we have not scanned zero digits + * before this, do not turn off prefixing + * (someone else will turn it off if we + * have scanned any nonzero digits). + */ + case '0': + if (base == 0) { + base = 8; + flags |= PFXOK; + } + if (flags & NZDIGITS) + flags &= ~(SIGNOK|NZDIGITS|NDIGITS); + else + flags &= ~(SIGNOK|PFXOK|NDIGITS); + goto ok; + + /* 1 through 7 always legal */ + case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + base = basefix[base]; + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + + /* digits 8 and 9 ok iff decimal or hex */ + case '8': case '9': + base = basefix[base]; + if (base <= 8) + break; /* not legal here */ + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + + /* letters ok iff hex */ + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + /* no need to fix base here */ + if (base <= 10) + break; /* not legal here */ + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + + /* sign ok only as first character */ + case '+': case '-': + if (flags & SIGNOK) { + flags &= ~SIGNOK; + flags |= HAVESIGN; + goto ok; + } + break; + + /* + * x ok iff flag still set and 2nd char (or + * 3rd char if we have a sign). + */ + case 'x': case 'X': + if ((flags & PFXOK) && p == + buf + 1 + !!(flags & HAVESIGN)) { + base = 16; /* if %i */ + flags &= ~PFXOK; + goto ok; + } + break; + } + + /* + * If we got here, c is not a legal character + * for a number. Stop accumulating digits. + */ + if (c != WEOF) + __ungetwc(c, fp); + break; + ok: + /* + * c is legal: store it and look at the next. + */ + *p++ = (wchar_t)c; + } + /* + * If we had only a sign, it is no good; push + * back the sign. If the number ends in `x', + * it was [sign] '0' 'x', so push back the x + * and treat it as [sign] '0'. + */ + if (flags & NDIGITS) { + if (p > buf) + __ungetwc(*--p, fp); + goto match_failure; + } + c = p[-1]; + if (c == 'x' || c == 'X') { + --p; + __ungetwc(c, fp); + } + if ((flags & SUPPRESS) == 0) { + uintmax_t res; + + *p = '\0'; + if (flags & UNSIGNED) + res = wcstoimax(buf, NULL, base); + else + res = wcstoumax(buf, NULL, base); + if (flags & POINTER) + *va_arg(ap, void **) = + (void *)(uintptr_t)res; + else if (flags & MAXINT) + *va_arg(ap, intmax_t *) = res; + else if (flags & LLONG) + *va_arg(ap, long long *) = res; + else if (flags & SIZEINT) + *va_arg(ap, ssize_t *) = res; + else if (flags & PTRINT) + *va_arg(ap, ptrdiff_t *) = res; + else if (flags & LONG) + *va_arg(ap, long *) = res; + else if (flags & SHORT) + *va_arg(ap, short *) = res; + else if (flags & SHORTSHORT) + *va_arg(ap, __signed char *) = res; + else + *va_arg(ap, int *) = res; + nassigned++; + } + nread += p - buf; + nconversions++; + break; + +#ifdef FLOATING_POINT + case CT_FLOAT: + /* scan a floating point number as if by strtod */ + if (width == 0 || width > sizeof(buf) / + sizeof(*buf) - 1) + width = sizeof(buf) / sizeof(*buf) - 1; + flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; + for (p = buf; width; width--) { + c = __fgetwc_unlock(fp); + /* + * This code mimicks the integer conversion + * code, but is much simpler. + */ + switch (c) { + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + flags &= ~(SIGNOK | NDIGITS); + goto fok; + + case '+': case '-': + if (flags & SIGNOK) { + flags &= ~SIGNOK; + goto fok; + } + break; + case 'e': case 'E': + /* no exponent without some digits */ + if ((flags&(NDIGITS|EXPOK)) == EXPOK) { + flags = + (flags & ~(EXPOK|DPTOK)) | + SIGNOK | NDIGITS; + goto fok; + } + break; + default: + if (decimal_point == 0) { + bzero(&mbs, sizeof(mbs)); + nconv = mbrtowc(&decimal_point, + localeconv()->decimal_point, + MB_CUR_MAX, &mbs); + if (nconv == 0 || + nconv == (size_t)-1 || + nconv == (size_t)-2) + decimal_point = '.'; + } + if (c == decimal_point && + (flags & DPTOK)) { + flags &= ~(SIGNOK | DPTOK); + goto fok; + } + break; + } + if (c != WEOF) + __ungetwc(c, fp); + break; + fok: + *p++ = c; + } + /* + * If no digits, might be missing exponent digits + * (just give back the exponent) or might be missing + * regular digits, but had sign and/or decimal point. + */ + if (flags & NDIGITS) { + if (flags & EXPOK) { + /* no digits at all */ + while (p > buf) + __ungetwc(*--p, fp); + goto match_failure; + } + /* just a bad exponent (e and maybe sign) */ + c = *--p; + if (c != 'e' && c != 'E') { + __ungetwc(c, fp);/* sign */ + c = *--p; + } + __ungetwc(c, fp); + } + if ((flags & SUPPRESS) == 0) { + *p = 0; + if (flags & LONGDBL) { + long double res = wcstold(buf, NULL); + *va_arg(ap, long double *) = res; + } else if (flags & LONG) { + double res = wcstod(buf, NULL); + *va_arg(ap, double *) = res; + } else { + float res = wcstof(buf, NULL); + *va_arg(ap, float *) = res; + } + nassigned++; + } + nread += p - buf; + nconversions++; + break; +#endif /* FLOATING_POINT */ + } + } +input_failure: + return (nconversions != 0 ? nassigned : EOF); +match_failure: + return (nassigned); +} + +int +vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, __va_list ap) +{ + int r; + + FLOCKFILE(fp); + r = __vfwscanf(fp, fmt, ap); + FUNLOCKFILE(fp); + return (r); +} diff --git a/lib/libc/stdio/vswscanf.c b/lib/libc/stdio/vswscanf.c new file mode 100644 index 00000000000..0057ab17eb2 --- /dev/null +++ b/lib/libc/stdio/vswscanf.c @@ -0,0 +1,89 @@ +/* $OpenBSD: vswscanf.c,v 1.1 2011/10/16 13:20:51 stsp Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Donn Seeley at UUNET Technologies, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include "local.h" + +static int eofread(void *, char *, int); + +static int +eofread(void *cookie, char *buf, int len) +{ + return (0); +} + +int +vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, + __va_list ap) +{ + mbstate_t mbs; + FILE f; + struct __sfileext fext; + char *mbstr; + size_t len, mlen; + int r; + const wchar_t *strp; + + /* + * XXX Convert the wide character string to multibyte, which + * __vfwscanf() will convert back to wide characters. + */ + len = wcslen(str) * MB_CUR_MAX; + if ((mbstr = malloc(len + 1)) == NULL) + return (EOF); + bzero(&mbs, sizeof(mbs)); + strp = str; + if ((mlen = wcsrtombs(mbstr, &strp, len, &mbs)) == (size_t)-1) { + free(mbstr); + return (EOF); + } + if (mlen == len) + mbstr[len] = '\0'; + _FILEEXT_SETUP(&f, &fext); + f._flags = __SRD; + f._bf._base = f._p = (unsigned char *)mbstr; + f._bf._size = f._r = mlen; + f._read = eofread; + f._lb._base = NULL; + r = __vfwscanf(&f, fmt, ap); + free(mbstr); + + return (r); +} diff --git a/lib/libc/stdio/vwscanf.c b/lib/libc/stdio/vwscanf.c new file mode 100644 index 00000000000..c05c5d90587 --- /dev/null +++ b/lib/libc/stdio/vwscanf.c @@ -0,0 +1,40 @@ +/* $OpenBSD: vwscanf.c,v 1.1 2011/10/16 13:20:51 stsp Exp $ */ + +/*- + * Copyright (c) 2002 Tim J. Robbins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +#include <stdarg.h> +#include <stdio.h> +#include <wchar.h> + +int +vwscanf(const wchar_t * __restrict fmt, __va_list ap) +{ + + return (vfwscanf(stdin, fmt, ap)); +} diff --git a/lib/libc/stdio/wscanf.3 b/lib/libc/stdio/wscanf.3 new file mode 100644 index 00000000000..9f17be70a3c --- /dev/null +++ b/lib/libc/stdio/wscanf.3 @@ -0,0 +1,447 @@ +.\" $OpenBSD: wscanf.3,v 1.1 2011/10/16 13:20:51 stsp Exp $ +.\" +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Chris Torek and the American National Standards Committee X3, +.\" on Information Processing Systems. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)scanf.3 8.2 (Berkeley) 12/11/93 +.\" FreeBSD: src/lib/libc/stdio/scanf.3,v 1.24 2003/06/28 09:03:25 das Exp +.\" +.Dd $Mdocdate: October 16 2011 $ +.Dt WSCANF 3 +.Os +.Sh NAME +.Nm wscanf , +.Nm fwscanf , +.Nm swscanf , +.Nm vwscanf , +.Nm vswscanf , +.Nm vfwscanf +.Nd wide character input format conversion +.Sh SYNOPSIS +.In stdio.h +.In wchar.h +.Ft int +.Fn wscanf "const wchar_t * restrict format" ... +.Ft int +.Fn fwscanf "FILE * restrict stream" "const wchar_t * restrict format" ... +.Ft int +.Fn swscanf "const wchar_t * restrict str" "const wchar_t * restrict format" ... +.In stdarg.h +.Ft int +.Fn vwscanf "const wchar_t * restrict format" "va_list ap" +.Ft int +.Fn vswscanf "const wchar_t * restrict str" "const wchar_t * restrict format" "va_list ap" +.Ft int +.Fn vfwscanf "FILE * restrict stream" "const wchar_t * restrict format" "va_list ap" +.Sh DESCRIPTION +The +.Fn wscanf +family of functions read input according to the given +.Fa format +as described below. +This format may contain +.Dq conversion specifiers ; +the results of such conversions, if any, are stored through a set of pointer +arguments. +.Pp +The +.Fn wscanf +function reads input from the standard input stream +.Em stdin , +.Fn fwscanf +reads input from the supplied stream pointer +.Fa stream , +and +.Fn swscanf +reads its input from the wide character string pointed to by +.Fa str . +.Pp +The +.Fn vfwscanf +function is analogous to +.Xr vfwprintf 3 +and reads input from the stream pointer +.Fa stream +using a variable argument list of pointers (see +.Xr stdarg 3 ) . +The +.Fn vwscanf +function scans a variable argument list from the standard input and the +.Fn vswscanf +function scans it from a wide character string; these are analogous to the +.Fn vwprintf +and +.Fn vswprintf +functions, respectively. +.Pp +Each successive +.Em pointer +argument must correspond properly with each successive conversion specifier +(but see the +.Cm * +conversion below). +All conversions are introduced by the +.Cm % +(percent sign) character. +The +.Fa format +string may also contain other characters. +Whitespace (such as blanks, tabs, or newlines) in the +.Fa format +string match any amount of whitespace, including none, in the input. +Everything else matches only itself. +Scanning stops when an input character does not match such a format character. +Scanning also stops when an input conversion cannot be made (see below). +.Sh CONVERSIONS +Following the +.Cm % +character, introducing a conversion, there may be a number of +.Em flag +characters, as follows: +.Bl -tag -width "ll (ell ell)" +.It Cm * +Suppresses assignment. +The conversion that follows occurs as usual, but no pointer is used; +the result of the conversion is simply discarded. +.It Cm hh +Indicates that the conversion will be one of +.Cm dioux +or +.Cm n +and the next pointer is a pointer to a +.Vt char +(rather than +.Vt int ) . +.It Cm h +Indicates that the conversion will be one of +.Cm dioux +or +.Cm n +and the next pointer is a pointer to a +.Vt "short int" +(rather than +.Vt int ) . +.It Cm l No (ell) +Indicates that the conversion will be one of +.Cm dioux +or +.Cm n +and the next pointer is a pointer to a +.Vt "long int" +(rather than +.Vt int ) , +that the conversion will be one of +.Cm a , e , f , +or +.Cm g +and the next pointer is a pointer to +.Vt double +(rather than +.Vt float ) , +or that the conversion will be one of +.Cm c +or +.Cm s +and the next pointer is a pointer to an array of +.Vt wchar_t +(rather than +.Vt char ) . +.It Cm ll No (ell ell) +Indicates that the conversion will be one of +.Cm dioux +or +.Cm n +and the next pointer is a pointer to a +.Vt "long long int" +(rather than +.Vt int ) . +.It Cm L +Indicates that the conversion will be one of +.Cm a , e , f , +or +.Cm g +and the next pointer is a pointer to +.Vt "long double" . +.It Cm j +Indicates that the conversion will be one of +.Cm dioux +or +.Cm n +and the next pointer is a pointer to an +.Vt intmax_t +(rather than +.Vt int ) . +.It Cm t +Indicates that the conversion will be one of +.Cm dioux +or +.Cm n +and the next pointer is a pointer to a +.Vt ptrdiff_t +(rather than +.Vt int ) . +.It Cm z +Indicates that the conversion will be one of +.Cm dioux +or +.Cm n +and the next pointer is a pointer to a +.Vt size_t +(rather than +.Vt int ) . +.It Cm q +(deprecated) +Indicates that the conversion will be one of +.Cm dioux +or +.Cm n +and the next pointer is a pointer to a +.Vt "long long int" +(rather than +.Vt int ) . +.El +.Pp +In addition to these flags, there may be an optional maximum field width, +expressed as a decimal integer, between the +.Cm % +and the conversion. +If no width is given, +a default of +.Dq infinity +is used (with one exception, below); +otherwise at most this many characters are scanned in processing the +conversion. +Before conversion begins, most conversions skip whitespace; +this whitespace is not counted against the field width. +.Pp +The following conversions are available: +.Bl -tag -width XXXX +.It Cm % +Matches a literal +.Ql % . +That is, +.Dq Li %% +in the format string matches a single input +.Ql % +character. +No conversion is done, and assignment does not occur. +.It Cm d +Matches an optionally signed decimal integer; +the next pointer must be a pointer to +.Vt int . +.It Cm i +Matches an optionally signed integer; +the next pointer must be a pointer to +.Vt int . +The integer is read in base 16 if it begins +with +.Ql 0x +or +.Ql 0X , +in base 8 if it begins with +.Ql 0 , +and in base 10 otherwise. +Only characters that correspond to the base are used. +.It Cm o +Matches an octal integer; +the next pointer must be a pointer to +.Vt "unsigned int" . +.It Cm u +Matches an optionally signed decimal integer; +the next pointer must be a pointer to +.Vt "unsigned int" . +.It Cm x , X +Matches an optionally signed hexadecimal integer; +the next pointer must be a pointer to +.Vt "unsigned int" . +.It Cm a , A , e , E , f , F , g , G +Matches a floating-point number in the style of +.Xr wcstod 3 . +The next pointer must be a pointer to +.Vt float +(unless +.Cm l +or +.Cm L +is specified.) +.It Cm s +Matches a sequence of non-whitespace wide characters; +the next pointer must be a pointer to +.Vt char , +and the provided array must be large enough to accept and store +the multibyte representation of all the sequence and the +terminating NUL character. +The input string stops at whitespace +or at the maximum field width, whichever occurs first. +If specified, the maximum field length refers to the sequence +being scanned rather than the storage space, hence the provided +array must be 1 larger for the terminating NUL character. +.Pp +If an +.Cm l +qualifier is present, the next pointer must be a pointer to +.Vt wchar_t , +into which the input will be placed. +.It Cm c +Matches a sequence of wide characters consuming the number of wide characters +specified by the field width (defaults to 1 if unspecified); +the next pointer must be a pointer to +.Vt char , +and there must be enough room for the multibyte representation +of all the characters +(no terminating NUL is added). +The usual skip of leading whitespace is suppressed. +To skip whitespace first, use an explicit space in the format. +.Pp +If an +.Cm l +qualifier is present, the next pointer must be a pointer to +.Vt wchar_t , +into which the input will be placed. +.It Cm \&[ +Matches a nonempty sequence of characters from the specified set +of accepted characters; +the next pointer must be a pointer to +.Vt char , +and there must be enough room for the multibyte representation of +all the characters in the string, +plus a terminating NUL character. +The usual skip of leading whitespace is suppressed. +.Pp +The string is to be made up of characters in +(or not in) +a particular set; +the set is defined by the characters between the open bracket +.Cm \&[ +character +and a close bracket +.Cm \&] +character. +The set +.Em excludes +those characters +if the first character after the open bracket is a circumflex +.Cm ^ . +To include a close bracket in the set, +make it the first character after the open bracket +or the circumflex; +any other position will end the set. +To include a hyphen in the set, +make it the last character before the final close bracket; +some implementations of +.Fn wscanf +use +.Dq Li A-Z +to represent the range of characters between +.Ql A +and +.Ql Z . +The string ends with the appearance of a character not in +(or, with a circumflex, in) the set +or when the field width runs out. +.Pp +If an +.Cm l +qualifier is present, the next pointer must be a pointer to +.Vt wchar_t , +into which the input will be placed. +.It Cm p +Matches a pointer value (as printed by +.Ql %p +in +.Xr wprintf 3 ) ; +the next pointer must be a pointer to +.Vt void . +.It Cm n +Nothing is expected; +instead, the number of characters consumed thus far from the input +is stored through the next pointer, +which must be a pointer to +.Vt int . +This is +.Em not +a conversion, although it can be suppressed with the +.Cm * +flag. +.El +.Pp +The decimal point +character is defined in the program's locale (category +.Dv LC_NUMERIC ) . +.Pp +For backwards compatibility, a +.Dq conversion +of +.Ql %\e0 +causes an immediate return of +.Dv EOF . +.Sh RETURN VALUES +These functions return the number of input items assigned, which can be fewer +than provided for, or even zero, in the event of a matching failure. +Zero indicates that, while there was input available, no conversions were +assigned; typically this is due to an invalid input character, +such as an alphabetic character for a +.Ql %d +conversion. +The value +.Dv EOF +is returned if an input failure occurs before any conversion such as an +end-of-file occurs. +If an error or end-of-file occurs after conversion has begun, +the number of conversions which were successfully completed is returned. +.Sh SEE ALSO +.Xr fgetwc 3 , +.Xr scanf 3 , +.Xr wcrtomb 3 , +.Xr wcstod 3 , +.Xr wcstol 3 , +.Xr wcstoul 3 , +.Xr wprintf 3 +.Sh STANDARDS +The functions +.Fn wscanf , +.Fn fwscanf , +.Fn swscanf , +.Fn vwscanf , +.Fn vfwscanf , +and +.Fn vswscanf +conform to +.St -isoC-99 . +.Sh BUGS +In addition to the bugs documented in +.Xr scanf 3 , +.Fn wscanf +does not support the +.Dq Li A-Z +notation for specifying character ranges with the character +class conversion +.Pq Sq Cm %[ . diff --git a/lib/libc/stdio/wscanf.c b/lib/libc/stdio/wscanf.c new file mode 100644 index 00000000000..d5e7c261a03 --- /dev/null +++ b/lib/libc/stdio/wscanf.c @@ -0,0 +1,45 @@ +/* $OpenBSD: wscanf.c,v 1.1 2011/10/16 13:20:51 stsp Exp $ */ + +/*- + * Copyright (c) 2002 Tim J. Robbins + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#include <stdarg.h> +#include <stdio.h> +#include <wchar.h> + +int +wscanf(const wchar_t * __restrict fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = vfwscanf(stdin, fmt, ap); + va_end(ap); + + return (r); +} |