diff options
| author | christos <christos@NetBSD.org> | 2005-05-14 23:51:02 +0000 |
|---|---|---|
| committer | christos <christos@NetBSD.org> | 2005-05-14 23:51:02 +0000 |
| commit | f432bbb6fd73bc9d4d16cf9c092973e4e42be033 (patch) | |
| tree | 56cbac36b68d8cb044f5972fa52a2acea82b3a69 /lib | |
| parent | f023cb8f18705041e5180cb1052cdd3f01e81b9b (diff) | |
Add the missing wide char support functions from freebsd.
XXX: long double support is missing until we get gdtoa, and add the
necessary wide functions.
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/libc/stdio/Makefile.inc | 37 | ||||
| -rw-r--r-- | lib/libc/stdio/fgetstr.c | 6 | ||||
| -rw-r--r-- | lib/libc/stdio/fgetwln.3 | 121 | ||||
| -rw-r--r-- | lib/libc/stdio/fgetwln.c | 78 | ||||
| -rw-r--r-- | lib/libc/stdio/floatio.h | 13 | ||||
| -rw-r--r-- | lib/libc/stdio/fwprintf.c | 53 | ||||
| -rw-r--r-- | lib/libc/stdio/fwscanf.c | 53 | ||||
| -rw-r--r-- | lib/libc/stdio/local.h | 7 | ||||
| -rw-r--r-- | lib/libc/stdio/swprintf.c | 53 | ||||
| -rw-r--r-- | lib/libc/stdio/swscanf.c | 53 | ||||
| -rw-r--r-- | lib/libc/stdio/vfwprintf.c | 1748 | ||||
| -rw-r--r-- | lib/libc/stdio/vfwscanf.c | 886 | ||||
| -rw-r--r-- | lib/libc/stdio/vswprintf.c | 100 | ||||
| -rw-r--r-- | lib/libc/stdio/vswscanf.c | 104 | ||||
| -rw-r--r-- | lib/libc/stdio/vwprintf.c | 47 | ||||
| -rw-r--r-- | lib/libc/stdio/vwscanf.c | 47 | ||||
| -rw-r--r-- | lib/libc/stdio/wprintf.3 | 623 | ||||
| -rw-r--r-- | lib/libc/stdio/wprintf.c | 53 | ||||
| -rw-r--r-- | lib/libc/stdio/wscanf.3 | 484 | ||||
| -rw-r--r-- | lib/libc/stdio/wscanf.c | 53 |
20 files changed, 4598 insertions, 21 deletions
diff --git a/lib/libc/stdio/Makefile.inc b/lib/libc/stdio/Makefile.inc index e3ecfb0f002..0f9224968db 100644 --- a/lib/libc/stdio/Makefile.inc +++ b/lib/libc/stdio/Makefile.inc @@ -1,5 +1,5 @@ # from: @(#)Makefile.inc 5.7 (Berkeley) 6/27/91 -# $NetBSD: Makefile.inc,v 1.28 2004/05/10 17:02:21 drochner Exp $ +# $NetBSD: Makefile.inc,v 1.29 2005/05/14 23:51:02 christos Exp $ # stdio sources .PATH: ${.CURDIR}/stdio @@ -7,17 +7,19 @@ CPPFLAGS+=-DFLOATING_POINT SRCS+= asprintf.c clrerr.c fclose.c fdopen.c feof.c ferror.c fflush.c \ - fgetc.c fgetln.c fgetpos.c fgets.c fileno.c findfp.c flags.c \ - flockfile.c fopen.c fprintf.c fpurge.c fputc.c fputs.c fread.c \ + fgetc.c fgetln.c fgetpos.c fgets.c fgetstr.c fgetwc.c fgetwln.c \ + fgetws.c fileno.c findfp.c flags.c flockfile.c fopen.c fparseln.c \ + fprintf.c fpurge.c fputc.c fputs.c fputwc.c fputws.c fread.c \ freopen.c fscanf.c fseek.c fseeko.c fsetpos.c ftell.c ftello.c \ - funopen.c fvwrite.c fwalk.c fwrite.c getc.c getchar.c gettemp.c \ - getw.c makebuf.c mkdtemp.c mkstemp.c perror.c printf.c putc.c \ - putchar.c puts.c putw.c refill.c remove.c rewind.c rget.c scanf.c \ - setbuf.c setbuffer.c setvbuf.c snprintf.c sscanf.c stdio.c tmpfile.c \ - ungetc.c vasprintf.c vfprintf.c vfscanf.c vprintf.c vscanf.c \ - vsnprintf.c vsscanf.c wbuf.c wsetup.c fputwc.c fputws.c \ - fgetwc.c fgetws.c ungetwc.c putwc.c putwchar.c getwc.c getwchar.c \ - fwide.c fparseln.c fgetstr.c + funopen.c fvwrite.c fwalk.c fwide.c fwprintf.c fwrite.c fwscanf.c \ + getc.c getchar.c gettemp.c getw.c getwc.c getwchar.c makebuf.c \ + mkdtemp.c mkstemp.c perror.c printf.c putc.c putchar.c puts.c \ + putw.c putwc.c putwchar.c refill.c remove.c rewind.c rget.c \ + scanf.c setbuf.c setbuffer.c setvbuf.c snprintf.c sscanf.c \ + stdio.c swprintf.c swscanf.c tmpfile.c ungetc.c ungetwc.c \ + vasprintf.c vfprintf.c vfscanf.c vfwprintf.c vfwscanf.c vprintf.c \ + vscanf.c vsnprintf.c vsscanf.c vswprintf.c vswscanf.c vwprintf.c \ + vwscanf.c wbuf.c wprintf.c wscanf.c wsetup.c .if !defined(AUDIT) SRCS+= gets.c sprintf.c vsprintf.c tempnam.c tmpnam.c mktemp.c @@ -26,10 +28,11 @@ SRCS+= gets.c sprintf.c vsprintf.c tempnam.c tmpnam.c mktemp.c # namespace purity wrappers SRCS+= _fileno.c _fseeko.c _ftello.c -MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 flockfile.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 putwc.3 \ - getwc.3 ungetwc.3 fwide.3 fparseln.3 fgetws.3 fputws.3 +MAN+= fclose.3 ferror.3 fflush.3 fgetln.3 fgets.3 fgetwln.3 fgetws.3 \ + flockfile.3 fopen.3 fparseln.3 fputs.3 fputws.3 fread.3 fseek.3 \ + funopen.3 fwide.3 getc.3 getwc.3 mktemp.3 perror.3 printf.3 \ + putc.3 putwc.3 remove.3 scanf.3 setbuf.3 stdio.3 tmpnam.3 \ + ungetc.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 @@ -55,3 +58,7 @@ MLINKS+=setbuf.3 setbuffer.3 setbuf.3 setlinebuf.3 setbuf.3 setvbuf.3 MLINKS+=tmpnam.3 tempnam.3 tmpnam.3 tmpfile.3 MLINKS+=putwc.3 fputwc.3 putwc.3 putwchar.3 MLINKS+=getwc.3 fgetwc.3 getwc.3 getwchar.3 +MLINKS+=wprintf.3 fwprintf.3 wprintf.3 swprintf.3 +MLINKS+=wprintf.3 vwprintf.3 wprintf.3 vfwprintf.3 wprintf.3 vswprintf.3 +MLINKS+=wscanf.3 fwscanf.3 wscanf.3 swscanf.3 wscanf.3 vwscanf.3 +MLINKS+=wscanf.3 vswscanf.3 wscanf.3 vfwscanf.3 diff --git a/lib/libc/stdio/fgetstr.c b/lib/libc/stdio/fgetstr.c index f04dcf60154..0a74389f015 100644 --- a/lib/libc/stdio/fgetstr.c +++ b/lib/libc/stdio/fgetstr.c @@ -1,4 +1,4 @@ -/* $NetBSD: fgetstr.c,v 1.2 2004/05/10 16:47:11 drochner Exp $ */ +/* $NetBSD: fgetstr.c,v 1.3 2005/05/14 23:51:02 christos Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)fgetline.c 8.1 (Berkeley) 6/4/93"; #else -__RCSID("$NetBSD: fgetstr.c,v 1.2 2004/05/10 16:47:11 drochner Exp $"); +__RCSID("$NetBSD: fgetstr.c,v 1.3 2005/05/14 23:51:02 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -50,8 +50,6 @@ __RCSID("$NetBSD: fgetstr.c,v 1.2 2004/05/10 16:47:11 drochner Exp $"); #include "reentrant.h" #include "local.h" -int __slbexpand __P((FILE *, size_t)); - /* * Expand the line buffer. Return -1 on error. #ifdef notdef diff --git a/lib/libc/stdio/fgetwln.3 b/lib/libc/stdio/fgetwln.3 new file mode 100644 index 00000000000..e041f8f3780 --- /dev/null +++ b/lib/libc/stdio/fgetwln.3 @@ -0,0 +1,121 @@ +.\" $NetBSD: fgetwln.3,v 1.1 2005/05/14 23:51:02 christos Exp $ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 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. +.\" +.\" @(#)fgetln.3 8.3 (Berkeley) 4/19/94 +.\" $FreeBSD: src/lib/libc/stdio/fgetwln.3,v 1.1 2004/07/16 06:06:09 tjr Exp $ +.\" +.Dd July 16, 2004 +.Dt FGETWLN 3 +.Os +.Sh NAME +.Nm fgetwln +.Nd get a line of wide characters from a stream +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdio.h +.In wchar.h +.Ft wchar_t * +.Fn fgetwln "FILE * restrict stream" "size_t * restrict len" +.Sh DESCRIPTION +The +.Fn fgetwln +function +returns a pointer to the next line from the stream referenced by +.Fa stream . +This line is +.Em not +a standard wide character string as it does not end with a terminating +null wide character. +The length of the line, including the final newline, +is stored in the memory location to which +.Fa len +points. +(Note, however, that if the line is the last +in a file that does not end in a newline, +the returned text will not contain a newline.) +.Sh RETURN VALUES +Upon successful completion a pointer is returned; +this pointer becomes invalid after the next +.Tn I/O +operation on +.Fa stream +(whether successful or not) +or as soon as the stream is closed. +Otherwise, +.Dv NULL +is returned. +The +.Fn fgetwln +function +does not distinguish between end-of-file and error; the routines +.Xr feof 3 +and +.Xr ferror 3 +must be used +to determine which occurred. +If an error occurs, the global variable +.Va errno +is set to indicate the error. +The end-of-file condition is remembered, even on a terminal, and all +subsequent attempts to read will return +.Dv NULL +until the condition is +cleared with +.Xr clearerr 3 . +.Pp +The text to which the returned pointer points may be modified, +provided that no changes are made beyond the returned size. +These changes are lost as soon as the pointer becomes invalid. +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EBADF +The argument +.Fa stream +is not a stream open for reading. +.El +.Pp +The +.Fn fgetwln +function +may also fail and set +.Va errno +for any of the errors specified for the routines +.Xr mbrtowc 3 , +.Xr realloc 3 , +or +.Xr read 2 . +.Sh SEE ALSO +.Xr ferror 3 , +.Xr fgetln 3 , +.Xr fgetws 3 , +.Xr fopen 3 diff --git a/lib/libc/stdio/fgetwln.c b/lib/libc/stdio/fgetwln.c new file mode 100644 index 00000000000..761f1da6e6f --- /dev/null +++ b/lib/libc/stdio/fgetwln.c @@ -0,0 +1,78 @@ +/* $NetBSD: fgetwln.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ + +/*- + * Copyright (c) 2002-2004 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/fgetwln.c,v 1.2 2004/08/06 17:00:09 tjr Exp $"); +#else +__RCSID("$NetBSD: fgetwln.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" +#include <stdio.h> +#include <wchar.h> +#include "reentrant.h" +#include "local.h" + +#ifdef __weak_alias +__weak_alias(fgetwln,_fgetwln) +#endif + +wchar_t * +fgetwln(FILE * __restrict fp, size_t *lenp) +{ + wint_t wc; + size_t len; + + FLOCKFILE(fp); + _SET_ORIENTATION(fp, 1); + + len = 0; + while ((wc = __fgetwc_unlock(fp)) != WEOF) { +#define GROW 512 + if (len * sizeof(wchar_t) >= fp->_lb._size && + __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) + goto error; + *((wchar_t *)(void *)fp->_lb._base + len++) = wc; + if (wc == L'\n') + break; + } + if (len == 0) + goto error; + + FUNLOCKFILE(fp); + *lenp = len; + return ((wchar_t *)(void *)fp->_lb._base); + +error: + FUNLOCKFILE(fp); + *lenp = 0; + return (NULL); +} diff --git a/lib/libc/stdio/floatio.h b/lib/libc/stdio/floatio.h index ecef6340c97..6c04cc2e2c6 100644 --- a/lib/libc/stdio/floatio.h +++ b/lib/libc/stdio/floatio.h @@ -1,4 +1,4 @@ -/* $NetBSD: floatio.h,v 1.4 2003/08/07 16:43:24 agc Exp $ */ +/* $NetBSD: floatio.h,v 1.5 2005/05/14 23:51:02 christos Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -42,3 +42,14 @@ #define MAXEXP 308 /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */ #define MAXFRACT 39 +/* + * MAXEXPDIG is the maximum number of decimal digits needed to store a + * floating point exponent in the largest supported format. It should + * be ceil(log10(LDBL_MAX_10_EXP)) or, if hexadecimal floating point + * conversions are supported, ceil(log10(LDBL_MAX_EXP)). But since it + * is presently never greater than 5 in practice, we fudge it. + */ +#define MAXEXPDIG 6 +#if LDBL_MAX_EXP > 999999 +#error "floating point buffers too small" +#endif diff --git a/lib/libc/stdio/fwprintf.c b/lib/libc/stdio/fwprintf.c new file mode 100644 index 00000000000..5360687d9ad --- /dev/null +++ b/lib/libc/stdio/fwprintf.c @@ -0,0 +1,53 @@ +/* $NetBSD: fwprintf.c,v 1.1 2005/05/14 23:51:02 christos 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/fwprintf.c,v 1.1 2002/09/21 13:00:30 tjr Exp $"); +#else +__RCSID("$NetBSD: fwprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <stdarg.h> +#include <stdio.h> +#include <wchar.h> + +int +fwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vfwprintf(fp, fmt, ap); + va_end(ap); + + return (ret); +} diff --git a/lib/libc/stdio/fwscanf.c b/lib/libc/stdio/fwscanf.c new file mode 100644 index 00000000000..4595c330ab7 --- /dev/null +++ b/lib/libc/stdio/fwscanf.c @@ -0,0 +1,53 @@ +/* $NetBSD: fwscanf.c,v 1.1 2005/05/14 23:51:02 christos 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/fwscanf.c,v 1.1 2002/09/23 12:40:06 tjr Exp $"); +#else +__RCSID("$NetBSD: fwscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#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 379f4fa0950..3dd68f36201 100644 --- a/lib/libc/stdio/local.h +++ b/lib/libc/stdio/local.h @@ -1,4 +1,4 @@ -/* $NetBSD: local.h,v 1.19 2005/02/09 21:35:47 kleink Exp $ */ +/* $NetBSD: local.h,v 1.20 2005/05/14 23:51:02 christos Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -76,6 +76,11 @@ extern wint_t __fgetwc_unlock __P((FILE *)); extern wint_t __fputwc_unlock __P((wchar_t, FILE *)); extern char *__fgetstr __P((FILE * __restrict, size_t * __restrict, int)); +extern int __slbexpand __P((FILE *, size_t)); +extern int __vfwprintf_unlocked __P((FILE *, const wchar_t *, + _BSD_VA_LIST_)); +extern int __vfwscanf_unlocked __P((FILE * __restrict, + const wchar_t * __restrict, _BSD_VA_LIST_)); /* * Return true iff the given FILE cannot be written now. diff --git a/lib/libc/stdio/swprintf.c b/lib/libc/stdio/swprintf.c new file mode 100644 index 00000000000..b769b3186d2 --- /dev/null +++ b/lib/libc/stdio/swprintf.c @@ -0,0 +1,53 @@ +/* $NetBSD: swprintf.c,v 1.1 2005/05/14 23:51:02 christos 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/swprintf.c,v 1.1 2002/09/21 13:00:30 tjr Exp $"); +#else +__RCSID("$NetBSD: swprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <stdarg.h> +#include <stdio.h> +#include <wchar.h> + +int +swprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vswprintf(s, n, fmt, ap); + va_end(ap); + + return (ret); +} diff --git a/lib/libc/stdio/swscanf.c b/lib/libc/stdio/swscanf.c new file mode 100644 index 00000000000..9e7eecddc86 --- /dev/null +++ b/lib/libc/stdio/swscanf.c @@ -0,0 +1,53 @@ +/* $NetBSD: swscanf.c,v 1.1 2005/05/14 23:51:02 christos 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/swscanf.c,v 1.1 2002/09/23 12:40:06 tjr Exp $"); +#else +__RCSID("$NetBSD: swscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#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/vfwprintf.c b/lib/libc/stdio/vfwprintf.c new file mode 100644 index 00000000000..7fe250e913e --- /dev/null +++ b/lib/libc/stdio/vfwprintf.c @@ -0,0 +1,1748 @@ +/* $NetBSD: vfwprintf.c,v 1.1 2005/05/14 23:51:02 christos 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93"; +__FBSDID("$FreeBSD: src/lib/libc/stdio/vfwprintf.c,v 1.24 2005/04/16 22:36:51 das Exp $"); +#else +__RCSID("$NetBSD: vfwprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +/* + * Actual wprintf innards. + * + * Avoid making gratuitous changes to this source file; it should be kept + * as close as possible to vfprintf.c for ease of maintenance. + */ + +#include "namespace.h" +#include <sys/types.h> + +#include <assert.h> +#include <ctype.h> +#include <limits.h> +#include <locale.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <wchar.h> +#include <wctype.h> + +#include "reentrant.h" +#include "local.h" +#include "extern.h" +#include "fvwrite.h" + +union arg { + int intarg; + u_int uintarg; + long longarg; + u_long ulongarg; + quad_t longlongarg; + u_quad_t ulonglongarg; + ptrdiff_t ptrdiffarg; + size_t sizearg; + intmax_t intmaxarg; + uintmax_t uintmaxarg; + void *pvoidarg; + char *pchararg; + signed char *pschararg; + short *pshortarg; + int *pintarg; + long *plongarg; + quad_t *plonglongarg; + ptrdiff_t *pptrdiffarg; + size_t *psizearg; + intmax_t *pintmaxarg; +#ifndef NO_FLOATING_POINT + double doublearg; + long double longdoublearg; +#endif + wint_t wintarg; + wchar_t *pwchararg; +}; + +/* + * Type ids for argument type table. + */ +enum typeid { + T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT, + T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG, + T_PTRDIFFT, TP_PTRDIFFT, T_SIZET, TP_SIZET, + T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR, + T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR +}; + +static int __sbprintf(FILE *, const wchar_t *, va_list); +static wint_t __xfputwc(wchar_t, FILE *); +static wchar_t *__ujtoa(uintmax_t, wchar_t *, int, int, const char *, int, + char, const char *); +static wchar_t *__ultoa(u_long, wchar_t *, int, int, const char *, int, + char, const char *); +static wchar_t *__mbsconv(char *, int); +static void __find_arguments(const wchar_t *, va_list, union arg **); +static void __grow_type_table(int, enum typeid **, int *); + +/* + * Helper function for `fprintf to unbuffered unix file': creates a + * temporary buffer. We only work on write-only files; this avoids + * worries about ungetc buffers and so forth. + */ +static int +__sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) +{ + int ret; + FILE fake; + unsigned char buf[BUFSIZ]; + + /* copy the important variables */ + fake._flags = fp->_flags & ~__SNBF; + fake._file = fp->_file; + fake._cookie = fp->_cookie; + fake._write = fp->_write; + + /* set up the buffer */ + fake._bf._base = fake._p = buf; + fake._bf._size = fake._w = sizeof(buf); + fake._lbfsize = 0; /* not actually used, but Just In Case */ + + /* do the work, then copy any error status */ + ret = __vfwprintf_unlocked(&fake, fmt, ap); + if (ret >= 0 && fflush(&fake)) + ret = WEOF; + if (fake._flags & __SERR) + fp->_flags |= __SERR; + return (ret); +} + +/* + * Like __fputwc, but handles fake string (__SSTR) files properly. + * File must already be locked. + */ +static wint_t +__xfputwc(wchar_t wc, FILE *fp) +{ + static const mbstate_t initial; + mbstate_t mbs; + char buf[MB_LEN_MAX]; + struct __suio uio; + struct __siov iov; + size_t len; + + if ((fp->_flags & __SSTR) == 0) + return (__fputwc_unlock(wc, fp)); + + mbs = initial; + if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) { + fp->_flags |= __SERR; + return (WEOF); + } + uio.uio_iov = &iov; + uio.uio_resid = len; + uio.uio_iovcnt = 1; + iov.iov_base = buf; + iov.iov_len = len; + return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF); +} + +/* + * Macros for converting digits to letters and vice versa + */ +#define to_digit(c) ((c) - '0') +#define is_digit(c) ((unsigned)to_digit(c) <= 9) +#define to_char(n) (wchar_t)((n) + '0') + +/* + * Convert an unsigned long to ASCII for printf purposes, returning + * a pointer to the first character of the string representation. + * Octal numbers can be forced to have a leading zero; hex numbers + * use the given digits. + */ +static wchar_t * +__ultoa(u_long val, wchar_t *endp, int base, int octzero, const char *xdigs, + int needgrp, char thousep, const char *grp) +{ + wchar_t *cp = endp; + long sval; + int ndig; + + /* + * Handle the three cases separately, in the hope of getting + * better/faster code. + */ + switch (base) { + case 10: + if (val < 10) { /* many numbers are 1 digit */ + *--cp = to_char(val); + return (cp); + } + ndig = 0; + /* + * On many machines, unsigned arithmetic is harder than + * signed arithmetic, so we do at most one unsigned mod and + * divide; this is sufficient to reduce the range of + * the incoming value to where signed arithmetic works. + */ + if (val > LONG_MAX) { + *--cp = to_char(val % 10); + ndig++; + sval = val / 10; + } else + sval = val; + do { + *--cp = to_char(sval % 10); + ndig++; + /* + * If (*grp == CHAR_MAX) then no more grouping + * should be performed. + */ + if (needgrp && ndig == *grp && *grp != CHAR_MAX + && sval > 9) { + *--cp = thousep; + ndig = 0; + /* + * If (*(grp+1) == '\0') then we have to + * use *grp character (last grouping rule) + * for all next cases + */ + if (*(grp+1) != '\0') + grp++; + } + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + if (octzero && *cp != '0') + *--cp = '0'; + break; + + case 16: + do { + *--cp = xdigs[(size_t)val & 15]; + val >>= 4; + } while (val); + break; + + default: /* oops */ + abort(); + } + return (cp); +} + +/* Identical to __ultoa, but for intmax_t. */ +static wchar_t * +__ujtoa(uintmax_t val, wchar_t *endp, int base, int octzero, + const char *xdigs, int needgrp, char thousep, const char *grp) +{ + wchar_t *cp = endp; + intmax_t sval; + int ndig; + + /* quick test for small values; __ultoa is typically much faster */ + /* (perhaps instead we should run until small, then call __ultoa?) */ + if (val <= ULONG_MAX) + return (__ultoa((u_long)val, endp, base, octzero, xdigs, + needgrp, thousep, grp)); + switch (base) { + case 10: + if (val < 10) { + *--cp = to_char(val % 10); + return (cp); + } + ndig = 0; + if (val > INTMAX_MAX) { + *--cp = to_char(val % 10); + ndig++; + sval = val / 10; + } else + sval = val; + do { + *--cp = to_char(sval % 10); + ndig++; + /* + * If (*grp == CHAR_MAX) then no more grouping + * should be performed. + */ + if (needgrp && *grp != CHAR_MAX && ndig == *grp + && sval > 9) { + *--cp = thousep; + ndig = 0; + /* + * If (*(grp+1) == '\0') then we have to + * use *grp character (last grouping rule) + * for all next cases + */ + if (*(grp+1) != '\0') + grp++; + } + sval /= 10; + } while (sval != 0); + break; + + case 8: + do { + *--cp = to_char(val & 7); + val >>= 3; + } while (val); + if (octzero && *cp != '0') + *--cp = '0'; + break; + + case 16: + do { + *--cp = xdigs[(size_t)val & 15]; + val >>= 4; + } while (val); + break; + + default: + abort(); + } + return (cp); +} + +/* + * Convert a multibyte character string argument for the %s format to a wide + * string representation. ``prec'' specifies the maximum number of bytes + * to output. If ``prec'' is greater than or equal to zero, we can't assume + * that the multibyte char. string ends in a null character. + */ +static wchar_t * +__mbsconv(char *mbsarg, int prec) +{ + static const mbstate_t initial; + mbstate_t mbs; + wchar_t *convbuf, *wcp; + const char *p; + size_t insize, nchars, nconv; + + if (mbsarg == NULL) + return (NULL); + + /* + * Supplied argument is a multibyte string; convert it to wide + * characters first. + */ + if (prec >= 0) { + /* + * String is not guaranteed to be NUL-terminated. Find the + * number of characters to print. + */ + p = mbsarg; + insize = nchars = 0; + mbs = initial; + while (nchars != (size_t)prec) { + nconv = mbrlen(p, MB_CUR_MAX, &mbs); + if (nconv == 0 || nconv == (size_t)-1 || + nconv == (size_t)-2) + break; + p += nconv; + nchars++; + insize += nconv; + } + if (nconv == (size_t)-1 || nconv == (size_t)-2) + return (NULL); + } else + insize = strlen(mbsarg); + + /* + * Allocate buffer for the result and perform the conversion, + * converting at most `size' bytes of the input multibyte string to + * wide characters for printing. + */ + convbuf = malloc((insize + 1) * sizeof(*convbuf)); + if (convbuf == NULL) + return (NULL); + wcp = convbuf; + p = mbsarg; + mbs = initial; + while (insize != 0) { + nconv = mbrtowc(wcp, p, insize, &mbs); + if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2) + break; + wcp++; + p += nconv; + insize -= nconv; + } + if (nconv == (size_t)-1 || nconv == (size_t)-2) { + free(convbuf); + return (NULL); + } + *wcp = L'\0'; + + return (convbuf); +} + +/* + * MT-safe version + */ +int +vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap) +{ + int ret; + + FLOCKFILE(fp); + ret = __vfwprintf_unlocked(fp, fmt0, ap); + FUNLOCKFILE(fp); + return (ret); +} + +#ifndef NO_FLOATING_POINT + +#define dtoa __dtoa +#define freedtoa __freedtoa + +#include <float.h> +#include <math.h> +#include "floatio.h" + +#define DEFPREC 6 + +static int exponent(wchar_t *, int, wchar_t); +static wchar_t *cvt(double, int, int, char *, int *, int, int *); + +#endif /* !NO_FLOATING_POINT */ + +/* + * The size of the buffer we use as scratch space for integer + * conversions, among other things. Technically, we would need the + * most space for base 10 conversions with thousands' grouping + * characters between each pair of digits. 100 bytes is a + * conservative overestimate even for a 128-bit uintmax_t. + */ +#define BUF 100 + +#define STATIC_ARG_TBL_SIZE 8 /* Size of static argument table. */ + +/* + * Flags used during conversion. + */ +#define ALT 0x001 /* alternate form */ +#define LADJUST 0x004 /* left adjustment */ +#define LONGDBL 0x008 /* long double */ +#define LONGINT 0x010 /* long integer */ +#define LLONGINT 0x020 /* quad_t integer */ +#define SHORTINT 0x040 /* short integer */ +#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */ +#define FPT 0x100 /* Floating point number */ +#define GROUPING 0x200 /* use grouping ("'" flag) */ + /* C99 additional size modifiers: */ +#define SIZET 0x400 /* size_t */ +#define PTRDIFFT 0x800 /* ptrdiff_t */ +#define INTMAXT 0x1000 /* intmax_t */ +#define CHARINT 0x2000 /* print char using int format */ + +/* + * Non-MT-safe version + */ +int +__vfwprintf_unlocked(FILE *fp, const wchar_t *fmt0, va_list ap) +{ + wchar_t *fmt; /* format string */ + wchar_t ch; /* character from fmt */ + int n, n2, n3; /* handy integer (short term usage) */ + wchar_t *cp; /* handy char pointer (short term usage) */ + int flags; /* flags as above */ + int ret; /* return value accumulator */ + int width; /* width from format (%8d), or 0 */ + int prec; /* precision from format; <0 for N/A */ + wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */ + char thousands_sep; /* locale specific thousands separator */ + const char *grouping; /* locale specific numeric grouping rules */ +#ifndef NO_FLOATING_POINT + /* + * We can decompose the printed representation of floating + * point numbers into several parts, some of which may be empty: + * + * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ + * A B ---C--- D E F + * + * A: 'sign' holds this value if present; '\0' otherwise + * B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal + * C: cp points to the string MMMNNN. Leading and trailing + * zeros are not in the string and must be added. + * D: expchar holds this character; '\0' if no exponent, e.g. %f + * F: at least two digits for decimal, at least one digit for hex + */ + char *decimal_point; /* locale specific decimal point */ +#ifdef notyet + int signflag; /* true if float is negative */ + union { /* floating point arguments %[aAeEfFgG] */ + double dbl; + long double ldbl; + } fparg; + char *dtoaend; /* pointer to end of converted digits */ + char *dtoaresult; /* buffer allocated by dtoa */ +#else + double _double; /* double precision arguments %[eEfgG] */ + char softsign; /* temporary negative sign for floats */ +#endif + int expt; /* integer value of exponent */ + char expchar; /* exponent character: [eEpP\0] */ + int expsize; /* character count for expstr */ + int lead; /* sig figs before decimal or group sep */ + int ndig; /* actual number of digits returned by dtoa */ + wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ + int nseps; /* number of group separators with ' */ + int nrepeats; /* number of repeats of the last group */ +#endif + u_long ulval; /* integer arguments %[diouxX] */ + uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */ + int base; /* base for [diouxX] conversion */ + int dprec; /* a copy of prec if [diouxX], 0 otherwise */ + int realsz; /* field size expanded by dprec, sign, etc */ + int size; /* size of converted field or string */ + int prsize; /* max size of printed field */ + const char *xdigs; /* digits for [xX] conversion */ + wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */ + wchar_t ox[2]; /* space for 0x hex-prefix */ + union arg *argtable; /* args, built due to positional arg */ + union arg statargtable [STATIC_ARG_TBL_SIZE]; + int nextarg; /* 1-based argument index */ + va_list orgap; /* original argument pointer */ + wchar_t *convbuf; /* multibyte to wide conversion result */ + + /* + * Choose PADSIZE to trade efficiency vs. size. If larger printf + * fields occur frequently, increase PADSIZE and make the initialisers + * below longer. + */ +#define PADSIZE 16 /* pad chunk size */ + static wchar_t blanks[PADSIZE] = + {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; + static wchar_t zeroes[PADSIZE] = + {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'}; + + static const char xdigs_lower[16] = "0123456789abcdef"; + static const char xdigs_upper[16] = "0123456789ABCDEF"; + + /* + * BEWARE, these `goto error' on error, PRINT uses `n2' and + * PAD uses `n'. + */ +#define PRINT(ptr, len) do { \ + for (n3 = 0; n3 < (len); n3++) \ + __xfputwc((ptr)[n3], fp); \ +} while (/*CONSTCOND*/0) +#define PAD(howmany, with) do { \ + if ((n = (howmany)) > 0) { \ + while (n > PADSIZE) { \ + PRINT(with, PADSIZE); \ + n -= PADSIZE; \ + } \ + PRINT(with, n); \ + } \ +} while (/*CONSTCOND*/0) +#define PRINTANDPAD(p, ep, len, with) do { \ + n2 = (ep) - (p); \ + if (n2 > (len)) \ + n2 = (len); \ + if (n2 > 0) \ + PRINT((p), n2); \ + PAD((len) - (n2 > 0 ? n2 : 0), (with)); \ +} while(/*CONSTCOND*/0) + + /* + * Get the argument indexed by nextarg. If the argument table is + * built, use it to get the argument. If its not, get the next + * argument (and arguments must be gotten sequentially). + */ +#define GETARG(type) \ + ((/*CONSTCOND*/argtable != NULL) ? *((type*)(void*)(&argtable[nextarg++])) : \ + (nextarg++, va_arg(ap, type))) + + /* + * To extend shorts properly, we need both signed and unsigned + * argument extraction methods. + */ +#define SARG() \ + (flags&LONGINT ? GETARG(long) : \ + flags&SHORTINT ? (long)(short)GETARG(int) : \ + flags&CHARINT ? (long)(signed char)GETARG(int) : \ + (long)GETARG(int)) +#define UARG() \ + (flags&LONGINT ? GETARG(u_long) : \ + flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \ + flags&CHARINT ? (u_long)(u_char)GETARG(int) : \ + (u_long)GETARG(u_int)) +#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT) +#define SJARG() \ + (flags&INTMAXT ? GETARG(intmax_t) : \ + flags&SIZET ? (intmax_t)GETARG(size_t) : \ + flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \ + (intmax_t)GETARG(quad_t)) +#define UJARG() \ + (flags&INTMAXT ? GETARG(uintmax_t) : \ + flags&SIZET ? (uintmax_t)GETARG(size_t) : \ + flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \ + (uintmax_t)GETARG(u_quad_t)) + + /* + * Get * arguments, including the form *nn$. Preserve the nextarg + * that the argument can be gotten once the type is determined. + */ +#define GETASTER(val) \ + n2 = 0; \ + cp = fmt; \ + while (is_digit(*cp)) { \ + n2 = 10 * n2 + to_digit(*cp); \ + cp++; \ + } \ + if (*cp == '$') { \ + int hold = nextarg; \ + if (argtable == NULL) { \ + argtable = statargtable; \ + __find_arguments (fmt0, orgap, &argtable); \ + } \ + nextarg = n2; \ + val = GETARG (int); \ + nextarg = hold; \ + fmt = ++cp; \ + } else { \ + val = GETARG (int); \ + } + + + thousands_sep = '\0'; + grouping = NULL; +#ifndef NO_FLOATING_POINT + decimal_point = localeconv()->decimal_point; +#endif + convbuf = NULL; + /* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */ + if (cantwrite(fp)) { + errno = EBADF; + return (WEOF); + } + + /* optimise fprintf(stderr) (and other unbuffered Unix files) */ + if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && + fp->_file >= 0) + return (__sbprintf(fp, fmt0, ap)); + + fmt = (wchar_t *)__UNCONST(fmt0); + argtable = NULL; + nextarg = 1; + va_copy(orgap, ap); + ret = 0; + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) + /* void */; + if ((n = fmt - cp) != 0) { + if ((unsigned)ret + n > INT_MAX) { + ret = EOF; + goto error; + } + PRINT(cp, n); + ret += n; + } + if (ch == '\0') + goto done; + fmt++; /* skip over '%' */ + + flags = 0; + dprec = 0; + width = 0; + prec = -1; + sign = '\0'; + ox[1] = '\0'; + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + /*- + * ``If the space and + flags both appear, the space + * flag will be ignored.'' + * -- ANSI X3J11 + */ + if (!sign) + sign = ' '; + goto rflag; + case '#': + flags |= ALT; + goto rflag; + case '*': + /*- + * ``A negative field width argument is taken as a + * - flag followed by a positive field width.'' + * -- ANSI X3J11 + * They don't exclude field widths read from args. + */ + GETASTER (width); + if (width >= 0) + goto rflag; + width = -width; + /* FALLTHROUGH */ + case '-': + flags |= LADJUST; + goto rflag; + case '+': + sign = '+'; + goto rflag; + case '\'': + flags |= GROUPING; + thousands_sep = *(localeconv()->thousands_sep); + grouping = localeconv()->grouping; + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + GETASTER (prec); + goto rflag; + } + prec = 0; + while (is_digit(ch)) { + prec = 10 * prec + to_digit(ch); + ch = *fmt++; + } + goto reswitch; + case '0': + /*- + * ``Note that 0 is taken as a flag, not as the + * beginning of a field width.'' + * -- ANSI X3J11 + */ + flags |= ZEROPAD; + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } while (is_digit(ch)); + if (ch == '$') { + nextarg = n; + if (argtable == NULL) { + argtable = statargtable; + __find_arguments (fmt0, orgap, + &argtable); + } + goto rflag; + } + width = n; + goto reswitch; +#ifndef NO_FLOATING_POINT + case 'L': + flags |= LONGDBL; + goto rflag; +#endif + case 'h': + if (flags & SHORTINT) { + flags &= ~SHORTINT; + flags |= CHARINT; + } else + flags |= SHORTINT; + goto rflag; + case 'j': + flags |= INTMAXT; + goto rflag; + case 'l': + if (flags & LONGINT) { + flags &= ~LONGINT; + flags |= LLONGINT; + } else + flags |= LONGINT; + goto rflag; + case 'q': + flags |= LLONGINT; /* not necessarily */ + goto rflag; + case 't': + flags |= PTRDIFFT; + goto rflag; + case 'z': + flags |= SIZET; + goto rflag; + case 'C': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'c': + if (flags & LONGINT) + *(cp = buf) = (wchar_t)GETARG(wint_t); + else + *(cp = buf) = (wchar_t)btowc(GETARG(int)); + size = 1; + sign = '\0'; + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + if (flags & INTMAX_SIZE) { + ujval = SJARG(); + if ((intmax_t)ujval < 0) { + ujval = -ujval; + sign = '-'; + } + } else { + ulval = SARG(); + if ((long)ulval < 0) { + ulval = -ulval; + sign = '-'; + } + } + base = 10; + goto number; +#ifndef NO_FLOATING_POINT +#ifdef notyet + case 'a': + case 'A': + if (ch == 'a') { + ox[1] = 'x'; + xdigs = xdigs_lower; + expchar = 'p'; + } else { + ox[1] = 'X'; + xdigs = xdigs_upper; + expchar = 'P'; + } + if (prec >= 0) + prec++; + if (flags & LONGDBL) { + fparg.ldbl = GETARG(long double); + dtoaresult = + __hldtoa(fparg.ldbl, xdigs, prec, + &expt, &signflag, &dtoaend); + } else { + fparg.dbl = GETARG(double); + dtoaresult = + __hdtoa(fparg.dbl, xdigs, prec, + &expt, &signflag, &dtoaend); + } + + if (prec < 0) + prec = dtoaend - dtoaresult; + if (expt == INT_MAX) + ox[1] = '\0'; + if (convbuf != NULL) + free(convbuf); + ndig = dtoaend - dtoaresult; + cp = convbuf = __mbsconv(dtoaresult, -1); + freedtoa(dtoaresult); + goto fp_common; + case 'e': + case 'E': + expchar = ch; + if (prec < 0) /* account for digit before decpt */ + prec = DEFPREC + 1; + else + prec++; + goto fp_begin; + case 'f': + case 'F': + expchar = '\0'; + goto fp_begin; + case 'g': + case 'G': + expchar = ch - ('g' - 'e'); + if (prec == 0) + prec = 1; +fp_begin: + if (prec < 0) + prec = DEFPREC; + if (convbuf != NULL) + free(convbuf); + if (flags & LONGDBL) { + fparg.ldbl = GETARG(long double); + dtoaresult = + __ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec, + &expt, &signflag, &dtoaend); + } else { + fparg.dbl = GETARG(double); + dtoaresult = + dtoa(fparg.dbl, expchar ? 2 : 3, prec, + &expt, &signflag, &dtoaend); + if (expt == 9999) + expt = INT_MAX; + } + ndig = dtoaend - dtoaresult; + cp = convbuf = __mbsconv(dtoaresult, -1); + freedtoa(dtoaresult); +fp_common: + if (signflag) + sign = '-'; + if (expt == INT_MAX) { /* inf or nan */ + if (*cp == 'N') { + cp = (ch >= 'a') ? L"nan" : L"NAN"; + sign = '\0'; + } else + cp = (ch >= 'a') ? L"inf" : L"INF"; + size = 3; + break; + } +#else + case 'e': + case 'E': + case 'f': + case 'F': + case 'g': + case 'G': + if (prec == -1) { + prec = DEFPREC; + } else if ((ch == 'g' || ch == 'G') && prec == 0) { + prec = 1; + } + + if (flags & LONGDBL) { + _double = (double) GETARG(long double); + } else { + _double = GETARG(double); + } + + /* do this before tricky precision changes */ + if (isinf(_double)) { + if (_double < 0) + sign = '-'; + if (ch == 'E' || ch == 'F' || ch == 'G') + cp = L"INF"; + else + cp = L"inf"; + size = 3; + break; + } + if (isnan(_double)) { + if (ch == 'E' || ch == 'F' || ch == 'G') + cp = L"NAN"; + else + cp = L"nan"; + size = 3; + break; + } + + flags |= FPT; + cp = cvt(_double, prec, flags, &softsign, + &expt, ch, &ndig); + if (softsign) + sign = '-'; +#endif + flags |= FPT; + if (ch == 'g' || ch == 'G') { + if (expt > -4 && expt <= prec) { + /* Make %[gG] smell like %[fF] */ + expchar = '\0'; + if (flags & ALT) + prec -= expt; + else + prec = ndig - expt; + if (prec < 0) + prec = 0; + } else { + /* + * Make %[gG] smell like %[eE], but + * trim trailing zeroes if no # flag. + */ + if (!(flags & ALT)) + prec = ndig; + } + } + if (expchar) { + expsize = exponent(expstr, expt - 1, expchar); + size = expsize + prec; + if (prec > 1 || flags & ALT) + ++size; + } else { + /* space for digits before decimal point */ + if (expt > 0) + size = expt; + else /* "0" */ + size = 1; + /* space for decimal pt and following digits */ + if (prec || flags & ALT) + size += prec + 1; + if (grouping && expt > 0) { + /* space for thousands' grouping */ + nseps = nrepeats = 0; + lead = expt; + while (*grouping != CHAR_MAX) { + if (lead <= *grouping) + break; + lead -= *grouping; + if (*(grouping+1)) { + nseps++; + grouping++; + } else + nrepeats++; + } + size += nseps + nrepeats; + } else + lead = expt; + } + break; +#endif /* !NO_FLOATING_POINT */ + case 'n': + /* + * Assignment-like behavior is specified if the + * value overflows or is otherwise unrepresentable. + * C99 says to use `signed char' for %hhn conversions. + */ + if (flags & LLONGINT) + *GETARG(quad_t *) = ret; + else if (flags & SIZET) + *GETARG(ssize_t *) = (ssize_t)ret; + else if (flags & PTRDIFFT) + *GETARG(ptrdiff_t *) = ret; + else if (flags & INTMAXT) + *GETARG(intmax_t *) = ret; + else if (flags & LONGINT) + *GETARG(long *) = ret; + else if (flags & SHORTINT) + *GETARG(short *) = ret; + else if (flags & CHARINT) + *GETARG(signed char *) = ret; + else + *GETARG(int *) = ret; + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + if (flags & INTMAX_SIZE) + ujval = UJARG(); + else + ulval = UARG(); + base = 8; + goto nosign; + case 'p': + /*- + * ``The argument shall be a pointer to void. The + * value of the pointer is converted to a sequence + * of printable characters, in an implementation- + * defined manner.'' + * -- ANSI X3J11 + */ + ujval = (uintmax_t)(uintptr_t)GETARG(void *); + base = 16; + xdigs = xdigs_lower; + flags = flags | INTMAXT; + ox[1] = 'x'; + goto nosign; + case 'S': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 's': + if (flags & LONGINT) { + if ((cp = GETARG(wchar_t *)) == NULL) + cp = L"(null)"; + } else { + char *mbp; + + if (convbuf != NULL) + free(convbuf); + if ((mbp = GETARG(char *)) == NULL) + cp = L"(null)"; + else { + convbuf = __mbsconv(mbp, prec); + if (convbuf == NULL) { + fp->_flags |= __SERR; + goto error; + } + cp = convbuf; + } + } + + if (prec >= 0) { + /* + * can't use wcslen; can only look for the + * NUL in the first `prec' characters, and + * wcslen() will go further. + */ + wchar_t *p = wmemchr(cp, 0, (size_t)prec); + + if (p != NULL) { + size = p - cp; + if (size > prec) + size = prec; + } else + size = prec; + } else + size = wcslen(cp); + sign = '\0'; + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + if (flags & INTMAX_SIZE) + ujval = UJARG(); + else + ulval = UARG(); + base = 10; + goto nosign; + case 'X': + xdigs = xdigs_upper; + goto hex; + case 'x': + xdigs = xdigs_lower; +hex: + if (flags & INTMAX_SIZE) + ujval = UJARG(); + else + ulval = UARG(); + base = 16; + /* leading 0x/X only if non-zero */ + if (flags & ALT && + (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0)) + ox[1] = ch; + + flags &= ~GROUPING; + /* unsigned conversions */ +nosign: sign = '\0'; + /*- + * ``... diouXx conversions ... if a precision is + * specified, the 0 flag will be ignored.'' + * -- ANSI X3J11 + */ +number: if ((dprec = prec) >= 0) + flags &= ~ZEROPAD; + + /*- + * ``The result of converting a zero value with an + * explicit precision of zero is no characters.'' + * -- ANSI X3J11 + * + * ``The C Standard is clear enough as is. The call + * printf("%#.0o", 0) should print 0.'' + * -- Defect Report #151 + */ + cp = buf + BUF; + if (flags & INTMAX_SIZE) { + if (ujval != 0 || prec != 0 || + (flags & ALT && base == 8)) + cp = __ujtoa(ujval, cp, base, + flags & ALT, xdigs, + flags & GROUPING, thousands_sep, + grouping); + } else { + if (ulval != 0 || prec != 0 || + (flags & ALT && base == 8)) + cp = __ultoa(ulval, cp, base, + flags & ALT, xdigs, + flags & GROUPING, thousands_sep, + grouping); + } + size = buf + BUF - cp; + if (size > BUF) /* should never happen */ + abort(); + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + /* pretend it was %c with argument ch */ + cp = buf; + *cp = ch; + size = 1; + sign = '\0'; + break; + } + + /* + * All reasonable formats wind up here. At this point, `cp' + * points to a string which (if not flags&LADJUST) should be + * padded out to `width' places. If flags&ZEROPAD, it should + * first be prefixed by any sign or other prefix; otherwise, + * it should be blank padded before the prefix is emitted. + * After any left-hand padding and prefixing, emit zeroes + * required by a decimal [diouxX] precision, then print the + * string proper, then emit zeroes required by any leftover + * floating precision; finally, if LADJUST, pad with blanks. + * + * Compute actual size, so we know how much to pad. + * size excludes decimal prec; realsz includes it. + */ + realsz = dprec > size ? dprec : size; + if (sign) + realsz++; + if (ox[1]) + realsz += 2; + + prsize = width > realsz ? width : realsz; + if ((unsigned)ret + prsize > INT_MAX) { + ret = EOF; + goto error; + } + + /* right-adjusting blank padding */ + if ((flags & (LADJUST|ZEROPAD)) == 0) + PAD(width - realsz, blanks); + + /* prefix */ + if (sign) + PRINT(&sign, 1); + + if (ox[1]) { /* ox[1] is either x, X, or \0 */ + ox[0] = '0'; + PRINT(ox, 2); + } + + /* right-adjusting zero padding */ + if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD) + PAD(width - realsz, zeroes); + + /* leading zeroes from decimal precision */ + PAD(dprec - size, zeroes); + + /* the string or number proper */ +#ifndef NO_FLOATING_POINT + if ((flags & FPT) == 0) { + PRINT(cp, size); + } else { /* glue together f_p fragments */ + if (!expchar) { /* %[fF] or sufficiently short %[gG] */ + if (expt <= 0) { + PRINT(zeroes, 1); + if (prec || flags & ALT) + PRINT(decimal_point, 1); + PAD(-expt, zeroes); + /* already handled initial 0's */ + prec += expt; + } else { + PRINTANDPAD(cp, convbuf + ndig, lead, zeroes); + cp += lead; + if (grouping) { + while (nseps>0 || nrepeats>0) { + if (nrepeats > 0) + nrepeats--; + else { + grouping--; + nseps--; + } + PRINT(&thousands_sep, + 1); + PRINTANDPAD(cp, + convbuf + ndig, + *grouping, zeroes); + cp += *grouping; + } + if (cp > convbuf + ndig) + cp = convbuf + ndig; + } + if (prec || flags & ALT) { + buf[0] = *decimal_point; + PRINT(buf, 1); + } + } + PRINTANDPAD(cp, convbuf + ndig, prec, zeroes); + } else { /* %[eE] or sufficiently long %[gG] */ + if (prec > 1 || flags & ALT) { + buf[0] = *cp++; + buf[1] = *decimal_point; + PRINT(buf, 2); + PRINT(cp, ndig-1); + PAD(prec - ndig, zeroes); + } else /* XeYYY */ + PRINT(cp, 1); + PRINT(expstr, expsize); + } + } +#else + PRINT(cp, size); +#endif + /* left-adjusting padding (always blank) */ + if (flags & LADJUST) + PAD(width - realsz, blanks); + + /* finally, adjust ret */ + ret += prsize; + } +done: +error: + va_end(orgap); + if (convbuf != NULL) + free(convbuf); + if (__sferror(fp)) + ret = EOF; + if ((argtable != NULL) && (argtable != statargtable)) + free (argtable); + return (ret); + /* NOTREACHED */ +} + +/* + * Find all arguments when a positional parameter is encountered. Returns a + * table, indexed by argument number, of pointers to each arguments. The + * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries. + * It will be replaces with a malloc-ed one if it overflows. + */ +static void +__find_arguments (const wchar_t *fmt0, va_list ap, union arg **argtable) +{ + wchar_t *fmt; /* format string */ + wchar_t ch; /* character from fmt */ + int n, n2; /* handy integer (short term usage) */ + wchar_t *cp; /* handy char pointer (short term usage) */ + int flags; /* flags as above */ + enum typeid *typetable; /* table of types */ + enum typeid stattypetable [STATIC_ARG_TBL_SIZE]; + int tablesize; /* current size of type table */ + int tablemax; /* largest used index in table */ + int nextarg; /* 1-based argument index */ + + /* + * Add an argument type to the table, expanding if necessary. + */ +#define ADDTYPE(type) \ + /*LINTED null effect*/ \ + (void)((nextarg >= tablesize) ? \ + __grow_type_table(nextarg, &typetable, &tablesize) : (void)0, \ + (nextarg > tablemax) ? tablemax = nextarg : 0, \ + typetable[nextarg++] = type) + +#define ADDSARG() \ + (void)((flags&INTMAXT) ? ADDTYPE(T_INTMAXT) : \ + ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ + ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ + ((flags&LLONGINT) ? ADDTYPE(T_LLONG) : \ + ((flags&LONGINT) ? ADDTYPE(T_LONG) : ADDTYPE(T_INT)))))) + +#define ADDUARG() \ + (void)((flags&INTMAXT) ? ADDTYPE(T_UINTMAXT) : \ + ((flags&SIZET) ? ADDTYPE(T_SIZET) : \ + ((flags&PTRDIFFT) ? ADDTYPE(T_PTRDIFFT) : \ + ((flags&LLONGINT) ? ADDTYPE(T_U_LLONG) : \ + ((flags&LONGINT) ? ADDTYPE(T_U_LONG) : ADDTYPE(T_U_INT)))))) + + /* + * Add * arguments to the type array. + */ +#define ADDASTER() \ + n2 = 0; \ + cp = fmt; \ + while (is_digit(*cp)) { \ + n2 = 10 * n2 + to_digit(*cp); \ + cp++; \ + } \ + if (*cp == '$') { \ + int hold = nextarg; \ + nextarg = n2; \ + ADDTYPE (T_INT); \ + nextarg = hold; \ + fmt = ++cp; \ + } else { \ + ADDTYPE (T_INT); \ + } + fmt = (wchar_t *)__UNCONST(fmt0); + typetable = stattypetable; + tablesize = STATIC_ARG_TBL_SIZE; + tablemax = 0; + nextarg = 1; + for (n = 0; n < STATIC_ARG_TBL_SIZE; n++) + typetable[n] = T_UNUSED; + + /* + * Scan the format for conversions (`%' character). + */ + for (;;) { + for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++) + /* void */; + if (ch == '\0') + goto done; + fmt++; /* skip over '%' */ + + flags = 0; + +rflag: ch = *fmt++; +reswitch: switch (ch) { + case ' ': + case '#': + goto rflag; + case '*': + ADDASTER (); + goto rflag; + case '-': + case '+': + case '\'': + goto rflag; + case '.': + if ((ch = *fmt++) == '*') { + ADDASTER (); + goto rflag; + } + while (is_digit(ch)) { + ch = *fmt++; + } + goto reswitch; + case '0': + goto rflag; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + n = 0; + do { + n = 10 * n + to_digit(ch); + ch = *fmt++; + } while (is_digit(ch)); + if (ch == '$') { + nextarg = n; + goto rflag; + } + goto reswitch; +#ifndef NO_FLOATING_POINT + case 'L': + flags |= LONGDBL; + goto rflag; +#endif + case 'h': + if (flags & SHORTINT) { + flags &= ~SHORTINT; + flags |= CHARINT; + } else + flags |= SHORTINT; + goto rflag; + case 'j': + flags |= INTMAXT; + goto rflag; + case 'l': + if (flags & LONGINT) { + flags &= ~LONGINT; + flags |= LLONGINT; + } else + flags |= LONGINT; + goto rflag; + case 'q': + flags |= LLONGINT; /* not necessarily */ + goto rflag; + case 't': + flags |= PTRDIFFT; + goto rflag; + case 'z': + flags |= SIZET; + goto rflag; + case 'C': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'c': + if (flags & LONGINT) + ADDTYPE(T_WINT); + else + ADDTYPE(T_INT); + break; + case 'D': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'd': + case 'i': + ADDSARG(); + break; +#ifndef NO_FLOATING_POINT + case 'a': + case 'A': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + if (flags & LONGDBL) + ADDTYPE(T_LONG_DOUBLE); + else + ADDTYPE(T_DOUBLE); + break; +#endif /* !NO_FLOATING_POINT */ + case 'n': + if (flags & INTMAXT) + ADDTYPE(TP_INTMAXT); + else if (flags & PTRDIFFT) + ADDTYPE(TP_PTRDIFFT); + else if (flags & SIZET) + ADDTYPE(TP_SIZET); + else if (flags & LLONGINT) + ADDTYPE(TP_LLONG); + else if (flags & LONGINT) + ADDTYPE(TP_LONG); + else if (flags & SHORTINT) + ADDTYPE(TP_SHORT); + else if (flags & CHARINT) + ADDTYPE(TP_SCHAR); + else + ADDTYPE(TP_INT); + continue; /* no output */ + case 'O': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'o': + ADDUARG(); + break; + case 'p': + ADDTYPE(TP_VOID); + break; + case 'S': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 's': + if (flags & LONGINT) + ADDTYPE(TP_WCHAR); + else + ADDTYPE(TP_CHAR); + break; + case 'U': + flags |= LONGINT; + /*FALLTHROUGH*/ + case 'u': + case 'X': + case 'x': + ADDUARG(); + break; + default: /* "%?" prints ?, unless ? is NUL */ + if (ch == '\0') + goto done; + break; + } + } +done: + /* + * Build the argument table. + */ + if (tablemax >= STATIC_ARG_TBL_SIZE) { + *argtable = (union arg *) + malloc (sizeof (union arg) * (tablemax + 1)); + } + + (*argtable) [0].intarg = 0; + for (n = 1; n <= tablemax; n++) { + switch (typetable [n]) { + case T_UNUSED: /* whoops! */ + (*argtable) [n].intarg = va_arg (ap, int); + break; + case TP_SCHAR: + (*argtable) [n].pschararg = va_arg (ap, signed char *); + break; + case TP_SHORT: + (*argtable) [n].pshortarg = va_arg (ap, short *); + break; + case T_INT: + (*argtable) [n].intarg = va_arg (ap, int); + break; + case T_U_INT: + (*argtable) [n].uintarg = va_arg (ap, unsigned int); + break; + case TP_INT: + (*argtable) [n].pintarg = va_arg (ap, int *); + break; + case T_LONG: + (*argtable) [n].longarg = va_arg (ap, long); + break; + case T_U_LONG: + (*argtable) [n].ulongarg = va_arg (ap, unsigned long); + break; + case TP_LONG: + (*argtable) [n].plongarg = va_arg (ap, long *); + break; + case T_LLONG: + (*argtable) [n].longlongarg = va_arg (ap, quad_t); + break; + case T_U_LLONG: + (*argtable) [n].ulonglongarg = va_arg (ap, u_quad_t); + break; + case TP_LLONG: + (*argtable) [n].plonglongarg = va_arg (ap, quad_t *); + break; + case T_PTRDIFFT: + (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t); + break; + case TP_PTRDIFFT: + (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *); + break; + case T_SIZET: + (*argtable) [n].sizearg = va_arg (ap, size_t); + break; + case TP_SIZET: + (*argtable) [n].psizearg = va_arg (ap, size_t *); + break; + case T_INTMAXT: + (*argtable) [n].intmaxarg = va_arg (ap, intmax_t); + break; + case T_UINTMAXT: + (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t); + break; + case TP_INTMAXT: + (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *); + break; +#ifndef NO_FLOATING_POINT + case T_DOUBLE: + (*argtable) [n].doublearg = va_arg (ap, double); + break; + case T_LONG_DOUBLE: + (*argtable) [n].longdoublearg = va_arg (ap, long double); + break; +#endif + case TP_CHAR: + (*argtable) [n].pchararg = va_arg (ap, char *); + break; + case TP_VOID: + (*argtable) [n].pvoidarg = va_arg (ap, void *); + break; + case T_WINT: + (*argtable) [n].wintarg = va_arg (ap, wint_t); + break; + case TP_WCHAR: + (*argtable) [n].pwchararg = va_arg (ap, wchar_t *); + break; + } + } + + if ((typetable != NULL) && (typetable != stattypetable)) + free (typetable); +} + +/* + * Increase the size of the type table. + */ +static void +__grow_type_table (int nextarg, enum typeid **typetable, int *tablesize) +{ + enum typeid *const oldtable = *typetable; + const int oldsize = *tablesize; + enum typeid *newtable; + int n, newsize = oldsize * 2; + + if (newsize < nextarg + 1) + newsize = nextarg + 1; + if (oldsize == STATIC_ARG_TBL_SIZE) { + if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL) + abort(); /* XXX handle better */ + bcopy(oldtable, newtable, oldsize * sizeof(enum typeid)); + } else { + newtable = realloc(oldtable, newsize * sizeof(enum typeid)); + if (newtable == NULL) + abort(); /* XXX handle better */ + } + for (n = oldsize; n < newsize; n++) + newtable[n] = T_UNUSED; + + *typetable = newtable; + *tablesize = newsize; +} + + +#ifndef NO_FLOATING_POINT +static wchar_t * +cvt(double value, int ndigits, int flags, char *sign, int *decpt, int ch, + int *length) +{ + int mode, dsgn; + char *digits, *bp, *rve; + static wchar_t buf[512]; + + _DIAGASSERT(decpt != NULL); + _DIAGASSERT(length != NULL); + _DIAGASSERT(sign != NULL); + + if (ch == 'f') { + mode = 3; /* ndigits after the decimal point */ + } else { + /* To obtain ndigits after the decimal point for the 'e' + * and 'E' formats, round to ndigits + 1 significant + * figures. + */ + if (ch == 'e' || ch == 'E') { + ndigits++; + } + mode = 2; /* ndigits significant digits */ + } + + digits = __dtoa(value, mode, ndigits, decpt, &dsgn, &rve); + if (dsgn) { + value = -value; + *sign = '-'; + } else + *sign = '\000'; + if ((ch != 'g' && ch != 'G') || flags & ALT) { /* Print trailing zeros */ + bp = digits + ndigits; + if (ch == 'f') { + if (*digits == '0' && value) + *decpt = -ndigits + 1; + bp += *decpt; + } + if (value == 0) /* kludge for __dtoa irregularity */ + rve = bp; + while (rve < bp) + *rve++ = '0'; + } + *length = rve - digits; + (void)mbstowcs(buf, digits, sizeof(buf)/sizeof(buf[0])); + return buf; +} +static int +exponent(wchar_t *p0, int expo, wchar_t fmtch) +{ + wchar_t *p, *t; + wchar_t expbuf[MAXEXPDIG]; + + p = p0; + *p++ = fmtch; + if (expo < 0) { + expo = -expo; + *p++ = '-'; + } + else + *p++ = '+'; + t = expbuf + MAXEXPDIG; + if (expo > 9) { + do { + *--t = to_char(expo % 10); + } while ((expo /= 10) > 9); + *--t = to_char(expo); + for (; t < expbuf + MAXEXPDIG; *p++ = *t++); + } + else { + /* + * Exponents for decimal floating point conversions + * (%[eEgG]) must be at least two characters long, + * whereas exponents for hexadecimal conversions can + * be only one character long. + */ + if (fmtch == 'e' || fmtch == 'E') + *p++ = '0'; + *p++ = to_char(expo); + } + return (p - p0); +} +#endif /* !NO_FLOATING_POINT */ diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c new file mode 100644 index 00000000000..867f8fbf998 --- /dev/null +++ b/lib/libc/stdio/vfwscanf.c @@ -0,0 +1,886 @@ +/* $NetBSD: vfwscanf.c,v 1.1 2005/05/14 23:51:02 christos 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)ftell.c 8.2 (Berkeley) 5/4/95"; +__FBSDID("$FreeBSD: src/lib/libc/stdio/vfwscanf.c,v 1.12 2004/05/02 20:13:29 obrien Exp $"); +#else +__RCSID("$NetBSD: vfwscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include "namespace.h" +#include <ctype.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdarg.h> +#include <string.h> +#include <limits.h> +#include <wchar.h> +#include <wctype.h> + +#include "reentrant.h" +#include "local.h" + +#ifndef NO_FLOATING_POINT +#include <locale.h> +#endif + +#define BUF 513 /* Maximum length of numeric string. */ + +/* + * Flags used during conversion. + */ +#define LONG 0x01 /* l: long or double */ +#define LONGDBL 0x02 /* L: long double */ +#define SHORT 0x04 /* h: short */ +#define SUPPRESS 0x08 /* *: suppress assignment */ +#define POINTER 0x10 /* p: void * (as hex) */ +#define NOSKIP 0x20 /* [ or c: do not skip blanks */ +#define LONGLONG 0x400 /* ll: quad_t (+ deprecated q: quad) */ +#define INTMAXT 0x800 /* j: intmax_t */ +#define PTRDIFFT 0x1000 /* t: ptrdiff_t */ +#define SIZET 0x2000 /* z: size_t */ +#define SHORTSHORT 0x4000 /* hh: char */ +#define UNSIGNED 0x8000 /* %[oupxX] conversions */ + +/* + * The following are used in integral conversions only: + * SIGNOK, NDIGITS, PFXOK, and NZDIGITS + */ +#define SIGNOK 0x40 /* +/- is (still) legal */ +#define NDIGITS 0x80 /* no digits detected */ +#define PFXOK 0x100 /* 0x prefix is (still) legal */ +#define NZDIGITS 0x200 /* no zero digits detected */ +#define HAVESIGN 0x10000 /* sign detected */ + +/* + * Conversion types. + */ +#define CT_CHAR 0 /* %c conversion */ +#define CT_CCL 1 /* %[...] conversion */ +#define CT_STRING 2 /* %s conversion */ +#define CT_INT 3 /* %[dioupxX] conversion */ +#define CT_FLOAT 4 /* %[efgEFG] conversion */ + +static int parsefloat(FILE *, wchar_t *, wchar_t *); + +#define INCCL(_c) \ + (cclcompl ? (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) == NULL) : \ + (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) != NULL)) + +/* + * MT-safe version. + */ +int +vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) +{ + int ret; + + FLOCKFILE(fp); + _SET_ORIENTATION(fp, 1); + ret = __vfwscanf_unlocked(fp, fmt, ap); + FUNLOCKFILE(fp); + return (ret); +} + +/* + * Non-MT-safe version. + */ +int +__vfwscanf_unlocked(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 conversion function */ + 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 */ + static const mbstate_t initial; + mbstate_t mbs; + + /* `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 }; + + nassigned = 0; + nconversions = 0; + nread = 0; + 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 |= INTMAXT; + goto again; + case 'l': + if (flags & LONG) { + flags &= ~LONG; + flags |= LONGLONG; + } else + flags |= LONG; + goto again; + case 'q': + flags |= LONGLONG; /* not quite */ + goto again; + case 't': + flags |= PTRDIFFT; + goto again; + case 'z': + flags |= SIZET; + goto again; + case 'L': + flags |= LONGDBL; + goto again; + case 'h': + if (flags & SHORT) { + flags &= ~SHORT; + flags |= SHORTSHORT; + } else + flags |= SHORT; + 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. + */ + case 'd': + c = CT_INT; + base = 10; + break; + + case 'i': + c = CT_INT; + base = 0; + break; + + 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; + +#ifndef NO_FLOATING_POINT + case 'A': case 'E': case 'F': case 'G': + case 'a': case 'e': case 'f': case 'g': + c = CT_FLOAT; + break; +#endif + + case 'S': + flags |= LONG; + /* FALLTHROUGH */ + 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 |= LONG; + /* FALLTHROUGH */ + case 'c': + flags |= NOSKIP; + c = CT_CHAR; + break; + + case 'p': /* pointer format is like hex */ + flags |= POINTER | PFXOK; + c = CT_INT; /* assumes sizeof(uintmax_t) */ + flags |= UNSIGNED; /* >= sizeof(uintptr_t) */ + base = 16; + break; + + case 'n': + nconversions++; + if (flags & SUPPRESS) /* ??? */ + continue; + if (flags & SHORTSHORT) + *va_arg(ap, char *) = nread; + else if (flags & SHORT) + *va_arg(ap, short *) = nread; + else if (flags & LONG) + *va_arg(ap, long *) = nread; + else if (flags & LONGLONG) + *va_arg(ap, quad_t *) = nread; + else if (flags & INTMAXT) + *va_arg(ap, intmax_t *) = nread; + else if (flags & SIZET) + *va_arg(ap, size_t *) = nread; + else if (flags & PTRDIFFT) + *va_arg(ap, ptrdiff_t *) = nread; + else + *va_arg(ap, int *) = nread; + continue; + + default: + goto match_failure; + + /* + * Disgusting backwards compatibility hack. XXX + */ + case '\0': /* compat */ + return (EOF); + } + + /* + * 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; + mbs = initial; + 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; + mbs = initial; + 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 *); + mbs = initial; + 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 the conversion function */ + 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 & 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) == 0) + 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 & SHORTSHORT) + *va_arg(ap, char *) = (char)res; + else if (flags & SHORT) + *va_arg(ap, short *) = (short)res; + else if (flags & LONG) + *va_arg(ap, long *) = (long)res; + else if (flags & LONGLONG) + *va_arg(ap, quad_t *) = res; + else if (flags & INTMAXT) + *va_arg(ap, intmax_t *) = res; + else if (flags & PTRDIFFT) + *va_arg(ap, ptrdiff_t *) = (ptrdiff_t)res; + else if (flags & SIZET) + *va_arg(ap, size_t *) = (size_t)res; + else + *va_arg(ap, int *) = (int)res; + nassigned++; + } + nread += p - buf; + nconversions++; + break; + +#ifndef NO_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; + if ((width = parsefloat(fp, buf, buf + width)) == 0) + goto match_failure; + if ((flags & SUPPRESS) == 0) { +#ifdef notyet + if (flags & LONGDBL) { + long double res = wcstold(buf, &p); + *va_arg(ap, long double *) = res; + } else +#endif + if (flags & LONG) { + double res = wcstod(buf, &p); + *va_arg(ap, double *) = res; +#ifdef notyet + } else { + float res = wcstof(buf, &p); + *va_arg(ap, float *) = res; +#endif + } +#ifdef DEBUG + if (p - buf != width) + abort(); +#endif + nassigned++; + } + nread += width; + nconversions++; + break; +#endif /* !NO_FLOATING_POINT */ + } + } +input_failure: + return (nconversions != 0 ? nassigned : EOF); +match_failure: + return (nassigned); +} + +#ifndef NO_FLOATING_POINT +static int +parsefloat(FILE *fp, wchar_t *buf, wchar_t *end) +{ + wchar_t *commit, *p; + int infnanpos = 0; + enum { + S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX, + S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS + } state = S_START; + wchar_t c; + wchar_t decpt = (wchar_t)(unsigned char)*localeconv()->decimal_point; + int gotmantdig = 0, ishex = 0; + + /* + * We set commit = p whenever the string we have read so far + * constitutes a valid representation of a floating point + * number by itself. At some point, the parse will complete + * or fail, and we will ungetc() back to the last commit point. + * To ensure that the file offset gets updated properly, it is + * always necessary to read at least one character that doesn't + * match; thus, we can't short-circuit "infinity" or "nan(...)". + */ + commit = buf - 1; + c = WEOF; + for (p = buf; p < end; ) { + if ((c = __fgetwc_unlock(fp)) == WEOF) + break; +reswitch: + switch (state) { + case S_START: + state = S_GOTSIGN; + if (c == '-' || c == '+') + break; + else + goto reswitch; + case S_GOTSIGN: + switch (c) { + case '0': + state = S_MAYBEHEX; + commit = p; + break; + case 'I': + case 'i': + state = S_INF; + break; + case 'N': + case 'n': + state = S_NAN; + break; + default: + state = S_DIGITS; + goto reswitch; + } + break; + case S_INF: + if (infnanpos > 6 || + (c != "nfinity"[infnanpos] && + c != "NFINITY"[infnanpos])) + goto parsedone; + if (infnanpos == 1 || infnanpos == 6) + commit = p; /* inf or infinity */ + infnanpos++; + break; + case S_NAN: + switch (infnanpos) { + case -1: /* XXX kludge to deal with nan(...) */ + goto parsedone; + case 0: + if (c != 'A' && c != 'a') + goto parsedone; + break; + case 1: + if (c != 'N' && c != 'n') + goto parsedone; + else + commit = p; + break; + case 2: + if (c != '(') + goto parsedone; + break; + default: + if (c == ')') { + commit = p; + infnanpos = -2; + } else if (!iswalnum(c) && c != '_') + goto parsedone; + break; + } + infnanpos++; + break; + case S_MAYBEHEX: + state = S_DIGITS; + if (c == 'X' || c == 'x') { + ishex = 1; + break; + } else { /* we saw a '0', but no 'x' */ + gotmantdig = 1; + goto reswitch; + } + case S_DIGITS: + if ((ishex && iswxdigit(c)) || iswdigit(c)) + gotmantdig = 1; + else { + state = S_FRAC; + if (c != decpt) + goto reswitch; + } + if (gotmantdig) + commit = p; + break; + case S_FRAC: + if (((c == 'E' || c == 'e') && !ishex) || + ((c == 'P' || c == 'p') && ishex)) { + if (!gotmantdig) + goto parsedone; + else + state = S_EXP; + } else if ((ishex && iswxdigit(c)) || iswdigit(c)) { + commit = p; + gotmantdig = 1; + } else + goto parsedone; + break; + case S_EXP: + state = S_EXPDIGITS; + if (c == '-' || c == '+') + break; + else + goto reswitch; + case S_EXPDIGITS: + if (iswdigit(c)) + commit = p; + else + goto parsedone; + break; + default: + abort(); + } + *p++ = c; + c = WEOF; + } + +parsedone: + if (c != WEOF) + ungetwc(c, fp); + while (commit < --p) + ungetwc(*p, fp); + *++commit = '\0'; + return (commit - buf); +} +#endif diff --git a/lib/libc/stdio/vswprintf.c b/lib/libc/stdio/vswprintf.c new file mode 100644 index 00000000000..caa89ade73d --- /dev/null +++ b/lib/libc/stdio/vswprintf.c @@ -0,0 +1,100 @@ +/* $NetBSD: vswprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $ */ + +/* + * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> + * 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. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``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 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/vswprintf.c,v 1.6 2005/02/21 19:41:44 fjoe Exp $"); +#else +__RCSID("$NetBSD: vswprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <wchar.h> +#include <stdarg.h> +#include "reentrant.h" +#include "local.h" + +int +vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, + va_list ap) +{ + static const mbstate_t initial; + mbstate_t mbs; + FILE f; + char *mbp; + int ret, sverrno; + size_t nwc; + struct __sfileext fext; + + if (n == 0) { + errno = EINVAL; + return (-1); + } + + _FILEEXT_SETUP(&f, &fext); + f._file = -1; + f._flags = __SWR | __SSTR | __SALC; + f._bf._base = f._p = (unsigned char *)malloc(128); + if (f._bf._base == NULL) { + errno = ENOMEM; + return (-1); + } + f._bf._size = f._w = 127; /* Leave room for the NUL */ + ret = __vfwprintf_unlocked(&f, fmt, ap); + if (ret < 0) { + sverrno = errno; + free(f._bf._base); + errno = sverrno; + return (-1); + } + *f._p = '\0'; + mbp = (char *)f._bf._base; + /* + * XXX Undo the conversion from wide characters to multibyte that + * fputwc() did in __vfwprintf(). + */ + mbs = initial; + nwc = mbsrtowcs(s, (const char **)&mbp, n, &mbs); + free(f._bf._base); + if (nwc == (size_t)-1) { + errno = EILSEQ; + return (-1); + } + if (nwc == n) { + s[n - 1] = L'\0'; + errno = EOVERFLOW; + return (-1); + } + + return (ret); +} diff --git a/lib/libc/stdio/vswscanf.c b/lib/libc/stdio/vswscanf.c new file mode 100644 index 00000000000..60e04a0aaab --- /dev/null +++ b/lib/libc/stdio/vswscanf.c @@ -0,0 +1,104 @@ +/* $NetBSD: vswscanf.c,v 1.1 2005/05/14 23:51:02 christos 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)vsscanf.c 8.1 (Berkeley) 6/4/93"; +__FBSDID("$FreeBSD: src/lib/libc/stdio/vswscanf.c,v 1.3 2004/04/07 09:55:05 tjr Exp $"); +#else +__RCSID("$NetBSD: vswscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <limits.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include "reentrant.h" +#include "local.h" + +static int eofread(void *, char *, int); + +static int +/*ARGSUSED*/ +eofread(void *cookie, char *buf, int len) +{ + + return (0); +} + +int +vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, + va_list ap) +{ + static const mbstate_t initial; + mbstate_t mbs; + FILE f; + char *mbstr; + size_t mlen; + int r; + struct __sfileext fext; + + /* + * XXX Convert the wide character string to multibyte, which + * __vfwscanf() will convert back to wide characters. + */ + if ((mbstr = malloc(wcslen(str) * MB_CUR_MAX + 1)) == NULL) + return (EOF); + mbs = initial; + if ((mlen = wcsrtombs(mbstr, (const wchar_t ** __restrict)&str, + SIZE_T_MAX, &mbs)) == (size_t)-1) { + free(mbstr); + return (EOF); + } + _FILEEXT_SETUP(&f, &fext); + f._file = -1; + f._flags = __SRD; + f._bf._base = f._p = (unsigned char *)mbstr; + f._bf._size = f._r = mlen; + f._read = eofread; + _UB(&f)._base = NULL; + f._lb._base = NULL; + r = __vfwscanf_unlocked(&f, fmt, ap); + free(mbstr); + + return (r); +} diff --git a/lib/libc/stdio/vwprintf.c b/lib/libc/stdio/vwprintf.c new file mode 100644 index 00000000000..aa7db0e1c8a --- /dev/null +++ b/lib/libc/stdio/vwprintf.c @@ -0,0 +1,47 @@ +/* $NetBSD: vwprintf.c,v 1.1 2005/05/14 23:51:02 christos 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/vwprintf.c,v 1.1 2002/09/21 13:00:30 tjr Exp $"); +#else +__RCSID("$NetBSD: vwprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <stdarg.h> +#include <stdio.h> +#include <wchar.h> + +int +vwprintf(const wchar_t * __restrict fmt, va_list ap) +{ + + return (vfwprintf(stdout, fmt, ap)); +} diff --git a/lib/libc/stdio/vwscanf.c b/lib/libc/stdio/vwscanf.c new file mode 100644 index 00000000000..e908cbf4401 --- /dev/null +++ b/lib/libc/stdio/vwscanf.c @@ -0,0 +1,47 @@ +/* $NetBSD: vwscanf.c,v 1.1 2005/05/14 23:51:02 christos 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/vwscanf.c,v 1.1 2002/09/23 12:40:06 tjr Exp $"); +#else +__RCSID("$NetBSD: vwscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#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/wprintf.3 b/lib/libc/stdio/wprintf.3 new file mode 100644 index 00000000000..403d5a7b485 --- /dev/null +++ b/lib/libc/stdio/wprintf.3 @@ -0,0 +1,623 @@ +.\" $NetBSD: wprintf.3,v 1.1 2005/05/14 23:51:02 christos 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. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 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. +.\" +.\" @(#)printf.3 8.1 (Berkeley) 6/4/93 +.\" FreeBSD: src/lib/libc/stdio/printf.3,v 1.47 2002/09/06 11:23:55 tjr Exp +.\" $FreeBSD: src/lib/libc/stdio/wprintf.3,v 1.5 2003/07/05 07:55:34 tjr Exp $ +.\" +.Dd July 5, 2003 +.Dt WPRINTF 3 +.Os +.Sh NAME +.Nm wprintf , fwprintf , swprintf , +.Nm vwprintf , vfwprintf , vswprintf +.Nd formatted wide character output conversion +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdio.h +.In wchar.h +.Ft int +.Fn fwprintf "FILE * restrict stream" "const wchar_t * restrict format" ... +.Ft int +.Fn swprintf "wchar_t * restrict ws" "size_t n" "const wchar_t * restrict format" ... +.Ft int +.Fn wprintf "const wchar_t * restrict format" ... +.In stdarg.h +.Ft int +.Fn vfwprintf "FILE * restrict stream" "const wchar_t * restrict" "va_list ap" +.Ft int +.Fn vswprintf "wchar_t * restrict ws" "size_t n" "const wchar_t *restrict format" "va_list ap" +.Ft int +.Fn vwprintf "const wchar_t * restrict format" "va_list ap" +.Sh DESCRIPTION +The +.Fn wprintf +family of functions produces output according to a +.Fa format +as described below. +The +.Fn wprintf +and +.Fn vwprintf +functions +write output to +.Dv stdout , +the standard output stream; +.Fn fwprintf +and +.Fn vfwprintf +write output to the given output +.Fa stream ; +.Fn swprintf +and +.Fn vswprintf +write to the wide character string +.Fa ws . +.Pp +These functions write the output under the control of a +.Fa format +string that specifies how subsequent arguments +(or arguments accessed via the variable-length argument facilities of +.Xr stdarg 3 ) +are converted for output. +.Pp +These functions return the number of characters printed +(not including the trailing +.Ql \e0 +used to end output to strings). +.Pp +The +.Fn swprintf +and +.Fn vswprintf +functions will fail if +.Fa n +or more wide characters were requested to be written, +.Pp +The format string is composed of zero or more directives: +ordinary +characters (not +.Cm % ) , +which are copied unchanged to the output stream; +and conversion specifications, each of which results +in fetching zero or more subsequent arguments. +Each conversion specification is introduced by +the +.Cm % +character. +The arguments must correspond properly (after type promotion) +with the conversion specifier. +After the +.Cm % , +the following appear in sequence: +.Bl -bullet +.It +An optional field, consisting of a decimal digit string followed by a +.Cm $ , +specifying the next argument to access. +If this field is not provided, the argument following the last +argument accessed will be used. +Arguments are numbered starting at +.Cm 1 . +If unaccessed arguments in the format string are interspersed with ones that +are accessed the results will be indeterminate. +.It +Zero or more of the following flags: +.Bl -tag -width ".So \ Sc (space)" +.It Sq Cm # +The value should be converted to an +.Dq alternate form . +For +.Cm c , d , i , n , p , s , +and +.Cm u +conversions, this option has no effect. +For +.Cm o +conversions, the precision of the number is increased to force the first +character of the output string to a zero (except if a zero value is printed +with an explicit precision of zero). +For +.Cm x +and +.Cm X +conversions, a non-zero result has the string +.Ql 0x +(or +.Ql 0X +for +.Cm X +conversions) prepended to it. +For +.Cm a , A , e , E , f , F , g , +and +.Cm G +conversions, the result will always contain a decimal point, even if no +digits follow it (normally, a decimal point appears in the results of +those conversions only if a digit follows). +For +.Cm g +and +.Cm G +conversions, trailing zeros are not removed from the result as they +would otherwise be. +.It So Cm 0 Sc (zero) +Zero padding. +For all conversions except +.Cm n , +the converted value is padded on the left with zeros rather than blanks. +If a precision is given with a numeric conversion +.Cm ( d , i , o , u , i , x , +and +.Cm X ) , +the +.Cm 0 +flag is ignored. +.It Sq Cm \- +A negative field width flag; +the converted value is to be left adjusted on the field boundary. +Except for +.Cm n +conversions, the converted value is padded on the right with blanks, +rather than on the left with blanks or zeros. +A +.Cm \- +overrides a +.Cm 0 +if both are given. +.It So "\ " Sc (space) +A blank should be left before a positive number +produced by a signed conversion +.Cm ( a , A , d , e , E , f , F , g , G , +or +.Cm i ) . +.It Sq Cm + +A sign must always be placed before a +number produced by a signed conversion. +A +.Cm + +overrides a space if both are used. +.It Sq Cm ' +Decimal conversions +.Cm ( d , u , +or +.Cm i ) +or the integral portion of a floating point conversion +.Cm ( f +or +.Cm F ) +should be grouped and separated by thousands using +the non-monetary separator returned by +.Xr localeconv 3 . +.El +.It +An optional decimal digit string specifying a minimum field width. +If the converted value has fewer characters than the field width, it will +be padded with spaces on the left (or right, if the left-adjustment +flag has been given) to fill out +the field width. +.It +An optional precision, in the form of a period +.Cm \&. +followed by an +optional digit string. +If the digit string is omitted, the precision is taken as zero. +This gives the minimum number of digits to appear for +.Cm d , i , o , u , x , +and +.Cm X +conversions, the number of digits to appear after the decimal-point for +.Cm a , A , e , E , f , +and +.Cm F +conversions, the maximum number of significant digits for +.Cm g +and +.Cm G +conversions, or the maximum number of characters to be printed from a +string for +.Cm s +conversions. +.It +An optional length modifier, that specifies the size of the argument. +The following length modifiers are valid for the +.Cm d , i , n , o , u , x , +or +.Cm X +conversion: +.Bl -column ".Cm q Em (deprecated)" ".Vt signed char" ".Vt unsigned long long" ".Vt long long *" +.It Sy Modifier Ta Cm d , i Ta Cm o , u , x , X Ta Cm n +.It Cm hh Ta Vt "signed char" Ta Vt "unsigned char" Ta Vt "signed char *" +.It Cm h Ta Vt short Ta Vt "unsigned short" Ta Vt "short *" +.It Cm l No (ell) Ta Vt long Ta Vt "unsigned long" Ta Vt "long *" +.It Cm ll No (ell ell) Ta Vt "long long" Ta Vt "unsigned long long" Ta Vt "long long *" +.It Cm j Ta Vt intmax_t Ta Vt uintmax_t Ta Vt "intmax_t *" +.It Cm t Ta Vt ptrdiff_t Ta (see note) Ta Vt "ptrdiff_t *" +.It Cm z Ta (see note) Ta Vt size_t Ta (see note) +.It Cm q Em (deprecated) Ta Vt quad_t Ta Vt u_quad_t Ta Vt "quad_t *" +.El +.Pp +Note: +the +.Cm t +modifier, when applied to a +.Cm o , u , x , +or +.Cm X +conversion, indicates that the argument is of an unsigned type +equivalent in size to a +.Vt ptrdiff_t . +The +.Cm z +modifier, when applied to a +.Cm d +or +.Cm i +conversion, indicates that the argument is of a signed type equivalent in +size to a +.Vt size_t . +Similarly, when applied to an +.Cm n +conversion, it indicates that the argument is a pointer to a signed type +equivalent in size to a +.Vt size_t . +.Pp +The following length modifier is valid for the +.Cm a , A , e , E , f , F , g , +or +.Cm G +conversion: +.Bl -column ".Sy Modifier" ".Cm a , A , e , E , f , F , g , G" +.It Sy Modifier Ta Cm a , A , e , E , f , F , g , G +.It Cm L Ta Vt "long double" +.El +.Pp +The following length modifier is valid for the +.Cm c +or +.Cm s +conversion: +.Bl -column ".Sy Modifier" ".Vt wint_t" ".Vt wchar_t *" +.It Sy Modifier Ta Cm c Ta Cm s +.It Cm l No (ell) Ta Vt wint_t Ta Vt "wchar_t *" +.El +.It +A character that specifies the type of conversion to be applied. +.El +.Pp +A field width or precision, or both, may be indicated by +an asterisk +.Ql * +or an asterisk followed by one or more decimal digits and a +.Ql $ +instead of a +digit string. +In this case, an +.Vt int +argument supplies the field width or precision. +A negative field width is treated as a left adjustment flag followed by a +positive field width; a negative precision is treated as though it were +missing. +If a single format directive mixes positional +.Pq Li nn$ +and non-positional arguments, the results are undefined. +.Pp +The conversion specifiers and their meanings are: +.Bl -tag -width ".Cm diouxX" +.It Cm diouxX +The +.Vt int +(or appropriate variant) argument is converted to signed decimal +.Cm ( d +and +.Cm i ) , +unsigned octal +.Pq Cm o , +unsigned decimal +.Pq Cm u , +or unsigned hexadecimal +.Cm ( x +and +.Cm X ) +notation. +The letters +.Dq Li abcdef +are used for +.Cm x +conversions; the letters +.Dq Li ABCDEF +are used for +.Cm X +conversions. +The precision, if any, gives the minimum number of digits that must +appear; if the converted value requires fewer digits, it is padded on +the left with zeros. +.It Cm DOU +The +.Vt "long int" +argument is converted to signed decimal, unsigned octal, or unsigned +decimal, as if the format had been +.Cm ld , lo , +or +.Cm lu +respectively. +These conversion characters are deprecated, and will eventually disappear. +.It Cm eE +The +.Vt double +argument is rounded and converted in the style +.Sm off +.Oo \- Oc Ar d Li \&. Ar ddd Li e \\*[Pm] Ar dd +.Sm on +where there is one digit before the +decimal-point character +and the number of digits after it is equal to the precision; +if the precision is missing, +it is taken as 6; if the precision is +zero, no decimal-point character appears. +An +.Cm E +conversion uses the letter +.Ql E +(rather than +.Ql e ) +to introduce the exponent. +The exponent always contains at least two digits; if the value is zero, +the exponent is 00. +.Pp +For +.Cm a , A , e , E , f , F , g , +and +.Cm G +conversions, positive and negative infinity are represented as +.Li inf +and +.Li -inf +respectively when using the lowercase conversion character, and +.Li INF +and +.Li -INF +respectively when using the uppercase conversion character. +Similarly, NaN is represented as +.Li nan +when using the lowercase conversion, and +.Li NAN +when using the uppercase conversion. +.It Cm fF +The +.Vt double +argument is rounded and converted to decimal notation in the style +.Sm off +.Oo \- Oc Ar ddd Li \&. Ar ddd , +.Sm on +where the number of digits after the decimal-point character +is equal to the precision specification. +If the precision is missing, it is taken as 6; if the precision is +explicitly zero, no decimal-point character appears. +If a decimal point appears, at least one digit appears before it. +.It Cm gG +The +.Vt double +argument is converted in style +.Cm f +or +.Cm e +(or +.Cm F +or +.Cm E +for +.Cm G +conversions). +The precision specifies the number of significant digits. +If the precision is missing, 6 digits are given; if the precision is zero, +it is treated as 1. +Style +.Cm e +is used if the exponent from its conversion is less than \-4 or greater than +or equal to the precision. +Trailing zeros are removed from the fractional part of the result; a +decimal point appears only if it is followed by at least one digit. +.It Cm aA +The +.Vt double +argument is converted to hexadecimal notation in the style +.Sm off +.Oo \- Oc Li 0x Ar h Li \&. Ar hhhp Oo \\*[Pm] Oc Ar d , +.Sm on +where the number of digits after the hexadecimal-point character +is equal to the precision specification. +If the precision is missing, it is taken as enough to exactly +represent the floating-point number; if the precision is +explicitly zero, no hexadecimal-point character appears. +This is an exact conversion of the mantissa+exponent internal +floating point representation; the +.Sm off +.Oo \- Oc Li 0x Ar h Li \&. Ar hhh +.Sm on +portion represents exactly the mantissa; only denormalized +mantissas have a zero value to the left of the hexadecimal +point. +The +.Cm p +is a literal character +.Ql p ; +the exponent is preceded by a positive or negative sign +and is represented in decimal, using only enough characters +to represent the exponent. +The +.Cm A +conversion uses the prefix +.Dq Li 0X +(rather than +.Dq Li 0x ) , +the letters +.Dq Li ABCDEF +(rather than +.Dq Li abcdef ) +to represent the hex digits, and the letter +.Ql P +(rather than +.Ql p ) +to separate the mantissa and exponent. +.It Cm C +Treated as +.Cm c +with the +.Cm l +(ell) modifier. +.It Cm c +The +.Vt int +argument is converted to an +.Vt "unsigned char" , +then to a +.Vt wchar_t +as if by +.Xr btowc 3 , +and the resulting character is written. +.Pp +If the +.Cm l +(ell) modifier is used, the +.Vt wint_t +argument is converted to a +.Vt wchar_t +and written. +.It Cm S +Treated as +.Cm s +with the +.Cm l +(ell) modifier. +.It Cm s +The +.Vt "char *" +argument is expected to be a pointer to an array of character type (pointer +to a string) containing a multibyte sequence. +Characters from the array are converted to wide characters and written up to +(but not including) +a terminating +.Dv NUL +character; +if a precision is specified, no more than the number specified are +written. +If a precision is given, no null character +need be present; if the precision is not specified, or is greater than +the size of the array, the array must contain a terminating +.Dv NUL +character. +.Pp +If the +.Cm l +(ell) modifier is used, the +.Vt "wchar_t *" +argument is expected to be a pointer to an array of wide characters +(pointer to a wide string). +Each wide character in the string +is written. +Wide characters from the array are written up to (but not including) +a terminating wide +.Dv NUL +character; +if a precision is specified, no more than the number specified are +written (including shift sequences). +If a precision is given, no null character +need be present; if the precision is not specified, or is greater than +the number of characters in +the string, the array must contain a terminating wide +.Dv NUL +character. +.It Cm p +The +.Vt "void *" +pointer argument is printed in hexadecimal (as if by +.Ql %#x +or +.Ql %#lx ) . +.It Cm n +The number of characters written so far is stored into the +integer indicated by the +.Vt "int *" +(or variant) pointer argument. +No argument is converted. +.It Cm % +A +.Ql % +is written. +No argument is converted. +The complete conversion specification +is +.Ql %% . +.El +.Pp +The decimal point +character is defined in the program's locale (category +.Dv LC_NUMERIC ) . +.Pp +In no case does a non-existent or small field width cause truncation of +a numeric field; if the result of a conversion is wider than the field +width, the +field is expanded to contain the conversion result. +.Sh SECURITY CONSIDERATIONS +Refer to +.Xr printf 3 . +.Sh SEE ALSO +.Xr btowc 3 , +.Xr fputws 3 , +.Xr printf 3 , +.Xr putwc 3 , +.Xr setlocale 3 , +.Xr wcsrtombs 3 , +.Xr wscanf 3 +.Sh STANDARDS +Subject to the caveats noted in the +.Sx BUGS +section +of +.Xr printf 3 , +the +.Fn wprintf , +.Fn fwprintf , +.Fn swprintf , +.Fn vwprintf , +.Fn vfwprintf +and +.Fn vswprintf +functions +conform to +.St -isoC-99 . diff --git a/lib/libc/stdio/wprintf.c b/lib/libc/stdio/wprintf.c new file mode 100644 index 00000000000..6f6cd7b8777 --- /dev/null +++ b/lib/libc/stdio/wprintf.c @@ -0,0 +1,53 @@ +/* $NetBSD: wprintf.c,v 1.1 2005/05/14 23:51:02 christos 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/wprintf.c,v 1.1 2002/09/21 13:00:30 tjr Exp $"); +#else +__RCSID("$NetBSD: wprintf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#include <stdarg.h> +#include <stdio.h> +#include <wchar.h> + +int +wprintf(const wchar_t * __restrict fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vfwprintf(stdout, fmt, ap); + va_end(ap); + + return (ret); +} diff --git a/lib/libc/stdio/wscanf.3 b/lib/libc/stdio/wscanf.3 new file mode 100644 index 00000000000..158adf9b553 --- /dev/null +++ b/lib/libc/stdio/wscanf.3 @@ -0,0 +1,484 @@ +.\" $NetBSD: wscanf.3,v 1.1 2005/05/14 23:51:02 christos 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. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by the University of +.\" California, Berkeley and its contributors. +.\" 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. +.\" +.\" @(#)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 +.\" $FreeBSD: src/lib/libc/stdio/wscanf.3,v 1.6 2003/07/05 07:47:55 tjr Exp $ +.\" +.Dd July 5, 2003 +.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 LIBRARY +.Lb libc +.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 scans input according to a +.Fa format +as described below. +This format may contain +.Em conversion specifiers ; +the results from such conversions, if any, +are stored through the +.Em pointer +arguments. +The +.Fn wscanf +function +reads input from the standard input stream +.Dv stdin , +.Fn fwscanf +reads input from the stream pointer +.Fa stream , +and +.Fn swscanf +reads its input from the wide character string pointed to by +.Fa str . +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. +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. +White space (such as blanks, tabs, or newlines) in the +.Fa format +string match any amount of white space, 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 ".Cm l No (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 a +.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 white space; +this white space 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-white-space wide characters; +the next pointer must be a pointer to +.Vt char , +and the array must be large enough to accept the multibyte representation +of all the sequence and the +terminating +.Dv NUL +character. +The input string stops at white space +or at the maximum field width, whichever occurs first. +.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 S +The same as +.Cm ls . +.It Cm c +Matches a sequence of +.Em width +count +wide characters (default 1); +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 +.Dv NUL +is added). +The usual skip of leading white space is suppressed. +To skip white space 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 C +The same as +.Cm lc . +.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 +.Dv NUL +character. +The usual skip of leading white space is suppressed. +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 the +(or, with a circumflex, in) 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 +.Fn fwscanf , +.Fn wscanf , +.Fn swscanf , +.Fn vfwscanf , +.Fn vwscanf +and +.Fn vswscanf +functions +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..7bf3f333ecf --- /dev/null +++ b/lib/libc/stdio/wscanf.c @@ -0,0 +1,53 @@ +/* $NetBSD: wscanf.c,v 1.1 2005/05/14 23:51:02 christos 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> +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdio/wscanf.c,v 1.1 2002/09/23 12:40:06 tjr Exp $"); +#else +__RCSID("$NetBSD: wscanf.c,v 1.1 2005/05/14 23:51:02 christos Exp $"); +#endif +#endif /* LIBC_SCCS and not lint */ + +#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); +} |
