diff --git a/libc/Android.mk b/libc/Android.mk index 0fee71acd..1dff5ab60 100644 --- a/libc/Android.mk +++ b/libc/Android.mk @@ -343,12 +343,14 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/locale/wcscoll.c \ upstream-openbsd/lib/libc/locale/wcstod.c \ upstream-openbsd/lib/libc/locale/wcstof.c \ + upstream-openbsd/lib/libc/locale/wcstoimax.c \ upstream-openbsd/lib/libc/locale/wcstol.c \ upstream-openbsd/lib/libc/locale/wcstold.c \ upstream-openbsd/lib/libc/locale/wcstoll.c \ upstream-openbsd/lib/libc/locale/wcstombs.c \ upstream-openbsd/lib/libc/locale/wcstoul.c \ upstream-openbsd/lib/libc/locale/wcstoull.c \ + upstream-openbsd/lib/libc/locale/wcstoumax.c \ upstream-openbsd/lib/libc/locale/wcsxfrm.c \ upstream-openbsd/lib/libc/locale/wctob.c \ upstream-openbsd/lib/libc/stdio/asprintf.c \ @@ -361,6 +363,7 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/stdio/fgetln.c \ upstream-openbsd/lib/libc/stdio/fgetpos.c \ upstream-openbsd/lib/libc/stdio/fgets.c \ + upstream-openbsd/lib/libc/stdio/fgetwc.c \ upstream-openbsd/lib/libc/stdio/fileno.c \ upstream-openbsd/lib/libc/stdio/fprintf.c \ upstream-openbsd/lib/libc/stdio/fpurge.c \ @@ -375,6 +378,7 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/stdio/funopen.c \ upstream-openbsd/lib/libc/stdio/fvwrite.c \ upstream-openbsd/lib/libc/stdio/fwalk.c \ + upstream-openbsd/lib/libc/stdio/fwscanf.c \ upstream-openbsd/lib/libc/stdio/getc.c \ upstream-openbsd/lib/libc/stdio/getchar.c \ upstream-openbsd/lib/libc/stdio/getdelim.c \ @@ -395,18 +399,24 @@ libc_upstream_openbsd_src_files := \ upstream-openbsd/lib/libc/stdio/setbuffer.c \ upstream-openbsd/lib/libc/stdio/sscanf.c \ upstream-openbsd/lib/libc/stdio/stdio.c \ + upstream-openbsd/lib/libc/stdio/swscanf.c \ upstream-openbsd/lib/libc/stdio/tempnam.c \ upstream-openbsd/lib/libc/stdio/tmpnam.c \ upstream-openbsd/lib/libc/stdio/ungetc.c \ + upstream-openbsd/lib/libc/stdio/ungetwc.c \ upstream-openbsd/lib/libc/stdio/vasprintf.c \ upstream-openbsd/lib/libc/stdio/vfprintf.c \ upstream-openbsd/lib/libc/stdio/vfscanf.c \ + upstream-openbsd/lib/libc/stdio/vfwscanf.c \ upstream-openbsd/lib/libc/stdio/vprintf.c \ upstream-openbsd/lib/libc/stdio/vscanf.c \ upstream-openbsd/lib/libc/stdio/vsnprintf.c \ upstream-openbsd/lib/libc/stdio/vsprintf.c \ upstream-openbsd/lib/libc/stdio/vsscanf.c \ + upstream-openbsd/lib/libc/stdio/vswscanf.c \ + upstream-openbsd/lib/libc/stdio/vwscanf.c \ upstream-openbsd/lib/libc/stdio/wbuf.c \ + upstream-openbsd/lib/libc/stdio/wscanf.c \ upstream-openbsd/lib/libc/stdlib/atoi.c \ upstream-openbsd/lib/libc/stdlib/atol.c \ upstream-openbsd/lib/libc/stdlib/atoll.c \ diff --git a/libc/bionic/flockfile.cpp b/libc/bionic/flockfile.cpp index c60497d3d..3381e8eb9 100644 --- a/libc/bionic/flockfile.cpp +++ b/libc/bionic/flockfile.cpp @@ -29,7 +29,7 @@ #include #include -#include "fileext.h" +#include "local.h" // We can't use the OpenBSD implementation which uses kernel-specific // APIs not available on Linux. Instead we use a pthread_mutex_t within diff --git a/libc/bionic/wchar.cpp b/libc/bionic/wchar.cpp index e466c9122..d23b4b7ee 100644 --- a/libc/bionic/wchar.cpp +++ b/libc/bionic/wchar.cpp @@ -74,24 +74,6 @@ int vswprintf(wchar_t* /*s*/, size_t /*n*/, const wchar_t* /*format*/, va_list / return -1; } -int fwscanf(FILE* /*stream*/, const wchar_t* /*format*/, ... ) { - errno = ENOTSUP; - return -1; -} - -int wscanf(const wchar_t* format, ... ) { - va_list args; - va_start (args, format); - int result = fwscanf(stdout, format, args ); - va_end (args); - return result; -} - -int swscanf(const wchar_t* /*s*/, const wchar_t* /*format*/, ... ) { - errno = ENOTSUP; - return -1; -} - int iswalnum(wint_t wc) { return isalnum(wc); } int iswalpha(wint_t wc) { return isalpha(wc); } int iswblank(wint_t wc) { return isblank(wc); } @@ -123,10 +105,6 @@ int iswctype(wint_t wc, wctype_t char_class) { } } -wint_t fgetwc(FILE* stream) { - return static_cast(fgetc(stream)); -} - wchar_t* fgetws(wchar_t* ws, int n, FILE* stream) { return reinterpret_cast(fgets(reinterpret_cast(ws), n, stream)); } @@ -224,10 +202,6 @@ wint_t towupper(wint_t wc) { return toupper(wc); } -wint_t ungetwc(wint_t wc, FILE* stream) { - return ungetc(static_cast(wc), stream); -} - int wctomb(char* s, wchar_t wc) { if (s == NULL) { return 0; diff --git a/libc/include/inttypes.h b/libc/include/inttypes.h index 5199e4d1c..8853c08a3 100644 --- a/libc/include/inttypes.h +++ b/libc/include/inttypes.h @@ -254,13 +254,14 @@ typedef struct { } imaxdiv_t; __BEGIN_DECLS - intmax_t imaxabs(intmax_t) __pure2; imaxdiv_t imaxdiv(intmax_t, intmax_t) __pure2; - intmax_t strtoimax(const char *, char **, int); uintmax_t strtoumax(const char *, char **, int); - +intmax_t wcstoimax(const wchar_t * __restrict, + wchar_t ** __restrict, int); +uintmax_t wcstoumax(const wchar_t * __restrict, + wchar_t ** __restrict, int); __END_DECLS #endif /* _INTTYPES_H_ */ diff --git a/libc/include/wchar.h b/libc/include/wchar.h index 12715c279..669ce8d32 100644 --- a/libc/include/wchar.h +++ b/libc/include/wchar.h @@ -97,9 +97,12 @@ extern int swscanf(const wchar_t *, const wchar_t *, ...); extern wint_t towlower(wint_t); extern wint_t towupper(wint_t); extern wint_t ungetwc(wint_t, FILE *); -extern int vfwprintf(FILE *, const wchar_t *, va_list); -extern int vwprintf(const wchar_t *, va_list); -extern int vswprintf(wchar_t *, size_t, const wchar_t *, va_list); +extern int vfwprintf(FILE*, const wchar_t*, va_list); +extern int vfwscanf(FILE*, const wchar_t*, va_list); +extern int vswprintf(wchar_t*, size_t, const wchar_t*, va_list); +extern int vswscanf(const wchar_t*, const wchar_t*, va_list); +extern int vwprintf(const wchar_t*, va_list); +extern int vwscanf(const wchar_t*, va_list); extern size_t wcrtomb(char *, wchar_t, mbstate_t *); extern int wcscasecmp(const wchar_t *, const wchar_t *); extern wchar_t *wcscat(wchar_t *, const wchar_t *); diff --git a/libc/stdio/fileext.h b/libc/stdio/fileext.h index 864192408..fa6fed671 100644 --- a/libc/stdio/fileext.h +++ b/libc/stdio/fileext.h @@ -30,7 +30,6 @@ */ #include -#include "wcio.h" /* * file extension diff --git a/libc/stdio/findfp.c b/libc/stdio/findfp.c index 926e5a18d..2dd32c974 100644 --- a/libc/stdio/findfp.c +++ b/libc/stdio/findfp.c @@ -61,11 +61,7 @@ static struct glue uglue = { 0, FOPEN_MAX - 3, usual }; static struct glue *lastglue = &uglue; _THREAD_PRIVATE_MUTEX(__sfp_mutex); -static struct __sfileext __sFext[3] = { - _FILEEXT_INITIALIZER, - _FILEEXT_INITIALIZER, - _FILEEXT_INITIALIZER, -}; +static struct __sfileext __sFext[3]; FILE __sF[3] = { std(__SRD, STDIN_FILENO), /* stdin */ diff --git a/libc/stdio/local.h b/libc/stdio/local.h index eecfeef9c..5fb22924c 100644 --- a/libc/stdio/local.h +++ b/libc/stdio/local.h @@ -32,15 +32,15 @@ * SUCH DAMAGE. */ -#include "wcio.h" -#include "fileext.h" - - /* * Information local to this implementation of stdio, * in particular, macros and private variables. */ +#include +#include "wcio.h" +#include "fileext.h" + int __sflush(FILE *); int __sflush_locked(FILE *); FILE *__sfp(void); @@ -56,7 +56,12 @@ int __swhatbuf(FILE *, size_t *, int *); int _fwalk(int (*)(FILE *)); int __swsetup(FILE *); int __sflags(const char *, int *); +wint_t __fgetwc_unlock(FILE *); +wint_t __ungetwc(wint_t, FILE *); int __vfprintf(FILE *, const char *, __va_list); +int __svfscanf(FILE * __restrict, const char * __restrict, __va_list); +int __vfwprintf(FILE * __restrict, const wchar_t * __restrict, __va_list); +int __vfwscanf(FILE * __restrict, const wchar_t * __restrict, __va_list); /* * Function to clean up streams, called from abort() and exit(). diff --git a/libc/stdio/wcio.h b/libc/stdio/wcio.h index dd6db21a0..584a3f209 100644 --- a/libc/stdio/wcio.h +++ b/libc/stdio/wcio.h @@ -1,34 +1,34 @@ -/* - * Copyright (C) 2008 The Android Open Source Project +/* $OpenBSD: wcio.h,v 1.2 2013/04/17 17:40:35 tedu Exp $ */ +/* $NetBSD: wcio.h,v 1.3 2003/01/18 11:30:00 thorpej Exp $ */ + +/*- + * Copyright (c)2001 Citrus Project, * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * * Redistributions of source code must retain the above copyright + * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * * 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. + * 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 COPYRIGHT HOLDERS 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 - * COPYRIGHT OWNER 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 + * 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. + * + * $Citrus$ */ -/* this file is only used to quiet the BSD stdio implementation - * since we don't implement wchar support at all - */ #ifndef _WCIO_H_ #define _WCIO_H_ @@ -36,22 +36,46 @@ #define WCIO_UNGETWC_BUFSIZE 1 struct wchar_io_data { - int dummy; + mbstate_t wcio_mbstate_in; + mbstate_t wcio_mbstate_out; + + wchar_t wcio_ungetwc_buf[WCIO_UNGETWC_BUFSIZE]; + size_t wcio_ungetwc_inbuf; + + int wcio_mode; /* orientation */ }; -/* BIONIC: disable wchar support */ #define WCIO_GET(fp) \ - ((struct wchar_io_data*) 0) + (_EXT(fp) ? &(_EXT(fp)->_wcio) : (struct wchar_io_data *)0) -#define _SET_ORIENTATION(fp, mode) ((void)0) +#define _SET_ORIENTATION(fp, mode) \ +do {\ + struct wchar_io_data *_wcio = WCIO_GET(fp); \ + if (_wcio && _wcio->wcio_mode == 0) \ + _wcio->wcio_mode = (mode);\ +} while (0) /* * WCIO_FREE should be called by fclose */ -#define WCIO_FREE(fp) ((void)(0)) +#define WCIO_FREE(fp) \ +do {\ + struct wchar_io_data *_wcio = WCIO_GET(fp); \ + if (_wcio) { \ + _wcio->wcio_mode = 0;\ + _wcio->wcio_ungetwc_inbuf = 0;\ + } \ +} while (0) -#define WCIO_FREEUB(fp) ((void)0) +#define WCIO_FREEUB(fp) \ +do {\ + struct wchar_io_data *_wcio = WCIO_GET(fp); \ + if (_wcio) { \ + _wcio->wcio_ungetwc_inbuf = 0;\ + } \ +} while (0) -#define WCIO_INIT(fp) ((void)0) +#define WCIO_INIT(fp) \ + memset(&(_EXT(fp)->_wcio), 0, sizeof(struct wchar_io_data)) #endif /*_WCIO_H_*/ diff --git a/libc/upstream-openbsd/lib/libc/locale/wcstoimax.c b/libc/upstream-openbsd/lib/libc/locale/wcstoimax.c new file mode 100644 index 000000000..d46a7c7c4 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/locale/wcstoimax.c @@ -0,0 +1,19 @@ +/* $OpenBSD: wcstoimax.c,v 1.1 2009/01/13 18:13:51 kettenis Exp $ */ +/* $NetBSD: wcstol.c,v 1.2 2003/03/11 09:21:23 tshiozak Exp $ */ + +#include +#include +#include +#include +#include +#include +#include + +#include "wctoint.h" + +#define FUNCNAME wcstoimax +typedef intmax_t int_type; +#define MIN_VALUE INTMAX_MIN +#define MAX_VALUE INTMAX_MAX + +#include "_wcstol.h" diff --git a/libc/upstream-openbsd/lib/libc/locale/wcstoumax.c b/libc/upstream-openbsd/lib/libc/locale/wcstoumax.c new file mode 100644 index 000000000..ccd471340 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/locale/wcstoumax.c @@ -0,0 +1,18 @@ +/* $OpenBSD: wcstoumax.c,v 1.1 2009/01/13 18:13:51 kettenis Exp $ */ +/* $NetBSD: wcstoul.c,v 1.2 2003/03/11 09:21:24 tshiozak Exp $ */ + +#include +#include +#include +#include +#include +#include +#include + +#include "wctoint.h" + +#define FUNCNAME wcstoumax +typedef uintmax_t uint_type; +#define MAX_VALUE UINTMAX_MAX + +#include "_wcstoul.h" diff --git a/libc/upstream-openbsd/lib/libc/stdio/fgetwc.c b/libc/upstream-openbsd/lib/libc/stdio/fgetwc.c new file mode 100644 index 000000000..c16ffaf29 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/fgetwc.c @@ -0,0 +1,90 @@ +/* $OpenBSD: fgetwc.c,v 1.4 2009/11/09 00:18:27 kurt Exp $ */ +/* $NetBSD: fgetwc.c,v 1.3 2003/03/07 07:11:36 tshiozak Exp $ */ + +/*- + * Copyright (c)2001 Citrus Project, + * 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. + * + * $Citrus$ + */ + +#include +#include +#include +#include "local.h" + +wint_t +__fgetwc_unlock(FILE *fp) +{ + struct wchar_io_data *wcio; + mbstate_t *st; + wchar_t wc; + size_t size; + + _SET_ORIENTATION(fp, 1); + wcio = WCIO_GET(fp); + if (wcio == 0) { + errno = ENOMEM; + return WEOF; + } + + /* if there're ungetwc'ed wchars, use them */ + if (wcio->wcio_ungetwc_inbuf) { + wc = wcio->wcio_ungetwc_buf[--wcio->wcio_ungetwc_inbuf]; + + return wc; + } + + st = &wcio->wcio_mbstate_in; + + do { + char c; + int ch = __sgetc(fp); + + if (ch == EOF) { + return WEOF; + } + + c = ch; + size = mbrtowc(&wc, &c, 1, st); + if (size == (size_t)-1) { + errno = EILSEQ; + return WEOF; + } + } while (size == (size_t)-2); + + return wc; +} + +wint_t +fgetwc(FILE *fp) +{ + wint_t r; + + FLOCKFILE(fp); + r = __fgetwc_unlock(fp); + FUNLOCKFILE(fp); + + return (r); +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/fwscanf.c b/libc/upstream-openbsd/lib/libc/stdio/fwscanf.c new file mode 100644 index 000000000..b716cbff3 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/fwscanf.c @@ -0,0 +1,44 @@ +/* $OpenBSD: fwscanf.c,v 1.2 2012/12/05 23:20:01 deraadt 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 +#include +#include + +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/libc/upstream-openbsd/lib/libc/stdio/swscanf.c b/libc/upstream-openbsd/lib/libc/stdio/swscanf.c new file mode 100644 index 000000000..a85e9ee2b --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/swscanf.c @@ -0,0 +1,44 @@ +/* $OpenBSD: swscanf.c,v 1.2 2012/12/05 23:20:01 deraadt 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 +#include +#include + +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/libc/upstream-openbsd/lib/libc/stdio/ungetwc.c b/libc/upstream-openbsd/lib/libc/stdio/ungetwc.c new file mode 100644 index 000000000..c0321e9e1 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/ungetwc.c @@ -0,0 +1,77 @@ +/* $OpenBSD: ungetwc.c,v 1.5 2011/10/16 13:20:51 stsp Exp $ */ +/* $NetBSD: ungetwc.c,v 1.2 2003/01/18 11:29:59 thorpej Exp $ */ + +/*- + * Copyright (c)2001 Citrus Project, + * 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. + * + * $Citrus$ + */ + +#include +#include +#include +#include "local.h" + +wint_t +__ungetwc(wint_t wc, FILE *fp) +{ + struct wchar_io_data *wcio; + + if (wc == WEOF) + return WEOF; + + _SET_ORIENTATION(fp, 1); + /* + * XXX since we have no way to transform a wchar string to + * a char string in reverse order, we can't use ungetc. + */ + /* XXX should we flush ungetc buffer? */ + + wcio = WCIO_GET(fp); + if (wcio == 0) { + errno = ENOMEM; /* XXX */ + return WEOF; + } + + if (wcio->wcio_ungetwc_inbuf >= WCIO_UNGETWC_BUFSIZE) { + return WEOF; + } + + wcio->wcio_ungetwc_buf[wcio->wcio_ungetwc_inbuf++] = wc; + __sclearerr(fp); + + return wc; +} + +wint_t +ungetwc(wint_t wc, FILE *fp) +{ + wint_t r; + + FLOCKFILE(fp); + r = __ungetwc(wc, fp); + FUNLOCKFILE(fp); + return (r); +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/vfwscanf.c b/libc/upstream-openbsd/lib/libc/stdio/vfwscanf.c new file mode 100644 index 000000000..e5cf5e129 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/vfwscanf.c @@ -0,0 +1,799 @@ +/* $OpenBSD: vfwscanf.c,v 1.2 2012/01/18 17:23:11 chl Exp $ */ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Chris Torek. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "local.h" + +#ifdef FLOATING_POINT +#include "floatio.h" +#endif + +#define BUF 513 /* Maximum length of numeric string. */ + +/* + * Flags used during conversion. + */ +#define LONG 0x00001 /* l: long or double */ +#define LONGDBL 0x00002 /* L: long double */ +#define SHORT 0x00004 /* h: short */ +#define SHORTSHORT 0x00008 /* hh: 8 bit integer */ +#define LLONG 0x00010 /* ll: long long (+ deprecated q: quad) */ +#define POINTER 0x00020 /* p: void * (as hex) */ +#define SIZEINT 0x00040 /* z: (signed) size_t */ +#define MAXINT 0x00080 /* j: intmax_t */ +#define PTRINT 0x00100 /* t: ptrdiff_t */ +#define NOSKIP 0x00200 /* [ or c: do not skip blanks */ +#define SUPPRESS 0x00400 /* *: suppress assignment */ +#define UNSIGNED 0x00800 /* %[oupxX] conversions */ + +/* + * The following are used in numeric conversions only: + * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point; + * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral. + */ +#define SIGNOK 0x01000 /* +/- is (still) legal */ +#define HAVESIGN 0x02000 /* sign detected */ +#define NDIGITS 0x04000 /* no digits detected */ + +#define DPTOK 0x08000 /* (float) decimal point is still legal */ +#define EXPOK 0x10000 /* (float) exponent (e+3, etc) still legal */ + +#define PFXOK 0x08000 /* 0x prefix is (still) legal */ +#define NZDIGITS 0x10000 /* no zero digits detected */ + +/* + * Conversion types. + */ +#define CT_CHAR 0 /* %c conversion */ +#define CT_CCL 1 /* %[...] conversion */ +#define CT_STRING 2 /* %s conversion */ +#define CT_INT 3 /* integer, i.e., strtoimax or strtoumax */ +#define CT_FLOAT 4 /* floating, i.e., strtod */ + +#define u_char unsigned char +#define u_long unsigned long + +#define INCCL(_c) \ + (cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \ + (wmemchr(ccls, (_c), ccle - ccls) != NULL)) + +/* + * vfwscanf + */ +int +__vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, __va_list ap) +{ + wint_t c; /* character from format, or conversion */ + size_t width; /* field width, or 0 */ + wchar_t *p; /* points into all kinds of strings */ + int n; /* handy integer */ + int flags; /* flags as defined above */ + wchar_t *p0; /* saves original value of p when necessary */ + int nassigned; /* number of fields assigned */ + int nconversions; /* number of conversions */ + int nread; /* number of characters consumed from fp */ + int base; /* base argument to strtoimax/strtouimax */ + wchar_t buf[BUF]; /* buffer for numeric conversions */ + const wchar_t *ccls; /* character class start */ + const wchar_t *ccle; /* character class end */ + int cclcompl; /* ccl is complemented? */ + wint_t wi; /* handy wint_t */ + char *mbp; /* multibyte string pointer for %c %s %[ */ + size_t nconv; /* number of bytes in mb. conversion */ + char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */ + mbstate_t mbs; +#ifdef FLOATING_POINT + wchar_t decimal_point = 0; +#endif + + /* `basefix' is used to avoid `if' tests in the integer scanner */ + static short basefix[17] = + { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + + _SET_ORIENTATION(fp, 1); + + nassigned = 0; + nconversions = 0; + nread = 0; + base = 0; /* XXX just to keep gcc happy */ + ccls = ccle = NULL; + for (;;) { + c = *fmt++; + if (c == 0) { + return (nassigned); + } + if (iswspace(c)) { + while ((c = __fgetwc_unlock(fp)) != WEOF && + iswspace(c)) + ; + if (c != WEOF) + __ungetwc(c, fp); + continue; + } + if (c != '%') + goto literal; + width = 0; + flags = 0; + /* + * switch on the format. continue if done; + * break once format type is derived. + */ +again: c = *fmt++; + switch (c) { + case '%': +literal: + if ((wi = __fgetwc_unlock(fp)) == WEOF) + goto input_failure; + if (wi != c) { + __ungetwc(wi, fp); + goto input_failure; + } + nread++; + continue; + + case '*': + flags |= SUPPRESS; + goto again; + case 'j': + flags |= MAXINT; + goto again; + case 'L': + flags |= LONGDBL; + goto again; + case 'h': + if (*fmt == 'h') { + fmt++; + flags |= SHORTSHORT; + } else { + flags |= SHORT; + } + goto again; + case 'l': + if (*fmt == 'l') { + fmt++; + flags |= LLONG; + } else { + flags |= LONG; + } + goto again; + case 'q': + flags |= LLONG; /* deprecated */ + goto again; + case 't': + flags |= PTRINT; + goto again; + case 'z': + flags |= SIZEINT; + goto again; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + width = width * 10 + c - '0'; + goto again; + + /* + * Conversions. + * Those marked `compat' are for 4.[123]BSD compatibility. + * + * (According to ANSI, E and X formats are supposed + * to the same as e and x. Sorry about that.) + */ + case 'D': /* compat */ + flags |= LONG; + /* FALLTHROUGH */ + case 'd': + c = CT_INT; + base = 10; + break; + + case 'i': + c = CT_INT; + base = 0; + break; + + case 'O': /* compat */ + flags |= LONG; + /* FALLTHROUGH */ + case 'o': + c = CT_INT; + flags |= UNSIGNED; + base = 8; + break; + + case 'u': + c = CT_INT; + flags |= UNSIGNED; + base = 10; + break; + + case 'X': + case 'x': + flags |= PFXOK; /* enable 0x prefixing */ + c = CT_INT; + flags |= UNSIGNED; + base = 16; + break; + +#ifdef FLOATING_POINT + case 'e': case 'E': + case 'f': case 'F': + case 'g': case 'G': + case 'a': case 'A': + c = CT_FLOAT; + break; +#endif + + case 's': + c = CT_STRING; + break; + + case '[': + ccls = fmt; + if (*fmt == '^') { + cclcompl = 1; + fmt++; + } else + cclcompl = 0; + if (*fmt == ']') + fmt++; + while (*fmt != '\0' && *fmt != ']') + fmt++; + ccle = fmt; + fmt++; + flags |= NOSKIP; + c = CT_CCL; + break; + + case 'c': + flags |= NOSKIP; + c = CT_CHAR; + break; + + case 'p': /* pointer format is like hex */ + flags |= POINTER | PFXOK; + c = CT_INT; + flags |= UNSIGNED; + base = 16; + break; + + case 'n': + nconversions++; + if (flags & SUPPRESS) + continue; + if (flags & SHORTSHORT) + *va_arg(ap, __signed char *) = nread; + else if (flags & SHORT) + *va_arg(ap, short *) = nread; + else if (flags & LONG) + *va_arg(ap, long *) = nread; + else if (flags & SIZEINT) + *va_arg(ap, ssize_t *) = nread; + else if (flags & PTRINT) + *va_arg(ap, ptrdiff_t *) = nread; + else if (flags & LLONG) + *va_arg(ap, long long *) = nread; + else if (flags & MAXINT) + *va_arg(ap, intmax_t *) = nread; + else + *va_arg(ap, int *) = nread; + continue; + + /* + * Disgusting backwards compatibility hacks. XXX + */ + case '\0': /* compat */ + return (EOF); + + default: /* compat */ + if (isupper(c)) + flags |= LONG; + c = CT_INT; + base = 10; + break; + } + + /* + * Consume leading white space, except for formats + * that suppress this. + */ + if ((flags & NOSKIP) == 0) { + while ((wi = __fgetwc_unlock(fp)) != WEOF && + iswspace(wi)) + nread++; + if (wi == WEOF) + goto input_failure; + __ungetwc(wi, fp); + } + + /* + * Do the conversion. + */ + switch (c) { + + case CT_CHAR: + /* scan arbitrary characters (sets NOSKIP) */ + if (width == 0) + width = 1; + if (flags & LONG) { + if (!(flags & SUPPRESS)) + p = va_arg(ap, wchar_t *); + n = 0; + while (width-- != 0 && + (wi = __fgetwc_unlock(fp)) != WEOF) { + if (!(flags & SUPPRESS)) + *p++ = (wchar_t)wi; + n++; + } + if (n == 0) + goto input_failure; + nread += n; + if (!(flags & SUPPRESS)) + nassigned++; + } else { + if (!(flags & SUPPRESS)) + mbp = va_arg(ap, char *); + n = 0; + bzero(&mbs, sizeof(mbs)); + while (width != 0 && + (wi = __fgetwc_unlock(fp)) != WEOF) { + if (width >= MB_CUR_MAX && + !(flags & SUPPRESS)) { + nconv = wcrtomb(mbp, wi, &mbs); + if (nconv == (size_t)-1) + goto input_failure; + } else { + nconv = wcrtomb(mbbuf, wi, + &mbs); + if (nconv == (size_t)-1) + goto input_failure; + if (nconv > width) { + __ungetwc(wi, fp); + break; + } + if (!(flags & SUPPRESS)) + memcpy(mbp, mbbuf, + nconv); + } + if (!(flags & SUPPRESS)) + mbp += nconv; + width -= nconv; + n++; + } + if (n == 0) + goto input_failure; + nread += n; + if (!(flags & SUPPRESS)) + nassigned++; + } + nconversions++; + break; + + case CT_CCL: + /* scan a (nonempty) character class (sets NOSKIP) */ + if (width == 0) + width = (size_t)~0; /* `infinity' */ + /* take only those things in the class */ + if ((flags & SUPPRESS) && (flags & LONG)) { + n = 0; + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width-- != 0 && INCCL(wi)) + n++; + if (wi != WEOF) + __ungetwc(wi, fp); + if (n == 0) + goto match_failure; + } else if (flags & LONG) { + p0 = p = va_arg(ap, wchar_t *); + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width-- != 0 && INCCL(wi)) + *p++ = (wchar_t)wi; + if (wi != WEOF) + __ungetwc(wi, fp); + n = p - p0; + if (n == 0) + goto match_failure; + *p = 0; + nassigned++; + } else { + if (!(flags & SUPPRESS)) + mbp = va_arg(ap, char *); + n = 0; + bzero(&mbs, sizeof(mbs)); + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width != 0 && INCCL(wi)) { + if (width >= MB_CUR_MAX && + !(flags & SUPPRESS)) { + nconv = wcrtomb(mbp, wi, &mbs); + if (nconv == (size_t)-1) + goto input_failure; + } else { + nconv = wcrtomb(mbbuf, wi, + &mbs); + if (nconv == (size_t)-1) + goto input_failure; + if (nconv > width) + break; + if (!(flags & SUPPRESS)) + memcpy(mbp, mbbuf, + nconv); + } + if (!(flags & SUPPRESS)) + mbp += nconv; + width -= nconv; + n++; + } + if (wi != WEOF) + __ungetwc(wi, fp); + if (!(flags & SUPPRESS)) { + *mbp = 0; + nassigned++; + } + } + nread += n; + nconversions++; + break; + + case CT_STRING: + /* like CCL, but zero-length string OK, & no NOSKIP */ + if (width == 0) + width = (size_t)~0; + if ((flags & SUPPRESS) && (flags & LONG)) { + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width-- != 0 && + !iswspace(wi)) + nread++; + if (wi != WEOF) + __ungetwc(wi, fp); + } else if (flags & LONG) { + p0 = p = va_arg(ap, wchar_t *); + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width-- != 0 && + !iswspace(wi)) { + *p++ = (wchar_t)wi; + nread++; + } + if (wi != WEOF) + __ungetwc(wi, fp); + *p = 0; + nassigned++; + } else { + if (!(flags & SUPPRESS)) + mbp = va_arg(ap, char *); + bzero(&mbs, sizeof(mbs)); + while ((wi = __fgetwc_unlock(fp)) != WEOF && + width != 0 && + !iswspace(wi)) { + if (width >= MB_CUR_MAX && + !(flags & SUPPRESS)) { + nconv = wcrtomb(mbp, wi, &mbs); + if (nconv == (size_t)-1) + goto input_failure; + } else { + nconv = wcrtomb(mbbuf, wi, + &mbs); + if (nconv == (size_t)-1) + goto input_failure; + if (nconv > width) + break; + if (!(flags & SUPPRESS)) + memcpy(mbp, mbbuf, + nconv); + } + if (!(flags & SUPPRESS)) + mbp += nconv; + width -= nconv; + nread++; + } + if (wi != WEOF) + __ungetwc(wi, fp); + if (!(flags & SUPPRESS)) { + *mbp = 0; + nassigned++; + } + } + nconversions++; + continue; + + case CT_INT: + /* scan an integer as if by strtoimax/strtoumax */ + if (width == 0 || width > sizeof(buf) / + sizeof(*buf) - 1) + width = sizeof(buf) / sizeof(*buf) - 1; + flags |= SIGNOK | NDIGITS | NZDIGITS; + for (p = buf; width; width--) { + c = __fgetwc_unlock(fp); + /* + * Switch on the character; `goto ok' + * if we accept it as a part of number. + */ + switch (c) { + + /* + * The digit 0 is always legal, but is + * special. For %i conversions, if no + * digits (zero or nonzero) have been + * scanned (only signs), we will have + * base==0. In that case, we should set + * it to 8 and enable 0x prefixing. + * Also, if we have not scanned zero digits + * before this, do not turn off prefixing + * (someone else will turn it off if we + * have scanned any nonzero digits). + */ + case '0': + if (base == 0) { + base = 8; + flags |= PFXOK; + } + if (flags & NZDIGITS) + flags &= ~(SIGNOK|NZDIGITS|NDIGITS); + else + flags &= ~(SIGNOK|PFXOK|NDIGITS); + goto ok; + + /* 1 through 7 always legal */ + case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + base = basefix[base]; + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + + /* digits 8 and 9 ok iff decimal or hex */ + case '8': case '9': + base = basefix[base]; + if (base <= 8) + break; /* not legal here */ + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + + /* letters ok iff hex */ + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + /* no need to fix base here */ + if (base <= 10) + break; /* not legal here */ + flags &= ~(SIGNOK | PFXOK | NDIGITS); + goto ok; + + /* sign ok only as first character */ + case '+': case '-': + if (flags & SIGNOK) { + flags &= ~SIGNOK; + flags |= HAVESIGN; + goto ok; + } + break; + + /* + * x ok iff flag still set and 2nd char (or + * 3rd char if we have a sign). + */ + case 'x': case 'X': + if ((flags & PFXOK) && p == + buf + 1 + !!(flags & HAVESIGN)) { + base = 16; /* if %i */ + flags &= ~PFXOK; + goto ok; + } + break; + } + + /* + * If we got here, c is not a legal character + * for a number. Stop accumulating digits. + */ + if (c != WEOF) + __ungetwc(c, fp); + break; + ok: + /* + * c is legal: store it and look at the next. + */ + *p++ = (wchar_t)c; + } + /* + * If we had only a sign, it is no good; push + * back the sign. If the number ends in `x', + * it was [sign] '0' 'x', so push back the x + * and treat it as [sign] '0'. + */ + if (flags & NDIGITS) { + if (p > buf) + __ungetwc(*--p, fp); + goto match_failure; + } + c = p[-1]; + if (c == 'x' || c == 'X') { + --p; + __ungetwc(c, fp); + } + if ((flags & SUPPRESS) == 0) { + uintmax_t res; + + *p = '\0'; + if (flags & UNSIGNED) + res = wcstoimax(buf, NULL, base); + else + res = wcstoumax(buf, NULL, base); + if (flags & POINTER) + *va_arg(ap, void **) = + (void *)(uintptr_t)res; + else if (flags & MAXINT) + *va_arg(ap, intmax_t *) = res; + else if (flags & LLONG) + *va_arg(ap, long long *) = res; + else if (flags & SIZEINT) + *va_arg(ap, ssize_t *) = res; + else if (flags & PTRINT) + *va_arg(ap, ptrdiff_t *) = res; + else if (flags & LONG) + *va_arg(ap, long *) = res; + else if (flags & SHORT) + *va_arg(ap, short *) = res; + else if (flags & SHORTSHORT) + *va_arg(ap, __signed char *) = res; + else + *va_arg(ap, int *) = res; + nassigned++; + } + nread += p - buf; + nconversions++; + break; + +#ifdef FLOATING_POINT + case CT_FLOAT: + /* scan a floating point number as if by strtod */ + if (width == 0 || width > sizeof(buf) / + sizeof(*buf) - 1) + width = sizeof(buf) / sizeof(*buf) - 1; + flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; + for (p = buf; width; width--) { + c = __fgetwc_unlock(fp); + /* + * This code mimicks the integer conversion + * code, but is much simpler. + */ + switch (c) { + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + case '8': case '9': + flags &= ~(SIGNOK | NDIGITS); + goto fok; + + case '+': case '-': + if (flags & SIGNOK) { + flags &= ~SIGNOK; + goto fok; + } + break; + case 'e': case 'E': + /* no exponent without some digits */ + if ((flags&(NDIGITS|EXPOK)) == EXPOK) { + flags = + (flags & ~(EXPOK|DPTOK)) | + SIGNOK | NDIGITS; + goto fok; + } + break; + default: + if (decimal_point == 0) { + bzero(&mbs, sizeof(mbs)); + nconv = mbrtowc(&decimal_point, + localeconv()->decimal_point, + MB_CUR_MAX, &mbs); + if (nconv == 0 || + nconv == (size_t)-1 || + nconv == (size_t)-2) + decimal_point = '.'; + } + if (c == decimal_point && + (flags & DPTOK)) { + flags &= ~(SIGNOK | DPTOK); + goto fok; + } + break; + } + if (c != WEOF) + __ungetwc(c, fp); + break; + fok: + *p++ = c; + } + /* + * If no digits, might be missing exponent digits + * (just give back the exponent) or might be missing + * regular digits, but had sign and/or decimal point. + */ + if (flags & NDIGITS) { + if (flags & EXPOK) { + /* no digits at all */ + while (p > buf) + __ungetwc(*--p, fp); + goto match_failure; + } + /* just a bad exponent (e and maybe sign) */ + c = *--p; + if (c != 'e' && c != 'E') { + __ungetwc(c, fp);/* sign */ + c = *--p; + } + __ungetwc(c, fp); + } + if ((flags & SUPPRESS) == 0) { + *p = 0; + if (flags & LONGDBL) { + long double res = wcstold(buf, NULL); + *va_arg(ap, long double *) = res; + } else if (flags & LONG) { + double res = wcstod(buf, NULL); + *va_arg(ap, double *) = res; + } else { + float res = wcstof(buf, NULL); + *va_arg(ap, float *) = res; + } + nassigned++; + } + nread += p - buf; + nconversions++; + break; +#endif /* FLOATING_POINT */ + } + } +input_failure: + return (nconversions != 0 ? nassigned : EOF); +match_failure: + return (nassigned); +} + +int +vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, __va_list ap) +{ + int r; + + FLOCKFILE(fp); + r = __vfwscanf(fp, fmt, ap); + FUNLOCKFILE(fp); + return (r); +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/vswscanf.c b/libc/upstream-openbsd/lib/libc/stdio/vswscanf.c new file mode 100644 index 000000000..cbaa25091 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/vswscanf.c @@ -0,0 +1,88 @@ +/* $OpenBSD: vswscanf.c,v 1.2 2012/12/05 23:20:01 deraadt Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Donn Seeley at UUNET Technologies, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include "local.h" + +static int eofread(void *, char *, int); + +static int +eofread(void *cookie, char *buf, int len) +{ + return (0); +} + +int +vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, + __va_list ap) +{ + mbstate_t mbs; + FILE f; + struct __sfileext fext; + char *mbstr; + size_t len, mlen; + int r; + const wchar_t *strp; + + /* + * XXX Convert the wide character string to multibyte, which + * __vfwscanf() will convert back to wide characters. + */ + len = wcslen(str) * MB_CUR_MAX; + if ((mbstr = malloc(len + 1)) == NULL) + return (EOF); + bzero(&mbs, sizeof(mbs)); + strp = str; + if ((mlen = wcsrtombs(mbstr, &strp, len, &mbs)) == (size_t)-1) { + free(mbstr); + return (EOF); + } + if (mlen == len) + mbstr[len] = '\0'; + _FILEEXT_SETUP(&f, &fext); + f._flags = __SRD; + f._bf._base = f._p = (unsigned char *)mbstr; + f._bf._size = f._r = mlen; + f._read = eofread; + f._lb._base = NULL; + r = __vfwscanf(&f, fmt, ap); + free(mbstr); + + return (r); +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/vwscanf.c b/libc/upstream-openbsd/lib/libc/stdio/vwscanf.c new file mode 100644 index 000000000..7039f02d7 --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/vwscanf.c @@ -0,0 +1,38 @@ +/* $OpenBSD: vwscanf.c,v 1.2 2012/12/05 23:20:01 deraadt 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 +#include +#include + +int +vwscanf(const wchar_t * __restrict fmt, __va_list ap) +{ + + return (vfwscanf(stdin, fmt, ap)); +} diff --git a/libc/upstream-openbsd/lib/libc/stdio/wscanf.c b/libc/upstream-openbsd/lib/libc/stdio/wscanf.c new file mode 100644 index 000000000..06c0829ab --- /dev/null +++ b/libc/upstream-openbsd/lib/libc/stdio/wscanf.c @@ -0,0 +1,44 @@ +/* $OpenBSD: wscanf.c,v 1.2 2012/12/05 23:20:01 deraadt 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 +#include +#include + +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); +} diff --git a/tests/inttypes_test.cpp b/tests/inttypes_test.cpp index ac37e6295..e58850340 100644 --- a/tests/inttypes_test.cpp +++ b/tests/inttypes_test.cpp @@ -38,3 +38,11 @@ TEST(inttypes, misc) { sscanf(buf, "%08" SCNuPTR, &u); sscanf(buf, "%08" SCNxPTR, &u); } + +TEST(inttypes, wcstoimax) { + ASSERT_EQ(123, wcstoimax(L"123", NULL, 10)); +} + +TEST(inttypes, wcstoumax) { + ASSERT_EQ(123U, wcstoumax(L"123", NULL, 10)); +}