summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2003-08-01 20:08:59 +0000
committerManuel Novoa III <mjn3@codepoet.org>2003-08-01 20:08:59 +0000
commit1217289737588e65b088b3535428b27c7287d699 (patch)
tree6a292ac767d219702e26a6a2111737f84a96900c
parent32b76c5ec3c257b7287913d0d1a96e0cbb2e9c6a (diff)
Add a new *scanf implementation, includeing the *wscanf functions.
Should be standards compliant and with several optional features, including support for hexadecimal float notation, locale awareness, glibc-like locale-specific digit grouping with the `'' flag, and positional arg support. I tested it pretty well (finding several bugs in glibc's scanf in the process), but it is brand new so be aware. The *wprintf functions now support floating point output. Also, a couple of bugs were squashed. Finally, %a/%A conversions are now implemented. Implement the glibc xlocale interface for thread-specific locale support. Also add the various *_l(args, locale_t loc_arg) funcs. NOTE!!! setlocale() is NOT threadsafe! NOTE!!! The strto{floating point} conversion functions are now locale aware. The also now support hexadecimal floating point notation. Add the wcsto{floating point} conversion functions. Fix a bug in mktime() related to dst. Note that unlike glibc's mktime, uClibc's version always normalizes the struct tm before attempting to determine the correct dst setting if tm_isdst == -1 on entry. Add a stub version of the libintl functions. (untested) Fixed a known memory leak in setlocale() related to the collation data. Add lots of new config options (which Erik agreed to sort out :-), including finally exposing some of the stripped down stdio configs. Be careful with those though, as they haven't been tested in a long time. (temporary) GOTCHAs... The ctype functions are currently incorrect for 8-bit locales. They will be fixed shortly. The ctype functions are now table-based, resulting in larger staticly linked binaries. I'll be adding an option to use the old approach in the stub locale configuration.
-rw-r--r--TODO54
-rw-r--r--extra/Configs/Config.in393
-rw-r--r--extra/locale/Makefile8
-rw-r--r--extra/locale/gen_collate.c34
-rw-r--r--extra/locale/gen_ldc.c78
-rw-r--r--extra/locale/gen_locale.c62
-rw-r--r--extra/locale/gen_wc8bit.c68
-rw-r--r--extra/locale/gen_wctype.c18
-rw-r--r--extra/locale/locale_mmap.h79
-rw-r--r--include/ctype.h443
-rw-r--r--include/langinfo.h9
-rw-r--r--include/libintl.h126
-rw-r--r--include/locale.h97
-rw-r--r--include/signal.h2
-rw-r--r--include/stdio.h16
-rw-r--r--include/stdlib.h313
-rw-r--r--include/string.h75
-rw-r--r--include/sys/cdefs.h48
-rw-r--r--include/time.h90
-rw-r--r--include/wchar.h411
-rw-r--r--include/wctype.h108
-rw-r--r--include/xlocale.h62
-rw-r--r--libc/inet/rpc/rcmd.c13
-rw-r--r--libc/misc/Makefile4
-rw-r--r--libc/misc/assert/__assert.c16
-rw-r--r--libc/misc/ctype/Makefile29
-rw-r--r--libc/misc/ctype/ctype.c1041
-rw-r--r--libc/misc/intl/Makefile50
-rw-r--r--libc/misc/intl/intl.c149
-rw-r--r--libc/misc/locale/Makefile31
-rw-r--r--libc/misc/locale/locale.c1103
-rw-r--r--libc/misc/time/Makefile13
-rw-r--r--libc/misc/time/time.c245
-rw-r--r--libc/misc/wchar/Makefile1
-rw-r--r--libc/misc/wchar/wchar.c111
-rw-r--r--libc/misc/wchar/wstdio.c37
-rw-r--r--libc/misc/wctype/Makefile20
-rw-r--r--libc/misc/wctype/wctype.c661
-rw-r--r--libc/stdio/Makefile12
-rw-r--r--libc/stdio/old_vfprintf.c9
-rw-r--r--libc/stdio/printf.c1151
-rw-r--r--libc/stdio/scanf.c2370
-rw-r--r--libc/stdio/stdio.c200
-rw-r--r--libc/stdlib/Makefile48
-rw-r--r--libc/stdlib/stdlib.c252
-rw-r--r--libc/stdlib/strtod.c711
-rw-r--r--libc/string/Makefile32
-rw-r--r--libc/string/wstring.c262
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_ctype.h2
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_fpmax.h132
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_locale.h129
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_stdio.h123
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_touplow.h44
-rw-r--r--libc/sysdeps/linux/common/bits/uClibc_uwchar.h56
-rw-r--r--libc/sysdeps/linux/common/bits/xopen_lim.h6
-rw-r--r--libc/unistd/getopt.c6
-rw-r--r--libpthread/linuxthreads/Makefile5
-rw-r--r--libpthread/linuxthreads/internals.h6
-rw-r--r--libpthread/linuxthreads/locale.c58
-rw-r--r--libpthread/linuxthreads/manager.c9
-rw-r--r--libpthread/linuxthreads/pthread.c14
61 files changed, 8923 insertions, 2832 deletions
diff --git a/TODO b/TODO
index 8cfac9d7d..0737971c9 100644
--- a/TODO
+++ b/TODO
@@ -25,53 +25,43 @@ I'm currently working on completing the wide char and locale support.
1) Little things that need fixing:
----------------------------------
- *) Fix bug in *printf: outdigit precison bug
- a) Use locale decimal point in *printf() and strto*d() -- slightly
- complicated by the fact that at least one locale uses a wchar
- radix that does not map to a single byte in UTF-8.
- b) Use locale digit grouping in *printf() flosting point.
- c) Deal with mb format string issues in scanf and strftime (at least).
- d) Support gnu/bsd extension members tm_gmtoff and tm_zone in struct tm.
+ a) Fix the ctype support for 8-bit locales.
+ b) Fix bug in *printf: outdigit precison bug
+ c) Check that gnu/bsd extension members tm_gmtoff and tm_zone in struct tm
+ are respected where they should be.
+ d) Implement the obstack printf funcs for glibc compat.
+ e) Implement glibc 'a' flag for scanf string conversions.
+ f) Allow use of the older non-table-based ctype functions when using
+ stub locale support. (smaller)
- 2) Implement wide char floating point conversion functions -- wcsto*().
-
- 3) Reimplement scanf for narrow and wide streams.
- -------------------------------------------------
- The current char version of scanf() needs some cleanup. Also,
- modifying the char version of scanf() to create the wchar versions
- will require reworking the implementation of matching char sets
- (enclosed in []).
-
- 4) Additional str{f|p}time issues.
+ 2) Additional str{f|p}time issues.
----------------------------------
a) Spacing issue wrt strptime.
b) Support locale specific alternate digits. (data is in place)
c) Support locale era in year designations. (data is in place)
+ d) Deal with mb format string issues in strftime.
+ e) Implement wcsftime.
- 5) Other locale issues (my implementation):
+ 3) Other locale issues (my implementation):
-------------------------------------------
- a) Additional clean up of ctype and wctype, primarily to allow for mmap'd
- locales and updateable locale data.
- b) Build a C-only locale object for linking and allow full locale data to
- be mmap'd in later, to allow updating and to make locale support useful
- for staticly linked apps.
- c) Adapt regex lib to use my collation data and add the necessary collating
+ a) Do a little more clean up of ctype and wctype.
+ b) Rework of the locale data organization to make using locales reasonable
+ when staticly linking. (mmap)
+ c) Rewrite the locale data generation tools to process the text specifications
+ rather than relying on glibc.
+ d) Adapt regex lib to use my collation data and add the necessary collating
item tables to support SUSv3 required features.
- d) transliteration of unsupported wchars in 8-bit locales (like glibc).
- e) Support ISO/IEC 14652 draft locale extensions (LC_PAPER, etc).
+ e) transliteration of unsupported wchars in 8-bit locales (like glibc).
+ f) Support ISO/IEC 14652 draft locale extensions (LC_PAPER, etc).
+ g) Implement strfrom.
+ h) Shift-state codeset locale support?
Other stuff:
-Reimplement _dtostr to correct its deficiencies (%A support!) and hopefully
- reduce its size.
-
Move the target-specific sysconf.c generator to extra (as it needs to be
run on the target) and fix libc/unistd/Makefile.
-Make errno and endptr handling the default in the strto* functions and
- document how to turn those off to save space.
-
-----------------------------------------------------------------------------
ds's list:
diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in
index bbfbc854d..9de4a5e6f 100644
--- a/extra/Configs/Config.in
+++ b/extra/Configs/Config.in
@@ -298,12 +298,48 @@ endmenu
menu "String and Stdio Support"
+config UCLIBC_HAS_CTYPE_SIGNED
+ bool "Support Signed Characters In `ctype.h' Functions."
+ default y
+ help
+ Answer Y to enable support for passing signed char values to
+ the `ctype.h' functions. ANSI/ISO C99 and SUSv3 specify that
+ these functions are only defined for unsigned char values and
+ EOF. However, glibc allows negative signed char values as well
+ in order to support 'broken old programs'.
+
+ Most people will answer Y.
+
+choice
+ prompt "`ctype.h' Invalid Arg Behavior."
+ default UCLIBC_HAS_CTYPE_CHECKED
+ help
+ Please select the invalid arg behavior you want for the `ctype' functions.
+
+ The `ctype' functions are now implemented using table lookups, with
+ the arg being the index. This can result in incorrect memory accesses
+ or even segfaults for args outside of the allowed range.
+
+ NOTE: This only affects the `ctype' _functions_. It does not affect
+ the macro implementations.
+
+config UCLIBC_HAS_CTYPE_UNSAFE
+ bool "Do not check. (incorrect array access possible)"
+
+config UCLIBC_HAS_CTYPE_CHECKED
+ bool "Detect and handle appropriately."
+
+config UCLIBC_HAS_CTYPE_ENFORCED
+ bool "Issue a diagnostic and abort()."
+
+endchoice
+
config UCLIBC_HAS_WCHAR
bool "Wide Character Support"
default n
help
Answer Y to enable wide character support. This will make uClibc
- much larger.
+ much larger. It is also currently required for locale support.
Most people will answer N.
@@ -313,11 +349,67 @@ config UCLIBC_HAS_LOCALE
default n
help
Answer Y to enable locale support. This will make uClibc much
- bigger. uClibc's locale support is still under development, and
- should be finished in the next several weeks (November 2002).
+ bigger. uClibc's locale support is still under development.
Most people will wisely answer N.
+config UCLIBC_HAS_XLOCALE
+ bool "Extended Locale Support (experimental/incomplete)"
+ depends on UCLIBC_HAS_LOCALE
+ default n
+ help
+ Answer Y to enable extended locale support similar to that provided
+ by glibc. This is primarily intended to support libstd++ functionality.
+ However, it also allows thread-specific locale selection via uselocale().
+
+ Most people will answer N.
+
+config UCLIBC_HAS_SCANF_GLIBC_A_FLAG
+ bool "Support glibc's `a' flag for scanf string conversions"
+ default n
+ help
+ NOTE!!! Currently Not Implemented!!! Just A Place Holder!! NOTE!!!
+
+ Answer Y to enable support for glibc's `a' flag for the scanf string
+ conversions `%s', `%[', `%ls', `%l[`, and `%S'. This is used to
+ auto-allocate sufficient memory to hold the data retrieved.
+
+ Most people will answer N.
+
+config UCLIBC_HAS_HEXADECIMAL_FLOATS
+ bool "Support hexadecimal float notation"
+ default n
+ help
+ Answer Y to enable support for hexadecimal float notation in the
+ (wchar and) char string to floating point conversion functions, as
+ well as support for the %a and %A conversion specifiers in the
+ *printf() and *scanf() functions.
+
+ Most people will answer N.
+
+config UCLIBC_HAS_GLIBC_DIGIT_GROUPING
+ bool "Support glibc's `'' flag for allowing locale-specific digit grouping"
+ depends on UCLIBC_HAS_LOCALE
+ default n
+ help
+ Answer Y to enable support for glibc's `'' flag for allowing locale-specific
+ digit grouping in base 10 integer conversions and appropriate floating point
+ conversions in the *printf() and *scanf() functions.
+
+ Most people will answer N.
+
+config UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING
+ bool "Do not require digit grouping when the `'' flag is specified"
+ depends on UCLIBC_HAS_GLIBC_DIGIT_GROUPING
+ default y
+ help
+ Answer Y to make digit grouping optional when the `'' flag is specified.
+ This is the standard glibc behavior. If the initial string of digits
+ exceeds the maximum group number, the input will be treated as a normal
+ non-grouped number.
+
+ Most people will answer N.
+
config USE_OLD_VFPRINTF
bool "Use the old vfprintf implementation"
default n
@@ -332,6 +424,293 @@ config USE_OLD_VFPRINTF
Most people will answer N.
+config UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS
+ int "Maximum number of positional args. Either 0 or >= 9."
+ depends on !USE_OLD_VFPRINTF
+ default 9
+ help
+ Set the maximum number of positional args supported by the printf/scanf
+ functions. The Single Unix Specification Version 3 requires a minimum
+ value of 9. Setting this to a value lower than 9 will disable positional
+ arg support and cause the NL_ARGMAX macro in limits.h to be #undef'd.
+ WARNING! The workspace to support positional args is currently allocated
+ on the stack. You probably don't want to set this to too high a value.
+
+ Most people will answer 9.
+
+
+config UCLIBC_HAS_TZ_CACHING
+ bool "Enable caching of the last valid timezone `TZ' string"
+ default y
+ help
+ Answer Y to enable caching of the last valid `TZ' string describing
+ the timezone setting. This allows a quick string compare to avoid
+ repeated parsing of unchanged `TZ' strings when tzset() is called.
+
+ Most people will answer Y.
+
+config UCLIBC_HAS_TZ_FILE
+ bool "Enable `/etc/TZ' file support to set a default timezone (uClibc-specific)"
+ default y
+ help
+ Answer Y to enable the setting of a default timezone for uClibc.
+
+ Ordinarily, uClibc gets the timezone information exclusively from the
+ `TZ' environment variable. In particular, there is no support for
+ the zoneinfo directory tree or the /etc/timezone file used by glibc.
+
+ With this option enabled, uClibc will use the value stored in the
+ file `/etc/TZ' (default path) to obtain timezone information if the
+ `TZ' environment variable is missing or has an invalid value. The
+ file consists of a single line (newline required) of text describing
+ the timezone in the format specified for the TZ environment variable.
+
+ Simply doing `echo CST6CDT > /etc/TZ' is enough to create a valid file.
+ See
+ http://www.opengroup.org/onlinepubs/007904975/basedefs/xbd_chap08.html
+ for details on valid settings of `TZ'.
+
+ Most people will answer Y.
+
+config UCLIBC_TZ_FILE_PATH
+ string "Path to the `TZ' file for setting the global timezone"
+ depends on UCLIBC_HAS_TZ_FILE
+ default "/etc/TZ"
+ help
+ This is the path to the `TZ' file.
+
+ Most people will use the default of `/etc/TZ'.
+
+config UCLIBC_HAS_TZ_FILE_READ_MANY
+ bool "Repeatedly read the `/etc/TZ' file"
+ depends on UCLIBC_HAS_TZ_FILE
+ default y
+ help
+ Answer Y to enable repeated reading of the `/etc/TZ' file even after
+ a valid value has been read. This incurs the overhead of an open/read/close
+ for each tzset() call (explicit or implied). However, setting this
+ will allows applications to update their timezone information if the contents
+ of the file change.
+
+ Most people will answer Y.
+
+choice
+ prompt "Stdio buffer size"
+ default UCLIBC_HAS_STDIO_BUFSIZ_256
+ help
+ Please select a value for BUFSIZ. This will be used by the
+ stdio subsystem as the default buffer size for a file, and
+ affects fopen(), setvbuf(), etc.
+
+ NOTE: Setting this to `none' will disable buffering completely.
+ However, BUFSIZ will still be defined in stdio.h as 256 because
+ many applications use this value.
+
+config UCLIBC_HAS_STDIO_BUFSIZ_NONE
+ bool "none (WARNING - BUFSIZ will be 256 in stdio.h)"
+ depends !UCLIBC_HAS_WCHAR
+
+config UCLIBC_HAS_STDIO_BUFSIZ_256
+ bool "256 (minimum ANSI/ISO C99 value)"
+
+config UCLIBC_HAS_STDIO_BUFSIZ_512
+ bool "512"
+
+config UCLIBC_HAS_STDIO_BUFSIZ_1024
+ bool "1024"
+
+config UCLIBC_HAS_STDIO_BUFSIZ_2048
+ bool "2048"
+
+config UCLIBC_HAS_STDIO_BUFSIZ_4096
+ bool "4096"
+
+config UCLIBC_HAS_STDIO_BUFSIZ_8192
+ bool "8192"
+
+# If you add more choices, you will need to update uClibc_stdio.h.
+
+endchoice
+
+config UCLIBC_HAS_STDIO_GETC_MACRO
+ bool "Provide a macro version of getc()"
+ depends !UCLIBC_HAS_STDIO_BUFSIZ_NONE
+ default y
+ help
+ Provide a macro version of getc().
+
+ Most people will answer Y.
+
+config UCLIBC_HAS_STDIO_PUTC_MACRO
+ bool "Provide a macro version of putc()"
+ depends !UCLIBC_HAS_STDIO_BUFSIZ_NONE
+ default y
+ help
+ Provide a macro version of putc().
+
+ Most people will answer Y.
+
+config UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION
+ bool "Support auto-r/w transition"
+ default y
+ help
+ Answer Y to enable the stdio subsystem to automaticly transition
+ between reading and writing. This relaxes the ANSI/ISO C99 requirement:
+
+ When a file is opened with update mode ('+' as the second or third character
+ in the list of mode argument values), both input and output may be performed
+ on the associated stream. However, output shall not be directly followed by
+ input without an intervening call to the fflush function or to a file
+ positioning function (fseek, fsetpos, or rewind), and input shall not be
+ directly followed by output without an intervening call to a file positioning
+ function, unless the input operation encounters end­of­file.
+
+ Most people will answer Y.
+
+config UCLIBC_HAS_FOPEN_LARGEFILE_MODE
+ bool "Support an fopen() `F' flag for large file mode (uClibc-specific)"
+ depends on UCLIBC_HAS_LFS
+ default n
+ help
+ Answer Y to enable a uClibc-specific extension to allow passing an
+ additional `F' flag in the mode string for fopen() to specify that
+ the file should be open()ed with the O_LARGEFILE flag set.
+
+ Most people will answer N.
+
+config UCLIBC_HAS_FOPEN_EXCLUSIVE_MODE
+ bool "Support an fopen() `x' flag for exclusive mode (glibc-compat)"
+ default n
+ help
+ Answer Y to support a glibc extension to allow passing
+ additional `x' flag in the mode string for fopen() to specify that
+ the file should be open()ed with the O_EXCL flag set.
+
+ Most people will answer N.
+
+config UCLIBC_HAS_GLIBC_CUSTOM_STREAMS
+ bool "Support fmemopen(), open_memstream(), and fopencookie() (glibc-compat)"
+ default n
+ help
+ Answer Y to support the glibc `custom stream' extension functions
+ fmemopen(), open_memstream(), and fopencookie().
+
+ NOTE: There are some minor differences regarding seeking behavior.
+
+ Most people will answer N.
+
+choice
+ prompt "Stdio builtin buffer size (uClibc-specific)"
+ depends !UCLIBC_HAS_STDIO_BUFSIZ_NONE
+ default UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE
+ help
+ When a FILE is created with fopen(), an attempt is made to allocate
+ a BUFSIZ buffer for it. If the allocation fails, fopen() will still
+ succeed but the FILE will be unbuffered.
+
+ This option adds a small amount of space to each FILE to act as an
+ emergeny buffer in the event of a buffer allocation failure.
+
+ Most people will answer None.
+
+config UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE
+ bool "None"
+
+config UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4
+ bool "4"
+
+config UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8
+ bool "8"
+
+# If you add more choices, you will need to update uClibc_stdio.h.
+
+endchoice
+
+config UCLIBC_HAS_PRINTF_M_SPEC
+ bool "Support the `%m' specifier in printf format strings (glibc-compat)"
+ default n
+ help
+ Answer Y to support a glibc extension to interpret `%m' in printf
+ format strings as an instruction to output the error message string
+ (as generated by strerror) corresponding to the current value of `errno'.
+
+ Most people will answer N.
+
+config UCLIBC_HAS_GLIBC_CUSTOM_PRINTF
+ bool "Support glibc's register_printf_function() (glibc-compat)"
+ default n
+ help
+ Answer Y to support glibc's register_printf_function() to allow an
+ application to add its own printf conversion specifiers.
+
+ NOTE: This implementation limits the number or registered specifiers to 10.
+ NOTE: This implementation requires new conversion specifiers to be ASCII
+ characters (0-0x7f). This is to avoid problems with processing
+ format strings in locales with different multibyte conversions.
+
+ Most people will answer N.
+
+config UCLIBC_HAS_ERRNO_MESSAGES
+ bool "Include the errno message text in the library"
+ default y
+ help
+ Answer Y if you want to include the errno message text in the
+ library. This adds about 3K to the library, but enables strerror()
+ to generate text other than `Unknown error <number>'.
+
+ Most people will answer Y.
+
+config UCLIBC_HAS_SYS_ERRLIST
+ bool "Support sys_errlist[] (obsolete-compat)"
+ depends on UCLIBC_HAS_ERRNO_MESSAGES
+ default n
+ help
+ Answer Y if you want to support the obsolete sys_errlist[].
+ This adds about 0.5k to the library, except for the mips
+ arch where it adds over 4K.
+
+ WARNING! In the future, support for sys_errlist[] may be unavailable
+ in at least some configurations. In fact, it may be removed altogether.
+
+ Most people will answer N.
+
+config UCLIBC_HAS_SIGNUM_MESSAGES
+ bool "Include the signum message text in the library"
+ default y
+ help
+ Answer Y if you want to include the signum message text in the
+ library. This adds about 0.5K to the library, but enables strsignal()
+ to generate text other than `Unknown signal <number>'.
+
+ Most people will answer Y.
+
+config UCLIBC_HAS_SYS_SIGLIST
+ bool "Support sys_siglist[] (bsd-compat)"
+ depends on UCLIBC_HAS_SIGNUM_MESSAGES
+ default n
+ help
+ Answer Y if you want to support sys_siglist[].
+
+ WARNING! In the future, support for sys_siglist[] may be unavailable
+ in at least some configurations. In fact, it may be removed altogether.
+
+ Most people will answer N.
+
+config UCLIBC_HAS_GETTEXT_AWARENESS
+ bool "Include gettext awareness"
+ depends on UCLIBC_HAS_LOCALE
+ default n
+ help
+ NOTE!!! Not yet integrated with strerror and strsignal. NOTE!!!
+
+ Answer Y if you want to include weak stub gettext support and
+ make the *strerror*() and strsignal() functions gettext-aware.
+
+ Currently, to get functional gettext functionality you will need
+ to use gnu gettext.
+
+ Most people will answer N.
+
endmenu
menu "Library Installation Options"
@@ -482,4 +861,12 @@ config UCLIBC_MALLOC_DEBUGGING
the size of malloc appreciably (due to strings etc), you
should say N unless you need to debug a malloc problem.
+config UCLIBC_MJN3_ONLY
+ bool "Manuel's hidden warnings"
+ default n
+ help
+ Answer Y here to see all Manuel's personal notes, warnings, and todos.
+
+ Most people will answer N.
+
endmenu
diff --git a/extra/locale/Makefile b/extra/locale/Makefile
index 983c91c30..41438dadc 100644
--- a/extra/locale/Makefile
+++ b/extra/locale/Makefile
@@ -109,13 +109,17 @@ uClibc_locale_data.h: c8tables.h wctables.h lt_defines.h locale_mmap.h
links-target: locale_data.o uClibc_locale_data.h
ln -sf ../../../extra/locale/locale_data.o ../../libc/misc/locale
- cp uClibc_locale_data.h ../../libc/sysdeps/linux/common/bits/
+ cat uClibc_locale_data.h | awk 'BEGIN{i=1}{ if ( /WANT_/ ) i = /endif/ ; else if (i) print $0 }' > ../../include/bits/uClibc_locale_data.h
+
+# cp uClibc_locale_data.h ../../libc/sysdeps/linux/common/bits/
pregen:
$(CC) $(CFLAGS_mmap) -c locale_data.c
$(STRIPTOOL) -x -R .note -R .comment locale_data.o
ln -sf ../../../extra/locale/locale_data.o ../../libc/misc/locale
- cp uClibc_locale_data.h ../../libc/sysdeps/linux/common/bits/
+ cat uClibc_locale_data.h | awk 'BEGIN{i=1}{ if ( /WANT_/ ) i = /endif/ ; else if (i) print $0 }' > ../../include/bits/uClibc_locale_data.h
+
+# cp uClibc_locale_data.h ../../libc/sysdeps/linux/common/bits/
clean:
rm -f *.[oa] *~ core
diff --git a/extra/locale/gen_collate.c b/extra/locale/gen_collate.c
index 51b6b7383..7a524c8f7 100644
--- a/extra/locale/gen_collate.c
+++ b/extra/locale/gen_collate.c
@@ -1274,7 +1274,7 @@ static void error_msg(const char *fmt, ...)
static void pushfile(char *filename)
{
- static fbuf[PATH_MAX];
+ static char fbuf[PATH_MAX];
snprintf(fbuf, PATH_MAX, "collation/%s", filename);
@@ -2894,28 +2894,28 @@ static void finalize_base(void)
unsigned int u = 0xe40;
table_data *tbl = &table;
-#define WCctype_TI_MASK ((1 << tbl->ti_shift)-1)
-#define WCctype_TI_SHIFT (tbl->ti_shift)
-#define WCctype_TI_LEN (tbl->ti_len)
-#define WCctype_II_MASK ((1 << tbl->ii_shift)-1)
-#define WCctype_II_SHIFT (tbl->ii_shift)
-#define WCctype_II_LEN (tbl->ii_len)
+#define __LOCALE_DATA_WCctype_TI_MASK ((1 << tbl->ti_shift)-1)
+#define __LOCALE_DATA_WCctype_TI_SHIFT (tbl->ti_shift)
+#define __LOCALE_DATA_WCctype_TI_LEN (tbl->ti_len)
+#define __LOCALE_DATA_WCctype_II_MASK ((1 << tbl->ii_shift)-1)
+#define __LOCALE_DATA_WCctype_II_SHIFT (tbl->ii_shift)
+#define __LOCALE_DATA_WCctype_II_LEN (tbl->ii_len)
- sc = u & WCctype_TI_MASK;
- u >>= WCctype_TI_SHIFT;
- n = u & WCctype_II_MASK;
- u >>= WCctype_II_SHIFT;
+ sc = u & __LOCALE_DATA_WCctype_TI_MASK;
+ u >>= __LOCALE_DATA_WCctype_TI_SHIFT;
+ n = u & __LOCALE_DATA_WCctype_II_MASK;
+ u >>= __LOCALE_DATA_WCctype_II_SHIFT;
i0 = tbl->ii[u];
fprintf(stderr, "i0 = %d\n", i0);
- i0 <<= WCctype_II_SHIFT;
- i1 = tbl->ii[WCctype_II_LEN + i0 + n];
+ i0 <<= __LOCALE_DATA_WCctype_II_SHIFT;
+ i1 = tbl->ii[__LOCALE_DATA_WCctype_II_LEN + i0 + n];
/* i1 = tbl->ti[i0 + n]; */
fprintf(stderr, "i1 = %d\n", i1);
- i1 <<= WCctype_TI_SHIFT;
- /* return *(uint16_t *)(&(tbl->ii[WCctype_II_LEN + WCctype_TI_LEN + i1 + sc])); */
- fprintf(stderr, "i2 = %d\n", WCctype_II_LEN + WCctype_TI_LEN + i1 + sc);
- fprintf(stderr, "val = %d\n", tbl->ii[WCctype_II_LEN + WCctype_TI_LEN + i1 + sc]);
+ i1 <<= __LOCALE_DATA_WCctype_TI_SHIFT;
+ /* return *(uint16_t *)(&(tbl->ii[__LOCALE_DATA_WCctype_II_LEN + __LOCALE_DATA_WCctype_TI_LEN + i1 + sc])); */
+ fprintf(stderr, "i2 = %d\n", __LOCALE_DATA_WCctype_II_LEN + __LOCALE_DATA_WCctype_TI_LEN + i1 + sc);
+ fprintf(stderr, "val = %d\n", tbl->ii[__LOCALE_DATA_WCctype_II_LEN + __LOCALE_DATA_WCctype_TI_LEN + i1 + sc]);
/* return tbl->ut[i1 + sc]; */
diff --git a/extra/locale/gen_ldc.c b/extra/locale/gen_ldc.c
index 399587d96..3ffc90efe 100644
--- a/extra/locale/gen_ldc.c
+++ b/extra/locale/gen_ldc.c
@@ -17,10 +17,10 @@
/* #define __CTYPE_HAS_8_BIT_LOCALES */
#endif
-/* #define Cctype_TBL_LEN 328 */
-/* #define Cuplow_TBL_LEN 400 */
-/* #define Cc2wc_TBL_LEN 1448 */
-/* #define Cwc2c_TBL_LEN 3744 */
+/* #define __LOCALE_DATA_Cctype_TBL_LEN 328 */
+/* #define __LOCALE_DATA_Cuplow_TBL_LEN 400 */
+/* #define __LOCALE_DATA_Cc2wc_TBL_LEN 1448 */
+/* #define __LOCALE_DATA_Cwc2c_TBL_LEN 3744 */
#define WANT_WCctype_data
#define WANT_WCuplow_data
@@ -34,9 +34,9 @@
/* #undef WANT_WCcomb_data */
/* #undef WANT_WCwidth_data */
- #define WCctype_TBL_LEN (WCctype_II_LEN + WCctype_TI_LEN + WCctype_UT_LEN)
- #define WCuplow_TBL_LEN (WCuplow_II_LEN + WCuplow_TI_LEN + WCuplow_UT_LEN)
- #define WCuplow_diff_TBL_LEN (2 * WCuplow_diffs)
+ #define __LOCALE_DATA_WCctype_TBL_LEN (__LOCALE_DATA_WCctype_II_LEN + __LOCALE_DATA_WCctype_TI_LEN + __LOCALE_DATA_WCctype_UT_LEN)
+ #define __LOCALE_DATA_WCuplow_TBL_LEN (__LOCALE_DATA_WCuplow_II_LEN + __LOCALE_DATA_WCuplow_TI_LEN + __LOCALE_DATA_WCuplow_UT_LEN)
+ #define __LOCALE_DATA_WCuplow_diff_TBL_LEN (2 * __LOCALE_DATA_WCuplow_diffs)
/* #define WCcomb_TBL_LEN (WCcomb_II_LEN + WCcomb_TI_LEN + WCcomb_UT_LEN) */
#include "locale_collate.h"
@@ -50,7 +50,7 @@
/* #define __PASTE3(A,B,C) A ## B ## C */
-/* #define MAGIC_SIZE 64 */
+/* #define __LOCALE_DATA_MAGIC_SIZE 64 */
/* #define COMMON_MMAP(X) \ */
/* unsigned char __PASTE3(lc_,X,_data)[__PASTE3(__lc_,X,_data_LEN)]; */
@@ -69,7 +69,7 @@
offsetof(__locale_mmap_t, __PASTE3(lc_,X,_data)) \
-static const size_t common_tbl_offsets[CATEGORIES*4] = {
+static const size_t common_tbl_offsets[__LOCALE_DATA_CATEGORIES*4] = {
COMMON_OFFSETS(ctype),
COMMON_OFFSETS(numeric),
COMMON_OFFSETS(monetary),
@@ -152,9 +152,11 @@ int main(void)
{
FILE *lso; /* static object */
int i;
- unsigned char magic[MAGIC_SIZE];
+#ifdef __LOCALE_DATA_MAGIC_SIZE
+ unsigned char magic[__LOCALE_DATA_MAGIC_SIZE];
- memset(magic, 0, MAGIC_SIZE);
+ memset(magic, 0, __LOCALE_DATA_MAGIC_SIZE);
+#endif /* __LOCALE_DATA_MAGIC_SIZE */
if (!(lso = fopen("locale_data.c", "w"))) {
printf("can't open locale_data.c!\n");
@@ -174,20 +176,22 @@ int main(void)
"#include \"locale_mmap.h\"\n\n"
"static const __locale_mmap_t locale_mmap = {\n\n"
);
- out_uc(lso, magic, MAGIC_SIZE, "magic");
+#ifdef __LOCALE_DATA_MAGIC_SIZE
+ out_uc(lso, magic, __LOCALE_DATA_MAGIC_SIZE, "magic");
+#endif /* __LOCALE_DATA_MAGIC_SIZE */
#ifdef __CTYPE_HAS_8_BIT_LOCALES
- out_uc(lso, Cctype_data, Cctype_TBL_LEN, "tbl8ctype");
- out_uc(lso, Cuplow_data, Cuplow_TBL_LEN, "tbl8uplow");
+ out_uc(lso, __LOCALE_DATA_Cctype_data, __LOCALE_DATA_Cctype_TBL_LEN, "tbl8ctype");
+ out_uc(lso, __LOCALE_DATA_Cuplow_data, __LOCALE_DATA_Cuplow_TBL_LEN, "tbl8uplow");
#ifdef __WCHAR_ENABLED
- out_u16(lso, Cc2wc_data, Cc2wc_TBL_LEN, "tbl8c2wc");
- out_uc(lso, Cwc2c_data, Cwc2c_TBL_LEN, "tbl8wc2c");
+ out_u16(lso, __LOCALE_DATA_Cc2wc_data, __LOCALE_DATA_Cc2wc_TBL_LEN, "tbl8c2wc");
+ out_uc(lso, __LOCALE_DATA_Cwc2c_data, __LOCALE_DATA_Cwc2c_TBL_LEN, "tbl8wc2c");
/* translit */
#endif /* __WCHAR_ENABLED */
#endif /* __CTYPE_HAS_8_BIT_LOCALES */
#ifdef __WCHAR_ENABLED
- out_uc(lso, WCctype_data, WCctype_TBL_LEN, "tblwctype");
- out_uc(lso, WCuplow_data, WCuplow_TBL_LEN, "tblwuplow");
- out_i16(lso, WCuplow_diff_data, WCuplow_diff_TBL_LEN, "tblwuplow_diff");
+ out_uc(lso, __LOCALE_DATA_WCctype_data, __LOCALE_DATA_WCctype_TBL_LEN, "tblwctype");
+ out_uc(lso, __LOCALE_DATA_WCuplow_data, __LOCALE_DATA_WCuplow_TBL_LEN, "tblwuplow");
+ out_i16(lso, __LOCALE_DATA_WCuplow_diff_data, __LOCALE_DATA_WCuplow_diff_TBL_LEN, "tblwuplow_diff");
/* const unsigned char tblwcomb[WCcomb_TBL_LEN]; */
/* width?? */
#endif /* __WCHAR_ENABLED */
@@ -200,12 +204,12 @@ int main(void)
#ifdef __CTYPE_HAS_8_BIT_LOCALES
fprintf(lso, "{ /* codeset_8_bit array */\n");
- for (i = 0 ; i < NUM_CODESETS ; i++) {
+ for (i = 0 ; i < __LOCALE_DATA_NUM_CODESETS ; i++) {
fprintf(lso, "{ /* codeset_8_bit[%d] */\n", i);
- out_uc(lso, codeset_8_bit[i].idx8ctype, Cctype_IDX_LEN, "idx8ctype");
- out_uc(lso, codeset_8_bit[i].idx8uplow, Cuplow_IDX_LEN, "idx8uplow");
- out_uc(lso, codeset_8_bit[i].idx8c2wc, Cc2wc_IDX_LEN, "idx8c2wc");
- out_uc(lso, codeset_8_bit[i].idx8wc2c, Cwc2c_II_LEN, "idx8wc2c");
+ out_uc(lso, codeset_8_bit[i].idx8ctype, __LOCALE_DATA_Cctype_IDX_LEN, "idx8ctype");
+ out_uc(lso, codeset_8_bit[i].idx8uplow, __LOCALE_DATA_Cuplow_IDX_LEN, "idx8uplow");
+ out_uc(lso, codeset_8_bit[i].idx8c2wc, __LOCALE_DATA_Cc2wc_IDX_LEN, "idx8c2wc");
+ out_uc(lso, codeset_8_bit[i].idx8wc2c, __LOCALE_DATA_Cwc2c_II_LEN, "idx8wc2c");
fprintf(lso, "},\n");
}
fprintf(lso, "},\n");
@@ -237,7 +241,7 @@ int main(void)
{
- unsigned char co_buf[CATEGORIES] = {
+ unsigned char co_buf[__LOCALE_DATA_CATEGORIES] = {
__lc_ctype_item_offsets_LEN,
__lc_numeric_item_offsets_LEN,
__lc_monetary_item_offsets_LEN,
@@ -245,26 +249,26 @@ int main(void)
0,
__lc_messages_item_offsets_LEN
};
- out_uc(lso, co_buf, CATEGORIES, "lc_common_item_offsets_LEN");
+ out_uc(lso, co_buf, __LOCALE_DATA_CATEGORIES, "lc_common_item_offsets_LEN");
}
- out_size_t(lso, common_tbl_offsets, CATEGORIES * 4, "lc_common_tbl_offsets");
+ out_size_t(lso, common_tbl_offsets, __LOCALE_DATA_CATEGORIES * 4, "lc_common_tbl_offsets");
/* offsets from start of locale_mmap_t */
/* rows, item_offsets, item_idx, data */
-#ifdef NUM_LOCALES
- out_uc(lso, __locales, NUM_LOCALES * WIDTH_LOCALES, "locales");
- out_uc(lso, __locale_names5, 5 * NUM_LOCALE_NAMES, "locale_names5");
-#ifdef LOCALE_AT_MODIFIERS_LENGTH
- out_uc(lso, __locale_at_modifiers, LOCALE_AT_MODIFIERS_LENGTH, "locale_at_modifiers");
+#ifdef __LOCALE_DATA_NUM_LOCALES
+ out_uc(lso, __locales, __LOCALE_DATA_NUM_LOCALES * __LOCALE_DATA_WIDTH_LOCALES, "locales");
+ out_uc(lso, __locale_names5, 5 * __LOCALE_DATA_NUM_LOCALE_NAMES, "locale_names5");
+#ifdef __LOCALE_DATA_AT_MODIFIERS_LENGTH
+ out_uc(lso, __locale_at_modifiers, __LOCALE_DATA_AT_MODIFIERS_LENGTH, "locale_at_modifiers");
#else
-#error LOCALE_AT_MODIFIERS_LENGTH not defined!
-#endif /* LOCALE_AT_MODIFIERS_LENGTH */
-#endif /* NUM_LOCALES */
+#error __LOCALE_DATA_AT_MODIFIERS_LENGTH not defined!
+#endif /* __LOCALE_DATA_AT_MODIFIERS_LENGTH */
+#endif /* __LOCALE_DATA_NUM_LOCALES */
- out_uc(lso, lc_names, lc_names_LEN, "lc_names");
+ out_uc(lso, lc_names, __lc_names_LEN, "lc_names");
#ifdef __CTYPE_HAS_8_BIT_LOCALES
- out_uc(lso, (const unsigned char*) CODESET_LIST, sizeof(CODESET_LIST), "codeset_list");
+ out_uc(lso, (const unsigned char*) __LOCALE_DATA_CODESET_LIST, sizeof(__LOCALE_DATA_CODESET_LIST), "codeset_list");
#endif /* __CTYPE_HAS_8_BIT_LOCALES */
fprintf(lso,
diff --git a/extra/locale/gen_locale.c b/extra/locale/gen_locale.c
index 1d50480ee..388f543c5 100644
--- a/extra/locale/gen_locale.c
+++ b/extra/locale/gen_locale.c
@@ -13,7 +13,7 @@
#include "c8tables.h"
-#define CATEGORIES 6
+#define __LOCALE_DATA_CATEGORIES 6
/* must agree with ordering of gen_mmap! */
static const unsigned char *lc_names[] = {
@@ -23,15 +23,15 @@ static const unsigned char *lc_names[] = {
"LC_TIME",
"LC_COLLATE",
"LC_MESSAGES",
-#if CATEGORIES == 12
+#if __LOCALE_DATA_CATEGORIES == 12
"LC_PAPER",
"LC_NAME",
"LC_ADDRESS",
"LC_TELEPHONE",
"LC_MEASUREMENT",
"LC_IDENTIFICATION",
-#elif CATEGORIES != 6
-#error unsupported CATEGORIES value!
+#elif __LOCALE_DATA_CATEGORIES != 6
+#error unsupported __LOCALE_DATA_CATEGORIES value!
#endif
};
@@ -48,8 +48,8 @@ typedef struct {
unsigned char lc_monetary_row;
unsigned char lc_messages_row;
unsigned char lc_ctype_row;
-#if CATEGORIES != 6
-#error unsupported CATEGORIES value
+#if __LOCALE_DATA_CATEGORIES != 6
+#error unsupported __LOCALE_DATA_CATEGORIES value
#endif
} locale_entry;
@@ -99,17 +99,17 @@ static void do_locale_names(void)
if (num_locales <= 1) {
/* printf("error - only C locale?\n"); */
/* exit(EXIT_FAILURE); */
- fprintf(ofp, "static const unsigned char __locales[%d];\n", (3 + CATEGORIES));
+ fprintf(ofp, "static const unsigned char __locales[%d];\n", (3 + __LOCALE_DATA_CATEGORIES));
fprintf(ofp, "static const unsigned char __locale_names5[5];\n");
} else {
if (default_utf8) {
fprintf(ofp, "#define __CTYPE_HAS_UTF_8_LOCALES\t\t\t1\n");
}
- fprintf(ofp, "#define CATEGORIES\t\t\t%d\n", CATEGORIES);
- fprintf(ofp, "#define WIDTH_LOCALES\t\t\t%d\n", 3+CATEGORIES);
- fprintf(ofp, "#define NUM_LOCALES\t\t\t%d\n", num_locales);
+ fprintf(ofp, "#define __LOCALE_DATA_CATEGORIES\t\t\t%d\n", __LOCALE_DATA_CATEGORIES);
+ fprintf(ofp, "#define __LOCALE_DATA_WIDTH_LOCALES\t\t\t%d\n", 3+__LOCALE_DATA_CATEGORIES);
+ fprintf(ofp, "#define __LOCALE_DATA_NUM_LOCALES\t\t\t%d\n", num_locales);
fprintf(ofp, "static const unsigned char __locales[%d] = {\n",
- (num_locales) * (3 + CATEGORIES));
+ (num_locales) * (3 + __LOCALE_DATA_CATEGORIES));
for (i=0 ; i < num_locales ; i++) {
if (memcmp(locales[i].name, locales[i-1].name, 5) != 0) {
locales[i].idx_name = uniq;
@@ -143,7 +143,7 @@ static void do_locale_names(void)
}
fprintf(ofp, "};\n\n");
- fprintf(ofp, "#define NUM_LOCALE_NAMES\t\t%d\n", uniq );
+ fprintf(ofp, "#define __LOCALE_DATA_NUM_LOCALE_NAMES\t\t%d\n", uniq );
fprintf(ofp, "static const unsigned char __locale_names5[%d] = \n\t", uniq * 5);
uniq = 0;
for (i=1 ; i < num_locales ; i++) {
@@ -167,7 +167,7 @@ static void do_locale_names(void)
p += 1 + (unsigned char) *p;
}
/* len, char, string\0 */
- fprintf(ofp, "#define LOCALE_AT_MODIFIERS_LENGTH\t\t%d\n",
+ fprintf(ofp, "#define __LOCALE_DATA_AT_MODIFIERS_LENGTH\t\t%d\n",
i + (at_strings_end - at_strings));
fprintf(ofp, "static const unsigned char __locale_at_modifiers[%d] = {",
i + (at_strings_end - at_strings));
@@ -188,41 +188,41 @@ static void do_locale_names(void)
}
{
- int pos[CATEGORIES];
- pos[0] = CATEGORIES;
- for (i=0 ; i < CATEGORIES ; i++) {
+ int pos[__LOCALE_DATA_CATEGORIES];
+ pos[0] = __LOCALE_DATA_CATEGORIES;
+ for (i=0 ; i < __LOCALE_DATA_CATEGORIES ; i++) {
fprintf(ofp, "#define __%s\t\t%d\n", lc_names[i], i);
- if (i + 1 < CATEGORIES) {
+ if (i + 1 < __LOCALE_DATA_CATEGORIES) {
pos[i+1] = 1 + strlen(lc_names[i]) + pos[i];
}
}
- if (pos[CATEGORIES-1] > 255) {
- printf("error - lc_names is too big (%d)\n", pos[CATEGORIES-1]);
+ if (pos[__LOCALE_DATA_CATEGORIES-1] > 255) {
+ printf("error - lc_names is too big (%d)\n", pos[__LOCALE_DATA_CATEGORIES-1]);
exit(EXIT_FAILURE);
}
fprintf(ofp, "#define __LC_ALL\t\t%d\n\n", i);
- fprintf(ofp, "#define lc_names_LEN\t\t%d\n",
- pos[CATEGORIES-1] + strlen(lc_names[CATEGORIES-1]) + 1);
- total_size += pos[CATEGORIES-1] + strlen(lc_names[CATEGORIES-1]) + 1;
+ fprintf(ofp, "#define __lc_names_LEN\t\t%d\n",
+ pos[__LOCALE_DATA_CATEGORIES-1] + strlen(lc_names[__LOCALE_DATA_CATEGORIES-1]) + 1);
+ total_size += pos[__LOCALE_DATA_CATEGORIES-1] + strlen(lc_names[__LOCALE_DATA_CATEGORIES-1]) + 1;
fprintf(ofp, "static unsigned const char lc_names[%d] =\n",
- pos[CATEGORIES-1] + strlen(lc_names[CATEGORIES-1]) + 1);
+ pos[__LOCALE_DATA_CATEGORIES-1] + strlen(lc_names[__LOCALE_DATA_CATEGORIES-1]) + 1);
fprintf(ofp, "\t\"");
- for (i=0 ; i < CATEGORIES ; i++) {
+ for (i=0 ; i < __LOCALE_DATA_CATEGORIES ; i++) {
fprintf(ofp, "\\x%02x", (unsigned char) pos[i]);
}
fprintf(ofp, "\"");
- for (i=0 ; i < CATEGORIES ; i++) {
+ for (i=0 ; i < __LOCALE_DATA_CATEGORIES ; i++) {
fprintf(ofp, "\n\t\"%s\\0\"", lc_names[i]);
}
fprintf(ofp, ";\n\n");
}
printf("locale data = %d name data = %d for %d uniq\n",
- num_locales * (3 + CATEGORIES), uniq * 5, uniq);
+ num_locales * (3 + __LOCALE_DATA_CATEGORIES), uniq * 5, uniq);
- total_size += num_locales * (3 + CATEGORIES) + uniq * 5;
+ total_size += num_locales * (3 + __LOCALE_DATA_CATEGORIES) + uniq * 5;
}
}
@@ -343,19 +343,19 @@ static void read_enable_disable(void)
} while (1);
}
-#ifdef CODESET_LIST
+#ifdef __LOCALE_DATA_CODESET_LIST
static int find_codeset_num(const char *cs)
{
int r = 2;
- char *s = CODESET_LIST;
+ char *s = __LOCALE_DATA_CODESET_LIST;
/* 7-bit is 1, UTF-8 is 2, 8-bits are > 2 */
if (strcmp(cs, "UTF-8") != 0) {
++r;
- while (*s && strcmp(CODESET_LIST+ ((unsigned char) *s), cs)) {
-/* printf("tried %s\n", CODESET_LIST + ((unsigned char) *s)); */
+ while (*s && strcmp(__LOCALE_DATA_CODESET_LIST+ ((unsigned char) *s), cs)) {
+/* printf("tried %s\n", __LOCALE_DATA_CODESET_LIST + ((unsigned char) *s)); */
++r;
++s;
}
diff --git a/extra/locale/gen_wc8bit.c b/extra/locale/gen_wc8bit.c
index 0c39d0f12..75054667a 100644
--- a/extra/locale/gen_wc8bit.c
+++ b/extra/locale/gen_wc8bit.c
@@ -111,8 +111,8 @@ int main(int argc, char **argv)
fprintf(out, "#endif\n");
fprintf(out, "#undef __CTYPE_HAS_8_BIT_LOCALES\n\n");
- fprintf(out, "#define NUM_CODESETS\t\t0\n");
- fprintf(out, "#define CODESET_LIST\t\t\"\"\n");
+ fprintf(out, "#define __LOCALE_DATA_NUM_CODESETS\t\t0\n");
+ fprintf(out, "#define __LOCALE_DATA_CODESET_LIST\t\t\"\"\n");
fclose(out);
return EXIT_SUCCESS;
}
@@ -124,30 +124,30 @@ int main(int argc, char **argv)
if (argc == 1) {
fprintf(out, "#undef __CTYPE_HAS_8_BIT_LOCALES\n\n");
- fprintf(out, "#define NUM_CODESETS\t\t0\n");
- fprintf(out, "#define CODESET_LIST\t\t\"\"\n");
+ fprintf(out, "#define __LOCALE_DATA_NUM_CODESETS\t\t0\n");
+ fprintf(out, "#define __LOCALE_DATA_CODESET_LIST\t\t\"\"\n");
} else {
fprintf(out, "#define __CTYPE_HAS_8_BIT_LOCALES\t\t1\n\n");
}
- fprintf(out, "#define Cctype_IDX_SHIFT\t%d\n", CTYPE_IDX_SHIFT);
- fprintf(out, "#define Cctype_IDX_LEN\t\t%d\n", CTYPE_IDX_LEN);
+ fprintf(out, "#define __LOCALE_DATA_Cctype_IDX_SHIFT\t%d\n", CTYPE_IDX_SHIFT);
+ fprintf(out, "#define __LOCALE_DATA_Cctype_IDX_LEN\t\t%d\n", CTYPE_IDX_LEN);
#ifdef CTYPE_PACKED
- fprintf(out, "#define Cctype_ROW_LEN\t\t%d\n", CTYPE_ROW_LEN >> 1);
- fprintf(out, "#define Cctype_PACKED\t\t1\n");
+ fprintf(out, "#define __LOCALE_DATA_Cctype_ROW_LEN\t\t%d\n", CTYPE_ROW_LEN >> 1);
+ fprintf(out, "#define __LOCALE_DATA_Cctype_PACKED\t\t1\n");
#else
- fprintf(out, "#define Cctype_ROW_LEN\t\t%d\n", CTYPE_ROW_LEN);
- fprintf(out, "#undef Cctype_PACKED\n");
+ fprintf(out, "#define __LOCALE_DATA_Cctype_ROW_LEN\t\t%d\n", CTYPE_ROW_LEN);
+ fprintf(out, "#undef __LOCALE_DATA_Cctype_PACKED\n");
#endif
- fprintf(out, "\n#define Cuplow_IDX_SHIFT\t%d\n", UPLOW_IDX_SHIFT);
- fprintf(out, "#define Cuplow_IDX_LEN\t\t%d\n", UPLOW_IDX_LEN);
- fprintf(out, "#define Cuplow_ROW_LEN\t\t%d\n", UPLOW_ROW_LEN);
+ fprintf(out, "\n#define __LOCALE_DATA_Cuplow_IDX_SHIFT\t%d\n", UPLOW_IDX_SHIFT);
+ fprintf(out, "#define __LOCALE_DATA_Cuplow_IDX_LEN\t\t%d\n", UPLOW_IDX_LEN);
+ fprintf(out, "#define __LOCALE_DATA_Cuplow_ROW_LEN\t\t%d\n", UPLOW_ROW_LEN);
#ifdef DO_WIDE_CHAR
- fprintf(out, "\n#define Cc2wc_IDX_LEN\t\t%d\n", C2WC_IDX_LEN);
- fprintf(out, "#define Cc2wc_IDX_SHIFT\t\t%d\n", C2WC_IDX_SHIFT);
- fprintf(out, "#define Cc2wc_ROW_LEN\t\t%d\n", C2WC_ROW_LEN);
+ fprintf(out, "\n#define __LOCALE_DATA_Cc2wc_IDX_LEN\t\t%d\n", C2WC_IDX_LEN);
+ fprintf(out, "#define __LOCALE_DATA_Cc2wc_IDX_SHIFT\t\t%d\n", C2WC_IDX_SHIFT);
+ fprintf(out, "#define __LOCALE_DATA_Cc2wc_ROW_LEN\t\t%d\n", C2WC_ROW_LEN);
#endif
fprintf(out, "\ntypedef struct {\n");
@@ -157,10 +157,10 @@ int main(int argc, char **argv)
fprintf(out, "\tunsigned char idx8c2wc[%d];\n", C2WC_IDX_LEN);
fprintf(out, "\tunsigned char idx8wc2c[%d];\n", II_LEN);
#endif
- fprintf(out, "} codeset_8_bit_t;\n\n");
+ fprintf(out, "} __codeset_8_bit_t;\n\n");
fprintf(out, "#ifdef WANT_DATA\n\n");
- fprintf(out, "static const codeset_8_bit_t codeset_8_bit[%d] = {\n", argc-1);
+ fprintf(out, "static const __codeset_8_bit_t codeset_8_bit[%d] = {\n", argc-1);
max_wchar = 0x7f;
numsets = 0;
@@ -514,19 +514,19 @@ int main(int argc, char **argv)
#ifdef DO_WIDE_CHAR
fprintf(out, "\n");
- fprintf(out, "#define Cwc2c_DOMAIN_MAX\t%#x\n", RANGE);
- fprintf(out, "#define Cwc2c_TI_SHIFT\t\t%d\n", TI_SHIFT);
- fprintf(out, "#define Cwc2c_TT_SHIFT\t\t%d\n", TT_SHIFT);
- fprintf(out, "#define Cwc2c_II_LEN\t\t%d\n", II_LEN);
- fprintf(out, "#define Cwc2c_TI_LEN\t\t%d\n", ti_num << TI_SHIFT);
- fprintf(out, "#define Cwc2c_TT_LEN\t\t%d\n", tt_num << TT_SHIFT);
+ fprintf(out, "#define __LOCALE_DATA_Cwc2c_DOMAIN_MAX\t%#x\n", RANGE);
+ fprintf(out, "#define __LOCALE_DATA_Cwc2c_TI_SHIFT\t\t%d\n", TI_SHIFT);
+ fprintf(out, "#define __LOCALE_DATA_Cwc2c_TT_SHIFT\t\t%d\n", TT_SHIFT);
+ fprintf(out, "#define __LOCALE_DATA_Cwc2c_II_LEN\t\t%d\n", II_LEN);
+ fprintf(out, "#define __LOCALE_DATA_Cwc2c_TI_LEN\t\t%d\n", ti_num << TI_SHIFT);
+ fprintf(out, "#define __LOCALE_DATA_Cwc2c_TT_LEN\t\t%d\n", tt_num << TT_SHIFT);
fprintf(out, "\n");
- fprintf(out, "\n#define Cwc2c_TBL_LEN\t\t%d\n",
+ fprintf(out, "\n#define __LOCALE_DATA_Cwc2c_TBL_LEN\t\t%d\n",
(ti_num << TI_SHIFT) + (tt_num << TT_SHIFT));
fprintf(out, "#ifdef WANT_DATA\n\n");
- fprintf(out, "static const unsigned char Cwc2c_data[%d] = {\n",
+ fprintf(out, "static const unsigned char __LOCALE_DATA_Cwc2c_data[%d] = {\n",
(ti_num << TI_SHIFT) + (tt_num << TT_SHIFT));
fprintf(out, "\t/* ti_table */\n\t");
for (i=0 ; i < ti_num << TI_SHIFT ; i++) {
@@ -548,11 +548,11 @@ int main(int argc, char **argv)
fprintf(out, "\n#endif /* WANT_DATA */\n");
#endif /* DO_WIDE_CHAR */
- fprintf(out, "\n#define Cuplow_TBL_LEN\t\t%d\n",
+ fprintf(out, "\n#define __LOCALE_DATA_Cuplow_TBL_LEN\t\t%d\n",
n_uplow_rows * UPLOW_ROW_LEN);
fprintf(out, "\n#ifdef WANT_DATA\n\n");
- fprintf(out, "\nstatic const unsigned char Cuplow_data[%d] = {\n",
+ fprintf(out, "\nstatic const unsigned char __LOCALE_DATA_Cuplow_data[%d] = {\n",
n_uplow_rows * UPLOW_ROW_LEN);
p = uplow_tbl;
for (j=0 ; j < n_uplow_rows ; j++) {
@@ -566,7 +566,7 @@ int main(int argc, char **argv)
fprintf(out, "};\n");
fprintf(out, "\n#endif /* WANT_DATA */\n");
- fprintf(out, "\n#define Cctype_TBL_LEN\t\t%d\n",
+ fprintf(out, "\n#define __LOCALE_DATA_Cctype_TBL_LEN\t\t%d\n",
#ifdef CTYPE_PACKED
n_ctype_rows * CTYPE_ROW_LEN / 2
#else
@@ -576,7 +576,7 @@ int main(int argc, char **argv)
fprintf(out, "\n#ifdef WANT_DATA\n\n");
- fprintf(out, "\nstatic const unsigned char Cctype_data[%d] = {\n",
+ fprintf(out, "\nstatic const unsigned char __LOCALE_DATA_Cctype_data[%d] = {\n",
#ifdef CTYPE_PACKED
n_ctype_rows * CTYPE_ROW_LEN / 2
#else
@@ -603,11 +603,11 @@ int main(int argc, char **argv)
#ifdef DO_WIDE_CHAR
- fprintf(out, "\n#define Cc2wc_TBL_LEN\t\t%d\n",
+ fprintf(out, "\n#define __LOCALE_DATA_Cc2wc_TBL_LEN\t\t%d\n",
n_c2wc_rows * C2WC_ROW_LEN);
fprintf(out, "\n#ifdef WANT_DATA\n\n");
- fprintf(out, "\nstatic const unsigned short Cc2wc_data[%d] = {\n",
+ fprintf(out, "\nstatic const unsigned short __LOCALE_DATA_Cc2wc_data[%d] = {\n",
n_c2wc_rows * C2WC_ROW_LEN);
p = (char *) c2wc_tbl;
for (j=0 ; j < n_c2wc_rows ; j++) {
@@ -623,8 +623,8 @@ int main(int argc, char **argv)
#endif /* DO_WIDE_CHAR */
fprintf(out, "\n\n");
- fprintf(out, "#define NUM_CODESETS\t\t%d\n", numsets);
- fprintf(out, "#define CODESET_LIST \\\n\t\"");
+ fprintf(out, "#define __LOCALE_DATA_NUM_CODESETS\t\t%d\n", numsets);
+ fprintf(out, "#define __LOCALE_DATA_CODESET_LIST \\\n\t\"");
for (i=0 ; i < numsets ; i++) {
fprintf(out, "\\x%02x", numsets + 1 + (unsigned char) codeset_index[i]);
if (((i & 7) == 7) && (i + 1 < numsets)) {
diff --git a/extra/locale/gen_wctype.c b/extra/locale/gen_wctype.c
index 1c8c10c43..a9bcf614b 100644
--- a/extra/locale/gen_wctype.c
+++ b/extra/locale/gen_wctype.c
@@ -159,17 +159,17 @@ void output_table(FILE *fp, const char *name, table_data *tbl)
{
size_t i;
- fprintf(fp, "#define WC%s_II_LEN %7u\n", name, tbl->ii_len);
- fprintf(fp, "#define WC%s_TI_LEN %7u\n", name, tbl->ti_len);
- fprintf(fp, "#define WC%s_UT_LEN %7u\n", name, tbl->ut_len);
+ fprintf(fp, "#define __LOCALE_DATA_WC%s_II_LEN %7u\n", name, tbl->ii_len);
+ fprintf(fp, "#define __LOCALE_DATA_WC%s_TI_LEN %7u\n", name, tbl->ti_len);
+ fprintf(fp, "#define __LOCALE_DATA_WC%s_UT_LEN %7u\n", name, tbl->ut_len);
- fprintf(fp, "#define WC%s_II_SHIFT %7u\n", name, tbl->ii_shift);
- fprintf(fp, "#define WC%s_TI_SHIFT %7u\n", name, tbl->ti_shift);
+ fprintf(fp, "#define __LOCALE_DATA_WC%s_II_SHIFT %7u\n", name, tbl->ii_shift);
+ fprintf(fp, "#define __LOCALE_DATA_WC%s_TI_SHIFT %7u\n", name, tbl->ti_shift);
fprintf(fp, "\n#ifdef WANT_WC%s_data\n", name);
i = tbl->ii_len + tbl->ti_len + tbl->ut_len;
- fprintf(fp, "\nstatic const unsigned char WC%s_data[%zu] = {", name, i);
+ fprintf(fp, "\nstatic const unsigned char __LOCALE_DATA_WC%s_data[%zu] = {", name, i);
for (i=0 ; i < tbl->ii_len ; i++) {
if (i % 12 == 0) {
fprintf(fp, "\n");
@@ -730,16 +730,16 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
- fprintf(fp, "#define WC_TABLE_DOMAIN_MAX %#8lx\n\n",
+ fprintf(fp, "#define __LOCALE_DATA_WC_TABLE_DOMAIN_MAX %#8lx\n\n",
(unsigned long) RANGE);
output_table(fp, "ctype", &cttable);
output_table(fp, "uplow", &ultable);
#warning fix the upper bound on the upper/lower tables... save 200 bytes or so
- fprintf(fp, "#define WCuplow_diffs %7u\n", ul_count);
+ fprintf(fp, "#define __LOCALE_DATA_WCuplow_diffs %7u\n", ul_count);
fprintf(fp, "\n#ifdef WANT_WCuplow_diff_data\n\n");
- fprintf(fp, "\nstatic const short WCuplow_diff_data[%zu] = {",
+ fprintf(fp, "\nstatic const short __LOCALE_DATA_WCuplow_diff_data[%zu] = {",
2 * (size_t) ul_count);
for (i=0 ; i < ul_count ; i++) {
if (i % 4 == 0) {
diff --git a/extra/locale/locale_mmap.h b/extra/locale/locale_mmap.h
index 12c4025e1..1b748239b 100644
--- a/extra/locale/locale_mmap.h
+++ b/extra/locale/locale_mmap.h
@@ -1,13 +1,16 @@
-/* #include "lt_defines.h" */
-
-/* TODO - fix */
-#define MAGIC_SIZE 64
+/* #define __LOCALE_DATA_MAGIC_SIZE 64 */
+#ifndef __WCHAR_ENABLED
+#if 0
+#warning WHOA!!! __WCHAR_ENABLED is not defined! defining it now...
+#endif
+#define __WCHAR_ENABLED
+#endif
/* TODO - fix */
#ifdef __WCHAR_ENABLED
-#define WCctype_TBL_LEN (WCctype_II_LEN + WCctype_TI_LEN + WCctype_UT_LEN)
-#define WCuplow_TBL_LEN (WCuplow_II_LEN + WCuplow_TI_LEN + WCuplow_UT_LEN)
-#define WCuplow_diff_TBL_LEN (2 * WCuplow_diffs)
+#define __LOCALE_DATA_WCctype_TBL_LEN (__LOCALE_DATA_WCctype_II_LEN + __LOCALE_DATA_WCctype_TI_LEN + __LOCALE_DATA_WCctype_UT_LEN)
+#define __LOCALE_DATA_WCuplow_TBL_LEN (__LOCALE_DATA_WCuplow_II_LEN + __LOCALE_DATA_WCuplow_TI_LEN + __LOCALE_DATA_WCuplow_UT_LEN)
+#define __LOCALE_DATA_WCuplow_diff_TBL_LEN (2 * __LOCALE_DATA_WCuplow_diffs)
/* #define WCcomb_TBL_LEN (WCcomb_II_LEN + WCcomb_TI_LEN + WCcomb_UT_LEN) */
#endif
@@ -16,70 +19,72 @@
#undef __PASTE3
#define __PASTE3(A,B,C) A ## B ## C
-#define COMMON_MMAP(X) \
+#define __LOCALE_DATA_COMMON_MMAP(X) \
unsigned char __PASTE3(lc_,X,_data)[__PASTE3(__lc_,X,_data_LEN)];
-#define COMMON_MMIDX(X) \
+#define __LOCALE_DATA_COMMON_MMIDX(X) \
unsigned char __PASTE3(lc_,X,_rows)[__PASTE3(__lc_,X,_rows_LEN)]; \
uint16_t __PASTE3(lc_,X,_item_offsets)[__PASTE3(__lc_,X,_item_offsets_LEN)]; \
uint16_t __PASTE3(lc_,X,_item_idx)[__PASTE3(__lc_,X,_item_idx_LEN)]; \
typedef struct {
- unsigned char magic[MAGIC_SIZE];
+#ifdef __LOCALE_DATA_MAGIC_SIZE
+ unsigned char magic[__LOCALE_DATA_MAGIC_SIZE];
+#endif /* __LOCALE_DATA_MAGIC_SIZE */
#ifdef __CTYPE_HAS_8_BIT_LOCALES
- const unsigned char tbl8ctype[Cctype_TBL_LEN];
- const unsigned char tbl8uplow[Cuplow_TBL_LEN];
+ const unsigned char tbl8ctype[__LOCALE_DATA_Cctype_TBL_LEN];
+ const unsigned char tbl8uplow[__LOCALE_DATA_Cuplow_TBL_LEN];
#ifdef __WCHAR_ENABLED
- const uint16_t tbl8c2wc[Cc2wc_TBL_LEN]; /* char > 0x7f to wide char */
- const unsigned char tbl8wc2c[Cwc2c_TBL_LEN];
+ const uint16_t tbl8c2wc[__LOCALE_DATA_Cc2wc_TBL_LEN]; /* char > 0x7f to wide char */
+ const unsigned char tbl8wc2c[__LOCALE_DATA_Cwc2c_TBL_LEN];
/* translit */
#endif /* __WCHAR_ENABLED */
#endif /* __CTYPE_HAS_8_BIT_LOCALES */
#ifdef __WCHAR_ENABLED
- const unsigned char tblwctype[WCctype_TBL_LEN];
- const unsigned char tblwuplow[WCuplow_TBL_LEN];
- const int16_t tblwuplow_diff[WCuplow_diff_TBL_LEN];
+ const unsigned char tblwctype[__LOCALE_DATA_WCctype_TBL_LEN];
+ const unsigned char tblwuplow[__LOCALE_DATA_WCuplow_TBL_LEN];
+ const int16_t tblwuplow_diff[__LOCALE_DATA_WCuplow_diff_TBL_LEN];
/* const unsigned char tblwcomb[WCcomb_TBL_LEN]; */
/* width?? */
#endif /* __WCHAR_ENABLED */
- COMMON_MMAP(ctype);
- COMMON_MMAP(numeric);
- COMMON_MMAP(monetary);
- COMMON_MMAP(time);
+ __LOCALE_DATA_COMMON_MMAP(ctype);
+ __LOCALE_DATA_COMMON_MMAP(numeric);
+ __LOCALE_DATA_COMMON_MMAP(monetary);
+ __LOCALE_DATA_COMMON_MMAP(time);
/* collate is different */
- COMMON_MMAP(messages);
+ __LOCALE_DATA_COMMON_MMAP(messages);
#ifdef __CTYPE_HAS_8_BIT_LOCALES
- const codeset_8_bit_t codeset_8_bit[NUM_CODESETS];
+ const __codeset_8_bit_t codeset_8_bit[__LOCALE_DATA_NUM_CODESETS];
#endif /* __CTYPE_HAS_8_BIT_LOCALES */
- COMMON_MMIDX(ctype);
- COMMON_MMIDX(numeric);
- COMMON_MMIDX(monetary);
- COMMON_MMIDX(time);
+ __LOCALE_DATA_COMMON_MMIDX(ctype);
+ __LOCALE_DATA_COMMON_MMIDX(numeric);
+ __LOCALE_DATA_COMMON_MMIDX(monetary);
+ __LOCALE_DATA_COMMON_MMIDX(time);
/* collate is different */
- COMMON_MMIDX(messages);
+ __LOCALE_DATA_COMMON_MMIDX(messages);
const uint16_t collate_data[__lc_collate_data_LEN];
- unsigned char lc_common_item_offsets_LEN[CATEGORIES];
- size_t lc_common_tbl_offsets[CATEGORIES * 4];
+ unsigned char lc_common_item_offsets_LEN[__LOCALE_DATA_CATEGORIES];
+ size_t lc_common_tbl_offsets[__LOCALE_DATA_CATEGORIES * 4];
/* offsets from start of locale_mmap_t */
/* rows, item_offsets, item_idx, data */
-#ifdef NUM_LOCALES
- unsigned char locales[NUM_LOCALES * WIDTH_LOCALES];
- unsigned char locale_names5[5*NUM_LOCALE_NAMES];
- unsigned char locale_at_modifiers[LOCALE_AT_MODIFIERS_LENGTH];
-#endif /* NUM_LOCALES */
+#ifdef __LOCALE_DATA_NUM_LOCALES
+ unsigned char locales[__LOCALE_DATA_NUM_LOCALES * __LOCALE_DATA_WIDTH_LOCALES];
+ unsigned char locale_names5[5*__LOCALE_DATA_NUM_LOCALE_NAMES];
+ unsigned char locale_at_modifiers[__LOCALE_DATA_AT_MODIFIERS_LENGTH];
+#endif /* __LOCALE_DATA_NUM_LOCALES */
- unsigned char lc_names[lc_names_LEN];
+ unsigned char lc_names[__lc_names_LEN];
#ifdef __CTYPE_HAS_8_BIT_LOCALES
- unsigned char codeset_list[sizeof(CODESET_LIST)]; /* TODO - fix */
+ unsigned char codeset_list[sizeof(__LOCALE_DATA_CODESET_LIST)]; /* TODO - fix */
#endif /* __CTYPE_HAS_8_BIT_LOCALES */
diff --git a/include/ctype.h b/include/ctype.h
index c6faf3d9b..23ff199e4 100644
--- a/include/ctype.h
+++ b/include/ctype.h
@@ -1,129 +1,382 @@
-/* Copyright (C) 2002 Manuel Novoa III
+/* Copyright (C) 1991,92,93,95,96,97,98,99,2001,02
+ Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/*
+ * ISO C99 Standard 7.4: Character handling <ctype.h>
+ */
+
+#ifndef _CTYPE_H
+#define _CTYPE_H 1
+
+#include <features.h>
+#include <bits/types.h>
+
+__BEGIN_DECLS
+
+#ifndef _ISbit
+/* These are all the characteristics of characters.
+ If there get to be more than 16 distinct characteristics,
+ many things must be changed that use `__uint16_t's. */
+
+# define _ISbit(bit) (1 << (bit))
+
+enum
+{
+ _ISupper = _ISbit (0), /* UPPERCASE. */
+ _ISlower = _ISbit (1), /* lowercase. */
+ _ISalpha = _ISbit (2), /* Alphabetic. */
+ _ISdigit = _ISbit (3), /* Numeric. */
+ _ISxdigit = _ISbit (4), /* Hexadecimal numeric. */
+ _ISspace = _ISbit (5), /* Whitespace. */
+ _ISprint = _ISbit (6), /* Printing. */
+ _ISgraph = _ISbit (7), /* Graphical. */
+ _ISblank = _ISbit (8), /* Blank (usually SPC and TAB). */
+ _IScntrl = _ISbit (9), /* Control character. */
+ _ISpunct = _ISbit (10), /* Punctuation. */
+ _ISalnum = _ISbit (11) /* Alphanumeric. */
+};
+#else
+#error _ISbit already defined!
+#endif /* ! _ISbit */
+
+#include <bits/uClibc_touplow.h>
+
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+# define __UCLIBC_CTYPE_IN_TO_DOMAIN(c) (((unsigned int)((c) + 128)) < 384)
+
+#else /* __UCLIBC_HAS_CTYPE_SIGNED__ */
+# define __UCLIBC_CTYPE_IN_TO_DOMAIN(c) (((unsigned int)(c)) < 256)
+
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__ */
+
+/* In the thread-specific locale model (see `uselocale' in <locale.h>)
+ we cannot use global variables for these as was done in the past.
+ Instead, the following accessor functions return the address of
+ each variable, which is local to the current thread if multithreaded.
+
+ These point into arrays of 384, so they can be indexed by any `unsigned
+ char' value [0,255]; by EOF (-1); or by any `signed char' value
+ [-128,-1). ISO C requires that the ctype functions work for `unsigned
+ char' values and for EOF; we also support negative `signed char' values
+ for broken old programs. The case conversion arrays are of `int's
+ rather than `unsigned char's because tolower (EOF) must be EOF, which
+ doesn't fit into an `unsigned char'. But today more important is that
+ the arrays are also used for multi-byte character sets. */
+
+/* uClibc differences:
+ *
+ * When __UCLIBC_HAS_CTYPE_SIGNED is defined,
*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
+ * The upper and lower mapping arrays are type int16_t, so that
+ * they may store all char values plus EOF. The glibc reasoning
+ * given above for these being type int is questionable, as the
+ * ctype mapping functions map from the set of (unsigned) char
+ * and EOF back into the set. They have no awareness of multi-byte
+ * or wide characters.
*
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
+ * Otherwise,
*
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * The ctype array is defined for -1..255.
+ * The upper and lower mapping arrays are defined for 0..255.
+ * The upper and lower mapping arrays are type unsigned char.
*/
-/* NOTE: It is assumed here and throughout the library that the underlying
- * char encoding for the portable C character set is ASCII (host & target). */
+/* Pointers to the default C-locale data. */
+extern const __uint16_t *__C_ctype_b;
+extern const __ctype_touplow_t *__C_ctype_toupper;
+extern const __ctype_touplow_t *__C_ctype_tolower;
-#ifndef _CTYPE_H
-#define _CTYPE_H
+#ifdef __UCLIBC_HAS_XLOCALE__
-#include <features.h>
-#include <bits/uClibc_ctype.h>
+extern __const __uint16_t **__ctype_b_loc (void)
+ __attribute__ ((__const));
+extern __const __ctype_touplow_t **__ctype_tolower_loc (void)
+ __attribute__ ((__const));
+extern __const __ctype_touplow_t **__ctype_toupper_loc (void)
+ __attribute__ ((__const));
-__BEGIN_DECLS
+#define __UCLIBC_CTYPE_B (*__ctype_b_loc())
+#define __UCLIBC_CTYPE_TOLOWER (*__ctype_tolower_loc())
+#define __UCLIBC_CTYPE_TOUPPER (*__ctype_toupper_loc())
-extern int isalnum(int c) __THROW;
-extern int isalpha(int c) __THROW;
-#ifdef __USE_ISOC99
-extern int isblank(int c) __THROW;
-#endif
-extern int iscntrl(int c) __THROW;
-extern int isdigit(int c) __THROW;
-extern int isgraph(int c) __THROW;
-extern int islower(int c) __THROW;
-extern int isprint(int c) __THROW;
-extern int ispunct(int c) __THROW;
-extern int isspace(int c) __THROW;
-extern int isupper(int c) __THROW;
-extern int isxdigit(int c) __THROW;
-
-extern int tolower(int c) __THROW;
-extern int toupper(int c) __THROW;
+#else /* __UCLIBC_HAS_XLOCALE__ */
-#if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
-extern int isascii(int c) __THROW;
-extern int toascii(int c) __THROW;
-#endif
+/* Pointers to the current global locale data in use. */
+extern const __uint16_t *__ctype_b;
+extern const __ctype_touplow_t *__ctype_toupper;
+extern const __ctype_touplow_t *__ctype_tolower;
+
+#define __UCLIBC_CTYPE_B (__ctype_b)
+#define __UCLIBC_CTYPE_TOLOWER (__ctype_tolower)
+#define __UCLIBC_CTYPE_TOUPPER (__ctype_toupper)
+
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+#define __isctype(c, type) \
+ ((__UCLIBC_CTYPE_B)[(int) (c)] & (__uint16_t) type)
+
+#define __isascii(c) (((c) & ~0x7f) == 0) /* If C is a 7 bit value. */
+#define __toascii(c) ((c) & 0x7f) /* Mask off high bits. */
-/* The following are included for compatibility with older versions of
- * uClibc; but now they're only visible if MISC funcctionality is requested.
- * However, as they are locale-independent, the hidden macro versions are
- * always present. */
#ifdef __USE_MISC
-extern int isxlower(int c) __THROW; /* uClibc-specific. */
-extern int isxupper(int c) __THROW; /* uClibc-specific. */
+
+/* The following are included for compatibility with older versions of
+ * uClibc; but now they're only visible if MISC funcctionality is requested. */
+extern int isxlower(int c) __THROW;
+extern int isxupper(int c) __THROW;
+
+/* isdigit() is really locale-invariant, so provide some small fast macros.
+ * These are uClibc-specific. */
+#define __isdigit_char(C) (((unsigned char)((C) - '0')) <= 9)
+#define __isdigit_int(C) (((unsigned int)((C) - '0')) <= 9)
+
#endif
-/* Next, some ctype macros which are valid for all supported locales. */
-/* WARNING: isspace and isblank need to be reverified if more 8-bit codesets
- * are added!!! But isdigit and isxdigit are always valid. */
+#define __exctype(name) extern int name (int) __THROW
-#define __isspace(c) __C_isspace(c)
-#define __isblank(c) __C_isblank(c)
+__BEGIN_NAMESPACE_STD
-#define __isdigit(c) __C_isdigit(c)
-#define __isxdigit(c) __C_isxdigit(c)
+/* The following names are all functions:
+ int isCHARACTERISTIC(int c);
+ which return nonzero iff C has CHARACTERISTIC.
+ For the meaning of the characteristic names, see the `enum' above. */
+__exctype (isalnum);
+__exctype (isalpha);
+__exctype (iscntrl);
+__exctype (isdigit);
+__exctype (islower);
+__exctype (isgraph);
+__exctype (isprint);
+__exctype (ispunct);
+__exctype (isspace);
+__exctype (isupper);
+__exctype (isxdigit);
-/* Now some non-ansi/iso c99 macros. */
-#define __isascii(c) (((c) & ~0x7f) == 0)
-#define __toascii(c) ((c) & 0x7f)
-#define _toupper(c) ((c) ^ 0x20)
-#define _tolower(c) ((c) | 0x20)
+/* Return the lowercase version of C. */
+extern int tolower (int __c) __THROW;
+/* Return the uppercase version of C. */
+extern int toupper (int __c) __THROW;
-/* For compatibility with older versions of uClibc. Are these ever used? */
-#define __isxlower(c) __C_isxlower(c) /* uClibc-specific. */
-#define __isxupper(c) __C_isxupper(c) /* uClibc-specific. */
+__END_NAMESPACE_STD
-/* Apparently, glibc implements things as macros if __NO_CTYPE isn't defined.
- * If we don't have locale support, we'll do the same. Otherwise, we'll
- * only use macros for the supported-locale-invariant cases. */
-#if 0
-/* Currently broken, since masking macros, other than getc and putc, must
- * evaluate their args exactly once. Will be fixed by the next release. mjn3 */
-/* #ifndef __NO_CTYPE */
-#define isdigit(c) __isdigit(c)
-#define isxdigit(c) __isxdigit(c)
-#define isspace(c) __isspace(c)
-#ifdef __USE_ISOC99
-#define isblank(c) __isblank(c)
-#endif
+/* ISO C99 introduced one new function. */
+#ifdef __USE_ISOC99
+__BEGIN_NAMESPACE_C99
-#if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
-#define isascii(c) __isascii(c)
-#define toascii(c) __toascii(c)
+__exctype (isblank);
+
+__END_NAMESPACE_C99
#endif
-#ifdef __USE_MISC
-#define isxlower(c) __C_isxlower(c) /* uClibc-specific. */
-#define isxupper(c) __C_isxupper(c) /* uClibc-specific. */
+#ifdef __USE_GNU
+/* Test C for a set of character classes according to MASK. */
+extern int isctype (int __c, int __mask) __THROW;
#endif
-/* TODO - Should test for 8-bit codesets instead, but currently impossible. */
-#ifndef __UCLIBC_HAS_LOCALE__
+#if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
+
+/* Return nonzero iff C is in the ASCII set
+ (i.e., is no more than 7 bits wide). */
+extern int isascii (int __c) __THROW;
+
+/* Return the part of C that is in the ASCII set
+ (i.e., the low-order 7 bits of C). */
+extern int toascii (int __c) __THROW;
+
+/* These are the same as `toupper' and `tolower' except that they do not
+ check the argument for being in the range of a `char'. */
+__exctype (_toupper);
+__exctype (_tolower);
+#endif /* Use SVID or use misc. */
+
+/* This code is needed for the optimized mapping functions. */
+#define __tobody(c, f, a, args) \
+ (__extension__ \
+ ({ int __res; \
+ if (sizeof (c) > 1) \
+ { \
+ if (__builtin_constant_p (c)) \
+ { \
+ int __c = (c); \
+ __res = __UCLIBC_CTYPE_IN_TO_DOMAIN(__c) ? (a)[__c] : __c; \
+ } \
+ else \
+ __res = f args; \
+ } \
+ else \
+ __res = (a)[(int) (c)]; \
+ __res; }))
+
+#if !defined __NO_CTYPE && !defined __cplusplus
+# define isalnum(c) __isctype((c), _ISalnum)
+# define isalpha(c) __isctype((c), _ISalpha)
+# define iscntrl(c) __isctype((c), _IScntrl)
+# define isdigit(c) __isctype((c), _ISdigit)
+# define islower(c) __isctype((c), _ISlower)
+# define isgraph(c) __isctype((c), _ISgraph)
+# define isprint(c) __isctype((c), _ISprint)
+# define ispunct(c) __isctype((c), _ISpunct)
+# define isspace(c) __isctype((c), _ISspace)
+# define isupper(c) __isctype((c), _ISupper)
+# define isxdigit(c) __isctype((c), _ISxdigit)
+
+# ifdef __USE_ISOC99
+# define isblank(c) __isctype((c), _ISblank)
+# endif
+
+# ifdef __USE_EXTERN_INLINES
+extern __inline int
+tolower (int __c) __THROW
+{
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(__c) ? (__UCLIBC_CTYPE_TOLOWER)[__c] : __c;
+}
+
+extern __inline int
+toupper (int __c) __THROW
+{
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(__c) ? (__UCLIBC_CTYPE_TOUPPER)[__c] : __c;
+}
+# endif
+
+# if __GNUC__ >= 2 && defined __OPTIMIZE__ && !defined __cplusplus
+# define tolower(c) __tobody (c, tolower, __UCLIBC_CTYPE_TOLOWER, (c))
+# define toupper(c) __tobody (c, toupper, __UCLIBC_CTYPE_TOUPPER, (c))
+# endif /* Optimizing gcc */
+
+# if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
+# define isascii(c) __isascii (c)
+# define toascii(c) __toascii (c)
+
+# define _tolower(c) ((int) (__UCLIBC_CTYPE_TOLOWER)[(int) (c)])
+# define _toupper(c) ((int) (__UCLIBC_CTYPE_TOUPPER)[(int) (c)])
+# endif
+
+#endif /* Not __NO_CTYPE. */
+
+
+#if defined(__USE_GNU) && defined(__UCLIBC_HAS_XLOCALE__)
+/* The concept of one static locale per category is not very well
+ thought out. Many applications will need to process its data using
+ information from several different locales. Another application is
+ the implementation of the internationalization handling in the
+ upcoming ISO C++ standard library. To support this another set of
+ the functions using locale data exist which have an additional
+ argument.
+
+ Attention: all these functions are *not* standardized in any form.
+ This is a proof-of-concept implementation. */
+
+/* Structure for reentrant locale using functions. This is an
+ (almost) opaque type for the user level programs. */
+# include <xlocale.h>
+
+/* These definitions are similar to the ones above but all functions
+ take as an argument a handle for the locale which shall be used. */
+# define __isctype_l(c, type, locale) \
+ ((locale)->__ctype_b[(int) (c)] & (__uint16_t) type)
+
+# define __exctype_l(name) \
+ extern int name (int, __locale_t) __THROW
+
+/* The following names are all functions:
+ int isCHARACTERISTIC(int c, locale_t *locale);
+ which return nonzero iff C has CHARACTERISTIC.
+ For the meaning of the characteristic names, see the `enum' above. */
+__exctype_l (isalnum_l);
+__exctype_l (isalpha_l);
+__exctype_l (iscntrl_l);
+__exctype_l (isdigit_l);
+__exctype_l (islower_l);
+__exctype_l (isgraph_l);
+__exctype_l (isprint_l);
+__exctype_l (ispunct_l);
+__exctype_l (isspace_l);
+__exctype_l (isupper_l);
+__exctype_l (isxdigit_l);
+
+__exctype_l (isblank_l);
+
+
+/* Return the lowercase version of C in locale L. */
+extern int __tolower_l (int __c, __locale_t __l) __THROW;
+extern int tolower_l (int __c, __locale_t __l) __THROW;
+
+/* Return the uppercase version of C. */
+extern int __toupper_l (int __c, __locale_t __l) __THROW;
+extern int toupper_l (int __c, __locale_t __l) __THROW;
+
+# if __GNUC__ >= 2 && defined __OPTIMIZE__ && !defined __cplusplus
+# define __tolower_l(c, locale) \
+ __tobody (c, __tolower_l, (locale)->__ctype_tolower, (c, locale))
+# define __toupper_l(c, locale) \
+ __tobody (c, __toupper_l, (locale)->__ctype_toupper, (c, locale))
+# define tolower_l(c, locale) __tolower_l ((c), (locale))
+# define toupper_l(c, locale) __toupper_l ((c), (locale))
+# endif /* Optimizing gcc */
+
+
+# ifndef __NO_CTYPE
+# define __isalnum_l(c,l) __isctype_l((c), _ISalnum, (l))
+# define __isalpha_l(c,l) __isctype_l((c), _ISalpha, (l))
+# define __iscntrl_l(c,l) __isctype_l((c), _IScntrl, (l))
+# define __isdigit_l(c,l) __isctype_l((c), _ISdigit, (l))
+# define __islower_l(c,l) __isctype_l((c), _ISlower, (l))
+# define __isgraph_l(c,l) __isctype_l((c), _ISgraph, (l))
+# define __isprint_l(c,l) __isctype_l((c), _ISprint, (l))
+# define __ispunct_l(c,l) __isctype_l((c), _ISpunct, (l))
+# define __isspace_l(c,l) __isctype_l((c), _ISspace, (l))
+# define __isupper_l(c,l) __isctype_l((c), _ISupper, (l))
+# define __isxdigit_l(c,l) __isctype_l((c), _ISxdigit, (l))
+
+# define __isblank_l(c,l) __isctype_l((c), _ISblank, (l))
+
+# if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
+# define __isascii_l(c,l) ((l), __isascii (c))
+# define __toascii_l(c,l) ((l), __toascii (c))
+# endif
+
+# define isalnum_l(c,l) __isalnum_l ((c), (l))
+# define isalpha_l(c,l) __isalpha_l ((c), (l))
+# define iscntrl_l(c,l) __iscntrl_l ((c), (l))
+# define isdigit_l(c,l) __isdigit_l ((c), (l))
+# define islower_l(c,l) __islower_l ((c), (l))
+# define isgraph_l(c,l) __isgraph_l ((c), (l))
+# define isprint_l(c,l) __isprint_l ((c), (l))
+# define ispunct_l(c,l) __ispunct_l ((c), (l))
+# define isspace_l(c,l) __isspace_l ((c), (l))
+# define isupper_l(c,l) __isupper_l ((c), (l))
+# define isxdigit_l(c,l) __isxdigit_l ((c), (l))
-#define isalnum(c) __C_isalnum(c)
-#define isalpha(c) __C_isalpha(c)
-#define iscntrl(c) __C_iscntrl(c)
-#define isgraph(c) __C_isgraph(c)
-#define islower(c) __C_islower(c)
-#define isprint(c) __C_isprint(c)
-#define ispunct(c) __C_ispunct(c)
-#define isupper(c) __C_isupper(c)
+# define isblank_l(c,l) __isblank_l ((c), (l))
-#define tolower(c) __C_tolower(c)
-#define toupper(c) __C_toupper(c)
+# if defined __USE_SVID || defined __USE_MISC || defined __USE_XOPEN
+# define isascii_l(c,l) __isascii_l ((c), (l))
+# define toascii_l(c,l) __toascii_l ((c), (l))
+# endif
-#endif /* __UCLIBC_HAS_LOCALE__ */
+# endif /* Not __NO_CTYPE. */
-#endif /* __NO_CTYPE */
+#endif /* Use GNU. */
__END_DECLS
-#endif /* _CTYPE_H */
+#endif /* ctype.h */
diff --git a/include/langinfo.h b/include/langinfo.h
index a57a871c5..a129c12ae 100644
--- a/include/langinfo.h
+++ b/include/langinfo.h
@@ -605,8 +605,8 @@ enum
extern char *nl_langinfo (nl_item __item) __THROW;
-#if 0
-/*#ifdef __USE_GNU*/
+#ifdef __UCLIBC_HAS_XLOCALE__
+#ifdef __USE_GNU
/* This interface is for the extended locale model. See <locale.h> for
more information. */
@@ -614,8 +614,9 @@ extern char *nl_langinfo (nl_item __item) __THROW;
# include <xlocale.h>
/* Just like nl_langinfo but get the information from the locale object L. */
-extern char *__nl_langinfo_l (nl_item __item, __locale_t l);
-#endif /* 0 */
+extern char *nl_langinfo_l (nl_item __item, __locale_t l);
+#endif
+#endif
__END_DECLS
diff --git a/include/libintl.h b/include/libintl.h
index ae1ac88e8..89db38f3b 100644
--- a/include/libintl.h
+++ b/include/libintl.h
@@ -1,18 +1,122 @@
-/* Message catalog support for internationalization is not currently
- * provided by uClibc, and so I have added macros here to disable it.
- * Sorry about that.
- */
+/* Message catalogs for internationalization.
+ Copyright (C) 1995-1999, 2000-2002 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ This file is derived from the file libgettext.h in the GNU gettext package.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
#ifndef _LIBINTL_H
#define _LIBINTL_H 1
-#undef bindtextdomain
-#define bindtextdomain(Domain, Directory) /* empty */
-#undef textdomain
-#define textdomain(Domain) /* empty */
-#define _(Text) (Text)
-#define N_(Text) (Text)
+#include <features.h>
+
+/* We define an additional symbol to signal that we use the GNU
+ implementation of gettext. */
+#define __USE_GNU_GETTEXT 1
+
+/* Provide information about the supported file formats. Returns the
+ maximum minor revision number supported for a given major revision. */
+#define __GNU_GETTEXT_SUPPORTED_REVISION(major) \
+ ((major) == 0 ? 1 : -1)
+
+__BEGIN_DECLS
+
+/* Look up MSGID in the current default message catalog for the current
+ LC_MESSAGES locale. If not found, returns MSGID itself (the default
+ text). */
+extern char *gettext (__const char *__msgid) __THROW;
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current
+ LC_MESSAGES locale. */
+extern char *dgettext (__const char *__domainname, __const char *__msgid)
+ __THROW;
+extern char *__dgettext (__const char *__domainname, __const char *__msgid)
+ __THROW __attribute_format_arg__ (2);
+
+/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
+ locale. */
+extern char *dcgettext (__const char *__domainname,
+ __const char *__msgid, int __category) __THROW;
+extern char *__dcgettext (__const char *__domainname,
+ __const char *__msgid, int __category)
+ __THROW __attribute_format_arg__ (2);
+
+
+/* Similar to `gettext' but select the plural form corresponding to the
+ number N. */
+extern char *ngettext (__const char *__msgid1, __const char *__msgid2,
+ unsigned long int __n)
+ __THROW __attribute_format_arg__ (1) __attribute_format_arg__ (2);
+
+/* Similar to `dgettext' but select the plural form corresponding to the
+ number N. */
+extern char *dngettext (__const char *__domainname, __const char *__msgid1,
+ __const char *__msgid2, unsigned long int __n)
+ __THROW __attribute_format_arg__ (2) __attribute_format_arg__ (3);
+
+/* Similar to `dcgettext' but select the plural form corresponding to the
+ number N. */
+extern char *dcngettext (__const char *__domainname, __const char *__msgid1,
+ __const char *__msgid2, unsigned long int __n,
+ int __category)
+ __THROW __attribute_format_arg__ (2) __attribute_format_arg__ (3);
+
+
+/* Set the current default message catalog to DOMAINNAME.
+ If DOMAINNAME is null, return the current default.
+ If DOMAINNAME is "", reset to the default of "messages". */
+extern char *textdomain (__const char *__domainname) __THROW;
+
+/* Specify that the DOMAINNAME message catalog will be found
+ in DIRNAME rather than in the system locale data base. */
+extern char *bindtextdomain (__const char *__domainname,
+ __const char *__dirname) __THROW;
+
+/* Specify the character encoding in which the messages from the
+ DOMAINNAME message catalog will be returned. */
+extern char *bind_textdomain_codeset (__const char *__domainname,
+ __const char *__codeset) __THROW;
+
+
+/* Optimized version of the function above. */
+#if defined __OPTIMIZE__
+
+/* We need NULL for `gettext'. */
+# define __need_NULL
+# include <stddef.h>
+
+/* We need LC_MESSAGES for `dgettext'. */
+# include <locale.h>
+
+/* These must be macros. Inlined functions are useless because the
+ `__builtin_constant_p' predicate in dcgettext would always return
+ false. */
+
+# define gettext(msgid) dgettext (NULL, msgid)
+
+# define dgettext(domainname, msgid) \
+ dcgettext (domainname, msgid, LC_MESSAGES)
+
+# define ngettext(msgid1, msgid2, n) dngettext (NULL, msgid1, msgid2, n)
+
+# define dngettext(domainname, msgid1, msgid2, n) \
+ dcngettext (domainname, msgid1, msgid2, n, LC_MESSAGES)
+#endif /* Optimizing. */
-#endif /* _LIBINTL_H */
+__END_DECLS
+#endif /* libintl.h */
diff --git a/include/locale.h b/include/locale.h
index 1101bb15a..02d33a0d4 100644
--- a/include/locale.h
+++ b/include/locale.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991,92,1995-1999,2000,2001 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,95-99,2000,01,02 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -39,13 +39,15 @@ __BEGIN_DECLS
#define LC_COLLATE __LC_COLLATE
#define LC_MONETARY __LC_MONETARY
#define LC_MESSAGES __LC_MESSAGES
-/* #define LC_PAPER __LC_PAPER */
-/* #define LC_NAME __LC_NAME */
-/* #define LC_ADDRESS __LC_ADDRESS */
-/* #define LC_TELEPHONE __LC_TELEPHONE */
-/* #define LC_MEASUREMENT __LC_MEASUREMENT */
-/* #define LC_IDENTIFICATION __LC_IDENTIFICATION */
-#define LC_ALL __LC_ALL
+#if 0
+#define LC_PAPER __LC_PAPER
+#define LC_NAME __LC_NAME
+#define LC_ADDRESS __LC_ADDRESS
+#define LC_TELEPHONE __LC_TELEPHONE
+#define LC_MEASUREMENT __LC_MEASUREMENT
+#define LC_IDENTIFICATION __LC_IDENTIFICATION
+#endif
+#define LC_ALL __LC_ALL
/* Structure giving information about numeric and monetary notation. */
@@ -119,14 +121,18 @@ struct lconv
};
+__BEGIN_NAMESPACE_STD
+
/* Set and/or return the current locale. */
extern char *setlocale (int __category, __const char *__locale) __THROW;
/* Return the numeric/monetary information for the current locale. */
extern struct lconv *localeconv (void) __THROW;
-#if 0
-/* #ifdef __USE_GNU */
+__END_NAMESPACE_STD
+
+
+#if defined(__USE_GNU) && defined(__UCLIBC_HAS_XLOCALE__)
/* The concept of one static locale per category is not very well
thought out. Many applications will need to process its data using
information from several different locales. Another application is
@@ -141,22 +147,77 @@ extern struct lconv *localeconv (void) __THROW;
/* Get locale datatype definition. */
# include <xlocale.h>
+typedef __locale_t locale_t;
+
/* Return a reference to a data structure representing a set of locale
datasets. Unlike for the CATEGORY parameter for `setlocale' the
- CATEGORY_MASK parameter here uses a single bit for each category.
- I.e., 1 << LC_CTYPE means to load data for this category. If
- BASE is non-null the appropriate category information in the BASE
- record is replaced. */
-extern __locale_t __newlocale (int __category_mask, __const char *__locale,
- __locale_t __base) __THROW;
+ CATEGORY_MASK parameter here uses a single bit for each category,
+ made by OR'ing together LC_*_MASK bits above. */
+extern __locale_t newlocale (int __category_mask, __const char *__locale,
+ __locale_t __base) __THROW;
+
+/* These are the bits that can be set in the CATEGORY_MASK argument to
+ `newlocale'. In the GNU implementation, LC_FOO_MASK has the value
+ of (1 << LC_FOO), but this is not a part of the interface that
+ callers can assume will be true. */
+# define LC_CTYPE_MASK (1 << __LC_CTYPE)
+# define LC_NUMERIC_MASK (1 << __LC_NUMERIC)
+# define LC_TIME_MASK (1 << __LC_TIME)
+# define LC_COLLATE_MASK (1 << __LC_COLLATE)
+# define LC_MONETARY_MASK (1 << __LC_MONETARY)
+# define LC_MESSAGES_MASK (1 << __LC_MESSAGES)
+#ifdef L_newlocale
+#warning mask defines for extra locale categories
+#endif /* L_newlocale - uClibc note */
+#ifdef LC_PAPER
+# define LC_PAPER_MASK (1 << __LC_PAPER)
+# define LC_NAME_MASK (1 << __LC_NAME)
+# define LC_ADDRESS_MASK (1 << __LC_ADDRESS)
+# define LC_TELEPHONE_MASK (1 << __LC_TELEPHONE)
+# define LC_MEASUREMENT_MASK (1 << __LC_MEASUREMENT)
+# define LC_IDENTIFICATION_MASK (1 << __LC_IDENTIFICATION)
+# define LC_ALL_MASK (LC_CTYPE_MASK \
+ | LC_NUMERIC_MASK \
+ | LC_TIME_MASK \
+ | LC_COLLATE_MASK \
+ | LC_MONETARY_MASK \
+ | LC_MESSAGES_MASK \
+ | LC_PAPER_MASK \
+ | LC_NAME_MASK \
+ | LC_ADDRESS_MASK \
+ | LC_TELEPHONE_MASK \
+ | LC_MEASUREMENT_MASK \
+ | LC_IDENTIFICATION_MASK \
+ )
+#else /* LC_PAPER */
+# define LC_ALL_MASK (LC_CTYPE_MASK \
+ | LC_NUMERIC_MASK \
+ | LC_TIME_MASK \
+ | LC_COLLATE_MASK \
+ | LC_MONETARY_MASK \
+ | LC_MESSAGES_MASK \
+ )
+#endif /* LC_PAPER */
/* Return a duplicate of the set of locale in DATASET. All usage
counters are increased if necessary. */
-extern __locale_t __duplocale (__locale_t __dataset) __THROW;
+extern __locale_t duplocale (__locale_t __dataset) __THROW;
/* Free the data associated with a locale dataset previously returned
by a call to `setlocale_r'. */
-extern void __freelocale (__locale_t __dataset) __THROW;
+extern void freelocale (__locale_t __dataset) __THROW;
+
+/* Switch the current thread's locale to DATASET.
+ If DATASET is null, instead just return the current setting.
+ The special value LC_GLOBAL_LOCALE is the initial setting
+ for all threads and can also be installed any time, meaning
+ the thread uses the global settings controlled by `setlocale'. */
+extern __locale_t uselocale (__locale_t __dataset) __THROW;
+
+/* This value can be passed to `uselocale' and may be returned by it.
+ Passing this value to any other function has undefined behavior. */
+# define LC_GLOBAL_LOCALE ((__locale_t) -1L)
+
#endif
__END_DECLS
diff --git a/include/signal.h b/include/signal.h
index f0a24dbcf..7793cdbe1 100644
--- a/include/signal.h
+++ b/include/signal.h
@@ -273,10 +273,12 @@ extern int sigqueue (__pid_t __pid, int __sig, __const union sigval __val)
#ifdef __USE_BSD
+#ifdef __UCLIBC_HAS_SYS_SIGLIST__
/* Names of the signals. This variable exists only for compatibility.
Use `strsignal' instead (see <string.h>). */
extern __const char *__const _sys_siglist[_NSIG];
extern __const char *__const sys_siglist[_NSIG];
+#endif /* __UCLIBC_HAS_SYS_SIGLIST__ */
/* Structure passed to `sigvec'. */
struct sigvec
diff --git a/include/stdio.h b/include/stdio.h
index 3e27707ae..b11394da7 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -355,12 +355,19 @@ extern int getchar (void) __THROW;
/* The C standard explicitly says this is a macro, so we always do the
optimization for it. */
+#ifdef __UCLIBC_HAS_THREADS__
+#define getc(_fp) (getc)(_fp) /* SUSv3 says getc must be threadsafe. */
+#else /* __UCLIBC_HAS_THREADS__ */
#define getc(_fp) __GETC(_fp)
+#endif /* __UCLIBC_HAS_THREADS__ */
#if defined __USE_POSIX || defined __USE_MISC
/* These are defined in POSIX.1:1996. */
extern int getc_unlocked (FILE *__stream) __THROW;
extern int getchar_unlocked (void) __THROW;
+
+/* SUSv3 allows getc_unlocked to be a macro */
+#define getc_unlocked(_fp) __GETC(_fp)
#endif /* Use POSIX or MISC. */
#ifdef __USE_MISC
@@ -378,7 +385,11 @@ extern int putchar (int __c) __THROW;
/* The C standard explicitly says this can be a macro,
so we always do the optimization for it. */
+#ifdef __UCLIBC_HAS_THREADS__
+#define putc(_ch, _fp) (putc)(_ch, _fp) /* SUSv3 says putc must be threadsafe. */
+#else /* __UCLIBC_HAS_THREADS__ */
#define putc(_ch, _fp) __PUTC(_ch, _fp)
+#endif /* __UCLIBC_HAS_THREADS__ */
#ifdef __USE_MISC
/* Faster version when locking is not necessary. */
@@ -389,6 +400,9 @@ extern int fputc_unlocked (int __c, FILE *__stream) __THROW;
/* These are defined in POSIX.1:1996. */
extern int putc_unlocked (int __c, FILE *__stream) __THROW;
extern int putchar_unlocked (int __c) __THROW;
+
+/* SUSv3 allows putc_unlocked to be a macro */
+#define putc_unlocked(_ch, _fp) __PUTC(_ch, _fp)
#endif /* Use POSIX or MISC. */
@@ -544,6 +558,7 @@ extern int ferror_unlocked (FILE *__stream) __THROW;
/* Print a message describing the meaning of the value of errno. */
extern void perror (__const char *__s) __THROW;
+#ifdef __UCLIBC_HAS_SYS_ERRLIST__
/* These variables normally should not be used directly. The `strerror'
function provides all the needed functionality. */
#ifdef __USE_BSD
@@ -555,6 +570,7 @@ extern __const char *__const sys_errlist[];
extern int _sys_nerr;
extern __const char *__const _sys_errlist[];
#endif
+#endif /* __UCLIBC_HAS_SYS_ERRLIST__ */
#ifdef __USE_POSIX
diff --git a/include/stdlib.h b/include/stdlib.h
index ac73fc143..f7589d7ea 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-1999, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -92,6 +92,7 @@ typedef union
# define WIFSTOPPED(status) __WIFSTOPPED(__WAIT_INT(status))
#endif /* X/Open and <sys/wait.h> not included. */
+__BEGIN_NAMESPACE_STD
/* Returned by `div'. */
typedef struct
{
@@ -108,8 +109,10 @@ typedef struct
} ldiv_t;
# define __ldiv_t_defined 1
#endif
+__END_NAMESPACE_STD
#if defined __USE_ISOC99 && !defined __lldiv_t_defined
+__BEGIN_NAMESPACE_C99
/* Returned by `lldiv'. */
__extension__ typedef struct
{
@@ -117,6 +120,7 @@ __extension__ typedef struct
long long int rem; /* Remainder. */
} lldiv_t;
# define __lldiv_t_defined 1
+__END_NAMESPACE_C99
#endif
@@ -130,12 +134,17 @@ __extension__ typedef struct
#define EXIT_SUCCESS 0 /* Successful exit status. */
+/* Maximum length of a multibyte character in the current locale. */
+/* #define MB_CUR_MAX (__ctype_get_mb_cur_max ()) */
+/* extern size_t __ctype_get_mb_cur_max (void) __THROW; */
#ifdef __UCLIBC_HAS_WCHAR__
/* Maximum length of a multibyte character in the current locale. */
#define MB_CUR_MAX (_stdlib_mb_cur_max ())
extern size_t _stdlib_mb_cur_max (void) __THROW;
#endif
+
+__BEGIN_NAMESPACE_STD
#ifdef __UCLIBC_HAS_FLOATS__
/* Convert a string to a floating-point number. */
extern double atof (__const char *__nptr) __THROW __attribute_pure__;
@@ -144,28 +153,36 @@ extern double atof (__const char *__nptr) __THROW __attribute_pure__;
extern int atoi (__const char *__nptr) __THROW __attribute_pure__;
/* Convert a string to a long integer. */
extern long int atol (__const char *__nptr) __THROW __attribute_pure__;
+__END_NAMESPACE_STD
-#if defined __USE_ISOC99 || (defined __GNUC__ && defined __USE_MISC)
+#if defined __USE_ISOC99 || (defined __GLIBC_HAVE_LONG_LONG && defined __USE_MISC)
+__BEGIN_NAMESPACE_C99
/* Convert a string to a long long integer. */
__extension__ extern long long int atoll (__const char *__nptr)
__THROW __attribute_pure__;
+__END_NAMESPACE_C99
#endif
+#endif /* __UCLIBC_HAS_FLOATS__ */
#ifdef __UCLIBC_HAS_FLOATS__
+__BEGIN_NAMESPACE_STD
/* Convert a string to a floating-point number. */
extern double strtod (__const char *__restrict __nptr,
char **__restrict __endptr) __THROW;
+__END_NAMESPACE_STD
#ifdef __USE_ISOC99
+__BEGIN_NAMESPACE_C99
/* Likewise for `float' and `long double' sizes of floating-point numbers. */
extern float strtof (__const char *__restrict __nptr,
char **__restrict __endptr) __THROW;
extern long double strtold (__const char *__restrict __nptr,
char **__restrict __endptr) __THROW;
+__END_NAMESPACE_C99
#endif
-#endif /* __UCLIBC_HAS_FLOATS__ */
+__BEGIN_NAMESPACE_STD
/* Convert a string to a long integer. */
extern long int strtol (__const char *__restrict __nptr,
char **__restrict __endptr, int __base) __THROW;
@@ -173,8 +190,9 @@ extern long int strtol (__const char *__restrict __nptr,
extern unsigned long int strtoul (__const char *__restrict __nptr,
char **__restrict __endptr, int __base)
__THROW;
+__END_NAMESPACE_C99
-#if defined __GNUC__ && defined __USE_BSD
+#if defined __GLIBC_HAVE_LONG_LONG && defined __USE_BSD
/* Convert a string to a quadword integer. */
__extension__
extern long long int strtoq (__const char *__restrict __nptr,
@@ -186,9 +204,8 @@ extern unsigned long long int strtouq (__const char *__restrict __nptr,
__THROW;
#endif /* GCC and use BSD. */
-#if defined __USE_ISOC99 || (defined __GNUC__ && defined __USE_MISC)
-/* These functions will part of the standard C library in ISO C99. */
-
+#if defined __USE_ISOC99 || (defined __GLIBC_HAVE_LONG_LONG && defined __USE_MISC)
+__BEGIN_NAMESPACE_C99
/* Convert a string to a quadword integer. */
__extension__
extern long long int strtoll (__const char *__restrict __nptr,
@@ -198,10 +215,11 @@ __extension__
extern unsigned long long int strtoull (__const char *__restrict __nptr,
char **__restrict __endptr, int __base)
__THROW;
+__END_NAMESPACE_C99
#endif /* ISO C99 or GCC and use MISC. */
-#if 0
+#ifdef __UCLIBC_HAS_XLOCALE__
#ifdef __USE_GNU
/* The concept of one static locale per category is not very well
thought out. Many applications will need to process its data using
@@ -220,44 +238,43 @@ extern unsigned long long int strtoull (__const char *__restrict __nptr,
/* Special versions of the functions above which take the locale to
use as an additional parameter. */
-extern long int __strtol_l (__const char *__restrict __nptr,
- char **__restrict __endptr, int __base,
- __locale_t __loc) __THROW;
+extern long int strtol_l (__const char *__restrict __nptr,
+ char **__restrict __endptr, int __base,
+ __locale_t __loc) __THROW;
-extern unsigned long int __strtoul_l (__const char *__restrict __nptr,
- char **__restrict __endptr,
- int __base, __locale_t __loc) __THROW;
+extern unsigned long int strtoul_l (__const char *__restrict __nptr,
+ char **__restrict __endptr,
+ int __base, __locale_t __loc) __THROW;
__extension__
-extern long long int __strtoll_l (__const char *__restrict __nptr,
- char **__restrict __endptr, int __base,
- __locale_t __loc) __THROW;
+extern long long int strtoll_l (__const char *__restrict __nptr,
+ char **__restrict __endptr, int __base,
+ __locale_t __loc) __THROW;
__extension__
-extern unsigned long long int __strtoull_l (__const char *__restrict __nptr,
- char **__restrict __endptr,
- int __base, __locale_t __loc)
+extern unsigned long long int strtoull_l (__const char *__restrict __nptr,
+ char **__restrict __endptr,
+ int __base, __locale_t __loc)
__THROW;
-extern double __strtod_l (__const char *__restrict __nptr,
- char **__restrict __endptr, __locale_t __loc)
+extern double strtod_l (__const char *__restrict __nptr,
+ char **__restrict __endptr, __locale_t __loc)
__THROW;
-extern float __strtof_l (__const char *__restrict __nptr,
- char **__restrict __endptr, __locale_t __loc) __THROW;
+extern float strtof_l (__const char *__restrict __nptr,
+ char **__restrict __endptr, __locale_t __loc) __THROW;
-extern long double __strtold_l (__const char *__restrict __nptr,
- char **__restrict __endptr,
- __locale_t __loc) __THROW;
+extern long double strtold_l (__const char *__restrict __nptr,
+ char **__restrict __endptr,
+ __locale_t __loc) __THROW;
#endif /* GNU */
-#endif /* 0 */
+#endif /* __UCLIBC_HAS_XLOCALE__ */
#if 0
/* The internal entry points for `strtoX' take an extra flag argument
saying whether or not to parse locale-dependent number grouping. */
-#ifdef __UCLIBC_HAS_FLOATS__
extern double __strtod_internal (__const char *__restrict __nptr,
char **__restrict __endptr, int __group)
__THROW;
@@ -267,7 +284,6 @@ extern float __strtof_internal (__const char *__restrict __nptr,
extern long double __strtold_internal (__const char *__restrict __nptr,
char **__restrict __endptr,
int __group) __THROW;
-#endif /* __UCLIBC_HAS_FLOATS__ */
#ifndef __strtol_internal_defined
extern long int __strtol_internal (__const char *__restrict __nptr,
char **__restrict __endptr,
@@ -300,72 +316,78 @@ extern unsigned long long int __strtoull_internal (__const char *
#endif /* GCC */
#endif /* 0 */
-#ifdef __USE_EXTERN_INLINES
-#if 0
+#if defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ \
+ && defined __USE_EXTERN_INLINES
/* Define inline functions which call the internal entry points. */
-extern __inline double
-strtod (__const char *__restrict __nptr, char **__restrict __endptr) __THROW
-{
- return __strtod_internal (__nptr, __endptr, 0);
-}
-extern __inline long int
-strtol (__const char *__restrict __nptr, char **__restrict __endptr,
- int __base) __THROW
-{
- return __strtol_internal (__nptr, __endptr, __base, 0);
-}
-extern __inline unsigned long int
-strtoul (__const char *__restrict __nptr, char **__restrict __endptr,
- int __base) __THROW
-{
- return __strtoul_internal (__nptr, __endptr, __base, 0);
-}
-
-# ifdef __USE_ISOC99
-extern __inline float
-strtof (__const char *__restrict __nptr, char **__restrict __endptr) __THROW
-{
- return __strtof_internal (__nptr, __endptr, 0);
-}
-extern __inline long double
-strtold (__const char *__restrict __nptr, char **__restrict __endptr) __THROW
-{
- return __strtold_internal (__nptr, __endptr, 0);
-}
-# endif
-
-# ifdef __USE_BSD
-__extension__ extern __inline long long int
-strtoq (__const char *__restrict __nptr, char **__restrict __endptr,
- int __base) __THROW
-{
- return __strtoll_internal (__nptr, __endptr, __base, 0);
-}
-__extension__ extern __inline unsigned long long int
-strtouq (__const char *__restrict __nptr, char **__restrict __endptr,
- int __base) __THROW
-{
- return __strtoull_internal (__nptr, __endptr, __base, 0);
-}
-# endif
-
-# if defined __USE_MISC || defined __USE_ISOC99
-__extension__ extern __inline long long int
-strtoll (__const char *__restrict __nptr, char **__restrict __endptr,
- int __base) __THROW
-{
- return __strtoll_internal (__nptr, __endptr, __base, 0);
-}
-__extension__ extern __inline unsigned long long int
-strtoull (__const char * __restrict __nptr, char **__restrict __endptr,
- int __base) __THROW
-{
- return __strtoull_internal (__nptr, __endptr, __base, 0);
-}
-# endif
-#endif /* 0 */
-
+/* __BEGIN_NAMESPACE_STD */
+/* extern __inline double */
+/* strtod (__const char *__restrict __nptr, char **__restrict __endptr) __THROW */
+/* { */
+/* return __strtod_internal (__nptr, __endptr, 0); */
+/* } */
+/* extern __inline long int */
+/* strtol (__const char *__restrict __nptr, char **__restrict __endptr, */
+/* int __base) __THROW */
+/* { */
+/* return __strtol_internal (__nptr, __endptr, __base, 0); */
+/* } */
+/* extern __inline unsigned long int */
+/* strtoul (__const char *__restrict __nptr, char **__restrict __endptr, */
+/* int __base) __THROW */
+/* { */
+/* return __strtoul_internal (__nptr, __endptr, __base, 0); */
+/* } */
+/* __END_NAMESPACE_STD */
+
+/* # ifdef __USE_ISOC99 */
+/* __BEGIN_NAMESPACE_C99 */
+/* extern __inline float */
+/* strtof (__const char *__restrict __nptr, char **__restrict __endptr) __THROW */
+/* { */
+/* return __strtof_internal (__nptr, __endptr, 0); */
+/* } */
+/* extern __inline long double */
+/* strtold (__const char *__restrict __nptr, char **__restrict __endptr) __THROW */
+/* { */
+/* return __strtold_internal (__nptr, __endptr, 0); */
+/* } */
+/* __END_NAMESPACE_C99 */
+/* # endif */
+
+/* # ifdef __USE_BSD */
+/* __extension__ extern __inline long long int */
+/* strtoq (__const char *__restrict __nptr, char **__restrict __endptr, */
+/* int __base) __THROW */
+/* { */
+/* return __strtoll_internal (__nptr, __endptr, __base, 0); */
+/* } */
+/* __extension__ extern __inline unsigned long long int */
+/* strtouq (__const char *__restrict __nptr, char **__restrict __endptr, */
+/* int __base) __THROW */
+/* { */
+/* return __strtoull_internal (__nptr, __endptr, __base, 0); */
+/* } */
+/* # endif */
+
+/* # if defined __USE_MISC || defined __USE_ISOC99 */
+/* __BEGIN_NAMESPACE_C99 */
+/* __extension__ extern __inline long long int */
+/* strtoll (__const char *__restrict __nptr, char **__restrict __endptr, */
+/* int __base) __THROW */
+/* { */
+/* return __strtoll_internal (__nptr, __endptr, __base, 0); */
+/* } */
+/* __extension__ extern __inline unsigned long long int */
+/* strtoull (__const char * __restrict __nptr, char **__restrict __endptr, */
+/* int __base) __THROW */
+/* { */
+/* return __strtoull_internal (__nptr, __endptr, __base, 0); */
+/* } */
+/* __END_NAMESPACE_C99 */
+/* # endif */
+
+__BEGIN_NAMESPACE_STD
extern __inline double
atof (__const char *__nptr) __THROW
{
@@ -381,13 +403,16 @@ atol (__const char *__nptr) __THROW
{
return strtol (__nptr, (char **) NULL, 10);
}
+__END_NAMESPACE_STD
# if defined __USE_MISC || defined __USE_ISOC99
+__BEGIN_NAMESPACE_C99
__extension__ extern __inline long long int
atoll (__const char *__nptr) __THROW
{
return strtoll (__nptr, (char **) NULL, 10);
}
+__END_NAMESPACE_C99
# endif
#endif /* Optimizing and Inlining. */
@@ -401,7 +426,9 @@ extern char *l64a (long int __n) __THROW;
/* Read a number from a string S in base 64 as above. */
extern long int a64l (__const char *__s) __THROW __attribute_pure__;
+#endif /* Use SVID || extended X/Open. */
+#if defined __USE_SVID || defined __USE_XOPEN_EXTENDED || defined __USE_BSD
# include <sys/types.h> /* we need int32_t... */
/* These are the functions that actually do things. The `random', `srandom',
@@ -454,13 +481,15 @@ extern int initstate_r (unsigned int __seed, char *__restrict __statebuf,
extern int setstate_r (char *__restrict __statebuf,
struct random_data *__restrict __buf) __THROW;
# endif /* Use misc. */
-#endif /* Use SVID || extended X/Open. */
+#endif /* Use SVID || extended X/Open || BSD. */
+__BEGIN_NAMESPACE_STD
/* Return a random integer between 0 and RAND_MAX inclusive. */
extern int rand (void) __THROW;
/* Seed the random number generator with the given number. */
extern void srand (unsigned int __seed) __THROW;
+__END_NAMESPACE_STD
#ifdef __USE_POSIX
/* Reentrant interface according to POSIX.1. */
@@ -541,34 +570,24 @@ extern int lcong48_r (unsigned short int __param[7],
#endif /* don't just need malloc and calloc */
#ifndef __malloc_and_calloc_defined
-#define __malloc_and_calloc_defined
+# define __malloc_and_calloc_defined
+__BEGIN_NAMESPACE_STD
/* Allocate SIZE bytes of memory. */
extern void *malloc (size_t __size) __THROW __attribute_malloc__;
/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
extern void *calloc (size_t __nmemb, size_t __size)
__THROW __attribute_malloc__;
-#if 0
-/* Cope with autoconf's broken AC_FUNC_MALLOC macro, which
- * redefines malloc to rpl_malloc if it does not detect glibc
- * style returning-a-valid-pointer-for-malloc(0) behavior. This
- * calls malloc() as usual, but if __size is zero, we allocate and
- * return a 1-byte block instead.... sigh... */
-static __inline void *rpl_malloc (size_t __size)
-{
- if (__size == 0) {
- __size++;
- }
- return malloc(__size);
-}
-#endif
+__END_NAMESPACE_STD
#endif
#ifndef __need_malloc_and_calloc
+__BEGIN_NAMESPACE_STD
/* Re-allocate the previously allocated block
in PTR, making the new block SIZE bytes long. */
extern void *realloc (void *__ptr, size_t __size) __THROW __attribute_malloc__;
/* Free a block allocated by `malloc', `realloc' or `calloc'. */
extern void free (void *__ptr) __THROW;
+__END_NAMESPACE_STD
#ifdef __USE_MISC
/* Free a block. An alias for `free'. (Sun Unices). */
@@ -588,23 +607,30 @@ extern void *valloc (size_t __size) __THROW __attribute_malloc__;
/* Allocate memory of SIZE bytes with an alignment of ALIGNMENT. */
extern int posix_memalign (void **__memptr, size_t __alignment, size_t __size)
__THROW __attribute_malloc__;
+#if 0
+/* Cope with autoconf's broken AC_FUNC_MALLOC macro, which
+ * redefines malloc to rpl_malloc if it does not detect glibc
+ * style returning-a-valid-pointer-for-malloc(0) behavior. This
+ * calls malloc() as usual, but if __size is zero, we allocate and
+ * return a 1-byte block instead.... sigh... */
+static __inline void *rpl_malloc (size_t __size)
+{
+ if (__size == 0) {
+ __size++;
+ }
+ return malloc(__size);
+}
+#endif
#endif
+__BEGIN_NAMESPACE_STD
/* Abort execution and generate a core-dump. */
extern void abort (void) __THROW __attribute__ ((__noreturn__));
/* Register a function to be called when `exit' is called. */
extern int atexit (void (*__func) (void)) __THROW;
-
-/* The following is used by uClibc in atexit.c and sysconf.c */
-/* We have no limit when __UCLIBC_DYNAMIC_ATEXIT__ is enabled. */
-#ifdef __UCLIBC_DYNAMIC_ATEXIT__
-# define __UCLIBC_MAX_ATEXIT INT_MAX
-#else
-# define __UCLIBC_MAX_ATEXIT 20
-#endif
-
+__END_NAMESPACE_STD
#ifdef __USE_MISC
/* Register a function to be called with the status
@@ -613,20 +639,26 @@ extern int on_exit (void (*__func) (int __status, void *__arg), void *__arg)
__THROW;
#endif
+__BEGIN_NAMESPACE_STD
/* Call all functions registered with `atexit' and `on_exit',
in the reverse of the order in which they were registered
perform stdio cleanup, and terminate program execution with STATUS. */
extern void exit (int __status) __THROW __attribute__ ((__noreturn__));
+__END_NAMESPACE_STD
#ifdef __USE_ISOC99
+__BEGIN_NAMESPACE_C99
/* Terminate the program with STATUS without calling any of the
functions registered with `atexit' or `on_exit'. */
extern void _Exit (int __status) __THROW __attribute__ ((__noreturn__));
+__END_NAMESPACE_C99
#endif
+__BEGIN_NAMESPACE_STD
/* Return the value of envariable NAME, or NULL if it doesn't exist. */
extern char *getenv (__const char *__name) __THROW;
+__END_NAMESPACE_STD
/* This function is similar to the above but returns NULL if the
programs is running with SUID or SGID enabled. */
@@ -649,6 +681,15 @@ extern int setenv (__const char *__name, __const char *__value, int __replace)
extern int unsetenv (__const char *__name) __THROW;
#endif
+/* The following is used by uClibc in atexit.c and sysconf.c */
+/* We have no limit when __UCLIBC_DYNAMIC_ATEXIT__ is enabled. */
+#ifdef __UCLIBC_DYNAMIC_ATEXIT__
+# define __UCLIBC_MAX_ATEXIT INT_MAX
+#else
+# define __UCLIBC_MAX_ATEXIT 20
+#endif
+
+
#ifdef __USE_MISC
/* The `clearenv' was planned to be added to POSIX.1 but probably
never made it. Nevertheless the POSIX.9 standard (POSIX bindings
@@ -668,18 +709,21 @@ extern char *mktemp (char *__template) __THROW;
The last six characters of TEMPLATE must be "XXXXXX";
they are replaced with a string that makes the filename unique.
Returns a file descriptor open on the file for reading and writing,
- or -1 if it cannot create a uniquely-named file. */
+ or -1 if it cannot create a uniquely-named file.
+
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
# ifndef __USE_FILE_OFFSET64
-extern int mkstemp (char *__template) __THROW;
+extern int mkstemp (char *__template);
# else
# ifdef __REDIRECT
-extern int __REDIRECT (mkstemp, (char *__template) __THROW, mkstemp64);
+extern int __REDIRECT (mkstemp, (char *__template), mkstemp64);
# else
# define mkstemp mkstemp64
# endif
# endif
# ifdef __USE_LARGEFILE64
-extern int mkstemp64 (char *__template) __THROW;
+extern int mkstemp64 (char *__template);
# endif
#endif
@@ -693,8 +737,13 @@ extern char *mkdtemp (char *__template) __THROW;
#endif
-/* Execute the given line as a shell command. */
-extern int system (__const char *__command) __THROW;
+__BEGIN_NAMESPACE_STD
+/* Execute the given line as a shell command.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
+extern int system (__const char *__command);
+__END_NAMESPACE_STD
#if 0
@@ -727,6 +776,7 @@ typedef __compar_fn_t comparison_fn_t;
# endif
#endif
+__BEGIN_NAMESPACE_STD
/* Do a binary search for KEY in BASE, which consists of NMEMB elements
of SIZE bytes each, using COMPAR to perform the comparisons. */
extern void *bsearch (__const void *__key, __const void *__base,
@@ -741,12 +791,15 @@ extern void qsort (void *__base, size_t __nmemb, size_t __size,
/* Return the absolute value of X. */
extern int abs (int __x) __THROW __attribute__ ((__const__));
extern long int labs (long int __x) __THROW __attribute__ ((__const__));
+__END_NAMESPACE_STD
+
#ifdef __USE_ISOC99
__extension__ extern long long int llabs (long long int __x)
__THROW __attribute__ ((__const__));
#endif
+__BEGIN_NAMESPACE_STD
/* Return the `div_t', `ldiv_t' or `lldiv_t' representation
of the value of NUMER over DENOM. */
/* GCC may have built-ins for these someday. */
@@ -754,10 +807,14 @@ extern div_t div (int __numer, int __denom)
__THROW __attribute__ ((__const__));
extern ldiv_t ldiv (long int __numer, long int __denom)
__THROW __attribute__ ((__const__));
+__END_NAMESPACE_STD
+
#ifdef __USE_ISOC99
+__BEGIN_NAMESPACE_C99
__extension__ extern lldiv_t lldiv (long long int __numer,
long long int __denom)
__THROW __attribute__ ((__const__));
+__END_NAMESPACE_C99
#endif
@@ -814,7 +871,9 @@ extern int qfcvt_r (long double __value, int __ndigit,
#endif /* __UCLIBC_HAS_FLOATS__ */
#endif
+
#ifdef __UCLIBC_HAS_WCHAR__
+__BEGIN_NAMESPACE_STD
/* Return the length of the multibyte character
in S, which is no longer than N. */
extern int mblen (__const char *__s, size_t __n) __THROW;
@@ -834,7 +893,9 @@ extern size_t mbstowcs (wchar_t *__restrict __pwcs,
extern size_t wcstombs (char *__restrict __s,
__const wchar_t *__restrict __pwcs, size_t __n)
__THROW;
-#endif /* def __UCLIBC_HAS_WCHAR__ */
+__END_NAMESPACE_STD
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
#ifdef __USE_SVID
/* Determine whether the string value of RESPONSE matches the affirmation
diff --git a/include/string.h b/include/string.h
index 8aa40f262..f3ef812bf 100644
--- a/include/string.h
+++ b/include/string.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991,92,93,95,96,97,98,99,2000,2001 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1993, 1995-2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -33,6 +33,7 @@ __BEGIN_DECLS
#include <stddef.h>
+__BEGIN_NAMESPACE_STD
/* Copy N bytes of SRC to DEST. */
extern void *memcpy (void *__restrict __dest,
__const void *__restrict __src, size_t __n) __THROW;
@@ -40,6 +41,7 @@ extern void *memcpy (void *__restrict __dest,
correct behavior for overlapping strings. */
extern void *memmove (void *__dest, __const void *__src, size_t __n)
__THROW;
+__END_NAMESPACE_STD
/* Copy no more than N bytes of SRC to DEST, stopping when C is found.
Return the position in DEST one byte past where C was copied,
@@ -51,6 +53,7 @@ extern void *memccpy (void *__restrict __dest, __const void *__restrict __src,
#endif /* SVID. */
+__BEGIN_NAMESPACE_STD
/* Set N bytes of S to C. */
extern void *memset (void *__s, int __c, size_t __n) __THROW;
@@ -61,18 +64,20 @@ extern int memcmp (__const void *__s1, __const void *__s2, size_t __n)
/* Search N bytes of S for C. */
extern void *memchr (__const void *__s, int __c, size_t __n)
__THROW __attribute_pure__;
+__END_NAMESPACE_STD
#ifdef __USE_GNU
/* Search in S for C. This is similar to `memchr' but there is no
length limit. */
extern void *rawmemchr (__const void *__s, int __c) __THROW __attribute_pure__;
-#endif
/* Search N bytes of S for the final occurrence of C. */
extern void *memrchr (__const void *__s, int __c, size_t __n)
__THROW __attribute_pure__;
+#endif
+__BEGIN_NAMESPACE_STD
/* Copy SRC to DEST. */
extern char *strcpy (char *__restrict __dest, __const char *__restrict __src)
__THROW;
@@ -100,20 +105,22 @@ extern int strcoll (__const char *__s1, __const char *__s2)
/* Put a transformation of SRC into no more than N bytes of DEST. */
extern size_t strxfrm (char *__restrict __dest,
__const char *__restrict __src, size_t __n) __THROW;
+__END_NAMESPACE_STD
-#if 0
-/*#ifdef __USE_GNU*/
+#ifdef __UCLIBC_HAS_XLOCALE__
+#ifdef __USE_GNU
/* The following functions are equivalent to the both above but they
take the locale they use for the collation as an extra argument.
This is not standardsized but something like will come. */
# include <xlocale.h>
/* Compare the collated forms of S1 and S2 using rules from L. */
-extern int __strcoll_l (__const char *__s1, __const char *__s2, __locale_t __l)
+extern int strcoll_l (__const char *__s1, __const char *__s2, __locale_t __l)
__THROW __attribute_pure__;
/* Put a transformation of SRC into no more than N bytes of DEST. */
-extern size_t __strxfrm_l (char *__dest, __const char *__src, size_t __n,
- __locale_t __l) __THROW;
+extern size_t strxfrm_l (char *__dest, __const char *__src, size_t __n,
+ __locale_t __l) __THROW;
+#endif
#endif
#if defined __USE_SVID || defined __USE_BSD || defined __USE_XOPEN_EXTENDED
@@ -152,17 +159,20 @@ extern char *strndup (__const char *__string, size_t __n)
}))
#endif
+__BEGIN_NAMESPACE_STD
/* Find the first occurrence of C in S. */
extern char *strchr (__const char *__s, int __c) __THROW __attribute_pure__;
/* Find the last occurrence of C in S. */
extern char *strrchr (__const char *__s, int __c) __THROW __attribute_pure__;
+__END_NAMESPACE_STD
#ifdef __USE_GNU
-/* This funciton is similar to `strchr'. But it returns a pointer to
+/* This function is similar to `strchr'. But it returns a pointer to
the closing NUL byte in case C is not found in S. */
extern char *strchrnul (__const char *__s, int __c) __THROW __attribute_pure__;
#endif
+__BEGIN_NAMESPACE_STD
/* Return the length of the initial segment of S which
consists entirely of characters not in REJECT. */
extern size_t strcspn (__const char *__s, __const char *__reject)
@@ -178,15 +188,11 @@ extern char *strpbrk (__const char *__s, __const char *__accept)
extern char *strstr (__const char *__haystack, __const char *__needle)
__THROW __attribute_pure__;
-#ifdef __USE_GNU
-/* Similar to `strstr' but this function ignores the case of both strings. */
-extern char *strcasestr (__const char *__haystack, __const char *__needle)
- __THROW __attribute_pure__;
-#endif
/* Divide S into tokens separated by characters in DELIM. */
extern char *strtok (char *__restrict __s, __const char *__restrict __delim)
__THROW;
+__END_NAMESPACE_STD
/* Divide S into tokens separated by characters in DELIM. Information
passed between calls are stored in SAVE_PTR. */
@@ -199,6 +205,12 @@ extern char *strtok_r (char *__restrict __s, __const char *__restrict __delim,
#endif
#ifdef __USE_GNU
+/* Similar to `strstr' but this function ignores the case of both strings. */
+extern char *strcasestr (__const char *__haystack, __const char *__needle)
+ __THROW __attribute_pure__;
+#endif
+
+#ifdef __USE_GNU
/* Find the first occurrence of NEEDLE in HAYSTACK.
NEEDLE is NEEDLELEN bytes long;
HAYSTACK is HAYSTACKLEN bytes long. */
@@ -215,8 +227,10 @@ extern void *mempcpy (void *__restrict __dest,
#endif
+__BEGIN_NAMESPACE_STD
/* Return the length of S. */
extern size_t strlen (__const char *__s) __THROW __attribute_pure__;
+__END_NAMESPACE_STD
#ifdef __USE_GNU
/* Find the length of STRING, but scan at most MAXLEN characters.
@@ -226,12 +240,17 @@ extern size_t strnlen (__const char *__string, size_t __maxlen)
#endif
+__BEGIN_NAMESPACE_STD
/* Return a string describing the meaning of the `errno' code in ERRNUM. */
extern char *strerror (int __errnum) __THROW;
-
-/* Reentrant versions of `strerror'. If a temporary buffer is required,
- at most BUFLEN bytes of BUF will be used. These symbols are _NOT_ intended
- to be applications, and can change at any time. */
+__END_NAMESPACE_STD
+#if defined __USE_XOPEN2K || defined __USE_MISC
+/* Reentrant version of `strerror'. If a temporary buffer is required, at
+ most BUFLEN bytes of BUF will be used. */
+/* extern char *strerror_r (int __errnum, char *__buf, size_t __buflen) __THROW; */
+
+/* uClibc Note: glibc's strerror_r is different from that specified in SUSv3.
+ * So we try to compensate based on feature macros. */
extern char *_glibc_strerror_r (int __errnum, char *__buf, size_t __buflen) __THROW;
extern int _susv3_strerror_r (int __errnum, char *__buf, size_t buflen) __THROW;
@@ -243,7 +262,7 @@ extern int __REDIRECT (strerror_r,
# else
# define strerror_r _susv3_strerror_r
# endif
-#elif defined(__USE_MISC)
+#else /* defined(__USE_XOPEN2K) && !defined(__USE_GNU) */
# ifdef __REDIRECT
extern char *__REDIRECT (strerror_r,
(int __errnum, char *__buf, size_t buflen) __THROW,
@@ -251,13 +270,14 @@ extern char *__REDIRECT (strerror_r,
# else
# define strerror_r _glibc_strerror_r
# endif
+#endif /* defined(__USE_XOPEN2K) && !defined(__USE_GNU) */
#endif
/* We define this function always since `bzero' is sometimes needed when
the namespace rules does not allow this. */
extern void __bzero (void *__s, size_t __n) __THROW;
-#if defined __USE_BSD
+#ifdef __USE_BSD
/* Copy N bytes of SRC to DEST (like memmove, but args reversed). */
extern void bcopy (__const void *__src, void *__dest, size_t __n) __THROW;
@@ -280,8 +300,7 @@ extern int ffs (int __i) __THROW __attribute__ ((__const__));
/* The following two functions are non-standard but necessary for non-32 bit
platforms. */
-# if 0
-/*# ifdef __USE_GNU*/
+# ifdef __USE_GNU
extern int ffsl (long int __l) __THROW __attribute__ ((__const__));
# ifdef __GNUC__
__extension__ extern int ffsll (long long int __ll)
@@ -298,17 +317,18 @@ extern int strncasecmp (__const char *__s1, __const char *__s2, size_t __n)
__THROW __attribute_pure__;
#endif /* Use BSD. */
-#if 0
-/*#ifdef __USE_GNU*/
+#ifdef __UCLIBC_HAS_XLOCALE__
+#ifdef __USE_GNU
/* Again versions of a few functions which use the given locale instead
of the global one. */
-extern int __strcasecmp_l (__const char *__s1, __const char *__s2,
- __locale_t __loc) __THROW __attribute_pure__;
+extern int strcasecmp_l (__const char *__s1, __const char *__s2,
+ __locale_t __loc) __THROW __attribute_pure__;
-extern int __strncasecmp_l (__const char *__s1, __const char *__s2,
- size_t __n, __locale_t __loc)
+extern int strncasecmp_l (__const char *__s1, __const char *__s2,
+ size_t __n, __locale_t __loc)
__THROW __attribute_pure__;
#endif
+#endif
#ifdef __USE_BSD
/* Return the next DELIM-delimited token from *STRINGP,
@@ -357,6 +377,7 @@ extern char *basename (__const char *__filename) __THROW;
# endif
#endif
+
#if 0
#if defined __GNUC__ && __GNUC__ >= 2
# if defined __OPTIMIZE__ && !defined __OPTIMIZE_SIZE__ \
diff --git a/include/sys/cdefs.h b/include/sys/cdefs.h
index 3ae52c7a8..18143058f 100644
--- a/include/sys/cdefs.h
+++ b/include/sys/cdefs.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1992,93,94,95,96,97,98,99,2000,2001,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1992-2001, 2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -85,6 +85,31 @@
#endif
+/* The standard library needs the functions from the ISO C90 standard
+ in the std namespace. At the same time we want to be safe for
+ future changes and we include the ISO C99 code in the non-standard
+ namespace __c99. The C++ wrapper header take case of adding the
+ definitions to the global namespace. */
+#if defined __cplusplus && defined _GLIBCPP_USE_NAMESPACES
+# define __BEGIN_NAMESPACE_STD namespace std {
+# define __END_NAMESPACE_STD }
+# define __USING_NAMESPACE_STD(name) using std::name;
+# define __BEGIN_NAMESPACE_C99 namespace __c99 {
+# define __END_NAMESPACE_C99 }
+# define __USING_NAMESPACE_C99(name) using __c99::name;
+#else
+/* For compatibility we do not add the declarations into any
+ namespace. They will end up in the global namespace which is what
+ old code expects. */
+# define __BEGIN_NAMESPACE_STD
+# define __END_NAMESPACE_STD
+# define __USING_NAMESPACE_STD(name)
+# define __BEGIN_NAMESPACE_C99
+# define __END_NAMESPACE_C99
+# define __USING_NAMESPACE_C99(name)
+#endif
+
+
/* Support for bounded pointers. */
#ifndef __BOUNDED_POINTERS__
# define __bounded /* nothing */
@@ -124,7 +149,8 @@
#if defined __GNUC__ && __GNUC__ >= 2
# define __REDIRECT(name, proto, alias) name proto __asm__ (__ASMNAME (#alias))
-# define __ASMNAME(cname) __C_SYMBOL_PREFIX__ cname
+# define __ASMNAME(cname) __ASMNAME2 (__USER_LABEL_PREFIX__, cname)
+# define __ASMNAME2(prefix, cname) __STRING (prefix) cname
/*
#elif __SOME_OTHER_COMPILER__
@@ -159,6 +185,24 @@
# define __attribute_pure__ /* Ignore */
#endif
+/* At some point during the gcc 3.1 development the `used' attribute
+ for functions was introduced. We don't want to use it unconditionally
+ (although this would be possible) since it generates warnings. */
+#if __GNUC_PREREQ (3,1)
+# define __attribute_used__ __attribute__ ((__used__))
+# define __attribute_noinline__ __attribute__ ((__noinline__))
+#else
+# define __attribute_used__ __attribute__ ((__unused__))
+# define __attribute_noinline__ /* Ignore */
+#endif
+
+/* gcc allows marking deprecated functions. */
+#if __GNUC_PREREQ (3,2)
+# define __attribute_deprecated__ __attribute__ ((__deprecated__))
+#else
+# define __attribute_deprecated__ /* Ignore */
+#endif
+
/* At some point during the gcc 2.8 development the `format_arg' attribute
for functions was introduced. We don't want to use it unconditionally
(although this would be possible) since it generates warnings.
diff --git a/include/time.h b/include/time.h
index 5611defbb..8dc787917 100644
--- a/include/time.h
+++ b/include/time.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991-1999, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1991-1999,2000,2001,2002,2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -55,8 +55,13 @@ __BEGIN_DECLS
# include <bits/types.h>
+__BEGIN_NAMESPACE_STD
/* Returned by `clock'. */
typedef __clock_t clock_t;
+__END_NAMESPACE_STD
+#if defined __USE_XOPEN || defined __USE_POSIX || defined __USE_MISC
+__USING_NAMESPACE_STD(clock_t)
+#endif
#endif /* clock_t not defined and <time.h> or need clock_t. */
#undef __need_clock_t
@@ -66,8 +71,13 @@ typedef __clock_t clock_t;
# include <bits/types.h>
+__BEGIN_NAMESPACE_STD
/* Returned by `time'. */
typedef __time_t time_t;
+__END_NAMESPACE_STD
+#if defined __USE_POSIX || defined __USE_MISC || defined __USE_SVID
+__USING_NAMESPACE_STD(time_t)
+#endif
#endif /* time_t not defined and <time.h> or need time_t. */
#undef __need_time_t
@@ -97,15 +107,17 @@ typedef __timer_t timer_t;
#undef __need_timer_t
-#if !defined __timespec_defined && \
- ((defined _TIME_H && defined __USE_POSIX199309) || defined __need_timespec)
+#if !defined __timespec_defined && \
+ ((defined _TIME_H && \
+ (defined __USE_POSIX199309 || defined __USE_MISC)) || \
+ defined __need_timespec)
# define __timespec_defined 1
/* POSIX.1b structure for a time value. This is like a `struct timeval' but
has nanoseconds instead of microseconds. */
struct timespec
{
- long int tv_sec; /* Seconds. */
+ __time_t tv_sec; /* Seconds. */
long int tv_nsec; /* Nanoseconds. */
};
@@ -114,6 +126,7 @@ struct timespec
#ifdef _TIME_H
+__BEGIN_NAMESPACE_STD
/* Used by other time functions. */
struct tm
{
@@ -128,15 +141,20 @@ struct tm
int tm_isdst; /* DST. [-1/0/1]*/
#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
-# ifdef __USE_BSD
+#ifdef __USE_BSD
long int tm_gmtoff; /* Seconds east of UTC. */
- __const char tm_zone[8]; /* Timezone abbreviation. */
-# else
+ __const char *tm_zone; /* Timezone abbreviation. */
+#else
long int __tm_gmtoff; /* Seconds east of UTC. */
- __const char __tm_zone[8];/* Timezone abbreviation. */
-# endif
+ __const char *__tm_zone; /* Timezone abbreviation. */
+#endif
+ char __tm_tzname[8]; /* In uClibc, tm_zone points to __tm_tzname. */
#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
};
+__END_NAMESPACE_STD
+#if defined __USE_XOPEN || defined __USE_POSIX || defined __USE_MISC
+__USING_NAMESPACE_STD(tm)
+#endif
#ifdef __USE_POSIX199309
@@ -160,6 +178,7 @@ typedef __pid_t pid_t;
#endif
+__BEGIN_NAMESPACE_STD
/* Time used by the program so far (user time + system time).
The result / CLOCKS_PER_SECOND is program time in seconds. */
extern clock_t clock (void) __THROW;
@@ -181,6 +200,7 @@ extern time_t mktime (struct tm *__tp) __THROW;
extern size_t strftime (char *__restrict __s, size_t __maxsize,
__const char *__restrict __format,
__const struct tm *__restrict __tp) __THROW;
+__END_NAMESPACE_STD
# ifdef __USE_XOPEN
/* Parse S according to FORMAT and store binary time information in TP.
@@ -190,7 +210,25 @@ extern char *strptime (__const char *__restrict __s,
__THROW;
# endif
+#ifdef __UCLIBC_HAS_XLOCALE__
+# ifdef __USE_GNU
+/* Similar to the two functions above but take the information from
+ the provided locale and not the global locale. */
+# include <xlocale.h>
+
+extern size_t strftime_l (char *__restrict __s, size_t __maxsize,
+ __const char *__restrict __format,
+ __const struct tm *__restrict __tp,
+ __locale_t __loc) __THROW;
+
+extern char *strptime_l (__const char *__restrict __s,
+ __const char *__restrict __fmt, struct tm *__tp,
+ __locale_t __loc) __THROW;
+# endif
+#endif
+
+__BEGIN_NAMESPACE_STD
/* Return the `struct tm' representation of *TIMER
in Universal Coordinated Time (aka Greenwich Mean Time). */
extern struct tm *gmtime (__const time_t *__timer) __THROW;
@@ -198,6 +236,7 @@ extern struct tm *gmtime (__const time_t *__timer) __THROW;
/* Return the `struct tm' representation
of *TIMER in the local timezone. */
extern struct tm *localtime (__const time_t *__timer) __THROW;
+__END_NAMESPACE_STD
# if defined __USE_POSIX || defined __USE_MISC
/* Return the `struct tm' representation of *TIMER in UTC,
@@ -211,12 +250,14 @@ extern struct tm *localtime_r (__const time_t *__restrict __timer,
struct tm *__restrict __tp) __THROW;
# endif /* POSIX or misc */
+__BEGIN_NAMESPACE_STD
/* Return a string of the form "Day Mon dd hh:mm:ss yyyy\n"
that is the representation of TP in this format. */
extern char *asctime (__const struct tm *__tp) __THROW;
/* Equivalent to `asctime (localtime (timer))'. */
extern char *ctime (__const time_t *__timer) __THROW;
+__END_NAMESPACE_STD
# if defined __USE_POSIX || defined __USE_MISC
/* Reentrant versions of the above functions. */
@@ -281,9 +322,12 @@ extern int dysize (int __year) __THROW __attribute__ ((__const__));
# ifdef __USE_POSIX199309
-/* Pause execution for a number of nanoseconds. */
+/* Pause execution for a number of nanoseconds.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
extern int nanosleep (__const struct timespec *__requested_time,
- struct timespec *__remaining) __THROW;
+ struct timespec *__remaining);
/* Get resolution of clock CLOCK_ID. */
@@ -297,10 +341,13 @@ extern int clock_settime (clockid_t __clock_id, __const struct timespec *__tp)
__THROW;
# ifdef __USE_XOPEN2K
-/* High-resolution sleep with the specified clock. */
+/* High-resolution sleep with the specified clock.
+
+ This function is a cancellation point and therefore not marked with
+ __THROW. */
extern int clock_nanosleep (clockid_t __clock_id, int __flags,
__const struct timespec *__req,
- struct timespec *__rem) __THROW;
+ struct timespec *__rem);
/* Return clock ID for CPU-time clock. */
extern int clock_getcpuclockid (pid_t __pid, clockid_t *__clock_id) __THROW;
@@ -346,8 +393,11 @@ extern int getdate_err;
/* Parse the given string as a date specification and return a value
representing the value. The templates from the file identified by
the environment variable DATEMSK are used. In case of an error
- `getdate_err' is set. */
-extern struct tm *getdate (__const char *__string) __THROW;
+ `getdate_err' is set.
+
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
+extern struct tm *getdate (__const char *__string);
# endif
# ifdef __USE_GNU
@@ -355,12 +405,16 @@ extern struct tm *getdate (__const char *__string) __THROW;
and the static buffer to return the result in, we provide a thread-safe
variant. The functionality is the same. The result is returned in
the buffer pointed to by RESBUFP and in case of an error the return
- value is != 0 with the same values as given above for `getdate_err'. */
+ value is != 0 with the same values as given above for `getdate_err'.
+
+ This function is not part of POSIX and therefore no official
+ cancellation point. But due to similarity with an POSIX interface
+ or due to the implementation it is a cancellation point and
+ therefore not marked with __THROW. */
extern int getdate_r (__const char *__restrict __string,
- struct tm *__restrict __resbufp) __THROW;
+ struct tm *__restrict __resbufp);
# endif
-
__END_DECLS
#endif /* <time.h> included. */
diff --git a/include/wchar.h b/include/wchar.h
index 67a3664bf..5fb44f418 100644
--- a/include/wchar.h
+++ b/include/wchar.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
+/* Copyright (C) 1995-2002, 2003 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -62,6 +62,15 @@
member of the extended character set. */
# define _WINT_T
typedef unsigned int wint_t;
+#else
+/* Work around problems with the <stddef.h> file which doesn't put
+ wint_t in the std namespace. */
+# if defined __cplusplus && defined _GLIBCPP_USE_NAMESPACES \
+ && defined __WINT_TYPE__
+__BEGIN_NAMESPACE_STD
+typedef __WINT_TYPE__ wint_t;
+__END_NAMESPACE_STD
+# endif
#endif
@@ -93,8 +102,13 @@ typedef struct
defined. */
#ifdef _WCHAR_H
+__BEGIN_NAMESPACE_C99
/* Public type. */
typedef __mbstate_t mbstate_t;
+__END_NAMESPACE_C99
+#ifdef __USE_GNU
+__USING_NAMESPACE_C99(mbstate_t)
+#endif
#ifndef WCHAR_MIN
/* These constants might also be defined in <inttypes.h>. */
@@ -112,13 +126,21 @@ typedef __mbstate_t mbstate_t;
# include <wctype.h>
#endif
+
+__BEGIN_DECLS
+
+__BEGIN_NAMESPACE_STD
/* This incomplete type is defined in <time.h> but needed here because
of `wcsftime'. */
struct tm;
+/* XXX We have to clean this up at some point. Since tm is in the std
+ namespace but wcsftime is in __c99 the type wouldn't be found
+ without inserting it in the global namespace. */
+__USING_NAMESPACE_STD(tm)
+__END_NAMESPACE_STD
-__BEGIN_DECLS
-
+__BEGIN_NAMESPACE_C99
/* Copy SRC to DEST. */
extern wchar_t *wcscpy (wchar_t *__restrict __dest,
__const wchar_t *__restrict __src) __THROW;
@@ -141,6 +163,7 @@ extern int wcscmp (__const wchar_t *__s1, __const wchar_t *__s2)
/* Compare N wide-characters of S1 and S2. */
extern int wcsncmp (__const wchar_t *__s1, __const wchar_t *__s2, size_t __n)
__THROW __attribute_pure__;
+__END_NAMESPACE_C99
#ifdef __USE_GNU
/* Compare S1 and S2, ignoring case. */
@@ -150,19 +173,20 @@ extern int wcscasecmp (__const wchar_t *__s1, __const wchar_t *__s2) __THROW;
extern int wcsncasecmp (__const wchar_t *__s1, __const wchar_t *__s2,
size_t __n) __THROW;
+#ifdef __UCLIBC_HAS_XLOCALE__
/* Similar to the two functions above but take the information from
the provided locale and not the global locale. */
-#if 0
# include <xlocale.h>
-extern int __wcscasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
- __locale_t __loc) __THROW;
+extern int wcscasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
+ __locale_t __loc) __THROW;
-extern int __wcsncasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
- size_t __n, __locale_t __loc) __THROW;
-#endif
+extern int wcsncasecmp_l (__const wchar_t *__s1, __const wchar_t *__s2,
+ size_t __n, __locale_t __loc) __THROW;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
#endif
+__BEGIN_NAMESPACE_C99
/* Compare S1 and S2, both interpreted as appropriate to the
LC_COLLATE category of the current locale. */
extern int wcscoll (__const wchar_t *__s1, __const wchar_t *__s2) __THROW;
@@ -171,33 +195,37 @@ extern int wcscoll (__const wchar_t *__s1, __const wchar_t *__s2) __THROW;
`wcscoll' to the original strings. */
extern size_t wcsxfrm (wchar_t *__restrict __s1,
__const wchar_t *__restrict __s2, size_t __n) __THROW;
+__END_NAMESPACE_C99
#ifdef __USE_GNU
-#if 0
+#ifdef __UCLIBC_HAS_XLOCALE__
/* Similar to the two functions above but take the information from
the provided locale and not the global locale. */
/* Compare S1 and S2, both interpreted as appropriate to the
LC_COLLATE category of the given locale. */
-extern int __wcscoll_l (__const wchar_t *__s1, __const wchar_t *__s2,
- __locale_t __loc) __THROW;
+extern int wcscoll_l (__const wchar_t *__s1, __const wchar_t *__s2,
+ __locale_t __loc) __THROW;
+
/* Transform S2 into array pointed to by S1 such that if wcscmp is
applied to two transformed strings the result is the as applying
`wcscoll' to the original strings. */
-extern size_t __wcsxfrm_l (wchar_t *__s1, __const wchar_t *__s2,
- size_t __n, __locale_t __loc) __THROW;
-#endif
+extern size_t wcsxfrm_l (wchar_t *__s1, __const wchar_t *__s2,
+ size_t __n, __locale_t __loc) __THROW;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
/* Duplicate S, returning an identical malloc'd string. */
extern wchar_t *wcsdup (__const wchar_t *__s) __THROW __attribute_malloc__;
#endif
+__BEGIN_NAMESPACE_C99
/* Find the first occurrence of WC in WCS. */
extern wchar_t *wcschr (__const wchar_t *__wcs, wchar_t __wc)
__THROW __attribute_pure__;
/* Find the last occurrence of WC in WCS. */
extern wchar_t *wcsrchr (__const wchar_t *__wcs, wchar_t __wc)
__THROW __attribute_pure__;
+__END_NAMESPACE_C99
#ifdef __USE_GNU
/* This function is similar to `wcschr'. But it returns a pointer to
@@ -206,6 +234,7 @@ extern wchar_t *wcschrnul (__const wchar_t *__s, wchar_t __wc)
__THROW __attribute_pure__;
#endif
+__BEGIN_NAMESPACE_C99
/* Return the length of the initial segmet of WCS which
consists entirely of wide characters not in REJECT. */
extern size_t wcscspn (__const wchar_t *__wcs, __const wchar_t *__reject)
@@ -221,12 +250,6 @@ extern wchar_t *wcspbrk (__const wchar_t *__wcs, __const wchar_t *__accept)
extern wchar_t *wcsstr (__const wchar_t *__haystack, __const wchar_t *__needle)
__THROW __attribute_pure__;
-#ifdef __USE_XOPEN
-/* Another name for `wcsstr' from XPG4. */
-extern wchar_t *wcswcs (__const wchar_t *__haystack, __const wchar_t *__needle)
- __THROW __attribute_pure__;
-#endif
-
/* Divide WCS into tokens separated by characters in DELIM. */
extern wchar_t *wcstok (wchar_t *__restrict __s,
__const wchar_t *__restrict __delim,
@@ -234,6 +257,13 @@ extern wchar_t *wcstok (wchar_t *__restrict __s,
/* Return the number of wide characters in S. */
extern size_t wcslen (__const wchar_t *__s) __THROW __attribute_pure__;
+__END_NAMESPACE_C99
+
+#ifdef __USE_XOPEN
+/* Another name for `wcsstr' from XPG4. */
+extern wchar_t *wcswcs (__const wchar_t *__haystack, __const wchar_t *__needle)
+ __THROW __attribute_pure__;
+#endif
#ifdef __USE_GNU
/* Return the number of wide characters in S, but at most MAXLEN. */
@@ -242,6 +272,7 @@ extern size_t wcsnlen (__const wchar_t *__s, size_t __maxlen)
#endif
+__BEGIN_NAMESPACE_C99
/* Search N wide characters of S for C. */
extern wchar_t *wmemchr (__const wchar_t *__s, wchar_t __c, size_t __n)
__THROW __attribute_pure__;
@@ -262,6 +293,7 @@ extern wchar_t *wmemmove (wchar_t *__s1, __const wchar_t *__s2, size_t __n)
/* Set N wide characters of S to C. */
extern wchar_t *wmemset (wchar_t *__s, wchar_t __c, size_t __n) __THROW;
+__END_NAMESPACE_C99
#ifdef __USE_GNU
/* Copy N wide characters of SRC to DEST and return pointer to following
@@ -272,6 +304,7 @@ extern wchar_t *wmempcpy (wchar_t *__restrict __s1,
#endif
+__BEGIN_NAMESPACE_C99
/* Determine whether C constitutes a valid (one-byte) multibyte
character. */
extern wint_t btowc (int __c) __THROW;
@@ -299,9 +332,9 @@ extern size_t __mbrlen (__const char *__restrict __s, size_t __n,
mbstate_t *__restrict __ps) __THROW;
extern size_t mbrlen (__const char *__restrict __s, size_t __n,
mbstate_t *__restrict __ps) __THROW;
+__END_NAMESPACE_C99
-#if 0
-/* #ifdef __USE_EXTERN_INLINES */
+#ifdef __USE_EXTERN_INLINES
/* Define inline function as optimization. */
extern __inline size_t mbrlen (__const char *__restrict __s, size_t __n,
mbstate_t *__restrict __ps) __THROW
@@ -309,6 +342,7 @@ extern __inline size_t mbrlen (__const char *__restrict __s, size_t __n,
? mbrtowc (NULL, __s, __n, __ps) : __mbrlen (__s, __n, NULL)); }
#endif
+__BEGIN_NAMESPACE_C99
/* Write wide character representation of multibyte character string
SRC to DST. */
extern size_t mbsrtowcs (wchar_t *__restrict __dst,
@@ -320,6 +354,7 @@ extern size_t mbsrtowcs (wchar_t *__restrict __dst,
extern size_t wcsrtombs (char *__restrict __dst,
__const wchar_t **__restrict __src, size_t __len,
mbstate_t *__restrict __ps) __THROW;
+__END_NAMESPACE_C99
#ifdef __USE_GNU
@@ -349,6 +384,7 @@ extern int wcswidth (__const wchar_t *__s, size_t __n) __THROW;
#endif /* Use X/Open. */
+__BEGIN_NAMESPACE_C99
/* Convert initial portion of the wide string NPTR to `double'
representation. */
extern double wcstod (__const wchar_t *__restrict __nptr,
@@ -374,40 +410,41 @@ extern unsigned long int wcstoul (__const wchar_t *__restrict __nptr,
wchar_t **__restrict __endptr, int __base)
__THROW;
-#if defined __GNUC__ && defined __USE_GNU
+#if defined __USE_ISOC99 || (defined __GNUC__ && defined __USE_GNU)
/* Convert initial portion of wide string NPTR to `long int'
representation. */
__extension__
-extern long long int wcstoq (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr, int __base)
+extern long long int wcstoll (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr, int __base)
__THROW;
/* Convert initial portion of wide string NPTR to `unsigned long long int'
representation. */
__extension__
-extern unsigned long long int wcstouq (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr,
- int __base) __THROW;
-#endif /* GCC and use GNU. */
+extern unsigned long long int wcstoull (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr,
+ int __base) __THROW;
+#endif /* ISO C99 or GCC and GNU. */
+__END_NAMESPACE_C99
-#if defined __USE_ISOC99 || (defined __GNUC__ && defined __USE_GNU)
+#if defined __GNUC__ && defined __USE_GNU
/* Convert initial portion of wide string NPTR to `long int'
representation. */
__extension__
-extern long long int wcstoll (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr, int __base)
+extern long long int wcstoq (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr, int __base)
__THROW;
/* Convert initial portion of wide string NPTR to `unsigned long long int'
representation. */
__extension__
-extern unsigned long long int wcstoull (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr,
- int __base) __THROW;
-#endif /* ISO C99 or GCC and GNU. */
+extern unsigned long long int wcstouq (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr,
+ int __base) __THROW;
+#endif /* GCC and use GNU. */
-#if 0
-/* #ifdef __USE_GNU */
+#ifdef __USE_GNU
+#ifdef __UCLIBC_HAS_XLOCALE__
/* The concept of one static locale per category is not very well
thought out. Many applications will need to process its data using
information from several different locales. Another application is
@@ -425,36 +462,37 @@ extern unsigned long long int wcstoull (__const wchar_t *__restrict __nptr,
/* Special versions of the functions above which take the locale to
use as an additional parameter. */
-extern long int __wcstol_l (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr, int __base,
- __locale_t __loc) __THROW;
+extern long int wcstol_l (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr, int __base,
+ __locale_t __loc) __THROW;
-extern unsigned long int __wcstoul_l (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr,
- int __base, __locale_t __loc) __THROW;
+extern unsigned long int wcstoul_l (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr,
+ int __base, __locale_t __loc) __THROW;
__extension__
-extern long long int __wcstoll_l (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr,
- int __base, __locale_t __loc) __THROW;
+extern long long int wcstoll_l (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr,
+ int __base, __locale_t __loc) __THROW;
__extension__
-extern unsigned long long int __wcstoull_l (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr,
- int __base, __locale_t __loc)
+extern unsigned long long int wcstoull_l (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr,
+ int __base, __locale_t __loc)
__THROW;
-extern double __wcstod_l (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr, __locale_t __loc)
+extern double wcstod_l (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr, __locale_t __loc)
__THROW;
-extern float __wcstof_l (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr, __locale_t __loc)
+extern float wcstof_l (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr, __locale_t __loc)
__THROW;
-extern long double __wcstold_l (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr,
- __locale_t __loc) __THROW;
+extern long double wcstold_l (__const wchar_t *__restrict __nptr,
+ wchar_t **__restrict __endptr,
+ __locale_t __loc) __THROW;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
#endif /* GNU */
@@ -504,42 +542,44 @@ extern unsigned long long int __wcstoull_internal (__const wchar_t *
#if defined __OPTIMIZE__ && __GNUC__ >= 2
/* Define inline functions which call the internal entry points. */
-
-extern __inline double wcstod (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr) __THROW
-{ return __wcstod_internal (__nptr, __endptr, 0); }
-extern __inline long int wcstol (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr,
- int __base) __THROW
-{ return __wcstol_internal (__nptr, __endptr, __base, 0); }
-extern __inline unsigned long int wcstoul (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr,
- int __base) __THROW
-{ return __wcstoul_internal (__nptr, __endptr, __base, 0); }
+/* __BEGIN_NAMESPACE_C99 */
+
+/* extern __inline double wcstod (__const wchar_t *__restrict __nptr, */
+/* wchar_t **__restrict __endptr) __THROW */
+/* { return __wcstod_internal (__nptr, __endptr, 0); } */
+/* extern __inline long int wcstol (__const wchar_t *__restrict __nptr, */
+/* wchar_t **__restrict __endptr, */
+/* int __base) __THROW */
+/* { return __wcstol_internal (__nptr, __endptr, __base, 0); } */
+/* extern __inline unsigned long int wcstoul (__const wchar_t *__restrict __nptr, */
+/* wchar_t **__restrict __endptr, */
+/* int __base) __THROW */
+/* { return __wcstoul_internal (__nptr, __endptr, __base, 0); } */
+/* __END_NAMESPACE_C99 */
# ifdef __USE_GNU
-extern __inline float wcstof (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr) __THROW
-{ return __wcstof_internal (__nptr, __endptr, 0); }
-extern __inline long double wcstold (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr) __THROW
-{ return __wcstold_internal (__nptr, __endptr, 0); }
-
-
-__extension__
-extern __inline long long int wcstoq (__const wchar_t *__restrict __nptr,
- wchar_t **__restrict __endptr,
- int __base) __THROW
-{ return __wcstoll_internal (__nptr, __endptr, __base, 0); }
-__extension__
-extern __inline unsigned long long int wcstouq (__const wchar_t *
- __restrict __nptr,
- wchar_t **__restrict __endptr,
- int __base) __THROW
-{ return __wcstoull_internal (__nptr, __endptr, __base, 0); }
+/* extern __inline float wcstof (__const wchar_t *__restrict __nptr, */
+/* wchar_t **__restrict __endptr) __THROW */
+/* { return __wcstof_internal (__nptr, __endptr, 0); } */
+/* extern __inline long double wcstold (__const wchar_t *__restrict __nptr, */
+/* wchar_t **__restrict __endptr) __THROW */
+/* { return __wcstold_internal (__nptr, __endptr, 0); } */
+
+
+/* __extension__ */
+/* extern __inline long long int wcstoq (__const wchar_t *__restrict __nptr, */
+/* wchar_t **__restrict __endptr, */
+/* int __base) __THROW */
+/* { return __wcstoll_internal (__nptr, __endptr, __base, 0); } */
+/* __extension__ */
+/* extern __inline unsigned long long int wcstouq (__const wchar_t * */
+/* __restrict __nptr, */
+/* wchar_t **__restrict __endptr, */
+/* int __base) __THROW */
+/* { return __wcstoull_internal (__nptr, __endptr, __base, 0); } */
# endif /* Use GNU. */
#endif /* Optimizing GCC >=2. */
-#endif
+#endif /* 0 */
#ifdef __USE_GNU
@@ -556,32 +596,45 @@ extern wchar_t *wcpncpy (wchar_t *__dest, __const wchar_t *__src, size_t __n)
/* Wide character I/O functions. */
#if defined __USE_ISOC99 || defined __USE_UNIX98
+__BEGIN_NAMESPACE_C99
/* Select orientation for stream. */
extern int fwide (__FILE *__fp, int __mode) __THROW;
-/* Write formatted output to STREAM. */
+/* Write formatted output to STREAM.
+
+ This function is a possible cancellation point and therefore not
+ marked with __THROW. */
extern int fwprintf (__FILE *__restrict __stream,
__const wchar_t *__restrict __format, ...)
- __THROW /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */;
-/* Write formatted output to stdout. */
+ /* __attribute__ ((__format__ (__wprintf__, 2, 3))) */;
+/* Write formatted output to stdout.
+
+ This function is a possible cancellation point and therefore not
+ marked with __THROW. */
extern int wprintf (__const wchar_t *__restrict __format, ...)
- __THROW /* __attribute__ ((__format__ (__wprintf__, 1, 2))) */;
+ /* __attribute__ ((__format__ (__wprintf__, 1, 2))) */;
/* Write formatted output of at most N characters to S. */
extern int swprintf (wchar_t *__restrict __s, size_t __n,
__const wchar_t *__restrict __format, ...)
__THROW /* __attribute__ ((__format__ (__wprintf__, 3, 4))) */;
-/* Write formatted output to S from argument list ARG. */
+/* Write formatted output to S from argument list ARG.
+
+ This function is a possible cancellation point and therefore not
+ marked with __THROW. */
extern int vfwprintf (__FILE *__restrict __s,
__const wchar_t *__restrict __format,
__gnuc_va_list __arg)
- __THROW /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */;
-/* Write formatted output to stdout from argument list ARG. */
+ /* __attribute__ ((__format__ (__wprintf__, 2, 0))) */;
+/* Write formatted output to stdout from argument list ARG.
+
+ This function is a possible cancellation point and therefore not
+ marked with __THROW. */
extern int vwprintf (__const wchar_t *__restrict __format,
__gnuc_va_list __arg)
- __THROW /* __attribute__ ((__format__ (__wprintf__, 1, 0))) */;
+ /* __attribute__ ((__format__ (__wprintf__, 1, 0))) */;
/* Write formatted output of at most N character to S from argument
list ARG. */
extern int vswprintf (wchar_t *__restrict __s, size_t __n,
@@ -590,101 +643,187 @@ extern int vswprintf (wchar_t *__restrict __s, size_t __n,
__THROW /* __attribute__ ((__format__ (__wprintf__, 3, 0))) */;
-/* Read formatted input from STREAM. */
+/* Read formatted input from STREAM.
+
+ This function is a possible cancellation point and therefore not
+ marked with __THROW. */
extern int fwscanf (__FILE *__restrict __stream,
__const wchar_t *__restrict __format, ...)
- __THROW /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;
-/* Read formatted input from stdin. */
+ /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;
+/* Read formatted input from stdin.
+
+ This function is a possible cancellation point and therefore not
+ marked with __THROW. */
extern int wscanf (__const wchar_t *__restrict __format, ...)
- __THROW /* __attribute__ ((__format__ (__wscanf__, 1, 2))) */;
+ /* __attribute__ ((__format__ (__wscanf__, 1, 2))) */;
/* Read formatted input from S. */
extern int swscanf (__const wchar_t *__restrict __s,
__const wchar_t *__restrict __format, ...)
__THROW /* __attribute__ ((__format__ (__wscanf__, 2, 3))) */;
+
+__END_NAMESPACE_C99
#endif /* Use ISO C99 and Unix98. */
#ifdef __USE_ISOC99
-/* Read formatted input from S into argument list ARG. */
+__BEGIN_NAMESPACE_C99
+
+/* Read formatted input from S into argument list ARG.
+
+ This function is a possible cancellation point and therefore not
+ marked with __THROW. */
extern int vfwscanf (__FILE *__restrict __s,
__const wchar_t *__restrict __format,
__gnuc_va_list __arg)
- __THROW /* __attribute__ ((__format__ (__wscanf__, 2, 0))) */;
-/* Read formatted input from stdin into argument list ARG. */
+ /* __attribute__ ((__format__ (__wscanf__, 2, 0))) */;
+/* Read formatted input from stdin into argument list ARG.
+
+ This function is a possible cancellation point and therefore not
+ marked with __THROW. */
extern int vwscanf (__const wchar_t *__restrict __format,
__gnuc_va_list __arg)
- __THROW /* __attribute__ ((__format__ (__wscanf__, 1, 0))) */;
+ /* __attribute__ ((__format__ (__wscanf__, 1, 0))) */;
/* Read formatted input from S into argument list ARG. */
extern int vswscanf (__const wchar_t *__restrict __s,
__const wchar_t *__restrict __format,
__gnuc_va_list __arg)
__THROW /* __attribute__ ((__format__ (__wscanf__, 2, 0))) */;
+
+__END_NAMESPACE_C99
#endif /* Use ISO C99. */
-/* Read a character from STREAM. */
-extern wint_t fgetwc (__FILE *__stream) __THROW;
-extern wint_t getwc (__FILE *__stream) __THROW;
+__BEGIN_NAMESPACE_C99
+/* Read a character from STREAM.
+
+ These functions are possible cancellation points and therefore not
+ marked with __THROW. */
+extern wint_t fgetwc (__FILE *__stream);
+extern wint_t getwc (__FILE *__stream);
-/* Read a character from stdin. */
-extern wint_t getwchar (void) __THROW;
+/* Read a character from stdin.
+ This function is a possible cancellation point and therefore not
+ marked with __THROW. */
+extern wint_t getwchar (void);
-/* Write a character to STREAM. */
-extern wint_t fputwc (wchar_t __wc, __FILE *__stream) __THROW;
-extern wint_t putwc (wchar_t __wc, __FILE *__stream) __THROW;
-/* Write a character to stdout. */
-extern wint_t putwchar (wchar_t __wc) __THROW;
+/* Write a character to STREAM.
+
+ These functions are possible cancellation points and therefore not
+ marked with __THROW. */
+extern wint_t fputwc (wchar_t __wc, __FILE *__stream);
+extern wint_t putwc (wchar_t __wc, __FILE *__stream);
+
+/* Write a character to stdout.
+
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
+extern wint_t putwchar (wchar_t __wc);
/* Get a newline-terminated wide character string of finite length
- from STREAM. */
+ from STREAM.
+
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
extern wchar_t *fgetws (wchar_t *__restrict __ws, int __n,
- __FILE *__restrict __stream) __THROW;
+ __FILE *__restrict __stream);
+
+/* Write a string to STREAM.
-/* Write a string to STREAM. */
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
extern int fputws (__const wchar_t *__restrict __ws,
- __FILE *__restrict __stream) __THROW;
+ __FILE *__restrict __stream);
+
+/* Push a character back onto the input buffer of STREAM.
-/* Push a character back onto the input buffer of STREAM. */
-extern wint_t ungetwc (wint_t __wc, __FILE *__stream) __THROW;
+ This function is a possible cancellation points and therefore not
+ marked with __THROW. */
+extern wint_t ungetwc (wint_t __wc, __FILE *__stream);
+__END_NAMESPACE_C99
#ifdef __USE_GNU
/* These are defined to be equivalent to the `char' functions defined
- in POSIX.1:1996. */
-extern wint_t getwc_unlocked (__FILE *__stream) __THROW;
-extern wint_t getwchar_unlocked (void) __THROW;
+ in POSIX.1:1996.
-/* This is the wide character version of a GNU extension. */
-extern wint_t fgetwc_unlocked (__FILE *__stream) __THROW;
+ These functions are not part of POSIX and therefore no official
+ cancellation point. But due to similarity with an POSIX interface
+ or due to the implementation they are cancellation points and
+ therefore not marked with __THROW. */
+extern wint_t getwc_unlocked (__FILE *__stream);
+extern wint_t getwchar_unlocked (void);
-/* Faster version when locking is not necessary. */
-extern wint_t fputwc_unlocked (wchar_t __wc, __FILE *__stream) __THROW;
+/* This is the wide character version of a GNU extension.
+
+ This function is not part of POSIX and therefore no official
+ cancellation point. But due to similarity with an POSIX interface
+ or due to the implementation it is a cancellation point and
+ therefore not marked with __THROW. */
+extern wint_t fgetwc_unlocked (__FILE *__stream);
+
+/* Faster version when locking is not necessary.
+
+ This function is not part of POSIX and therefore no official
+ cancellation point. But due to similarity with an POSIX interface
+ or due to the implementation it is a cancellation point and
+ therefore not marked with __THROW. */
+extern wint_t fputwc_unlocked (wchar_t __wc, __FILE *__stream);
/* These are defined to be equivalent to the `char' functions defined
- in POSIX.1:1996. */
-extern wint_t putwc_unlocked (wchar_t __wc, __FILE *__stream) __THROW;
-extern wint_t putwchar_unlocked (wchar_t __wc) __THROW;
+ in POSIX.1:1996.
+ These functions are not part of POSIX and therefore no official
+ cancellation point. But due to similarity with an POSIX interface
+ or due to the implementation they are cancellation points and
+ therefore not marked with __THROW. */
+extern wint_t putwc_unlocked (wchar_t __wc, __FILE *__stream);
+extern wint_t putwchar_unlocked (wchar_t __wc);
-/* This function does the same as `fgetws' but does not lock the stream. */
+
+/* This function does the same as `fgetws' but does not lock the stream.
+
+ This function is not part of POSIX and therefore no official
+ cancellation point. But due to similarity with an POSIX interface
+ or due to the implementation it is a cancellation point and
+ therefore not marked with __THROW. */
extern wchar_t *fgetws_unlocked (wchar_t *__restrict __ws, int __n,
- __FILE *__restrict __stream) __THROW;
+ __FILE *__restrict __stream);
+
+/* This function does the same as `fputws' but does not lock the stream.
-/* This function does the same as `fputws' but does not lock the stream. */
+ This function is not part of POSIX and therefore no official
+ cancellation point. But due to similarity with an POSIX interface
+ or due to the implementation it is a cancellation point and
+ therefore not marked with __THROW. */
extern int fputws_unlocked (__const wchar_t *__restrict __ws,
- __FILE *__restrict __stream) __THROW;
+ __FILE *__restrict __stream);
#endif
+__BEGIN_NAMESPACE_C99
/* Format TP into S according to FORMAT.
Write no more than MAXSIZE wide characters and return the number
of wide characters written, or 0 if it would exceed MAXSIZE. */
extern size_t wcsftime (wchar_t *__restrict __s, size_t __maxsize,
__const wchar_t *__restrict __format,
__const struct tm *__restrict __tp) __THROW;
+__END_NAMESPACE_C99
+
+# ifdef __USE_GNU
+#ifdef __UCLIBC_HAS_XLOCALE__
+# include <xlocale.h>
+
+/* Similar to `wcsftime' but takes the information from
+ the provided locale and not the global locale. */
+extern size_t wcsftime_l (wchar_t *__restrict __s, size_t __maxsize,
+ __const wchar_t *__restrict __format,
+ __const struct tm *__restrict __tp,
+ __locale_t __loc) __THROW;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+# endif
/* The X/Open standard demands that most of the functions defined in
the <wctype.h> header must also appear here. This is probably
diff --git a/include/wctype.h b/include/wctype.h
index 515f36ff6..86b5db44c 100644
--- a/include/wctype.h
+++ b/include/wctype.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
+/* Copyright (C) 1996,97,98,99,2000,01,02 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -33,8 +33,6 @@
#ifndef __need_iswxxx
# define _WCTYPE_H 1
-#include <bits/uClibc_ctype.h>
-
/* We try to get wint_t from <stddef.h>, but not all GCC versions define it
there. So define it ourselves if it remains undefined. */
# define __need_wint_t
@@ -46,6 +44,11 @@
member of the extended character set. */
# define _WINT_T
typedef unsigned int wint_t;
+# else
+# ifdef __USE_ISOC99
+__USING_NAMESPACE_C99(wint_t)
+# endif
+__END_NAMESPACE_C99
# endif
/* Constant expression of type `wint_t' whose value does not correspond
@@ -62,14 +65,55 @@ typedef unsigned int wint_t;
#ifndef __iswxxx_defined
# define __iswxxx_defined 1
+__BEGIN_NAMESPACE_C99
/* Scalar type that can hold values which represent locale-specific
character classifications. */
-/* uClibc note: glibc uses an unsigned long int. */
+/* uClibc note: glibc uses - typedef unsigned long int wctype_t; */
typedef unsigned int wctype_t;
+__END_NAMESPACE_C99
+
+# ifndef _ISwbit
+# define _ISwbit(bit) (1 << (bit))
+
+enum
+{
+ __ISwupper = 0, /* UPPERCASE. */
+ __ISwlower = 1, /* lowercase. */
+ __ISwalpha = 2, /* Alphabetic. */
+ __ISwdigit = 3, /* Numeric. */
+ __ISwxdigit = 4, /* Hexadecimal numeric. */
+ __ISwspace = 5, /* Whitespace. */
+ __ISwprint = 6, /* Printing. */
+ __ISwgraph = 7, /* Graphical. */
+ __ISwblank = 8, /* Blank (usually SPC and TAB). */
+ __ISwcntrl = 9, /* Control character. */
+ __ISwpunct = 10, /* Punctuation. */
+ __ISwalnum = 11, /* Alphanumeric. */
+
+ _ISwupper = _ISwbit (__ISwupper), /* UPPERCASE. */
+ _ISwlower = _ISwbit (__ISwlower), /* lowercase. */
+ _ISwalpha = _ISwbit (__ISwalpha), /* Alphabetic. */
+ _ISwdigit = _ISwbit (__ISwdigit), /* Numeric. */
+ _ISwxdigit = _ISwbit (__ISwxdigit), /* Hexadecimal numeric. */
+ _ISwspace = _ISwbit (__ISwspace), /* Whitespace. */
+ _ISwprint = _ISwbit (__ISwprint), /* Printing. */
+ _ISwgraph = _ISwbit (__ISwgraph), /* Graphical. */
+ _ISwblank = _ISwbit (__ISwblank), /* Blank (usually SPC and TAB). */
+ _ISwcntrl = _ISwbit (__ISwcntrl), /* Control character. */
+ _ISwpunct = _ISwbit (__ISwpunct), /* Punctuation. */
+ _ISwalnum = _ISwbit (__ISwalnum) /* Alphanumeric. */
+};
+# else
+# if defined(__UCLIBC_MJN3_ONLY__) && defined(L_iswctype)
+#warning remove _ISwbit already defined check?
+#error _ISwbit already defined!
+# endif
+# endif /* Not _ISwbit */
__BEGIN_DECLS
+__BEGIN_NAMESPACE_C99
/*
* Wide-character classification functions: 7.15.2.1.
*/
@@ -141,21 +185,30 @@ extern wctype_t wctype (__const char *__property) __THROW;
/* Determine whether the wide-character WC has the property described by
DESC. */
extern int iswctype (wint_t __wc, wctype_t __desc) __THROW;
+__END_NAMESPACE_C99
+
/*
* Wide-character case-mapping functions: 7.15.3.1.
*/
+__BEGIN_NAMESPACE_C99
/* Scalar type that can hold values which represent locale-specific
character mappings. */
-/* typedef __const __int32_t *wctrans_t; */
-typedef unsigned int wctrans_t; /* TODO: fix this */
+/* uClibc note: glibc uses - typedef __const __int32_t *wctrans_t; */
+typedef unsigned int wctrans_t;
+__END_NAMESPACE_C99
+#ifdef __USE_GNU
+__USING_NAMESPACE_C99(wctrans_t)
+#endif
+__BEGIN_NAMESPACE_C99
/* Converts an uppercase letter to the corresponding lowercase letter. */
extern wint_t towlower (wint_t __wc) __THROW;
/* Converts an lowercase letter to the corresponding uppercase letter. */
extern wint_t towupper (wint_t __wc) __THROW;
+__END_NAMESPACE_C99
__END_DECLS
@@ -172,80 +225,81 @@ __END_DECLS
__BEGIN_DECLS
+__BEGIN_NAMESPACE_C99
/* Construct value that describes a mapping between wide characters
identified by the string argument PROPERTY. */
extern wctrans_t wctrans (__const char *__property) __THROW;
/* Map the wide character WC using the mapping described by DESC. */
extern wint_t towctrans (wint_t __wc, wctrans_t __desc) __THROW;
+__END_NAMESPACE_C99
-#if 0
-/* # ifdef __USE_GNU */
+#if defined(__USE_GNU) && defined(__UCLIBC_HAS_XLOCALE__)
/* Declare the interface to extended locale model. */
# include <xlocale.h>
/* Test for any wide character for which `iswalpha' or `iswdigit' is
true. */
-extern int __iswalnum_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswalnum_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any wide character for which `iswupper' or 'iswlower' is
true, or any wide character that is one of a locale-specific set of
wide-characters for which none of `iswcntrl', `iswdigit',
`iswpunct', or `iswspace' is true. */
-extern int __iswalpha_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswalpha_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any control wide character. */
-extern int __iswcntrl_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswcntrl_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any wide character that corresponds to a decimal-digit
character. */
-extern int __iswdigit_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswdigit_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any wide character for which `iswprint' is true and
`iswspace' is false. */
-extern int __iswgraph_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswgraph_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any wide character that corresponds to a lowercase letter
or is one of a locale-specific set of wide characters for which
none of `iswcntrl', `iswdigit', `iswpunct', or `iswspace' is true. */
-extern int __iswlower_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswlower_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any printing wide character. */
-extern int __iswprint_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswprint_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any printing wide character that is one of a
locale-specific et of wide characters for which neither `iswspace'
nor `iswalnum' is true. */
-extern int __iswpunct_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswpunct_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any wide character that corresponds to a locale-specific
set of wide characters for which none of `iswalnum', `iswgraph', or
`iswpunct' is true. */
-extern int __iswspace_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswspace_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any wide character that corresponds to an uppercase letter
or is one of a locale-specific set of wide character for which none
of `iswcntrl', `iswdigit', `iswpunct', or `iswspace' is true. */
-extern int __iswupper_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswupper_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any wide character that corresponds to a hexadecimal-digit
character equivalent to that performed be the functions described
in the previous subclause. */
-extern int __iswxdigit_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswxdigit_l (wint_t __wc, __locale_t __locale) __THROW;
/* Test for any wide character that corresponds to a standard blank
wide character or a locale-specific set of wide characters for
which `iswalnum' is false. */
-extern int __iswblank_l (wint_t __wc, __locale_t __locale) __THROW;
+extern int iswblank_l (wint_t __wc, __locale_t __locale) __THROW;
/* Construct value that describes a class of wide characters identified
by the string argument PROPERTY. */
-extern wctype_t __wctype_l (__const char *__property, __locale_t __locale)
+extern wctype_t wctype_l (__const char *__property, __locale_t __locale)
__THROW;
/* Determine whether the wide-character WC has the property described by
DESC. */
-extern int __iswctype_l (wint_t __wc, wctype_t __desc, __locale_t __locale)
+extern int iswctype_l (wint_t __wc, wctype_t __desc, __locale_t __locale)
__THROW;
@@ -254,19 +308,19 @@ extern int __iswctype_l (wint_t __wc, wctype_t __desc, __locale_t __locale)
*/
/* Converts an uppercase letter to the corresponding lowercase letter. */
-extern wint_t __towlower_l (wint_t __wc, __locale_t __locale) __THROW;
+extern wint_t towlower_l (wint_t __wc, __locale_t __locale) __THROW;
/* Converts an lowercase letter to the corresponding uppercase letter. */
-extern wint_t __towupper_l (wint_t __wc, __locale_t __locale) __THROW;
+extern wint_t towupper_l (wint_t __wc, __locale_t __locale) __THROW;
/* Construct value that describes a mapping between wide characters
identified by the string argument PROPERTY. */
-extern wctrans_t __wctrans_l (__const char *__property, __locale_t __locale)
+extern wctrans_t wctrans_l (__const char *__property, __locale_t __locale)
__THROW;
/* Map the wide character WC using the mapping described by DESC. */
-extern wint_t __towctrans_l (wint_t __wc, wctrans_t __desc,
- __locale_t __locale) __THROW;
+extern wint_t towctrans_l (wint_t __wc, wctrans_t __desc,
+ __locale_t __locale) __THROW;
# endif /* Use GNU. */
diff --git a/include/xlocale.h b/include/xlocale.h
new file mode 100644
index 000000000..6f726fef9
--- /dev/null
+++ b/include/xlocale.h
@@ -0,0 +1,62 @@
+/* Definition of locale datatype.
+ Copyright (C) 1997,2000,02 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _XLOCALE_H
+#define _XLOCALE_H 1
+
+#include <features.h>
+
+#ifndef __UCLIBC_HAS_XLOCALE__
+#error Attempted to include xlocale.h when uClibc built without extended locale support.
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+#include <bits/uClibc_locale.h>
+/* #include <bits/uClibc_touplow.h> */
+
+#if 0
+/* Structure for reentrant locale using functions. This is an
+ (almost) opaque type for the user level programs. The file and
+ this data structure is not standardized. Don't rely on it. It can
+ go away without warning. */
+typedef struct __locale_struct
+{
+#if 0
+ /* Note: LC_ALL is not a valid index into this array. */
+ struct locale_data *__locales[13]; /* 13 = __LC_LAST. */
+#endif
+
+ /* To increase the speed of this solution we add some special members. */
+/* const unsigned short int *__ctype_b; */
+/* const int *__ctype_tolower; */
+/* const int *__ctype_toupper; */
+ const __uint16_t *__ctype_b;
+ const __ctype_touplow_t *__ctype_tolower;
+ const __ctype_touplow_t *__ctype_toupper;
+
+ __uclibc_locale_t *__locale_ptr;
+
+#if 0
+ /* Note: LC_ALL is not a valid index into this array. */
+ const char *__names[13];
+#endif
+} *__locale_t;
+#endif
+
+#endif /* xlocale.h */
diff --git a/libc/inet/rpc/rcmd.c b/libc/inet/rpc/rcmd.c
index b8138497c..618a6f1b2 100644
--- a/libc/inet/rpc/rcmd.c
+++ b/libc/inet/rpc/rcmd.c
@@ -38,11 +38,6 @@ static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
#define __FORCE_GLIBC
#include <features.h>
-#ifdef __UCLIBC_HAS_THREADS__
-#undef __UCLIBC_HAS_THREADS__
-#warning FIXME I am not reentrant yet...
-#endif
-
#define __USE_GNU
#include <ctype.h>
#include <stdio.h>
@@ -62,10 +57,10 @@ static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
#include <netinet/in.h>
#include <arpa/inet.h>
-
-
-/* hmm. uClibc seems to have that, but it doesn't work for some reason */
-#define getc_unlocked getc
+#ifdef __UCLIBC_HAS_THREADS__
+#undef __UCLIBC_HAS_THREADS__
+#warning FIXME I am not reentrant yet...
+#endif
/* some forward declarations */
diff --git a/libc/misc/Makefile b/libc/misc/Makefile
index 46de813da..037e2154d 100644
--- a/libc/misc/Makefile
+++ b/libc/misc/Makefile
@@ -26,8 +26,8 @@ include $(TOPDIR)Rules.mak
DIRS = assert ctype dirent file fnmatch glob internals \
- mntent syslog time utmp locale sysvipc statfs \
- error ttyent gnu search
+ mntent syslog time utmp sysvipc statfs \
+ error ttyent gnu search intl locale
ifeq ($(strip $(UCLIBC_HAS_REGEX)),y)
DIRS += regex
endif
diff --git a/libc/misc/assert/__assert.c b/libc/misc/assert/__assert.c
index efffff1de..26bcc6516 100644
--- a/libc/misc/assert/__assert.c
+++ b/libc/misc/assert/__assert.c
@@ -37,15 +37,21 @@
#include <assert.h>
#undef assert
+
+#define ASSERT_SHOW_PROGNAME 1
+
+#ifdef ASSERT_SHOW_PROGNAME
+extern const char *__progname;
+#endif
+
#if 1
void __assert(const char *assertion, const char * filename,
int linenumber, register const char * function)
{
fprintf(stderr,
-#if 0
- /* TODO: support program_name like glibc? */
- "%s: %s: %d: %s: Assertion `%s' failed.\n", program_name,
+#ifdef ASSERT_SHOW_PROGNAME
+ "%s: %s: %d: %s: Assertion `%s' failed.\n", __progname,
#else
"%s: %d: %s: Assertion `%s' failed.\n",
#endif
@@ -66,8 +72,8 @@ void __assert(const char *assertion, const char * filename,
char buf[__BUFLEN_INT10TOSTR];
_stdio_fdout(STDERR_FILENO,
-#if 0
- program_name, /* TODO: support program_name like glibc? */
+#ifdef ASSERT_SHOW_PROGNAME
+ __progname,
": ",
#endif
filename,
diff --git a/libc/misc/ctype/Makefile b/libc/misc/ctype/Makefile
index 1d7c24535..2f1dd65f0 100644
--- a/libc/misc/ctype/Makefile
+++ b/libc/misc/ctype/Makefile
@@ -25,17 +25,26 @@ TOPDIR=../../../
include $(TOPDIR)Rules.mak
MSRC=ctype.c
-MOBJ= isalnum.o isalpha.o isascii.o iscntrl.o isdigit.o isgraph.o \
- islower.o isprint.o ispunct.o isspace.o isupper.o isxdigit.o \
- isxlower.o isxupper.o toascii.o tolower.o toupper.o isblank.o \
- __isctype_loc.o
+MOBJ= isalnum.o isalpha.o isascii.o iscntrl.o isdigit.o \
+ isgraph.o islower.o isprint.o ispunct.o isspace.o \
+ isupper.o isxdigit.o toascii.o tolower.o toupper.o \
+ isblank.o isctype.o isxlower.o isxupper.o \
+ __C_ctype_b.o __C_ctype_tolower.o __C_ctype_toupper.o \
+ __ctype_b_loc.o __ctype_tolower_loc.o __ctype_toupper_loc.o \
+ __ctype_assert.o
-CSRC=junk.c
-COBJS=$(patsubst %.c,%.o, $(CSRC))
+MOBJx= isalnum_l.o isalpha_l.o isascii_l.o iscntrl_l.o isdigit_l.o \
+ isgraph_l.o islower_l.o isprint_l.o ispunct_l.o isspace_l.o \
+ isupper_l.o isxdigit_l.o toascii_l.o tolower_l.o toupper_l.o \
+ isblank_l.o # isxlower_l.o isxupper_l.o
+OBJS=$(MOBJ)
-OBJS=$(MOBJ) $(COBJS)
-all: $(MOBJ) $(LIBC)
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+ OBJS += $(MOBJx)
+endif
+
+all: $(OBJS) $(LIBC)
$(LIBC): ar-target
@@ -46,8 +55,8 @@ $(MOBJ): $(MSRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
-$(COBJS): %.o : %.c
- $(CC) $(CFLAGS) -c $< -o $@
+$(MOBJx): $(MSRC)
+ $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
$(OBJS): Makefile
diff --git a/libc/misc/ctype/ctype.c b/libc/misc/ctype/ctype.c
index dedd5c00a..0eb97140d 100644
--- a/libc/misc/ctype/ctype.c
+++ b/libc/misc/ctype/ctype.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Manuel Novoa III
+/* Copyright (C) 2003 Manuel Novoa III
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -31,299 +31,1026 @@
#include <ctype.h>
#include <stdio.h>
+#include <stdlib.h>
#include <limits.h>
+#include <stdint.h>
#include <assert.h>
#include <locale.h>
+#ifdef __UCLIBC_HAS_XLOCALE__
+#include <xlocale.h>
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
/**********************************************************************/
-extern int __isctype_loc(int c, int ct);
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
-/* Some macros used throughout the file. */
-#define U ((unsigned char)c)
-/* #define LCT (__cur_locale->ctype) */
-#define LCT (&__global_locale)
+#if EOF >= CHAR_MIN
+#define CTYPE_DOMAIN_CHECK(C) \
+ (((unsigned int)((C) - CHAR_MIN)) <= (UCHAR_MAX - CHAR_MIN))
+#else
+#define CTYPE_DOMAIN_CHECK(C) \
+ ((((unsigned int)((C) - CHAR_MIN)) <= (UCHAR_MAX - CHAR_MIN)) || ((C) == EOF))
+#endif
-/**********************************************************************/
+#else /* __UCLIBC_HAS_CTYPE_SIGNED__ */
-#ifndef __PASTE
-#define __PASTE(X,Y) X ## Y
+#if EOF == -1
+#define CTYPE_DOMAIN_CHECK(C) \
+ (((unsigned int)((C) - EOF)) <= (UCHAR_MAX - EOF))
+#else
+#define CTYPE_DOMAIN_CHECK(C) \
+ ((((unsigned int)(C)) <= UCHAR_MAX) || ((C) == EOF))
#endif
-#define C_MACRO(X) __PASTE(__C_,X)(c)
-
-#define CT_MACRO(X) __PASTE(__ctype_,X)(c)
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__ */
/**********************************************************************/
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_isspace
+/* emit only once */
+#warning CONSIDER: Should we assert when debugging and __UCLIBC_HAS_CTYPE_CHECKED?
+#warning TODO: Fix asserts in to{upper|lower}{_l}.
+#warning TODO: Optimize the isx*() funcs.
+#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#undef CTYPE_NAME
+#undef ISCTYPE
+#undef CTYPE_ALIAS
+#ifdef __UCLIBC_DO_XLOCALE
+#define CTYPE_NAME(X) __is ## X ## _l
+#define ISCTYPE(C,F) __isctype_l( C, F, locale_arg)
+#define CTYPE_ALIAS(NAME) weak_alias( __is ## NAME ## _l , is ## NAME ## _l)
+#else
+#define CTYPE_NAME(X) is ## X
+#define ISCTYPE(C,F) __isctype( C, F )
+#define CTYPE_ALIAS(NAME)
+#endif
+#undef PASTE2
+#define PASTE2(X,Y) X ## Y
-#ifndef __CTYPE_HAS_8_BIT_LOCALES
-#define IS_FUNC_BODY(NAME) \
-int NAME (int c) \
-{ \
- return C_MACRO(NAME); \
-}
+#undef CTYPE_BODY
+
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+/* Make sure assert is active for to*() funcs below. */
+#undef NDEBUG
+#include <assert.h>
+
+extern void __isctype_assert(int c, int mask) __attribute__ ((__noreturn__));
+
+#define CTYPE_BODY(NAME,C,MASK) \
+ if (CTYPE_DOMAIN_CHECK(C)) { \
+ return ISCTYPE(C, MASK); \
+ } \
+ __isctype_assert(C, MASK);
+
+#elif defined(__UCLIBC_HAS_CTYPE_CHECKED__)
+
+#define CTYPE_BODY(NAME,C,MASK) \
+ return CTYPE_DOMAIN_CHECK(C) \
+ ? ISCTYPE(C, MASK) \
+ : 0;
+
+#elif defined(__UCLIBC_HAS_CTYPE_UNSAFE__)
+
+#define CTYPE_BODY(NAME,C,MASK) \
+ return ISCTYPE(C, MASK);
+
+
+#else /* No checking done. */
+
+#error Unknown type of ctype checking!
+
+#endif
-#else
-/* It may be worth defining __isctype_loc over the whole range of char. */
-/* #define IS_FUNC_BODY(NAME) \ */
-/* int NAME (int c) \ */
-/* { \ */
-/* return __isctype_loc(c, __PASTE(_CTYPE_,NAME)); \ */
-/* } */
#define IS_FUNC_BODY(NAME) \
-int NAME (int c) \
+int CTYPE_NAME(NAME) (int c __LOCALE_PARAM ) \
{ \
- if (((unsigned int) c) <= 0x7f) { \
- return C_MACRO(NAME); \
- } \
- return __isctype_loc(c, __PASTE(_CTYPE_,NAME)); \
+ CTYPE_BODY(NAME,c,PASTE2(_IS,NAME)) \
+} \
+CTYPE_ALIAS(NAME)
+
+
+/**********************************************************************/
+#ifdef L___ctype_assert
+#ifdef __UCLIBC_HAS_CTYPE_ENFORCED__
+
+extern const char *__progname;
+
+void __isctype_assert(int c, int mask)
+{
+ fprintf(stderr, "%s: __is*{_l}(%d,%#x {locale})\n", __progname, c, mask);
+ abort();
}
-#endif /* __CTYPE_HAS_8_BIT_LOCALES */
+#endif
+#endif
+/**********************************************************************/
+#if defined(L_isalnum) || defined(L_isalnum_l)
+
+IS_FUNC_BODY(alnum);
+
+#endif
+/**********************************************************************/
+#if defined(L_isalpha) || defined(L_isalpha_l)
+IS_FUNC_BODY(alpha);
+
+#endif
/**********************************************************************/
-#ifdef L_isalnum
+#if defined(L_isblank) || defined(L_isblank_l)
-IS_FUNC_BODY(isalnum);
+IS_FUNC_BODY(blank);
#endif
/**********************************************************************/
-#ifdef L_isalpha
+#if defined(L_iscntrl) || defined(L_iscntrl_l)
-IS_FUNC_BODY(isalpha);
+IS_FUNC_BODY(cntrl);
#endif
/**********************************************************************/
-#ifdef L_isblank
+#if defined(L_isdigit) || defined(L_isdigit_l)
-/* Warning!!! This is correct for all the currently supported 8-bit locales.
- * If any are added though, this will need to be verified. */
+/* The standards require EOF < 0. */
+#if EOF >= CHAR_MIN
+#define __isdigit_char_or_EOF(C) __isdigit_char((C))
+#else
+#define __isdigit_char_or_EOF(C) __isdigit_int((C))
+#endif
-int isblank(int c)
+int CTYPE_NAME(digit) (int C __LOCALE_PARAM)
{
- return __isblank(c);
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ if (CTYPE_DOMAIN_CHECK(C)) {
+ return __isdigit_char_or_EOF(C); /* C is (unsigned) char or EOF. */
+ }
+ __isctype_assert(C, _ISdigit);
+#else
+ return __isdigit_int(C); /* C could be invalid. */
+#endif
}
+CTYPE_ALIAS(digit)
+
#endif
/**********************************************************************/
-#ifdef L_iscntrl
+#if defined(L_isgraph) || defined(L_isgraph_l)
-IS_FUNC_BODY(iscntrl);
+IS_FUNC_BODY(graph);
#endif
/**********************************************************************/
-#ifdef L_isdigit
+#if defined(L_islower) || defined(L_islower_l)
-int isdigit(int c)
-{
- return __isdigit(c);
-}
+IS_FUNC_BODY(lower);
#endif
/**********************************************************************/
-#ifdef L_isgraph
+#if defined(L_isprint) || defined(L_isprint_l)
-IS_FUNC_BODY(isgraph);
+IS_FUNC_BODY(print);
#endif
/**********************************************************************/
-#ifdef L_islower
+#if defined(L_ispunct) || defined(L_ispunct_l)
-IS_FUNC_BODY(islower);
+IS_FUNC_BODY(punct);
#endif
/**********************************************************************/
-#ifdef L_isprint
+#if defined(L_isspace) || defined(L_isspace_l)
-IS_FUNC_BODY(isprint);
+IS_FUNC_BODY(space);
#endif
/**********************************************************************/
-#ifdef L_ispunct
+#if defined(L_isupper) || defined(L_isupper_l)
-IS_FUNC_BODY(ispunct);
+IS_FUNC_BODY(upper);
#endif
/**********************************************************************/
-#ifdef L_isspace
+#if defined(L_isxdigit) || defined(L_isxdigit_l)
-/* Warning!!! This is correct for all the currently supported 8-bit locales.
- * If any are added though, this will need to be verified. */
+IS_FUNC_BODY(xdigit);
-int isspace(int c)
+#endif
+/**********************************************************************/
+#ifdef L_tolower
+
+int tolower(int c)
{
- return __isspace(c);
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(c));
+#endif
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? (__UCLIBC_CTYPE_TOLOWER)[c] : c;
}
#endif
/**********************************************************************/
-#ifdef L_isupper
+#ifdef L_tolower_l
+
+#undef tolower_l
-IS_FUNC_BODY(isupper);
+int tolower_l(int c, __locale_t l)
+{
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(c));
+#endif
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? l->__ctype_tolower[c] : c;
+}
#endif
/**********************************************************************/
-#ifdef L_isxdigit
+#ifdef L_toupper
-int isxdigit(int c)
+int toupper(int c)
{
- return __isxdigit(c);
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(c));
+#endif
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? (__UCLIBC_CTYPE_TOUPPER)[c] : c;
}
#endif
/**********************************************************************/
-#ifdef L_tolower
+#ifdef L_toupper_l
-#ifdef __CTYPE_HAS_8_BIT_LOCALES
+#undef toupper_l
-int tolower(int c)
+int toupper_l(int c, __locale_t l)
{
- return ((((unsigned int) c) <= 0x7f)
- || (LCT->encoding != __ctype_encoding_8_bit))
- ? __C_tolower(c)
- : ( __isctype_loc(c, _CTYPE_isupper)
- ? (unsigned char)
- ( U - LCT->tbl8uplow[ ((int)
- (LCT->idx8uplow[(U & 0x7f)
- >> Cuplow_IDX_SHIFT])
- << Cuplow_IDX_SHIFT)
- + (U & ((1 << Cuplow_IDX_SHIFT) - 1)) ])
- : c );
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(c));
+#endif
+ return __UCLIBC_CTYPE_IN_TO_DOMAIN(c) ? l->__ctype_toupper[c] : c;
}
-#else /* __CTYPE_HAS_8_BIT_LOCALES */
+#endif
+/**********************************************************************/
+#if defined(L_isascii) || defined(L_isascii_l)
-int tolower(int c)
+int __XL(isascii)(int c)
{
- return __C_tolower(c);
+ return __isascii(c); /* locale-independent */
}
-#endif /* __CTYPE_HAS_8_BIT_LOCALES */
-
#endif
/**********************************************************************/
-#ifdef L_toupper
-
-#ifdef __CTYPE_HAS_8_BIT_LOCALES
+#if defined(L_toascii) || defined(L_toascii_l)
-int toupper(int c)
+int __XL(toascii)(int c)
{
- return ((((unsigned int) c) <= 0x7f)
- || (LCT->encoding != __ctype_encoding_8_bit))
- ? __C_toupper(c)
- : ( __isctype_loc(c, _CTYPE_islower)
- ? (unsigned char)
- ( U + LCT->tbl8uplow[ ((int)
- (LCT->idx8uplow[(U & 0x7f)
- >> Cuplow_IDX_SHIFT])
- << Cuplow_IDX_SHIFT)
- + (U & ((1 << Cuplow_IDX_SHIFT) - 1)) ])
- : c );
+ return __toascii(c); /* locale-independent */
}
-#else /* __CTYPE_HAS_8_BIT_LOCALES */
+#endif
+/**********************************************************************/
+/* old uClibc extensions */
+/**********************************************************************/
+#ifdef L_isxlower
-int toupper(int c)
+int isxlower(int C)
{
- return __C_toupper(c);
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(C));
+ return (__isctype(C, (_ISxdigit|_ISupper)) == _ISxdigit);
+#elif defined(__UCLIBC_HAS_CTYPE_CHECKED__)
+ return CTYPE_DOMAIN_CHECK(C)
+ ? (__isctype(C, (_ISxdigit|_ISupper)) == _ISxdigit)
+ : 0;
+#elif defined(__UCLIBC_HAS_CTYPE_UNSAFE__)
+ return (__isctype(C, (_ISxdigit|_ISupper)) == _ISxdigit);
+#else /* No checking done. */
+#error Unknown type of ctype checking!
+#endif
}
-#endif /* __CTYPE_HAS_8_BIT_LOCALES */
+#endif
+/**********************************************************************/
+#ifdef L_isxupper
+
+int isxupper(int C)
+{
+#if defined(__UCLIBC_HAS_CTYPE_ENFORCED__)
+ assert(CTYPE_DOMAIN_CHECK(C));
+ return (__isctype(C, (_ISxdigit|_ISlower)) == _ISxdigit);
+#elif defined(__UCLIBC_HAS_CTYPE_CHECKED__)
+ return CTYPE_DOMAIN_CHECK(C)
+ ? (__isctype(C, (_ISxdigit|_ISlower)) == _ISxdigit)
+ : 0;
+#elif defined(__UCLIBC_HAS_CTYPE_UNSAFE__)
+ return (__isctype(C, (_ISxdigit|_ISlower)) == _ISxdigit);
+#else /* No checking done. */
+#error Unknown type of ctype checking!
+#endif
+}
#endif
/**********************************************************************/
-#ifdef L_isascii
+/* glibc extensions */
+/**********************************************************************/
+#ifdef L_isctype
-int isascii(int c)
+int isctype(int c, int mask)
{
- return __isascii(c);
+ CTYPE_BODY(NAME,c,mask)
}
#endif
/**********************************************************************/
-#ifdef L_toascii
+#if L___ctype_b_loc
+
+#ifdef __UCLIBC_HAS_XLOCALE__
-int toascii(int c)
+const uint16_t **__ctype_b_loc(void)
{
- return __toascii(c);
+ return &(__UCLIBC_CURLOCALE_DATA).__ctype_b;
}
#endif
+
+#endif
/**********************************************************************/
-#ifdef L_isxlower
+#if L___ctype_tolower_loc
+
+#ifdef __UCLIBC_HAS_XLOCALE__
-int isxlower(int c)
+const __ctype_touplow_t **__ctype_tolower_loc(void)
{
- return __isxlower(c);
+ return &(__UCLIBC_CURLOCALE_DATA).__ctype_tolower;
}
#endif
+
+#endif
/**********************************************************************/
-#ifdef L_isxupper
+#if L___ctype_toupper_loc
+
+#ifdef __UCLIBC_HAS_XLOCALE__
-int isxupper(int c)
+const __ctype_touplow_t **__ctype_toupper_loc(void)
{
- return __isxupper(c);
+ return &(__UCLIBC_CURLOCALE_DATA).__ctype_toupper;
}
#endif
+
+#endif
/**********************************************************************/
-#ifdef L___isctype_loc
-#ifdef __CTYPE_HAS_8_BIT_LOCALES
+#ifdef L___C_ctype_b
+
+const uint16_t __C_ctype_b_data[] = {
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ /* -128 M-^@ */ 0,
+ /* -127 M-^A */ 0,
+ /* -126 M-^B */ 0,
+ /* -125 M-^C */ 0,
+ /* -124 M-^D */ 0,
+ /* -123 M-^E */ 0,
+ /* -122 M-^F */ 0,
+ /* -121 M-^G */ 0,
+ /* -120 M-^H */ 0,
+ /* -119 M-^I */ 0,
+ /* -118 M-^J */ 0,
+ /* -117 M-^K */ 0,
+ /* -116 M-^L */ 0,
+ /* -115 M-^M */ 0,
+ /* -114 M-^N */ 0,
+ /* -113 M-^O */ 0,
+ /* -112 M-^P */ 0,
+ /* -111 M-^Q */ 0,
+ /* -110 M-^R */ 0,
+ /* -109 M-^S */ 0,
+ /* -108 M-^T */ 0,
+ /* -107 M-^U */ 0,
+ /* -106 M-^V */ 0,
+ /* -105 M-^W */ 0,
+ /* -104 M-^X */ 0,
+ /* -103 M-^Y */ 0,
+ /* -102 M-^Z */ 0,
+ /* -101 M-^[ */ 0,
+ /* -100 M-^\ */ 0,
+ /* -99 M-^] */ 0,
+ /* -98 M-^^ */ 0,
+ /* -97 M-^_ */ 0,
+ /* -96 M- */ 0,
+ /* -95 M-! */ 0,
+ /* -94 M-" */ 0,
+ /* -93 M-# */ 0,
+ /* -92 M-$ */ 0,
+ /* -91 M-% */ 0,
+ /* -90 M-& */ 0,
+ /* -89 M-' */ 0,
+ /* -88 M-( */ 0,
+ /* -87 M-) */ 0,
+ /* -86 M-* */ 0,
+ /* -85 M-+ */ 0,
+ /* -84 M-, */ 0,
+ /* -83 M-- */ 0,
+ /* -82 M-. */ 0,
+ /* -81 M-/ */ 0,
+ /* -80 M-0 */ 0,
+ /* -79 M-1 */ 0,
+ /* -78 M-2 */ 0,
+ /* -77 M-3 */ 0,
+ /* -76 M-4 */ 0,
+ /* -75 M-5 */ 0,
+ /* -74 M-6 */ 0,
+ /* -73 M-7 */ 0,
+ /* -72 M-8 */ 0,
+ /* -71 M-9 */ 0,
+ /* -70 M-: */ 0,
+ /* -69 M-; */ 0,
+ /* -68 M-< */ 0,
+ /* -67 M-= */ 0,
+ /* -66 M-> */ 0,
+ /* -65 M-? */ 0,
+ /* -64 M-@ */ 0,
+ /* -63 M-A */ 0,
+ /* -62 M-B */ 0,
+ /* -61 M-C */ 0,
+ /* -60 M-D */ 0,
+ /* -59 M-E */ 0,
+ /* -58 M-F */ 0,
+ /* -57 M-G */ 0,
+ /* -56 M-H */ 0,
+ /* -55 M-I */ 0,
+ /* -54 M-J */ 0,
+ /* -53 M-K */ 0,
+ /* -52 M-L */ 0,
+ /* -51 M-M */ 0,
+ /* -50 M-N */ 0,
+ /* -49 M-O */ 0,
+ /* -48 M-P */ 0,
+ /* -47 M-Q */ 0,
+ /* -46 M-R */ 0,
+ /* -45 M-S */ 0,
+ /* -44 M-T */ 0,
+ /* -43 M-U */ 0,
+ /* -42 M-V */ 0,
+ /* -41 M-W */ 0,
+ /* -40 M-X */ 0,
+ /* -39 M-Y */ 0,
+ /* -38 M-Z */ 0,
+ /* -37 M-[ */ 0,
+ /* -36 M-\ */ 0,
+ /* -35 M-] */ 0,
+ /* -34 M-^ */ 0,
+ /* -33 M-_ */ 0,
+ /* -32 M-` */ 0,
+ /* -31 M-a */ 0,
+ /* -30 M-b */ 0,
+ /* -29 M-c */ 0,
+ /* -28 M-d */ 0,
+ /* -27 M-e */ 0,
+ /* -26 M-f */ 0,
+ /* -25 M-g */ 0,
+ /* -24 M-h */ 0,
+ /* -23 M-i */ 0,
+ /* -22 M-j */ 0,
+ /* -21 M-k */ 0,
+ /* -20 M-l */ 0,
+ /* -19 M-m */ 0,
+ /* -18 M-n */ 0,
+ /* -17 M-o */ 0,
+ /* -16 M-p */ 0,
+ /* -15 M-q */ 0,
+ /* -14 M-r */ 0,
+ /* -13 M-s */ 0,
+ /* -12 M-t */ 0,
+ /* -11 M-u */ 0,
+ /* -10 M-v */ 0,
+ /* -9 M-w */ 0,
+ /* -8 M-x */ 0,
+ /* -7 M-y */ 0,
+ /* -6 M-z */ 0,
+ /* -5 M-{ */ 0,
+ /* -4 M-| */ 0,
+ /* -3 M-} */ 0,
+ /* -2 M-~ */ 0,
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__*/
+ /* -1 M-^? */ 0,
+ /* 0 ^@ */ _IScntrl,
+ /* 1 ^A */ _IScntrl,
+ /* 2 ^B */ _IScntrl,
+ /* 3 ^C */ _IScntrl,
+ /* 4 ^D */ _IScntrl,
+ /* 5 ^E */ _IScntrl,
+ /* 6 ^F */ _IScntrl,
+ /* 7 ^G */ _IScntrl,
+ /* 8 ^H */ _IScntrl,
+ /* 9 ^I */ _ISspace|_ISblank|_IScntrl,
+ /* 10 ^J */ _ISspace|_IScntrl,
+ /* 11 ^K */ _ISspace|_IScntrl,
+ /* 12 ^L */ _ISspace|_IScntrl,
+ /* 13 ^M */ _ISspace|_IScntrl,
+ /* 14 ^N */ _IScntrl,
+ /* 15 ^O */ _IScntrl,
+ /* 16 ^P */ _IScntrl,
+ /* 17 ^Q */ _IScntrl,
+ /* 18 ^R */ _IScntrl,
+ /* 19 ^S */ _IScntrl,
+ /* 20 ^T */ _IScntrl,
+ /* 21 ^U */ _IScntrl,
+ /* 22 ^V */ _IScntrl,
+ /* 23 ^W */ _IScntrl,
+ /* 24 ^X */ _IScntrl,
+ /* 25 ^Y */ _IScntrl,
+ /* 26 ^Z */ _IScntrl,
+ /* 27 ^[ */ _IScntrl,
+ /* 28 ^\ */ _IScntrl,
+ /* 29 ^] */ _IScntrl,
+ /* 30 ^^ */ _IScntrl,
+ /* 31 ^_ */ _IScntrl,
+ /* 32 */ _ISspace|_ISprint|_ISblank,
+ /* 33 ! */ _ISprint|_ISgraph|_ISpunct,
+ /* 34 " */ _ISprint|_ISgraph|_ISpunct,
+ /* 35 # */ _ISprint|_ISgraph|_ISpunct,
+ /* 36 $ */ _ISprint|_ISgraph|_ISpunct,
+ /* 37 % */ _ISprint|_ISgraph|_ISpunct,
+ /* 38 & */ _ISprint|_ISgraph|_ISpunct,
+ /* 39 ' */ _ISprint|_ISgraph|_ISpunct,
+ /* 40 ( */ _ISprint|_ISgraph|_ISpunct,
+ /* 41 ) */ _ISprint|_ISgraph|_ISpunct,
+ /* 42 * */ _ISprint|_ISgraph|_ISpunct,
+ /* 43 + */ _ISprint|_ISgraph|_ISpunct,
+ /* 44 , */ _ISprint|_ISgraph|_ISpunct,
+ /* 45 - */ _ISprint|_ISgraph|_ISpunct,
+ /* 46 . */ _ISprint|_ISgraph|_ISpunct,
+ /* 47 / */ _ISprint|_ISgraph|_ISpunct,
+ /* 48 0 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 49 1 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 50 2 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 51 3 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 52 4 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 53 5 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 54 6 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 55 7 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 56 8 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 57 9 */ _ISdigit|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 58 : */ _ISprint|_ISgraph|_ISpunct,
+ /* 59 ; */ _ISprint|_ISgraph|_ISpunct,
+ /* 60 < */ _ISprint|_ISgraph|_ISpunct,
+ /* 61 = */ _ISprint|_ISgraph|_ISpunct,
+ /* 62 > */ _ISprint|_ISgraph|_ISpunct,
+ /* 63 ? */ _ISprint|_ISgraph|_ISpunct,
+ /* 64 @ */ _ISprint|_ISgraph|_ISpunct,
+ /* 65 A */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 66 B */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 67 C */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 68 D */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 69 E */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 70 F */ _ISupper|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 71 G */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 72 H */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 73 I */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 74 J */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 75 K */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 76 L */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 77 M */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 78 N */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 79 O */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 80 P */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 81 Q */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 82 R */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 83 S */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 84 T */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 85 U */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 86 V */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 87 W */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 88 X */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 89 Y */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 90 Z */ _ISupper|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 91 [ */ _ISprint|_ISgraph|_ISpunct,
+ /* 92 \ */ _ISprint|_ISgraph|_ISpunct,
+ /* 93 ] */ _ISprint|_ISgraph|_ISpunct,
+ /* 94 ^ */ _ISprint|_ISgraph|_ISpunct,
+ /* 95 _ */ _ISprint|_ISgraph|_ISpunct,
+ /* 96 ` */ _ISprint|_ISgraph|_ISpunct,
+ /* 97 a */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 98 b */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 99 c */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 100 d */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 101 e */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 102 f */ _ISlower|_ISalpha|_ISxdigit|_ISprint|_ISgraph|_ISalnum,
+ /* 103 g */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 104 h */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 105 i */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 106 j */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 107 k */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 108 l */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 109 m */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 110 n */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 111 o */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 112 p */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 113 q */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 114 r */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 115 s */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 116 t */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 117 u */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 118 v */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 119 w */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 120 x */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 121 y */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 122 z */ _ISlower|_ISalpha|_ISprint|_ISgraph|_ISalnum,
+ /* 123 { */ _ISprint|_ISgraph|_ISpunct,
+ /* 124 | */ _ISprint|_ISgraph|_ISpunct,
+ /* 125 } */ _ISprint|_ISgraph|_ISpunct,
+ /* 126 ~ */ _ISprint|_ISgraph|_ISpunct,
+ /* 127 ^? */ _IScntrl,
+ /* 128 M-^@ */ 0,
+ /* 129 M-^A */ 0,
+ /* 130 M-^B */ 0,
+ /* 131 M-^C */ 0,
+ /* 132 M-^D */ 0,
+ /* 133 M-^E */ 0,
+ /* 134 M-^F */ 0,
+ /* 135 M-^G */ 0,
+ /* 136 M-^H */ 0,
+ /* 137 M-^I */ 0,
+ /* 138 M-^J */ 0,
+ /* 139 M-^K */ 0,
+ /* 140 M-^L */ 0,
+ /* 141 M-^M */ 0,
+ /* 142 M-^N */ 0,
+ /* 143 M-^O */ 0,
+ /* 144 M-^P */ 0,
+ /* 145 M-^Q */ 0,
+ /* 146 M-^R */ 0,
+ /* 147 M-^S */ 0,
+ /* 148 M-^T */ 0,
+ /* 149 M-^U */ 0,
+ /* 150 M-^V */ 0,
+ /* 151 M-^W */ 0,
+ /* 152 M-^X */ 0,
+ /* 153 M-^Y */ 0,
+ /* 154 M-^Z */ 0,
+ /* 155 M-^[ */ 0,
+ /* 156 M-^\ */ 0,
+ /* 157 M-^] */ 0,
+ /* 158 M-^^ */ 0,
+ /* 159 M-^_ */ 0,
+ /* 160 M- */ 0,
+ /* 161 M-! */ 0,
+ /* 162 M-" */ 0,
+ /* 163 M-# */ 0,
+ /* 164 M-$ */ 0,
+ /* 165 M-% */ 0,
+ /* 166 M-& */ 0,
+ /* 167 M-' */ 0,
+ /* 168 M-( */ 0,
+ /* 169 M-) */ 0,
+ /* 170 M-* */ 0,
+ /* 171 M-+ */ 0,
+ /* 172 M-, */ 0,
+ /* 173 M-- */ 0,
+ /* 174 M-. */ 0,
+ /* 175 M-/ */ 0,
+ /* 176 M-0 */ 0,
+ /* 177 M-1 */ 0,
+ /* 178 M-2 */ 0,
+ /* 179 M-3 */ 0,
+ /* 180 M-4 */ 0,
+ /* 181 M-5 */ 0,
+ /* 182 M-6 */ 0,
+ /* 183 M-7 */ 0,
+ /* 184 M-8 */ 0,
+ /* 185 M-9 */ 0,
+ /* 186 M-: */ 0,
+ /* 187 M-; */ 0,
+ /* 188 M-< */ 0,
+ /* 189 M-= */ 0,
+ /* 190 M-> */ 0,
+ /* 191 M-? */ 0,
+ /* 192 M-@ */ 0,
+ /* 193 M-A */ 0,
+ /* 194 M-B */ 0,
+ /* 195 M-C */ 0,
+ /* 196 M-D */ 0,
+ /* 197 M-E */ 0,
+ /* 198 M-F */ 0,
+ /* 199 M-G */ 0,
+ /* 200 M-H */ 0,
+ /* 201 M-I */ 0,
+ /* 202 M-J */ 0,
+ /* 203 M-K */ 0,
+ /* 204 M-L */ 0,
+ /* 205 M-M */ 0,
+ /* 206 M-N */ 0,
+ /* 207 M-O */ 0,
+ /* 208 M-P */ 0,
+ /* 209 M-Q */ 0,
+ /* 210 M-R */ 0,
+ /* 211 M-S */ 0,
+ /* 212 M-T */ 0,
+ /* 213 M-U */ 0,
+ /* 214 M-V */ 0,
+ /* 215 M-W */ 0,
+ /* 216 M-X */ 0,
+ /* 217 M-Y */ 0,
+ /* 218 M-Z */ 0,
+ /* 219 M-[ */ 0,
+ /* 220 M-\ */ 0,
+ /* 221 M-] */ 0,
+ /* 222 M-^ */ 0,
+ /* 223 M-_ */ 0,
+ /* 224 M-` */ 0,
+ /* 225 M-a */ 0,
+ /* 226 M-b */ 0,
+ /* 227 M-c */ 0,
+ /* 228 M-d */ 0,
+ /* 229 M-e */ 0,
+ /* 230 M-f */ 0,
+ /* 231 M-g */ 0,
+ /* 232 M-h */ 0,
+ /* 233 M-i */ 0,
+ /* 234 M-j */ 0,
+ /* 235 M-k */ 0,
+ /* 236 M-l */ 0,
+ /* 237 M-m */ 0,
+ /* 238 M-n */ 0,
+ /* 239 M-o */ 0,
+ /* 240 M-p */ 0,
+ /* 241 M-q */ 0,
+ /* 242 M-r */ 0,
+ /* 243 M-s */ 0,
+ /* 244 M-t */ 0,
+ /* 245 M-u */ 0,
+ /* 246 M-v */ 0,
+ /* 247 M-w */ 0,
+ /* 248 M-x */ 0,
+ /* 249 M-y */ 0,
+ /* 250 M-z */ 0,
+ /* 251 M-{ */ 0,
+ /* 252 M-| */ 0,
+ /* 253 M-} */ 0,
+ /* 254 M-~ */ 0,
+ /* 255 M-^? */ 0
+};
+
+const uint16_t *__C_ctype_b = __C_ctype_b_data + 1
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ + 127
+#endif
+ ;
+
+#ifndef __UCLIBC_HAS_XLOCALE__
+
+const uint16_t *__ctype_b = __C_ctype_b_data + 1
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ + 127
+#endif
+ ;
-/* This internal routine is similar to iswctype(), but it doesn't
- * work for any non-standard types, itdoesn't work for "xdigit"s,
- * and it doesn't work for chars between 0 and 0x7f (although that
- * may change). */
+#endif
-static const char ctype_range[] = {
- __CTYPE_RANGES
+#endif
+/**********************************************************************/
+#ifdef L___C_ctype_tolower
+
+const __ctype_touplow_t __C_ctype_tolower_data[] = {
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ -128, -127, -126, -125,
+ -124, -123, -122, -121,
+ -120, -119, -118, -117,
+ -116, -115, -114, -113,
+ -112, -111, -110, -109,
+ -108, -107, -106, -105,
+ -104, -103, -102, -101,
+ -100, -99, -98, -97,
+ -96, -95, -94, -93,
+ -92, -91, -90, -89,
+ -88, -87, -86, -85,
+ -84, -83, -82, -81,
+ -80, -79, -78, -77,
+ -76, -75, -74, -73,
+ -72, -71, -70, -69,
+ -68, -67, -66, -65,
+ -64, -63, -62, -61,
+ -60, -59, -58, -57,
+ -56, -55, -54, -53,
+ -52, -51, -50, -49,
+ -48, -47, -46, -45,
+ -44, -43, -42, -41,
+ -40, -39, -38, -37,
+ -36, -35, -34, -33,
+ -32, -31, -30, -29,
+ -28, -27, -26, -25,
+ -24, -23, -22, -21,
+ -20, -19, -18, -17,
+ -16, -15, -14, -13,
+ -12, -11, -10, -9,
+ -8, -7, -6, -5,
+ -4, -3, -2, -1,
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__*/
+ 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14, 15,
+ 16, 17, 18, 19,
+ 20, 21, 22, 23,
+ 24, 25, 26, 27,
+ 28, 29, 30, 31,
+ 32, 33, 34, 35,
+ 36, 37, 38, 39,
+ 40, 41, 42, 43,
+ 44, 45, 46, 47,
+ 48, 49, 50, 51,
+ 52, 53, 54, 55,
+ 56, 57, 58, 59,
+ 60, 61, 62, 63,
+ 64, 97 /* a */, 98 /* b */, 99 /* c */,
+ 100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
+ 104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
+ 108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
+ 112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
+ 116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
+ 120 /* x */, 121 /* y */, 122 /* z */, 91,
+ 92, 93, 94, 95,
+ 96, 97, 98, 99,
+ 100, 101, 102, 103,
+ 104, 105, 106, 107,
+ 108, 109, 110, 111,
+ 112, 113, 114, 115,
+ 116, 117, 118, 119,
+ 120, 121, 122, 123,
+ 124, 125, 126, 127,
+ 128, 129, 130, 131,
+ 132, 133, 134, 135,
+ 136, 137, 138, 139,
+ 140, 141, 142, 143,
+ 144, 145, 146, 147,
+ 148, 149, 150, 151,
+ 152, 153, 154, 155,
+ 156, 157, 158, 159,
+ 160, 161, 162, 163,
+ 164, 165, 166, 167,
+ 168, 169, 170, 171,
+ 172, 173, 174, 175,
+ 176, 177, 178, 179,
+ 180, 181, 182, 183,
+ 184, 185, 186, 187,
+ 188, 189, 190, 191,
+ 192, 193, 194, 195,
+ 196, 197, 198, 199,
+ 200, 201, 202, 203,
+ 204, 205, 206, 207,
+ 208, 209, 210, 211,
+ 212, 213, 214, 215,
+ 216, 217, 218, 219,
+ 220, 221, 222, 223,
+ 224, 225, 226, 227,
+ 228, 229, 230, 231,
+ 232, 233, 234, 235,
+ 236, 237, 238, 239,
+ 240, 241, 242, 243,
+ 244, 245, 246, 247,
+ 248, 249, 250, 251,
+ 252, 253, 254, 255
};
-int __isctype_loc(int c, int ct)
-{
- unsigned char d;
+const __ctype_touplow_t *__C_ctype_tolower = __C_ctype_tolower_data
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ + 128
+#endif
+ ;
- assert(((unsigned int)ct) < _CTYPE_isxdigit);
- assert(((unsigned int)c) > 0x7f);
+#ifndef __UCLIBC_HAS_XLOCALE__
-#if (CHAR_MIN == 0) /* We don't have signed chars... */
- if ((LCT->encoding != __ctype_encoding_8_bit)
- || (((unsigned int) c) > UCHAR_MAX)
- ) {
- return 0;
- }
-#else
- /* Allow non-EOF negative char values for glibc compatiblity. */
- if ((LCT->encoding != __ctype_encoding_8_bit) || (c == EOF)
- || ( ((unsigned int)(c - CHAR_MIN)) > (UCHAR_MAX - CHAR_MIN))
- ) {
- return 0;
- }
+const __ctype_touplow_t *__ctype_tolower = __C_ctype_tolower_data
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ + 128
#endif
+ ;
- /* TODO - test assumptions??? 8-bit chars -- or ensure in generator. */
+#endif
-#define Cctype_TBL_MASK ((1 << Cctype_IDX_SHIFT) - 1)
-#define Cctype_IDX_OFFSET (128 >> Cctype_IDX_SHIFT)
+#endif
+/**********************************************************************/
+#ifdef L___C_ctype_toupper
+
+const __ctype_touplow_t __C_ctype_toupper_data[] = {
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ -128, -127, -126, -125,
+ -124, -123, -122, -121,
+ -120, -119, -118, -117,
+ -116, -115, -114, -113,
+ -112, -111, -110, -109,
+ -108, -107, -106, -105,
+ -104, -103, -102, -101,
+ -100, -99, -98, -97,
+ -96, -95, -94, -93,
+ -92, -91, -90, -89,
+ -88, -87, -86, -85,
+ -84, -83, -82, -81,
+ -80, -79, -78, -77,
+ -76, -75, -74, -73,
+ -72, -71, -70, -69,
+ -68, -67, -66, -65,
+ -64, -63, -62, -61,
+ -60, -59, -58, -57,
+ -56, -55, -54, -53,
+ -52, -51, -50, -49,
+ -48, -47, -46, -45,
+ -44, -43, -42, -41,
+ -40, -39, -38, -37,
+ -36, -35, -34, -33,
+ -32, -31, -30, -29,
+ -28, -27, -26, -25,
+ -24, -23, -22, -21,
+ -20, -19, -18, -17,
+ -16, -15, -14, -13,
+ -12, -11, -10, -9,
+ -8, -7, -6, -5,
+ -4, -3, -2, -1,
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__*/
+ 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14, 15,
+ 16, 17, 18, 19,
+ 20, 21, 22, 23,
+ 24, 25, 26, 27,
+ 28, 29, 30, 31,
+ 32, 33, 34, 35,
+ 36, 37, 38, 39,
+ 40, 41, 42, 43,
+ 44, 45, 46, 47,
+ 48, 49, 50, 51,
+ 52, 53, 54, 55,
+ 56, 57, 58, 59,
+ 60, 61, 62, 63,
+ 64, 65, 66, 67,
+ 68, 69, 70, 71,
+ 72, 73, 74, 75,
+ 76, 77, 78, 79,
+ 80, 81, 82, 83,
+ 84, 85, 86, 87,
+ 88, 89, 90, 91,
+ 92, 93, 94, 95,
+ 96, 65 /* A */, 66 /* B */, 67 /* C */,
+ 68 /* D */, 69 /* E */, 70 /* F */, 71 /* G */,
+ 72 /* H */, 73 /* I */, 74 /* J */, 75 /* K */,
+ 76 /* L */, 77 /* M */, 78 /* N */, 79 /* O */,
+ 80 /* P */, 81 /* Q */, 82 /* R */, 83 /* S */,
+ 84 /* T */, 85 /* U */, 86 /* V */, 87 /* W */,
+ 88 /* X */, 89 /* Y */, 90 /* Z */, 123,
+ 124, 125, 126, 127,
+ 128, 129, 130, 131,
+ 132, 133, 134, 135,
+ 136, 137, 138, 139,
+ 140, 141, 142, 143,
+ 144, 145, 146, 147,
+ 148, 149, 150, 151,
+ 152, 153, 154, 155,
+ 156, 157, 158, 159,
+ 160, 161, 162, 163,
+ 164, 165, 166, 167,
+ 168, 169, 170, 171,
+ 172, 173, 174, 175,
+ 176, 177, 178, 179,
+ 180, 181, 182, 183,
+ 184, 185, 186, 187,
+ 188, 189, 190, 191,
+ 192, 193, 194, 195,
+ 196, 197, 198, 199,
+ 200, 201, 202, 203,
+ 204, 205, 206, 207,
+ 208, 209, 210, 211,
+ 212, 213, 214, 215,
+ 216, 217, 218, 219,
+ 220, 221, 222, 223,
+ 224, 225, 226, 227,
+ 228, 229, 230, 231,
+ 232, 233, 234, 235,
+ 236, 237, 238, 239,
+ 240, 241, 242, 243,
+ 244, 245, 246, 247,
+ 248, 249, 250, 251,
+ 252, 253, 254, 255
+};
+
+const __ctype_touplow_t *__C_ctype_toupper = __C_ctype_toupper_data
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ + 128
+#endif
+ ;
+
+#ifndef __UCLIBC_HAS_XLOCALE__
+
+const __ctype_touplow_t *__ctype_toupper = __C_ctype_toupper_data
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+ + 128
+#endif
+ ;
- c &= 0x7f;
-#ifdef Cctype_PACKED
- d = LCT->tbl8ctype[ ((int)(LCT->idx8ctype[(U >> Cctype_IDX_SHIFT) ])
- << (Cctype_IDX_SHIFT - 1))
- + ((U & Cctype_TBL_MASK) >> 1)];
- d = (U & 1) ? (d >> 4) : (d & 0xf);
-#else
- d = LCT->tbl8ctype[ ((int)(LCT->idx8ctype[(U >> Cctype_IDX_SHIFT) ])
- << Cctype_IDX_SHIFT)
- + (U & Cctype_TBL_MASK) ];
#endif
- return ( ((unsigned char)(d - ctype_range[2*ct])) <= ctype_range[2*ct+1] );
-}
-#endif /* __CTYPE_HAS_8_BIT_LOCALES */
#endif
/**********************************************************************/
diff --git a/libc/misc/intl/Makefile b/libc/misc/intl/Makefile
new file mode 100644
index 000000000..75fbb321f
--- /dev/null
+++ b/libc/misc/intl/Makefile
@@ -0,0 +1,50 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000 by Lineo, inc.
+# Copyright (C) 2000,2001 Erik Andersen <andersen@uclibc.org>
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Library General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Derived in part from the Linux-8086 C library, the GNU C Library, and several
+# other sundry sources. Files within this library are copyright by their
+# respective copyright holders.
+
+TOPDIR=../../../
+include $(TOPDIR)Rules.mak
+
+MSRC= intl.c
+MOBJ= gettext.o ngettext.o dgettext.o dcgettext.o dngettext.o dcngettext.o \
+ textdomain.o bindtextdomain.o bind_textdomain_codeset.o
+
+OBJS=$(MOBJ)
+
+all: $(OBJS) $(LIBC)
+
+$(LIBC): ar-target
+
+ar-target: $(OBJS)
+ $(AR) $(ARFLAGS) $(LIBC) $(OBJS)
+
+$(MOBJ): $(MSRC)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+$(COBJS): %.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+clean:
+ rm -f *.[oa] *~ core
+
diff --git a/libc/misc/intl/intl.c b/libc/misc/intl/intl.c
new file mode 100644
index 000000000..183ffcc92
--- /dev/null
+++ b/libc/misc/intl/intl.c
@@ -0,0 +1,149 @@
+/* Copyright (C) 2003 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * Supply some weaks for gettext and friends. Used by strerror*().
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#undef __OPTIMIZE__
+#include <libintl.h>
+
+/**********************************************************************/
+#ifdef L_gettext
+
+char *weak_function gettext(const char *msgid)
+{
+ return (char *) msgid;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_dgettext
+
+char *__uClibc_dgettext(const char *domainname,
+ const char *msgid)
+{
+ return (char *) msgid;
+}
+
+weak_alias (__uClibc_dgettext, __dgettext)
+weak_alias (__uClibc_dgettext, dgettext)
+
+#endif
+/**********************************************************************/
+#ifdef L_dcgettext
+
+char * __uClibc_dcgettext(const char *domainname,
+ const char *msgid, int category)
+{
+ return (char *) msgid;
+}
+
+weak_alias (__uClibc_dcgettext, __dcgettext)
+weak_alias (__uClibc_dcgettext, dcgettext)
+
+#endif
+/**********************************************************************/
+#ifdef L_ngettext
+
+char *weak_function ngettext(const char *msgid1, const char *msgid2,
+ unsigned long int n)
+{
+ return (char *) ((n == 1) ? msgid1 : msgid2);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_dngettext
+
+char *weak_function dngettext(const char *domainname, const char *msgid1,
+ const char *msgid2, unsigned long int n)
+{
+ return (char *) ((n == 1) ? msgid1 : msgid2);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_dcngettext
+
+char *weak_function dcngettext(const char *domainname, const char *msgid1,
+ const char *msgid2, unsigned long int n,
+ int category)
+{
+ return (char *) ((n == 1) ? msgid1 : msgid2);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_textdomain
+
+char *weak_function textdomain(const char *domainname)
+{
+ static const char default_str[] = "messages";
+
+ if (domainname && *domainname && strcmp(domainname, default_str)) {
+ __set_errno(EINVAL);
+ return NULL;
+ }
+ return (char *) default_str;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_bindtextdomain
+
+char *weak_function bindtextdomain(const char *domainname, const char *dirname)
+{
+ static const char dir[] = "/";
+
+ if (!domainname || !*domainname
+ || (dirname
+#if 1
+ && ((dirname[0] != '/') || dirname[1])
+#else
+ && strcmp(dirname, dir)
+#endif
+ )
+ ) {
+ __set_errno(EINVAL);
+ return NULL;
+ }
+
+ return (char *) dir;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_bind_textdomain_codeset
+
+/* Specify the character encoding in which the messages from the
+ DOMAINNAME message catalog will be returned. */
+char *weak_function bind_textdomain_codeset(const char *domainname,
+ const char *codeset)
+{
+ if (!domainname || !*domainname || codeset) {
+ __set_errno(EINVAL);
+ }
+ return NULL;
+}
+
+#endif
+/**********************************************************************/
diff --git a/libc/misc/locale/Makefile b/libc/misc/locale/Makefile
index 29c8cd5a0..8ad041e69 100644
--- a/libc/misc/locale/Makefile
+++ b/libc/misc/locale/Makefile
@@ -26,14 +26,29 @@ include $(TOPDIR)Rules.mak
MSRC= locale.c
MOBJ= setlocale.o localeconv.o _locale_init.o nl_langinfo.o
+MOBJx=
-OBJS= $(MOBJ)
+ifeq ($(UCLIBC_HAS_LOCALE),y)
+ MOBJ += newlocale.o __locale_mbrtowc_l.o
+endif
+
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+ MOBJx += nl_langinfo_l.o duplocale.o freelocale.o uselocale.o __curlocale.o
+endif
+
+OBJS= $(MOBJ) $(MOBJx)
ifeq ($(UCLIBC_HAS_LOCALE),y)
- OBJS += locale_data.o
+ OBJS += $(COBJS) locale_data.o
endif
-all: data $(OBJS) $(LIBC)
+DATA=
+ifeq ($(UCLIBC_HAS_LOCALE),y)
+ DATA += locale_data.o
+endif
+
+all: $(DATA) $(OBJS) $(LIBC)
+
$(LIBC): ar-target
@@ -44,12 +59,14 @@ $(MOBJ): $(MSRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
+$(MOBJx): $(MSRC)
+ $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
$(OBJS): Makefile
-data:
-ifeq ($(UCLIBC_HAS_LOCALE),y)
- make -C $(TOPDIR)/extra/locale
-endif
+# locale_data.o:
+# make -C $(TOPDIR)/extra/locale
clean:
rm -f *.[oa] *~ core
diff --git a/libc/misc/locale/locale.c b/libc/misc/locale/locale.c
index 9c162a980..071a8df71 100644
--- a/libc/misc/locale/locale.c
+++ b/libc/misc/locale/locale.c
@@ -36,28 +36,94 @@
*/
#define _GNU_SOURCE
-#include <locale.h>
+
+#define __CTYPE_HAS_8_BIT_LOCALES 1
+
+
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <limits.h>
#include <stdint.h>
#include <assert.h>
+#include <errno.h>
+#include <ctype.h>
+
+#undef __LOCALE_C_ONLY
+#ifndef __UCLIBC_HAS_LOCALE__
+#define __LOCALE_C_ONLY
+#endif /* __UCLIBC_HAS_LOCALE__ */
+
+
+#ifdef __LOCALE_C_ONLY
+
+#include <locale.h>
+
+#else /* __LOCALE_C_ONLY */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_setlocale
+#warning TODO: Fix the __CTYPE_HAS_8_BIT_LOCALES define at the top of the file.
+#warning TODO: Fix __WCHAR_ENABLED.
+#endif
+#endif
-#ifndef __LOCALE_C_ONLY
+/* Need to include this before locale.h and xlocale.h! */
+#include <bits/uClibc_locale.h>
-#define CUR_LOCALE_SPEC (__global_locale.cur_locale)
#undef CODESET_LIST
#define CODESET_LIST (__locale_mmap->codeset_list)
+#ifdef __UCLIBC_HAS_XLOCALE__
+#include <xlocale.h>
+#include <locale.h>
+#else /* __UCLIBC_HAS_XLOCALE__ */
+/* We need this internally... */
+#define __UCLIBC_HAS_XLOCALE__ 1
+#include <xlocale.h>
+#include <locale.h>
+#undef __UCLIBC_HAS_XLOCALE__
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+#include <wchar.h>
+
+#define LOCALE_NAMES (__locale_mmap->locale_names5)
+#define LOCALES (__locale_mmap->locales)
+#define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers)
+#define CATEGORY_NAMES (__locale_mmap->lc_names)
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: redo the MAX_LOCALE_STR stuff...
+#endif
+#define MAX_LOCALE_STR 256 /* TODO: Only sufficient for current case. */
+#define MAX_LOCALE_CATEGORY_STR 32 /* TODO: Only sufficient for current case. */
+/* Note: Best if MAX_LOCALE_CATEGORY_STR is a power of 2. */
+
+extern int _locale_set_l(const unsigned char *p, __locale_t base);
+extern void _locale_init_l(__locale_t base);
+
#endif /* __LOCALE_C_ONLY */
+#undef LOCALE_STRING_SIZE
+#define LOCALE_SELECTOR_SIZE (2 * __LC_ALL + 2)
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_setlocale
+#warning TODO: Create a C locale selector string.
+#endif
+#endif
+#define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
+
+
+#include <langinfo.h>
+#include <nl_types.h>
+
/**********************************************************************/
#ifdef L_setlocale
#ifdef __LOCALE_C_ONLY
-link_warning(setlocale,"the 'setlocale' function supports only C|POSIX locales")
+link_warning(setlocale,"REMINDER: The 'setlocale' function supports only C|POSIX locales.")
static const char C_string[] = "C";
@@ -74,273 +140,125 @@ char *setlocale(int category, register const char *locale)
#else /* ---------------------------------------------- __LOCALE_C_ONLY */
-#if !defined(NUM_LOCALES) || (NUM_LOCALES <= 1)
-#error locales enabled, but not data other than for C locale!
+#ifdef __UCLIBC_HAS_THREADS__
+link_warning(setlocale,"REMINDER: The 'setlocale' function is _not_ threadsafe except for simple queries.")
#endif
-#define LOCALE_NAMES (__locale_mmap->locale_names5)
-#define LOCALES (__locale_mmap->locales)
-#define LOCALE_AT_MODIFIERS (__locale_mmap->locale_at_modifiers)
-#define CATEGORY_NAMES (__locale_mmap->lc_names)
+#if !defined(__LOCALE_DATA_NUM_LOCALES) || (__LOCALE_DATA_NUM_LOCALES <= 1)
+#error locales enabled, but not data other than for C locale!
+#endif
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Move posix and utf8 strings.
+#endif
static const char posix[] = "POSIX";
static const char utf8[] = "UTF-8";
#ifdef __UCLIBC_MJN3_ONLY__
-#warning REMINDER: redo the MAX_LOCALE_STR stuff...
+#warning TODO: Fix dimensions of hr_locale.
#endif
-#define MAX_LOCALE_STR 256 /* TODO: Only sufficient for current case. */
-
-static char hr_locale[MAX_LOCALE_STR];
+/* Individual category strings start at hr_locale + category * MAX_LOCALE_CATEGORY.
+ * This holds for LC_ALL as well.
+ */
+static char hr_locale[(MAX_LOCALE_CATEGORY_STR * LC_ALL) + MAX_LOCALE_STR];
-static __inline char *human_readable_locale(int category, const unsigned char *s)
+static void update_hr_locale(const unsigned char *spec)
{
const unsigned char *loc;
+ const unsigned char *s;
char *n;
- int i;
-
- ++s;
-
- if (category == LC_ALL) {
- for (i = 0 ; i < LC_ALL-1 ; i += 2) {
- if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) {
- goto SKIP;
- }
- }
- /* All categories the same, so simplify string by using a single
- * category. */
- category = LC_CTYPE;
- }
-
- SKIP:
- i = (category == LC_ALL) ? 0 : category;
- s += 2*i;
- n = hr_locale;
+ int i, category, done;
+ done = category = 0;
do {
- if ((*s != 0xff) || (s[1] != 0xff)) {
- loc = LOCALES + WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7) + (s[1] & 0x7f));
- if (category == LC_ALL) {
- n = stpcpy(n, CATEGORY_NAMES + (int) CATEGORY_NAMES[i]);
- *n++ = '=';
- }
- if (*loc == 0) {
- *n++ = 'C';
- *n = 0;
- } else {
- char at = 0;
- memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5);
- if (n[2] != '_') {
- at = n[2];
- n[2] = '_';
- }
- n += 5;
- *n++ = '.';
- if (loc[2] == 2) {
- n = stpcpy(n, utf8);
- } else if (loc[2] >= 3) {
- n = stpcpy(n, CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3]));
- }
- if (at) {
- const char *q;
- *n++ = '@';
- q = LOCALE_AT_MODIFIERS;
- do {
- if (q[1] == at) {
- n = stpcpy(n, q+2);
- break;
- }
- q += 2 + *q;
- } while (*q);
+ s = spec + 1;
+ n = hr_locale + category * MAX_LOCALE_CATEGORY_STR;
+
+ if (category == LC_ALL) {
+ done = 1;
+ for (i = 0 ; i < LC_ALL-1 ; i += 2) {
+ if ((s[i] != s[i+2]) || (s[i+1] != s[i+3])) {
+ goto SKIP;
}
}
- *n++ = ';';
+ /* All categories the same, so simplify string by using a single
+ * category. */
+ category = LC_CTYPE;
}
- s += 2;
- } while (++i < category);
- *--n = 0; /* Remove trailing ';' and nul-terminate. */
- assert(n-hr_locale < MAX_LOCALE_STR);
- return hr_locale;
-}
-
-static int find_locale(int category, const char *p, unsigned char *new_locale)
-{
- int i;
- const unsigned char *s;
- uint16_t n;
- unsigned char lang_cult, codeset;
-
-#if defined(LOCALE_AT_MODIFIERS_LENGTH) && 1
- /* Support standard locale handling for @-modifiers. */
+ SKIP:
+ i = (category == LC_ALL) ? 0 : category;
+ s += 2*i;
-#ifdef __UCLIBC_MJN3_ONLY__
-#warning REMINDER: fix buf size in find_locale
-#endif
- char buf[18]; /* TODO: 7+{max codeset name length} */
- const char *q;
-
- if ((q = strchr(p,'@')) != NULL) {
- if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) {
- return 0;
- }
- /* locale name at least 5 chars long and 3rd char is '_' */
- s = LOCALE_AT_MODIFIERS;
do {
- if (!strcmp(s+2, q+1)) {
- break;
- }
- s += 2 + *s; /* TODO - fix this throughout */
- } while (*s);
- if (!*s) {
- return 0;
- }
- assert(q - p < sizeof(buf));
- memcpy(buf, p, q-p);
- buf[q-p] = 0;
- buf[2] = s[1];
- p = buf;
- }
-#endif
-
- lang_cult = codeset = 0; /* Assume C and default codeset. */
- if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) {
- goto FIND_LOCALE;
- }
-
- if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */
- /* TODO: maybe CODESET_LIST + *s ??? */
- /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
- codeset = 2;
- if (strcmp(utf8,p+6) != 0) {/* TODO - fix! */
- s = CODESET_LIST;
- do {
- ++codeset; /* Increment codeset first. */
- if (!strcmp(CODESET_LIST+*s, p+6)) {
- goto FIND_LANG_CULT;
+ if ((*s != 0xff) || (s[1] != 0xff)) {
+ loc = LOCALES
+ + __LOCALE_DATA_WIDTH_LOCALES * ((((int)(*s & 0x7f)) << 7)
+ + (s[1] & 0x7f));
+ if (category == LC_ALL) {
+ n = stpcpy(n, CATEGORY_NAMES + (int) CATEGORY_NAMES[i]);
+ *n++ = '=';
}
- } while (*++s);
- return 0; /* No matching codeset! */
- }
- }
-
- FIND_LANG_CULT: /* Find language_culture number. */
- s = LOCALE_NAMES;
- do { /* TODO -- do a binary search? */
- /* TODO -- fix gen_mmap!*/
- ++lang_cult; /* Increment first since C/POSIX is 0. */
- if (!strncmp(s,p,5)) { /* Found a matching locale name; */
- goto FIND_LOCALE;
- }
- s += 5;
- } while (lang_cult < NUM_LOCALE_NAMES);
- return 0; /* No matching language_culture! */
-
- FIND_LOCALE: /* Find locale row matching name and codeset */
- s = LOCALES;
- n = 0;
- do { /* TODO -- do a binary search? */
- if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) {
- i = ((category == LC_ALL) ? 0 : category);
- s = new_locale + 2*i;
- do {
- /* Encode current locale row number. */
- *((unsigned char *) ++s) = (n >> 7) | 0x80;
- *((unsigned char *) ++s) = (n & 0x7f) | 0x80;
- } while (++i < category);
-
- return i; /* Return non-zero */
- }
- s += WIDTH_LOCALES;
- ++n;
- } while (n <= NUM_LOCALES); /* We started at 1!!! */
-
- return 0; /* Unsupported locale. */
-}
-
-static unsigned char *composite_locale(int category, const char *locale, unsigned char *new_locale)
-{
- char buf[MAX_LOCALE_STR];
- char *t;
- char *e;
- int c;
-
- if (!strchr(locale,'=')) {
- if (!find_locale(category, locale, new_locale)) {
- return NULL;
- }
- return new_locale;
- }
-
- if (strlen(locale) >= sizeof(buf)) {
- return NULL;
- }
- stpcpy(buf, locale);
-
- t = strtok_r(buf, "=", &e); /* This can't fail because of strchr test above. */
- do {
- for (c = 0 ; c < LC_ALL ; c++) { /* Find the category... */
- if (!strcmp(CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) {
- break;
- }
- }
- t = strtok_r(NULL, ";", &e);
- if ((category == LC_ALL) || (c == category)) {
- if (!t || !find_locale(c, t, new_locale)) {
- return NULL;
+ if (*loc == 0) {
+ *n++ = 'C';
+ *n = 0;
+ } else {
+ char at = 0;
+ memcpy(n, LOCALE_NAMES + 5*((*loc)-1), 5);
+ if (n[2] != '_') {
+ at = n[2];
+ n[2] = '_';
+ }
+ n += 5;
+ *n++ = '.';
+ if (loc[2] == 2) {
+ n = stpcpy(n, utf8);
+ } else if (loc[2] >= 3) {
+ n = stpcpy(n, CODESET_LIST + (int)(CODESET_LIST[loc[2] - 3]));
+ }
+ if (at) {
+ const char *q;
+ *n++ = '@';
+ q = LOCALE_AT_MODIFIERS;
+ do {
+ if (q[1] == at) {
+ n = stpcpy(n, q+2);
+ break;
+ }
+ q += 2 + *q;
+ } while (*q);
+ }
+ }
+ *n++ = ';';
}
- }
- } while ((t = strtok_r(NULL, "=", &e)) != NULL);
+ s += 2;
+ } while (++i < category);
+ *--n = 0; /* Remove trailing ';' and nul-terminate. */
- return new_locale;
+ ++category;
+ } while (!done);
}
char *setlocale(int category, const char *locale)
{
- const unsigned char *p;
- int i;
- unsigned char new_locale[LOCALE_STRING_SIZE];
-
if (((unsigned int)(category)) > LC_ALL) {
- /* TODO - set errno? SUSv3 doesn't say too. */
+#if 0
+ __set_errno(EINVAL); /* glibc sets errno -- SUSv3 doesn't say. */
+#endif
return NULL; /* Illegal/unsupported category. */
}
- if (locale != NULL) { /* Not just a query... */
- stpcpy(new_locale, CUR_LOCALE_SPEC); /* Start with current. */
-
- if (!*locale) { /* locale == "", so check environment. */
- i = ((category == LC_ALL) ? 0 : category);
- do {
- /* Note: SUSv3 doesn't define a fallback mechanism here. So,
- * if LC_ALL is invalid, we do _not_ continue trying the other
- * environment vars. */
- if (!(p = getenv("LC_ALL"))) {
- if (!(p = getenv(CATEGORY_NAMES + CATEGORY_NAMES[i]))) {
- if (!(p = getenv("LANG"))) {
- p = posix;
- }
- }
- }
-
- /* The user set something... is it valid? */
- /* Note: Since we don't support user-supplied locales and
- * alternate paths, we don't need to worry about special
- * handling for suid/sgid apps. */
- if (!find_locale(i, p, new_locale)) {
- return NULL;
- }
- } while (++i < category);
- } else if (!composite_locale(category, locale, new_locale)) {
+ if (locale != NULL) { /* Not just a query... */
+ if (!__newlocale((category == LC_ALL) ? LC_ALL_MASK : (1 << category),
+ locale, __global_locale)
+ ) { /* Failed! */
return NULL;
}
-
- /* TODO: Ok, everything checks out, so install the new locale. */
- _locale_set(new_locale);
+ update_hr_locale(__global_locale->cur_locale);
}
/* Either a query or a successful set, so return current locale string. */
- return human_readable_locale(category, CUR_LOCALE_SPEC);
+ return hr_locale + (category * MAX_LOCALE_CATEGORY_STR);
}
#endif /* __LOCALE_C_ONLY */
@@ -355,7 +273,7 @@ char *setlocale(int category, const char *locale)
#ifdef __LOCALE_C_ONLY
-link_warning(localeconv,"the 'localeconv' function is hardwired for C/POSIX locale only")
+link_warning(localeconv,"REMINDER: The 'localeconv' function is hardwired for C/POSIX locale only.")
static struct lconv the_lconv;
@@ -387,7 +305,7 @@ static struct lconv the_lconv;
struct lconv *localeconv(void)
{
register char *p = (char *) &the_lconv;
- register char **q = (char **) &__global_locale.decimal_point;
+ register char **q = (char **) &(__UCLIBC_CURLOCALE_DATA).decimal_point;
do {
*((char **)p) = *q;
@@ -408,16 +326,22 @@ struct lconv *localeconv(void)
#endif
/**********************************************************************/
-#ifdef L__locale_init
+#if defined(L__locale_init) && !defined(__LOCALE_C_ONLY)
-#ifndef __LOCALE_C_ONLY
+static __uclibc_locale_t __global_locale_data;
-#define C_LOCALE_SELECTOR "\x23\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80"
-#define LOCALE_INIT_FAILED "locale init failed!\n"
+__locale_t __global_locale = &__global_locale_data;
-#define CUR_LOCALE_SPEC (__global_locale.cur_locale)
+#ifdef __UCLIBC_HAS_XLOCALE__
+__locale_t __curlocale_var = &__global_locale_data;
+#endif
-__locale_t __global_locale;
+/*----------------------------------------------------------------------*/
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Move utf8 and ascii strings.
+#endif
+static const char utf8[] = "UTF-8";
+static const char ascii[] = "ASCII";
typedef struct {
uint16_t num_base;
@@ -461,9 +385,8 @@ typedef struct {
uint16_t multistart_offset;
} coldata_der_t;
-static int init_cur_collate(int der_num)
+static int init_cur_collate(int der_num, __collate_t *cur_collate)
{
- __collate_t *cur_collate = &__global_locale.collate;
const uint16_t *__locale_collate_tbl = __locale_mmap->collate_data;
coldata_header_t *cdh;
coldata_base_t *cdb;
@@ -485,9 +408,16 @@ static int init_cur_collate(int der_num)
cdh = (coldata_header_t *) __locale_collate_tbl;
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Should we assert here?
+#endif
+#if 0
if (der_num >= cdh->num_der) {
return 0;
}
+#else
+ assert((der_num < cdh->num_der));
+#endif
cdd = (coldata_der_t *)(__locale_collate_tbl
+ (sizeof(coldata_header_t)
@@ -539,14 +469,17 @@ static int init_cur_collate(int der_num)
cur_collate->MAX_WEIGHTS = cdh->MAX_WEIGHTS;
#ifdef __UCLIBC_MJN3_ONLY__
-#warning if calloc fails, this is WRONG. there is also a memory leak here at the moment
-#warning fix the +1 by increasing max_col_index?
+#warning CONSIDER: Fix the +1 by increasing max_col_index?
+#warning CONSIDER: Since this collate info is dependent only on LC_COLLATE ll_cc and not on codeset, we could just globally allocate this for each in a table
#endif
- cur_collate->index2weight = calloc(2*cur_collate->max_col_index+2, sizeof(uint16_t));
+
+ cur_collate->index2weight = calloc(2*cur_collate->max_col_index+2,
+ sizeof(uint16_t));
if (!cur_collate->index2weight) {
return 0;
}
- cur_collate->index2ruleidx = cur_collate->index2weight + cur_collate->max_col_index + 1;
+ cur_collate->index2ruleidx = cur_collate->index2weight
+ + cur_collate->max_col_index + 1;
memcpy(cur_collate->index2weight, cur_collate->index2weight_tbl,
cur_collate->num_col_base * sizeof(uint16_t));
@@ -602,61 +535,10 @@ static int init_cur_collate(int der_num)
return 1;
}
-void _locale_init(void)
-{
- /* TODO: mmap the locale file */
-
- /* TODO - ??? */
- memset(CUR_LOCALE_SPEC, 0, LOCALE_STRING_SIZE);
- CUR_LOCALE_SPEC[0] = '#';
-
- memcpy(__global_locale.category_item_count,
- __locale_mmap->lc_common_item_offsets_LEN,
- LC_ALL);
-
- ++__global_locale.category_item_count[0]; /* Increment for codeset entry. */
- __global_locale.category_offsets[0] = offsetof(__locale_t, outdigit0_mb);
- __global_locale.category_offsets[1] = offsetof(__locale_t, decimal_point);
- __global_locale.category_offsets[2] = offsetof(__locale_t, int_curr_symbol);
- __global_locale.category_offsets[3] = offsetof(__locale_t, abday_1);
-/* __global_locale.category_offsets[4] = offsetof(__locale_t, collate???); */
- __global_locale.category_offsets[5] = offsetof(__locale_t, yesexpr);
-
-#ifdef __CTYPE_HAS_8_BIT_LOCALES
- __global_locale.tbl8ctype
- = (const unsigned char *) &__locale_mmap->tbl8ctype;
- __global_locale.tbl8uplow
- = (const unsigned char *) &__locale_mmap->tbl8uplow;
-#ifdef __WCHAR_ENABLED
- __global_locale.tbl8c2wc
- = (const uint16_t *) &__locale_mmap->tbl8c2wc;
- __global_locale.tbl8wc2c
- = (const unsigned char *) &__locale_mmap->tbl8wc2c;
- /* translit */
-#endif /* __WCHAR_ENABLED */
-#endif /* __CTYPE_HAS_8_BIT_LOCALES */
-#ifdef __WCHAR_ENABLED
- __global_locale.tblwctype
- = (const unsigned char *) &__locale_mmap->tblwctype;
- __global_locale.tblwuplow
- = (const unsigned char *) &__locale_mmap->tblwuplow;
- __global_locale.tblwuplow_diff
- = (const uint16_t *) &__locale_mmap->tblwuplow_diff;
-/* __global_locale.tblwcomb */
-/* = (const unsigned char *) &__locale_mmap->tblwcomb; */
- /* width?? */
-#endif /* __WCHAR_ENABLED */
-
- _locale_set(C_LOCALE_SELECTOR);
-}
-
-static const char ascii[] = "ASCII";
-static const char utf8[] = "UTF-8";
-
-void _locale_set(const unsigned char *p)
+int _locale_set_l(const unsigned char *p, __locale_t base)
{
const char **x;
- unsigned char *s = CUR_LOCALE_SPEC + 1;
+ unsigned char *s = base->cur_locale + 1;
const size_t *stp;
const unsigned char *r;
const uint16_t *io;
@@ -667,12 +549,30 @@ void _locale_set(const unsigned char *p)
int len;
int c;
int i = 0;
+ __collate_t newcol;
++p;
+
+ newcol.index2weight = NULL;
+ if ((p[2*LC_COLLATE] != s[2*LC_COLLATE])
+ || (p[2*LC_COLLATE + 1] != s[2*LC_COLLATE + 1])
+ ) {
+ row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
+ assert(row < __LOCALE_DATA_NUM_LOCALES);
+ if (!init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES
+ * row + 3 + i ],
+ &newcol)
+ ) {
+ return 0; /* calloc failed. */
+ }
+ free(base->collate.index2weight);
+ memcpy(&base->collate, &newcol, sizeof(__collate_t));
+ }
+
do {
if ((*p != *s) || (p[1] != s[1])) {
row = (((int)(*p & 0x7f)) << 7) + (p[1] & 0x7f);
- assert(row < NUM_LOCALES);
+ assert(row < __LOCALE_DATA_NUM_LOCALES);
*s = *p;
s[1] = p[1];
@@ -680,10 +580,13 @@ void _locale_set(const unsigned char *p)
if ((i != LC_COLLATE)
&& ((len = __locale_mmap->lc_common_item_offsets_LEN[i]) != 0)
) {
- crow = __locale_mmap->locales[ WIDTH_LOCALES * row + 3 + i ]
+ crow = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
+ + 3 + i ]
* len;
- x = (const char **)(((char *) &__global_locale)
- + __global_locale.category_offsets[i]);
+
+ x = (const char **)(((char *) base)
+ + base->category_offsets[i]);
+
stp = __locale_mmap->lc_common_tbl_offsets + 4*i;
r = (const unsigned char *)( ((char *)__locale_mmap) + *stp );
io = (const uint16_t *)( ((char *)__locale_mmap) + *++stp );
@@ -694,67 +597,176 @@ void _locale_set(const unsigned char *p)
}
}
if (i == LC_CTYPE) {
- c = __locale_mmap->locales[ WIDTH_LOCALES * row + 2 ]; /* codeset */
+ c = __locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES * row
+ + 2 ]; /* codeset */
if (c <= 2) {
if (c == 2) {
- __global_locale.codeset = utf8;
- __global_locale.encoding = __ctype_encoding_utf8;
+ base->codeset = utf8;
+ base->encoding = __ctype_encoding_utf8;
/* TODO - fix for bcc */
- __global_locale.mb_cur_max = 6;
+ base->mb_cur_max = 6;
} else {
assert(c==1);
- __global_locale.codeset = ascii;
- __global_locale.encoding = __ctype_encoding_7_bit;
- __global_locale.mb_cur_max = 1;
+ base->codeset = ascii;
+ base->encoding = __ctype_encoding_7_bit;
+ base->mb_cur_max = 1;
}
} else {
- const codeset_8_bit_t *c8b;
+ const __codeset_8_bit_t *c8b;
r = CODESET_LIST;
- __global_locale.codeset = r + r[c -= 3];
- __global_locale.encoding = __ctype_encoding_8_bit;
+ base->codeset = r + r[c -= 3];
+ base->encoding = __ctype_encoding_8_bit;
#ifdef __UCLIBC_MJN3_ONLY__
-#warning REMINDER: update 8 bit mb_cur_max when trasnlit implemented!
+#warning REMINDER: update 8 bit mb_cur_max when translit implemented!
#endif
/* TODO - update when translit implemented! */
- __global_locale.mb_cur_max = 1;
+ base->mb_cur_max = 1;
c8b = __locale_mmap->codeset_8_bit + c;
#ifdef __CTYPE_HAS_8_BIT_LOCALES
- __global_locale.idx8ctype = c8b->idx8ctype;
- __global_locale.idx8uplow = c8b->idx8uplow;
-#ifdef __WCHAR_ENABLED
- __global_locale.idx8c2wc = c8b->idx8c2wc;
- __global_locale.idx8wc2c = c8b->idx8wc2c;
+ base->idx8ctype = c8b->idx8ctype;
+ base->idx8uplow = c8b->idx8uplow;
+#ifdef __UCLIBC_HAS_WCHAR__
+ base->idx8c2wc = c8b->idx8c2wc;
+ base->idx8wc2c = c8b->idx8wc2c;
/* translit */
-#endif /* __WCHAR_ENABLED */
+#endif /* __UCLIBC_HAS_WCHAR__ */
#endif /* __CTYPE_HAS_8_BIT_LOCALES */
}
#ifdef __UCLIBC_MJN3_ONLY__
-#warning might want to just put this in the locale_mmap object
+#warning TODO: Put the outdigit string length in the locale_mmap object.
#endif
- d = __global_locale.outdigit_length;
- x = &__global_locale.outdigit0_mb;
+ d = base->outdigit_length;
+ x = &base->outdigit0_mb;
for (c = 0 ; c < 10 ; c++) {
((unsigned char *)d)[c] = strlen(x[c]);
assert(d[c] > 0);
}
- } else if (i == LC_COLLATE) {
- init_cur_collate(__locale_mmap->locales[ WIDTH_LOCALES * row + 3 + i ]);
+ } else if (i == LC_NUMERIC) {
+ assert(LC_NUMERIC > LC_CTYPE); /* Need ctype initialized. */
+
+ base->decimal_point_len
+ = __locale_mbrtowc_l(&base->decimal_point_wc,
+ base->decimal_point, base);
+ assert(base->decimal_point_len > 0);
+ assert(base->decimal_point[base->decimal_point_len] == 0);
+
+ if (*base->grouping) {
+ base->thousands_sep_len
+ = __locale_mbrtowc_l(&base->thousands_sep_wc,
+ base->thousands_sep, base);
+ assert(base->thousands_sep_len > 0);
+ assert(base->thousands_sep[base->thousands_sep_len] == 0);
+ }
+
+/* } else if (i == LC_COLLATE) { */
+/* init_cur_collate(__locale_mmap->locales[ __LOCALE_DATA_WIDTH_LOCALES */
+/* * row + 3 + i ], */
+/* &base->collate); */
}
}
++i;
p += 2;
s += 2;
} while (i < LC_ALL);
+
+ return 1;
}
-#endif /* __LOCALE_C_ONLY */
+static const uint16_t __code2flag[16] = {
+ 0, /* unclassified = 0 */
+ _ISprint|_ISgraph|_ISalnum|_ISalpha, /* alpha_nonupper_nonlower */
+ _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower, /* alpha_lower */
+ _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISlower|_ISupper, /* alpha_upper_lower */
+ _ISprint|_ISgraph|_ISalnum|_ISalpha|_ISupper, /* alpha_upper */
+ _ISprint|_ISgraph|_ISalnum|_ISdigit, /* digit */
+ _ISprint|_ISgraph|_ISpunct, /* punct */
+ _ISprint|_ISgraph, /* graph */
+ _ISprint|_ISspace, /* print_space_nonblank */
+ _ISprint|_ISspace|_ISblank, /* print_space_blank */
+ _ISspace, /* space_nonblank_noncntrl */
+ _ISspace|_ISblank, /* space_blank_noncntrl */
+ _IScntrl|_ISspace, /* cntrl_space_nonblank */
+ _IScntrl|_ISspace|_ISblank, /* cntrl_space_blank */
+ _IScntrl /* cntrl_nonspace */
+};
+
+void _locale_init_l(__locale_t base)
+{
+ memset(base->cur_locale, 0, LOCALE_SELECTOR_SIZE);
+ base->cur_locale[0] = '#';
+
+ memcpy(base->category_item_count,
+ __locale_mmap->lc_common_item_offsets_LEN,
+ LC_ALL);
+
+ ++base->category_item_count[0]; /* Increment for codeset entry. */
+ base->category_offsets[0] = offsetof(__uclibc_locale_t, outdigit0_mb);
+ base->category_offsets[1] = offsetof(__uclibc_locale_t, decimal_point);
+ base->category_offsets[2] = offsetof(__uclibc_locale_t, int_curr_symbol);
+ base->category_offsets[3] = offsetof(__uclibc_locale_t, abday_1);
+/* base->category_offsets[4] = offsetof(__uclibc_locale_t, collate???); */
+ base->category_offsets[5] = offsetof(__uclibc_locale_t, yesexpr);
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ base->tbl8ctype
+ = (const unsigned char *) &__locale_mmap->tbl8ctype;
+ base->tbl8uplow
+ = (const unsigned char *) &__locale_mmap->tbl8uplow;
+#ifdef __UCLIBC_HAS_WCHAR__
+ base->tbl8c2wc
+ = (const uint16_t *) &__locale_mmap->tbl8c2wc;
+ base->tbl8wc2c
+ = (const unsigned char *) &__locale_mmap->tbl8wc2c;
+ /* translit */
+#endif /* __UCLIBC_HAS_WCHAR__ */
+#endif /* __CTYPE_HAS_8_BIT_LOCALES */
+#ifdef __UCLIBC_HAS_WCHAR__
+ base->tblwctype
+ = (const unsigned char *) &__locale_mmap->tblwctype;
+ base->tblwuplow
+ = (const unsigned char *) &__locale_mmap->tblwuplow;
+ base->tblwuplow_diff
+ = (const uint16_t *) &__locale_mmap->tblwuplow_diff;
+/* base->tblwcomb */
+/* = (const unsigned char *) &__locale_mmap->tblwcomb; */
+ /* width?? */
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning wrong for now, but always set ctype arrays to global C version
#endif
-/**********************************************************************/
-#ifdef L_nl_langinfo
+#ifdef __UCLIBC_HAS_XLOCALE__
+ base->__ctype_b = __C_ctype_b;
+ base->__ctype_tolower = __C_ctype_tolower;
+ base->__ctype_toupper = __C_ctype_toupper;
+#else /* __UCLIBC_HAS_XLOCALE__ */
+ __ctype_b = __C_ctype_b;
+ __ctype_tolower = __C_ctype_tolower;
+ __ctype_toupper = __C_ctype_toupper;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
-#include <langinfo.h>
-#include <nl_types.h>
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Initialize code2flag correctly based on locale_mmap.
+#endif
+ base->code2flag = __code2flag;
+
+
+ _locale_set_l(C_LOCALE_SELECTOR, base);
+}
+
+void _locale_init(void)
+{
+ /* TODO: mmap the locale file */
+
+ /* TODO - ??? */
+ _locale_init_l(__global_locale);
+}
+
+#endif
+/**********************************************************************/
+#if defined(L_nl_langinfo) || defined(L_nl_langinfo_l)
#ifdef __LOCALE_C_ONLY
@@ -853,22 +865,435 @@ char *nl_langinfo(nl_item item)
#else /* __LOCALE_C_ONLY */
-static const char empty[] = "";
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
char *nl_langinfo(nl_item item)
{
+ return nl_langinfo_l(item, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+static const char empty[] = "";
+
+char *__XL(nl_langinfo)(nl_item item __LOCALE_PARAM )
+{
unsigned int c = _NL_ITEM_CATEGORY(item);
unsigned int i = _NL_ITEM_INDEX(item);
- if ((c < LC_ALL) && (i < __global_locale.category_item_count[c])) {
- return ((char **)(((char *) &__global_locale)
- + __global_locale.category_offsets[c]))[i];
-
+ if ((c < LC_ALL) && (i < __LOCALE_PTR->category_item_count[c])) {
+ return ((char **)(((char *) __LOCALE_PTR)
+ + __LOCALE_PTR->category_offsets[c]))[i];
}
+
return (char *) empty;
}
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
#endif /* __LOCALE_C_ONLY */
#endif
/**********************************************************************/
+#ifdef L_newlocale
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Move posix and utf8 strings.
+#endif
+static const char posix[] = "POSIX";
+static const char utf8[] = "UTF-8";
+
+static int find_locale(int category_mask, const char *p,
+ unsigned char *new_locale)
+{
+ int i;
+ const unsigned char *s;
+ uint16_t n;
+ unsigned char lang_cult, codeset;
+
+#if defined(__LOCALE_DATA_AT_MODIFIERS_LENGTH) && 1
+ /* Support standard locale handling for @-modifiers. */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: Fix buf size in find_locale.
+#endif
+ char buf[18]; /* TODO: 7+{max codeset name length} */
+ const char *q;
+
+ if ((q = strchr(p,'@')) != NULL) {
+ if ((((size_t)((q-p)-5)) > (sizeof(buf) - 5)) || (p[2] != '_')) {
+ return 0;
+ }
+ /* locale name at least 5 chars long and 3rd char is '_' */
+ s = LOCALE_AT_MODIFIERS;
+ do {
+ if (!strcmp(s+2, q+1)) {
+ break;
+ }
+ s += 2 + *s; /* TODO - fix this throughout */
+ } while (*s);
+ if (!*s) {
+ return 0;
+ }
+ assert(q - p < sizeof(buf));
+ memcpy(buf, p, q-p);
+ buf[q-p] = 0;
+ buf[2] = s[1];
+ p = buf;
+ }
+#endif
+
+ lang_cult = codeset = 0; /* Assume C and default codeset. */
+ if (((*p == 'C') && !p[1]) || !strcmp(p, posix)) {
+ goto FIND_LOCALE;
+ }
+
+ if ((strlen(p) > 5) && (p[5] == '.')) { /* Codeset in locale name? */
+ /* TODO: maybe CODESET_LIST + *s ??? */
+ /* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
+ codeset = 2;
+ if (strcmp(utf8,p+6) != 0) {/* TODO - fix! */
+ s = CODESET_LIST;
+ do {
+ ++codeset; /* Increment codeset first. */
+ if (!strcmp(CODESET_LIST+*s, p+6)) {
+ goto FIND_LANG_CULT;
+ }
+ } while (*++s);
+ return 0; /* No matching codeset! */
+ }
+ }
+
+ FIND_LANG_CULT: /* Find language_culture number. */
+ s = LOCALE_NAMES;
+ do { /* TODO -- do a binary search? */
+ /* TODO -- fix gen_mmap!*/
+ ++lang_cult; /* Increment first since C/POSIX is 0. */
+ if (!strncmp(s,p,5)) { /* Found a matching locale name; */
+ goto FIND_LOCALE;
+ }
+ s += 5;
+ } while (lang_cult < __LOCALE_DATA_NUM_LOCALE_NAMES);
+ return 0; /* No matching language_culture! */
+
+ FIND_LOCALE: /* Find locale row matching name and codeset */
+ s = LOCALES;
+ n = 0;
+ do { /* TODO -- do a binary search? */
+ if ((lang_cult == *s) && ((codeset == s[1]) || (codeset == s[2]))) {
+ i = 1;
+ s = new_locale + 1;
+ do {
+ if (category_mask & i) {
+ /* Encode current locale row number. */
+ ((unsigned char *) s)[0] = (n >> 7) | 0x80;
+ ((unsigned char *) s)[1] = (n & 0x7f) | 0x80;
+ }
+ s += 2;
+ i += i;
+ } while (i < (1 << LC_ALL));
+
+ return i; /* Return non-zero */
+ }
+ s += __LOCALE_DATA_WIDTH_LOCALES;
+ ++n;
+ } while (n <= __LOCALE_DATA_NUM_LOCALES); /* We started at 1!!! */
+
+ return 0; /* Unsupported locale. */
+}
+
+static unsigned char *composite_locale(int category_mask, const char *locale,
+ unsigned char *new_locale)
+{
+ char buf[MAX_LOCALE_STR];
+ char *t;
+ char *e;
+ int c;
+ int component_mask;
+
+ if (!strchr(locale,'=')) {
+ if (!find_locale(category_mask, locale, new_locale)) {
+ return NULL;
+ }
+ return new_locale;
+ }
+
+ if (strlen(locale) >= sizeof(buf)) {
+ return NULL;
+ }
+ stpcpy(buf, locale);
+
+ component_mask = 0;
+ t = strtok_r(buf, "=", &e); /* This can't fail because of strchr test above. */
+ do {
+ c = 0;
+ while (strcmp(CATEGORY_NAMES + (int) CATEGORY_NAMES[c], t)) {
+ if (++c == LC_ALL) { /* Unknown category name! */
+ return NULL;
+ }
+ }
+ t = strtok_r(NULL, ";", &e);
+ c = (1 << c);
+ if (component_mask & c) { /* Multiple components for one category. */
+ return NULL;
+ }
+ component_mask |= c;
+ if ((category_mask & c) && (!t || !find_locale(c, t, new_locale))) {
+ return NULL;
+ }
+ } while ((t = strtok_r(NULL, "=", &e)) != NULL);
+
+ if (category_mask & ~component_mask) { /* Category component(s) missing. */
+ return NULL;
+ }
+
+ return new_locale;
+}
+
+__locale_t __newlocale(int category_mask, const char *locale, __locale_t base)
+{
+ const unsigned char *p;
+ int i, j, k;
+ unsigned char new_selector[LOCALE_SELECTOR_SIZE];
+
+ if (!locale || (((unsigned int)(category_mask)) > LC_ALL_MASK)) {
+ INVALID:
+ __set_errno(EINVAL);
+ return NULL; /* No locale or illegal/unsupported category. */
+ }
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Rename cur_locale to locale_selector.
+#endif
+ strcpy((char *) new_selector,
+ (base ? (char *) base->cur_locale : C_LOCALE_SELECTOR));
+
+ if (!*locale) { /* locale == "", so check environment. */
+#ifndef __UCLIBC_HAS_THREADS__
+ static /* If no threads, then envstr can be static. */
+#endif /* __UCLIBC_HAS_THREADS__ */
+ const char *envstr[4] = { "LC_ALL", NULL, "LANG", posix };
+
+ i = 1;
+ k = 0;
+ do {
+ if (category_mask & i) {
+ /* Note: SUSv3 doesn't define a fallback mechanism here.
+ * So, if LC_ALL is invalid, we do _not_ continue trying
+ * the other environment vars. */
+ envstr[1] = CATEGORY_NAMES + CATEGORY_NAMES[k];
+ j = 0;
+ do {
+ p = envstr[j];
+ } while ((++j < 4) && (!(p = getenv(p)) || !*p));
+
+
+ /* The user set something... is it valid? */
+ /* Note: Since we don't support user-supplied locales and
+ * alternate paths, we don't need to worry about special
+ * handling for suid/sgid apps. */
+ if (!find_locale(i, p, new_selector)) {
+ goto INVALID;
+ }
+ }
+ i += i;
+ } while (++k < LC_ALL);
+ } else if (!composite_locale(category_mask, locale, new_selector)) {
+ goto INVALID;
+ }
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Do a compatible codeset check!
+#endif
+
+ /* If we get here, the new selector corresponds to a valid locale. */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Probably want a _locale_new func to allow for caching of locales.
+#endif
+#if 0
+ if (base) {
+ _locale_set_l(new_selector, base);
+ } else {
+ base = _locale_new(new_selector);
+ }
+#else
+ if (!base) {
+ if ((base = malloc(sizeof(__uclibc_locale_t))) == NULL) {
+ return base;
+ }
+ _locale_init_l(base);
+ }
+
+ _locale_set_l(new_selector, base);
+#endif
+
+ return base;
+}
+
+weak_alias(__newlocale, newlocale)
+
+#endif
+/**********************************************************************/
+#ifdef L_duplocale
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: When we allocate ctype tables, remember to dup them.
+#endif
+
+__locale_t duplocale(__locale_t dataset)
+{
+ __locale_t r;
+ uint16_t * i2w;
+
+ assert(dataset != LC_GLOBAL_LOCALE);
+
+ if ((r = malloc(sizeof(__uclibc_locale_t))) != NULL) {
+ if ((i2w = calloc(2*dataset->collate.max_col_index+2,
+ sizeof(uint16_t)))
+ != NULL
+ ) {
+ memcpy(r, dataset, sizeof(__uclibc_locale_t));
+ r->collate.index2weight = i2w;
+ } else {
+ free(r);
+ r = NULL;
+ }
+ }
+ return r;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_freelocale
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: When we allocate ctype tables, remember to free them.
+#endif
+
+void freelocale(__locale_t dataset)
+{
+ assert(dataset != __global_locale);
+ assert(dataset != LC_GLOBAL_LOCALE);
+
+ free(dataset->collate.index2weight); /* Free collation data. */
+ free(dataset); /* Free locale */
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_uselocale
+
+__locale_t uselocale(__locale_t dataset)
+{
+ __locale_t old;
+
+ if (!dataset) {
+ old = __UCLIBC_CURLOCALE;
+ } else {
+ if (dataset == LC_GLOBAL_LOCALE) {
+ dataset = __global_locale;
+ }
+#ifdef __UCLIBC_HAS_THREADS__
+ old = __curlocale_set(dataset);
+#else
+ old = __curlocale_var;
+ __curlocale_var = dataset;
+#endif
+ }
+
+ if (old == __global_locale) {
+ return LC_GLOBAL_LOCALE;
+ }
+ return old;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L___curlocale
+
+#ifdef __UCLIBC_HAS_THREADS__
+
+__locale_t weak_const_function __curlocale(void)
+{
+ return __curlocale_var; /* This is overriden by the thread version. */
+}
+
+__locale_t weak_function __curlocale_set(__locale_t newloc)
+{
+ assert(newloc != LC_GLOBAL_LOCALE);
+
+ __locale_t oldloc = __curlocale_var;
+ __curlocale_var = newloc;
+ return oldloc;
+}
+
+#endif
+
+#endif
+/**********************************************************************/
+#ifdef L___locale_mbrtowc_l
+
+/* NOTE: This returns an int... not size_t. Also, it is not a general
+ * routine. It is actually a very stripped-down version of mbrtowc
+ * that takes a __locale_t arg. This is used by strcoll and strxfrm.
+ * It is also used above to generate wchar_t versions of the decimal point
+ * and thousands seperator. */
+
+
+#ifndef __CTYPE_HAS_UTF_8_LOCALES
+#warning __CTYPE_HAS_UTF_8_LOCALES not set!
+#endif
+#ifndef __CTYPE_HAS_8_BIT_LOCALES
+#warning __CTYPE_HAS_8_BIT_LOCALES not set!
+#endif
+
+#define Cc2wc_IDX_SHIFT __LOCALE_DATA_Cc2wc_IDX_SHIFT
+#define Cc2wc_ROW_LEN __LOCALE_DATA_Cc2wc_ROW_LEN
+
+extern size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
+ const char **__restrict src, size_t n,
+ mbstate_t *ps, int allow_continuation);
+
+int __locale_mbrtowc_l(wchar_t *__restrict dst,
+ const char *__restrict src,
+ __locale_t loc )
+{
+#ifdef __CTYPE_HAS_UTF_8_LOCALES
+ if (loc->encoding == __ctype_encoding_utf8) {
+ mbstate_t ps;
+ const char *p = src;
+ size_t r;
+ ps.mask = 0;
+ r = _wchar_utf8sntowcs(dst, 1, &p, SIZE_MAX, &ps, 1);
+ return (r == 1) ? (p-src) : r; /* Need to return 0 if nul char. */
+ }
+#endif
+
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ assert((loc->encoding == __ctype_encoding_7_bit) || (loc->encoding == __ctype_encoding_8_bit));
+#else
+ assert(loc->encoding == __ctype_encoding_7_bit);
+#endif
+
+ if ((*dst = ((unsigned char)(*src))) < 0x80) { /* ASCII... */
+ return (*src != 0);
+ }
+
+#ifdef __CTYPE_HAS_8_BIT_LOCALES
+ if (loc->encoding == __ctype_encoding_8_bit) {
+ wchar_t wc = *dst - 0x80;
+ *dst = __LOCALE_PTR->tbl8c2wc[
+ (__LOCALE_PTR->idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
+ << Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
+ if (*dst) {
+ return 1;
+ }
+ }
+#endif
+
+ return -1;
+}
+
+#endif
+/**********************************************************************/
diff --git a/libc/misc/time/Makefile b/libc/misc/time/Makefile
index b5714e511..302214baf 100644
--- a/libc/misc/time/Makefile
+++ b/libc/misc/time/Makefile
@@ -28,15 +28,22 @@ MSRC= time.c
MOBJ= asctime.o asctime_r.o clock.o ctime.o ctime_r.o gmtime.o gmtime_r.o \
localtime.o localtime_r.o mktime.o strftime.o strptime.o tzset.o \
_time_t2tm.o __time_tm.o _time_mktime.o dysize.o timegm.o
+MOBJx=
ifeq ($(UCLIBC_HAS_FLOATS),y)
MOBJ += difftime.o
endif
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+ MOBJx += strftime_l.o strptime_l.o
+endif
+
+ifeq ($(UCLIBC_HAS_WCHAR),y)
+endif
CSRC= adjtime.c ftime.c
COBJS=$(patsubst %.c,%.o, $(CSRC))
-OBJS=$(COBJS) $(MOBJ)
+OBJS=$(COBJS) $(MOBJ) $(MOBJx)
all: $(OBJS) $(LIBC)
@@ -49,6 +56,10 @@ $(MOBJ): $(MSRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
+$(MOBJx): $(MSRC)
+ $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
$(COBJS): %.o : %.c
$(CC) $(CFLAGS) -c $< -o $@
$(STRIPTOOL) -x -R .note -R .comment $*.o
diff --git a/libc/misc/time/time.c b/libc/misc/time/time.c
index 8d3cbc3b4..0ae91f69a 100644
--- a/libc/misc/time/time.c
+++ b/libc/misc/time/time.c
@@ -95,9 +95,32 @@
*
* Nov 26, 2002 Fix bug in setting daylight and timezone when no (valid) TZ.
* Bug reported by Arne Bernin <arne@alamut.de> in regards to freeswan.
+ *
+ * July 27, 2003 Adjust the struct tm extension field support.
+ * Change __tm_tzone back to a ptr and add the __tm_tzname[] buffer for
+ * __tm_tzone to point to. This gets around complaints from g++.
+ * Who knows... it might even fix the PPC timezone init problem.
+ *
+ * July 29, 2003 Fix a bug in mktime behavior when tm_isdst was -1.
+ * Bug reported by "Sid Wade" <sid@vivato.net> in regards to busybox.
+ *
+ * NOTE: uClibc mktime behavior is different than glibc's when
+ * the struct tm has tm_isdst == -1 and also had fields outside of
+ * the normal ranges.
+ *
+ * Apparently, glibc examines (at least) tm_sec and guesses the app's
+ * intention of assuming increasing or decreasing time when entering an
+ * ambiguous time period at the dst<->st boundaries.
+ *
+ * The uClibc behavior is to always normalize the struct tm and then
+ * try to determing the dst setting.
+ *
+ * As long as tm_isdst != -1 or the time specifiec by struct tm is
+ * unambiguous (not falling in the dst<->st transition region) both
+ * uClibc and glibc should produce the same result for mktime.
+ *
*/
-
#define _GNU_SOURCE
#define _STDIO_UTILITY
#include <stdio.h>
@@ -112,6 +135,10 @@
#include <langinfo.h>
#include <locale.h>
+#ifdef __UCLIBC_HAS_XLOCALE__
+#include <xlocale.h>
+#endif
+
#ifndef __isleap
#define __isleap(y) ( !((y) % 4) && ( ((y) % 100) || !((y) % 400) ) )
#endif
@@ -121,27 +148,26 @@
#endif
/**********************************************************************/
-
/* The era code is currently unfinished. */
/* #define ENABLE_ERA_CODE */
-#define __TIME_TZ_FILE
-/* #define __TIME_TZ_FILE_ONCE */
-
-#define __TIME_TZ_OPT_SPEED
-
#define TZ_BUFLEN (2*TZNAME_MAX + 56)
-#ifdef __TIME_TZ_FILE
+#ifdef __UCLIBC_HAS_TZ_FILE__
+
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "paths.h"
/* ":<tzname>+hh:mm:ss<tzname>+hh:mm:ss,Mmm.w.d/hh:mm:ss,Mmm.w.d/hh:mm:ss" + nul */
/* 1 + 2*(1+TZNAME_MAX+1 + 9 + 7 + 9) + 1 = 2*TZNAME_MAX + 56 */
-#else /* __TIME_TZ_FILE */
-#undef __TIME_TZ_FILE_ONCE
-#endif /* __TIME_TZ_FILE */
+
+#else /* __UCLIBC_HAS_TZ_FILE__ */
+
+/* Probably no longer needed. */
+#undef __UCLIBC_HAS_TZ_FILE_READ_MANY__
+
+#endif /* __UCLIBC_HAS_TZ_FILE__ */
/**********************************************************************/
@@ -592,7 +618,8 @@ struct tm *localtime_r(register const time_t *__restrict timer,
result->tm_isdst = dst;
#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
result->tm_gmtoff = - _time_tzinfo[dst].gmt_offset;
- strcpy( (char *)(result->tm_zone), _time_tzinfo[dst].tzname);
+ result->tm_zone = result->__tm_tzname;
+ strcpy(result->__tm_tzname, _time_tzinfo[dst].tzname);
#endif /* __UCLIBC_HAS_TM_EXTENSIONS__ */
} while ((++dst < 2) && (result->tm_isdst = tm_isdst(result)) != 0);
@@ -617,7 +644,18 @@ time_t mktime(struct tm *timeptr)
#endif
/**********************************************************************/
-#ifdef L_strftime
+#if defined(L_strftime) || defined(L_strftime_l)
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+size_t strftime(char *__restrict s, size_t maxsize,
+ const char *__restrict format,
+ const struct tm *__restrict timeptr)
+{
+ return strftime_l(s, maxsize, format, timeptr, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
#define NO_E_MOD 0x80
#define NO_O_MOD 0x40
@@ -811,9 +849,13 @@ static int load_field(int k, const struct tm *__restrict timeptr)
#define MAX_PUSH 4
-size_t strftime(char *__restrict s, size_t maxsize,
- const char *__restrict format,
- const struct tm *__restrict timeptr)
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Check multibyte format string validity.
+#endif
+
+size_t __XL(strftime)(char *__restrict s, size_t maxsize,
+ const char *__restrict format,
+ const struct tm *__restrict timeptr __LOCALE_PARAM )
{
long tzo;
register const char *p;
@@ -882,16 +924,19 @@ size_t strftime(char *__restrict s, size_t maxsize,
+ (code & 7);
#ifdef ENABLE_ERA_CODE
if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
- && (*(o = nl_langinfo(_NL_ITEM(LC_TIME,
- (int)(((unsigned char *)p)[4]))
+ && (*(o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME,
+ (int)(((unsigned char *)p)[4]))
+ __LOCALE_ARG
)))
) {
p = o;
goto LOOP;
}
#endif
- p = nl_langinfo(_NL_ITEM(LC_TIME,
- (int)(*((unsigned char *)p))));
+ p = __XL(nl_langinfo)(_NL_ITEM(LC_TIME,
+ (int)(*((unsigned char *)p)))
+ __LOCALE_ARG
+ );
goto LOOP;
}
@@ -1037,7 +1082,7 @@ size_t strftime(char *__restrict s, size_t maxsize,
if ((code & MASK_SPEC) == STRING_SPEC) {
o_count = SIZE_MAX;
field_val += spec[STRINGS_NL_ITEM_START + (code & 0xf)];
- o = nl_langinfo(_NL_ITEM(LC_TIME, field_val));
+ o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME, field_val) __LOCALE_ARG );
} else {
o_count = ((i >> 1) & 3) + 1;
o = buf + o_count;
@@ -1061,9 +1106,31 @@ size_t strftime(char *__restrict s, size_t maxsize,
goto LOOP;
}
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
#endif
/**********************************************************************/
-#ifdef L_strptime
+#if defined(L_strptime) || defined(L_strptime_l)
+
+#if defined(L_strptime) || defined(L_strptime_l)
+#define ISDIGIT(C) __isdigit_char((C))
+#endif
+
+#ifdef __UCLIBC_DO_XLOCALE
+#define ISSPACE(C) isspace_l((C), locale_arg)
+#else
+#define ISSPACE(C) isspace((C))
+#endif
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+char *strptime(const char *__restrict buf, const char *__restrict format,
+ struct tm *__restrict tm)
+{
+ return strptime_l(buf, format, tm, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
/* TODO:
* 1) %l and %k are space-padded, so "%l" by itself fails while " %l" succeeds.
@@ -1207,8 +1274,8 @@ static const unsigned char spec[] = {
#define MAX_PUSH 4
-char *strptime(const char *__restrict buf, const char *__restrict format,
- struct tm *__restrict tm)
+char *__XL(strptime)(const char *__restrict buf, const char *__restrict format,
+ struct tm *__restrict tm __LOCALE_PARAM)
{
register const char *p;
char *o;
@@ -1273,16 +1340,18 @@ char *strptime(const char *__restrict buf, const char *__restrict format,
+ (code & 7);
#ifdef ENABLE_ERA_CODE
if ((mod & NO_E_MOD) /* Actually, this means E modifier present. */
- && (*(o = nl_langinfo(_NL_ITEM(LC_TIME,
- (int)(((unsigned char *)p)[4]))
- )))
+ && (*(o = __XL(nl_langinfo)(_NL_ITEM(LC_TIME,
+ (int)(((unsigned char *)p)[4]))
+ __LOCALE_ARG
+ )))
) {
p = o;
goto LOOP;
}
#endif
- p = nl_langinfo(_NL_ITEM(LC_TIME,
- (int)(*((unsigned char *)p))));
+ p = __XL(nl_langinfo)(_NL_ITEM(LC_TIME,
+ (int)(*((unsigned char *)p)))
+ __LOCALE_ARG );
goto LOOP;
}
@@ -1295,9 +1364,9 @@ char *strptime(const char *__restrict buf, const char *__restrict format,
/* Go backwards to check full names before abreviations. */
do {
--j;
- o = nl_langinfo(i+j);
- if (!strncasecmp(buf,o,strlen(o)) && *o) { /* Found a match. */
- do {
+ o = __XL(nl_langinfo)(i+j __LOCALE_ARG);
+ if (!__XL(strncasecmp)(buf,o,strlen(o) __LOCALE_ARG) && *o) {
+ do { /* Found a match. */
++buf;
} while (*++o);
if (!code) { /* am/pm */
@@ -1322,11 +1391,11 @@ char *strptime(const char *__restrict buf, const char *__restrict format,
o = (char *) buf;
i = errno;
__set_errno(0);
- if (!isspace(*buf)) { /* Signal an error if whitespace. */
+ if (!ISSPACE(*buf)) { /* Signal an error if whitespace. */
#ifdef TIME_T_IS_UNSIGNED
- t = strtoul(buf, &o, 10);
+ t = __XL(strtoul)(buf, &o, 10 __LOCALE_ARG);
#else
- t = strtol(buf, &o, 10);
+ t = __XL(strtol)(buf, &o, 10 __LOCALE_ARG);
#endif
}
if ((o == buf) || errno) { /* Not a number or overflow. */
@@ -1356,7 +1425,7 @@ char *strptime(const char *__restrict buf, const char *__restrict format,
j = ((j==1) ? 366 : 9999);
}
i = -1;
- while (isdigit(*buf)) {
+ while (ISDIGIT(*buf)) {
if (i < 0) {
i = 0;
}
@@ -1401,9 +1470,9 @@ char *strptime(const char *__restrict buf, const char *__restrict format,
}
}
goto LOOP;
- } else if (isspace(*p)) {
+ } else if (ISSPACE(*p)) {
++p;
- while (isspace(*buf)) {
+ while (ISSPACE(*buf)) {
++buf;
}
goto LOOP;
@@ -1413,6 +1482,8 @@ char *strptime(const char *__restrict buf, const char *__restrict format,
return NULL;
}
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
#endif
/**********************************************************************/
#ifdef L_time
@@ -1478,10 +1549,10 @@ static const char *getoffset(register const char *e, long *pn)
f = -1;
do {
++s;
- if (isdigit(*e)) {
+ if (__isdigit_char(*e)) {
f = *e++ - '0';
}
- if (isdigit(*e)) {
+ if (__isdigit_char(*e)) {
f = 10 * f + (*e++ - '0');
}
if (((unsigned int)f) >= *s) {
@@ -1507,7 +1578,7 @@ static const char *getnumber(register const char *e, int *pn)
int f;
f = 0;
- while (n && isdigit(*e)) {
+ while (n && __isdigit_char(*e)) {
f = 10 * f + (*e++ - '0');
--n;
}
@@ -1519,7 +1590,7 @@ static const char *getnumber(register const char *e, int *pn)
n = 3;
f = 0;
- while (n && isdigit(*e)) {
+ while (n && __isdigit_char(*e)) {
f = 10 * f + (*e++ - '0');
--n;
}
@@ -1529,11 +1600,16 @@ static const char *getnumber(register const char *e, int *pn)
#endif /* __BCC__ */
}
-#ifdef __TIME_TZ_FILE
-#ifdef __TIME_TZ_FILE_ONCE
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Should we preserve errno from open/read/close errors re TZ file?
+#endif
+
+#ifdef __UCLIBC_HAS_TZ_FILE__
+
+#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
static int TZ_file_read; /* Let BSS initialization set this to 0. */
-#endif /* __TIME_TZ_FILE_ONCE */
+#endif /* __UCLIBC_HAS_TZ_FILE_READ_MANY__ */
static char *read_TZ_file(char *buf)
{
@@ -1542,7 +1618,7 @@ static char *read_TZ_file(char *buf)
size_t todo;
char *p = NULL;
- if ((fd = open("/etc/TZ", O_RDONLY)) >= 0) {
+ if ((fd = open(__UCLIBC_TZ_FILE_PATH__, O_RDONLY)) >= 0) {
todo = TZ_BUFLEN;
p = buf;
do {
@@ -1559,9 +1635,9 @@ static char *read_TZ_file(char *buf)
if ((p > buf) && (p[-1] == '\n')) { /* Must end with newline. */
p[-1] = 0;
p = buf;
-#ifdef __TIME_TZ_FILE_ONCE
+#ifndef __UCLIBC_HAS_TZ_FILE_READ_MANY__
++TZ_file_read;
-#endif /* __TIME_TZ_FILE_ONCE */
+#endif /* __UCLIBC_HAS_TZ_FILE_READ_MANY__ */
} else {
ERROR:
p = NULL;
@@ -1571,7 +1647,7 @@ static char *read_TZ_file(char *buf)
return p;
}
-#endif /* __TIME_TZ_FILE */
+#endif /* __UCLIBC_HAS_TZ_FILE__ */
void tzset(void)
{
@@ -1582,18 +1658,18 @@ void tzset(void)
rule_struct new_rules[2];
int n, count, f;
char c;
-#ifdef __TIME_TZ_FILE
+#ifdef __UCLIBC_HAS_TZ_FILE__
char buf[TZ_BUFLEN];
-#endif /* __TIME_TZ_FILE */
-#ifdef __TIME_TZ_OPT_SPEED
+#endif /* __UCLIBC_HAS_TZ_FILE__ */
+#ifdef __UCLIBC_HAS_TZ_CACHING__
static char oldval[TZ_BUFLEN]; /* BSS-zero'd. */
-#endif /* __TIME_TZ_OPT_SPEED */
+#endif /* __UCLIBC_HAS_TZ_CACHING__ */
TZLOCK;
e = getenv(TZ); /* TZ env var always takes precedence. */
-#ifdef __TIME_TZ_FILE_ONCE
+#if defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__)
/* Put this inside the lock to prevent the possiblity of two different
* timezones being used in a threaded app. */
@@ -1602,7 +1678,7 @@ void tzset(void)
} else if (TZ_file_read > 0) {
goto FAST_DONE;
}
-#endif /* __TIME_TZ_FILE_ONCE */
+#endif /* defined(__UCLIBC_HAS_TZ_FILE__) && !defined(__UCLIBC_HAS_TZ_FILE_READ_MANY__) */
/* Warning!!! Since uClibc doesn't do lib locking, the following is
* potentially unsafe in a multi-threaded program since it is remotely
@@ -1610,14 +1686,14 @@ void tzset(void)
* the string being parsed. So, don't do that... */
if ((!e /* TZ env var not set... */
-#ifdef __TIME_TZ_FILE
+#ifdef __UCLIBC_HAS_TZ_FILE__
&& !(e = read_TZ_file(buf)) /* and no file or invalid file */
-#endif /* __TIME_TZ_FILE */
+#endif /* __UCLIBC_HAS_TZ_FILE__ */
) || !*e) { /* or set to empty string. */
ILLEGAL: /* TODO: Clean up the following... */
-#ifdef __TIME_TZ_OPT_SPEED
+#ifdef __UCLIBC_HAS_TZ_CACHING__
*oldval = 0; /* Set oldval to an empty string. */
-#endif /* __TIME_TZ_OPT_SPEED */
+#endif /* __UCLIBC_HAS_TZ_CACHING__ */
s = _time_tzinfo[0].tzname;
*s = 'U';
*++s = 'T';
@@ -1632,7 +1708,7 @@ void tzset(void)
++e;
}
-#ifdef __TIME_TZ_OPT_SPEED
+#ifdef __UCLIBC_HAS_TZ_CACHING__
if (strcmp(e, oldval) == 0) { /* Same string as last time... */
goto FAST_DONE; /* So nothing to do. */
}
@@ -1640,7 +1716,7 @@ void tzset(void)
* it is too long, but it that case it will be illegal and will be reset
* to the empty string anyway. */
strncpy(oldval, e, TZ_BUFLEN);
-#endif /* __TIME_TZ_OPT_SPEED */
+#endif /* __UCLIBC_HAS_TZ_CACHING__ */
count = 0;
new_rules[1].tzname[0] = 0;
@@ -1675,7 +1751,7 @@ void tzset(void)
/* Get offset */
s = (char *) e;
if ((*e != '-') && (*e != '+')) {
- if (count && !isdigit(*e)) {
+ if (count && !__isdigit_char(*e)) {
off -= 3600; /* Default to 1 hour ahead of std. */
goto SKIP_OFFSET;
}
@@ -1938,8 +2014,9 @@ struct tm *_time_t2tm(const time_t *__restrict timer,
p[4] = 0; /* result[8] .. tm_isdst */
#ifdef __UCLIBC_HAS_TM_EXTENSIONS__
result->tm_gmtoff = 0;
+ result->tm_zone = result->__tm_tzname;
{
- register char *s = (char *) result->tm_zone;
+ register char *s = result->__tm_tzname;
*s = 'U';
*++s = 'T';
*++s = 'C';
@@ -1977,12 +2054,16 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)
/* 0:sec 1:min 2:hour 3:mday 4:mon 5:year 6:wday 7:yday 8:isdst */
register int *p = (int *) &x;
register const unsigned char *s;
- int d;
+ int d, default_dst;
tzset();
memcpy(p, timeptr, sizeof(struct tm));
+ if ((default_dst = p[8]) < 0) {
+ default_dst = 1; /* Assume advancing */
+ }
+
d = 400;
p[5] = (p[5] - ((p[6] = p[5]/d) * d)) + (p[7] = p[4]/12);
if ((p[4] -= 12 * p[7]) < 0) {
@@ -2007,49 +2088,69 @@ time_t _time_mktime(struct tm *timeptr, int store_on_success)
--d;
}
+ TZLOCK;
+
#ifdef __BCC__
d = p[5] - 1;
days = -719163L + ((long)d)*365 + ((d/4) - (d/100) + (d/400) + p[3] + p[7]);
secs = p[0] + 60*( p[1] + 60*((long)(p[2])) )
- + _time_tzinfo[timeptr->tm_isdst > 0].gmt_offset;
+ + _time_tzinfo[default_dst].gmt_offset;
+ DST_CORRECT:
if (secs < 0) {
secs += 120009600L;
days -= 1389;
}
if ( ((unsigned long)(days + secs/86400L)) > 49710L) {
- return -1;
+ t = ((time_t)(-1));
+ goto DONE;
}
secs += (days * 86400L);
#else
- TZLOCK;
d = p[5] - 1;
d = -719163L + d*365 + (d/4) - (d/100) + (d/400);
secs = p[0]
- + _time_tzinfo[timeptr->tm_isdst > 0].gmt_offset
+ + _time_tzinfo[default_dst].gmt_offset
+ 60*( p[1]
+ 60*(p[2]
+ 24*(((146073L * ((long long)(p[6])) + d)
+ p[3]) + p[7])));
- TZUNLOCK;
+
+ DST_CORRECT:
if (((unsigned long long)(secs - LONG_MIN))
> (((unsigned long long)LONG_MAX) - LONG_MIN)
) {
- return -1;
+ t = ((time_t)(-1));
+ goto DONE;
}
#endif
+ d = ((struct tm *)p)->tm_isdst;
t = secs;
localtime_r(&t, (struct tm *)p);
- if (t < 0) {
- return -1;
+ if (t == ((time_t)(-1))) { /* Remember, time_t can be unsigned. */
+ goto DONE;
+ }
+
+ if ((d < 0) && (((struct tm *)p)->tm_isdst != default_dst)) {
+#ifdef __BCC__
+ secs -= (days * 86400L);
+#endif
+ secs += (_time_tzinfo[1-default_dst].gmt_offset
+ - _time_tzinfo[default_dst].gmt_offset);
+ goto DST_CORRECT;
}
+
if (store_on_success) {
memcpy(timeptr, p, sizeof(struct tm));
}
+
+ DONE:
+ TZUNLOCK;
+
return t;
}
diff --git a/libc/misc/wchar/Makefile b/libc/misc/wchar/Makefile
index acc852195..4a3e2fc7a 100644
--- a/libc/misc/wchar/Makefile
+++ b/libc/misc/wchar/Makefile
@@ -42,7 +42,6 @@ MOBJ2= fwide.o \
# getwc (fgetwc alias) getwc_unlocked (fgetwc_unlocked alias)
# putwc (fputwc alias) putwc_unlocked (fputwc_unlocked alias)
-# fwscanf wscanf swscanf vfwscanf vwscanf vswscanf
# wcsftime
OBJS=$(MOBJ1) $(MOBJ2)
diff --git a/libc/misc/wchar/wchar.c b/libc/misc/wchar/wchar.c
index ff3e42a84..aa0c2735a 100644
--- a/libc/misc/wchar/wchar.c
+++ b/libc/misc/wchar/wchar.c
@@ -86,6 +86,9 @@
* Add a couple of ugly hacks to support *wprintf.
* Add a mini iconv() and iconv implementation (requires locale support).
*
+ * Aug 1, 2003
+ * Bug fix for mbrtowc.
+ *
* Manuel
*/
@@ -101,13 +104,39 @@
#include <assert.h>
#include <locale.h>
#include <wchar.h>
+#include <bits/uClibc_uwchar.h>
+/**********************************************************************/
#ifdef __UCLIBC_HAS_LOCALE__
-#define ENCODING (__global_locale.encoding)
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_iswspace
+/* generates one warning */
+#warning TODO: Fix Cc2wc* and Cwc2c* defines!
+#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#define ENCODING ((__UCLIBC_CURLOCALE_DATA).encoding)
+
+#define Cc2wc_IDX_SHIFT __LOCALE_DATA_Cc2wc_IDX_SHIFT
+#define Cc2wc_ROW_LEN __LOCALE_DATA_Cc2wc_ROW_LEN
+#define Cwc2c_DOMAIN_MAX __LOCALE_DATA_Cwc2c_DOMAIN_MAX
+#define Cwc2c_TI_SHIFT __LOCALE_DATA_Cwc2c_TI_SHIFT
+#define Cwc2c_TT_SHIFT __LOCALE_DATA_Cwc2c_TT_SHIFT
+#define Cwc2c_TI_LEN __LOCALE_DATA_Cwc2c_TI_LEN
+
#ifndef __CTYPE_HAS_UTF_8_LOCALES
#warning __CTYPE_HAS_UTF_8_LOCALES not set!
#endif
-#else
+
+#else /* __UCLIBC_HAS_LOCALE__ */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_btowc
+/* emit only once */
+#warning fix preprocessor logic testing locale settings
+#endif
+#endif
+
#define ENCODING (__ctype_encoding_7_bit)
#ifdef __CTYPE_HAS_8_BIT_LOCALES
#error __CTYPE_HAS_8_BIT_LOCALES is defined!
@@ -117,7 +146,9 @@
#endif
#undef L__wchar_utf8sntowcs
#undef L__wchar_wcsntoutf8s
-#endif
+
+#endif /* __UCLIBC_HAS_LOCALE__ */
+/**********************************************************************/
#if WCHAR_MAX > 0xffffUL
#define UTF_8_MAX_LEN 6
@@ -266,11 +297,18 @@ size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s,
#ifdef __CTYPE_HAS_UTF_8_LOCALES
/* Need to do this here since mbsrtowcs doesn't allow incompletes. */
if (ENCODING == __ctype_encoding_utf8) {
+ if (!pwc) {
+ pwc = wcbuf;
+ }
r = _wchar_utf8sntowcs(pwc, 1, &p, n, ps, 1);
return (r == 1) ? (p-s) : r; /* Need to return 0 if nul char. */
}
#endif
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: This adds a trailing nul!
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
r = __mbsnrtowcs(wcbuf, &p, SIZE_MAX, 1, ps);
if (((ssize_t) r) >= 0) {
@@ -291,7 +329,10 @@ size_t mbrtowc(wchar_t *__restrict pwc, const char *__restrict s,
size_t wcrtomb(register char *__restrict s, wchar_t wc,
mbstate_t *__restrict ps)
{
- wchar_t wcbuf[2];
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Should wcsnrtombs nul-terminate unconditionally? Check glibc.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+ wchar_t wcbuf[1];
const wchar_t *pwc;
size_t r;
char buf[MB_LEN_MAX];
@@ -303,9 +344,8 @@ size_t wcrtomb(register char *__restrict s, wchar_t wc,
pwc = wcbuf;
wcbuf[0] = wc;
- wcbuf[1] = 0;
- r = __wcsnrtombs(s, &pwc, SIZE_MAX, MB_LEN_MAX, ps);
+ r = __wcsnrtombs(s, &pwc, 1, MB_LEN_MAX, ps);
return (r != 0) ? r : 1;
}
@@ -418,7 +458,7 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
if ((wc = ((unsigned char) *s++)) >= 0x80) { /* Not ASCII... */
mask = 0x40;
#ifdef __UCLIBC_MJN3_ONLY__
-#warning fix range for 16 bit wides
+#warning TODO: Fix range for 16 bit wchar_t case.
#endif
if ( ((unsigned char)(s[-1] - 0xc0)) < (0xfe - 0xc0) ) {
goto START;
@@ -495,7 +535,6 @@ size_t _wchar_utf8sntowcs(wchar_t *__restrict pwc, size_t wn,
COMPLETE:
*pwc = wc;
pwc += incr;
-
}
#ifdef DECODER
while (--count);
@@ -684,8 +723,8 @@ size_t __mbsnrtowcs(wchar_t *__restrict dst, const char **__restrict src,
while (count) {
if ((wc = ((unsigned char)(*s))) >= 0x80) { /* Non-ASCII... */
wc -= 0x80;
- wc = __global_locale.tbl8c2wc[
- (__global_locale.idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
+ wc = __UCLIBC_CURLOCALE_DATA.tbl8c2wc[
+ (__UCLIBC_CURLOCALE_DATA.idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
<< Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
if (!wc) {
goto BAD;
@@ -797,12 +836,12 @@ size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src,
} else {
u = 0;
if (wc <= Cwc2c_DOMAIN_MAX) {
- u = __global_locale.idx8wc2c[wc >> (Cwc2c_TI_SHIFT
+ u = __UCLIBC_CURLOCALE_DATA.idx8wc2c[wc >> (Cwc2c_TI_SHIFT
+ Cwc2c_TT_SHIFT)];
- u = __global_locale.tbl8wc2c[(u << Cwc2c_TI_SHIFT)
+ u = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[(u << Cwc2c_TI_SHIFT)
+ ((wc >> Cwc2c_TT_SHIFT)
& ((1 << Cwc2c_TI_SHIFT)-1))];
- u = __global_locale.tbl8wc2c[Cwc2c_TI_LEN
+ u = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[Cwc2c_TI_LEN
+ (u << Cwc2c_TT_SHIFT)
+ (wc & ((1 << Cwc2c_TT_SHIFT)-1))];
}
@@ -859,7 +898,8 @@ size_t __wcsnrtombs(char *__restrict dst, const wchar_t **__restrict src,
#ifdef L_wcswidth
#ifdef __UCLIBC_MJN3_ONLY__
-#warning if we start doing translit, wcwidth and wcswidth will need updating.
+#warning REMINDER: If we start doing translit, wcwidth and wcswidth will need updating.
+#warning TODO: Update wcwidth to match latest by Kuhn.
#endif
#if defined(__UCLIBC_HAS_LOCALE__) && \
@@ -1163,7 +1203,7 @@ enum {
*
*/
-const unsigned char codesets[] =
+const unsigned char __iconv_codesets[] =
"\x0a\xe0""WCHAR_T\x00" /* superset of UCS-4 but platform-endian */
#if __BYTE_ORDER == __BIG_ENDIAN
"\x08\xec""UCS-4\x00" /* always BE */
@@ -1201,7 +1241,7 @@ static int find_codeset(const char *name)
const unsigned char *s;
int codeset;
- for (s = codesets ; *s ; s += *s) {
+ for (s = __iconv_codesets ; *s ; s += *s) {
if (!strcasecmp(s+2, name)) {
return s[1];
}
@@ -1212,10 +1252,10 @@ static int find_codeset(const char *name)
/* TODO: maybe CODESET_LIST + *s ??? */
/* 7bit is 1, UTF-8 is 2, 8-bit is >= 3 */
codeset = 2;
- s = CODESET_LIST;
+ s = __LOCALE_DATA_CODESET_LIST;
do {
++codeset; /* Increment codeset first. */
- if (!strcasecmp(CODESET_LIST+*s, name)) {
+ if (!strcasecmp(__LOCALE_DATA_CODESET_LIST+*s, name)) {
return codeset;
}
} while (*++s);
@@ -1223,7 +1263,7 @@ static int find_codeset(const char *name)
return 0; /* No matching codeset! */
}
-iconv_t iconv_open(const char *tocode, const char *fromcode)
+iconv_t weak_function iconv_open(const char *tocode, const char *fromcode)
{
register _UC_iconv_t *px;
int tocodeset, fromcodeset;
@@ -1244,16 +1284,17 @@ iconv_t iconv_open(const char *tocode, const char *fromcode)
return (iconv_t)(-1);
}
-int iconv_close(iconv_t cd)
+int weak_function iconv_close(iconv_t cd)
{
free(cd);
return 0;
}
-size_t iconv(iconv_t cd, char **__restrict inbuf,
- size_t *__restrict inbytesleft,
- char **__restrict outbuf, size_t *__restrict outbytesleft)
+size_t weak_function iconv(iconv_t cd, char **__restrict inbuf,
+ size_t *__restrict inbytesleft,
+ char **__restrict outbuf,
+ size_t *__restrict outbytesleft)
{
_UC_iconv_t *px = (_UC_iconv_t *) cd;
size_t nrcount, r;
@@ -1362,9 +1403,9 @@ size_t iconv(iconv_t cd, char **__restrict inbuf,
return (size_t)(-1);
}
#ifdef __UCLIBC_MJN3_ONLY__
-#warning optimize this
+#warning TODO: optimize this.
#endif
- if (p != NULL) { /* incomplet char case */
+ if (p != NULL) { /* incomplete char case */
goto INVALID;
}
p = *inbuf + 1; /* nul */
@@ -1374,10 +1415,10 @@ size_t iconv(iconv_t cd, char **__restrict inbuf,
if (px->fromcodeset == IC_ASCII) { /* US-ASCII codeset */
goto ILLEGAL;
} else { /* some other 8-bit ascii-extension codeset */
- const codeset_8_bit_t *c8b
+ const __codeset_8_bit_t *c8b
= __locale_mmap->codeset_8_bit + px->fromcodeset - 3;
wc -= 0x80;
- wc = __global_locale.tbl8c2wc[
+ wc = __UCLIBC_CURLOCALE_DATA.tbl8c2wc[
(c8b->idx8c2wc[wc >> Cc2wc_IDX_SHIFT]
<< Cc2wc_IDX_SHIFT) + (wc & (Cc2wc_ROW_LEN - 1))];
if (!wc) {
@@ -1439,7 +1480,7 @@ size_t iconv(iconv_t cd, char **__restrict inbuf,
r = _wchar_wcsntoutf8s(*outbuf, *outbytesleft, &pw, 1);
if (r != (size_t)(-1)) {
#ifdef __UCLIBC_MJN3_ONLY__
-#warning what happens for a nul?
+#warning TODO: What happens for a nul?
#endif
if (r == 0) {
if (wc != 0) {
@@ -1458,14 +1499,14 @@ size_t iconv(iconv_t cd, char **__restrict inbuf,
**outbuf = wc;
} else {
if ((px->tocodeset != 0x01) && (wc <= Cwc2c_DOMAIN_MAX)) {
- const codeset_8_bit_t *c8b
+ const __codeset_8_bit_t *c8b
= __locale_mmap->codeset_8_bit + px->tocodeset - 3;
__uwchar_t u;
u = c8b->idx8wc2c[wc >> (Cwc2c_TI_SHIFT + Cwc2c_TT_SHIFT)];
- u = __global_locale.tbl8wc2c[(u << Cwc2c_TI_SHIFT)
+ u = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[(u << Cwc2c_TI_SHIFT)
+ ((wc >> Cwc2c_TT_SHIFT)
& ((1 << Cwc2c_TI_SHIFT)-1))];
- wc = __global_locale.tbl8wc2c[Cwc2c_TI_LEN
+ wc = __UCLIBC_CURLOCALE_DATA.tbl8wc2c[Cwc2c_TI_LEN
+ (u << Cwc2c_TT_SHIFT)
+ (wc & ((1 << Cwc2c_TT_SHIFT)-1))];
if (wc) {
@@ -1497,7 +1538,7 @@ size_t iconv(iconv_t cd, char **__restrict inbuf,
#include <stdarg.h>
#include <libgen.h>
-extern const unsigned char codesets[];
+extern const unsigned char __iconv_codesets[];
#define IBUF BUFSIZ
#define OBUF BUFSIZ
@@ -1572,12 +1613,12 @@ int main(int argc, char **argv)
if (opts[5]) { /* -l */
fprintf(stderr, "Recognized codesets:\n");
- for (s = codesets ; *s ; s += *s) {
+ for (s = __iconv_codesets ; *s ; s += *s) {
fprintf(stderr," %s\n", s+2);
}
- s = CODESET_LIST;
+ s = __LOCALE_DATA_CODESET_LIST;
do {
- fprintf(stderr," %s\n", CODESET_LIST+ (unsigned char)(*s));
+ fprintf(stderr," %s\n", __LOCALE_DATA_CODESET_LIST+ (unsigned char)(*s));
} while (*++s);
return EXIT_SUCCESS;
diff --git a/libc/misc/wchar/wstdio.c b/libc/misc/wchar/wstdio.c
index dfeb35c30..1069ee938 100644
--- a/libc/misc/wchar/wstdio.c
+++ b/libc/misc/wchar/wstdio.c
@@ -171,7 +171,6 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream))
size_t r;
unsigned char c[1];
unsigned char sbuf[1];
- unsigned char ungot_width; /* Support ftell after wscanf ungetwc. */
wi = WEOF; /* Prepare for failure. */
@@ -183,8 +182,18 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream))
stream->modeflags |= __FLAG_WIDE;
if (stream->modeflags & __MASK_UNGOT) {/* Any ungetwc()s? */
- assert( (stream->modeflags & (__FLAG_READING|__FLAG_ERROR))
- == __FLAG_READING);
+
+ assert(stream->modeflags & __FLAG_READING);
+
+/* assert( (stream->modeflags & (__FLAG_READING|__FLAG_ERROR)) */
+/* == __FLAG_READING); */
+
+ if ((((stream->modeflags & __MASK_UNGOT) > 1) || stream->ungot[1])) {
+ stream->ungot_width[0] = 0; /* Application ungot... */
+ } else {
+ stream->ungot_width[0] = stream->ungot_width[1]; /* scanf ungot */
+ }
+
wi = stream->ungot[(--stream->modeflags) & __MASK_UNGOT];
stream->ungot[1] = 0;
goto DONE;
@@ -196,7 +205,9 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream))
++stream->bufend;
}
- ungot_width = 0;
+ if (stream->state.mask == 0) { /* If last was a complete char */
+ stream->ungot_width[0] = 0; /* then reset the width. */
+ }
LOOP:
if ((n = stream->bufread - stream->bufpos) == 0) {
@@ -204,12 +215,12 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream))
}
r = mbrtowc(wc, stream->bufpos, n, &stream->state);
- if (((ssize_t) r) >= 0) { /* Single byte... */
+ if (((ssize_t) r) >= 0) { /* Success... */
if (r == 0) { /* Nul wide char... means 0 byte for us so */
++r; /* increment r and handle below as single. */
}
stream->bufpos += r;
- stream->ungot_width[0] = ungot_width + r;
+ stream->ungot_width[0] += r;
wi = *wc;
goto DONE;
}
@@ -217,7 +228,7 @@ UNLOCKED(wint_t,fgetwc,(register FILE *stream),(stream))
if (r == ((size_t) -2)) {
/* Potentially valid but incomplete and no more buffered. */
stream->bufpos += n; /* Update bufpos for stream. */
- ungot_width += n;
+ stream->ungot_width[0] += n;
FILL_BUFFER:
if (_stdio_fread(c, (size_t) 1, stream) > 0) {
assert(stream->bufpos == stream->bufstart + 1);
@@ -371,7 +382,8 @@ UNLOCKED(int,fputws,(const wchar_t *__restrict ws,
#ifdef L_ungetwc
/*
* Note: This is the application-callable ungetwc. If wscanf calls this, it
- * should also set stream->ungot[1] to 0 if this is the only ungot.
+ * should also set stream->ungot[1] to 0 if this is the only ungot, as well
+ * as reset stream->ungot_width[1] for use by _stdio_adjpos().
*/
/* Reentrant. */
@@ -389,8 +401,7 @@ wint_t ungetwc(wint_t c, register FILE *stream)
}
stream->modeflags |= __FLAG_WIDE;
- /* If can't read or there's been an error, or c == EOF, or ungot slots
- * already filled, then return EOF */
+ /* If can't read or c == WEOF or ungot slots already filled, then fail. */
if ((stream->modeflags
& (__MASK_UNGOT2|__FLAG_WRITEONLY
#ifndef __STDIO_AUTO_RW_TRANSITION
@@ -406,14 +417,18 @@ wint_t ungetwc(wint_t c, register FILE *stream)
/* ungot_width */
#ifdef __STDIO_BUFFERS
- /* TODO: shouldn't allow writing??? */
+#ifdef __STDIO_AUTO_RW_TRANSITION
if (stream->modeflags & __FLAG_WRITING) {
fflush_unlocked(stream); /* Commit any write-buffered chars. */
}
+#endif /* __STDIO_AUTO_RW_TRANSITION */
#endif /* __STDIO_BUFFERS */
/* Clear EOF and WRITING flags, and set READING FLAG */
stream->modeflags &= ~(__FLAG_EOF|__FLAG_WRITING);
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Is setting the reading flag after an ungetwc necessary?
+#endif /* __UCLIBC_MJN3_ONLY__ */
stream->modeflags |= __FLAG_READING;
stream->ungot[1] = 1; /* Flag as app ungetc call; wscanf fixes up. */
stream->ungot[(stream->modeflags++) & __MASK_UNGOT] = c;
diff --git a/libc/misc/wctype/Makefile b/libc/misc/wctype/Makefile
index 875ccef56..44734945c 100644
--- a/libc/misc/wctype/Makefile
+++ b/libc/misc/wctype/Makefile
@@ -25,12 +25,22 @@ TOPDIR=../../../
include $(TOPDIR)Rules.mak
MSRC= wctype.c
-MOBJ= iswalnum.o iswalpha.o iswcntrl.o iswdigit.o iswgraph.o iswlower.o \
- iswprint.o iswpunct.o iswspace.o iswupper.o iswxdigit.o towlower.o \
- towupper.o iswblank.o wctype.o iswctype.o wctrans.o towctrans.o
+MOBJ= iswalnum.o iswalpha.o iswcntrl.o iswdigit.o iswgraph.o \
+ iswlower.o iswprint.o iswpunct.o iswspace.o iswupper.o \
+ iswxdigit.o iswblank.o wctrans.o towctrans.o \
+ wctype.o iswctype.o towlower.o towupper.o
+
+MOBJx= iswalnum_l.o iswalpha_l.o iswcntrl_l.o iswdigit_l.o iswgraph_l.o \
+ iswlower_l.o iswprint_l.o iswpunct_l.o iswspace_l.o iswupper_l.o \
+ iswxdigit_l.o iswblank_l.o \
+ wctype_l.o iswctype_l.o wctrans_l.o towctrans_l.o towlower_l.o towupper_l.o
OBJS=$(MOBJ)
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+ OBJS += $(MOBJx)
+endif
+
all: $(OBJS) $(LIBC)
$(LIBC): ar-target
@@ -42,6 +52,10 @@ $(MOBJ): $(MSRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
+$(MOBJx): $(MSRC)
+ $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
clean:
rm -f *.[oa] *~ core
diff --git a/libc/misc/wctype/wctype.c b/libc/misc/wctype/wctype.c
index 68b9e4579..e0dde3a1f 100644
--- a/libc/misc/wctype/wctype.c
+++ b/libc/misc/wctype/wctype.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Manuel Novoa III
+/* Copyright (C) 2002, 2003 Manuel Novoa III
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -35,149 +35,309 @@
#include <errno.h>
#include <locale.h>
#include <ctype.h>
+#include <stdint.h>
+#include <bits/uClibc_uwchar.h>
+
+#if defined(__LOCALE_C_ONLY) && defined(__UCLIBC_DO_XLOCALE)
+#error xlocale functionality is not supported in stub locale mode.
+#endif
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+#include <xlocale.h>
+
+extern int __iswctype_l (wint_t __wc, wctype_t __desc, __locale_t __locale);
+ __THROW;
+extern wint_t __towlower_l (wint_t __wc, __locale_t __locale) __THROW;
+
+extern wint_t __towupper_l (wint_t __wc, __locale_t __locale) __THROW;
+extern wint_t __towctrans_l (wint_t __wc, wctrans_t __desc,
+ __locale_t __locale) __THROW;
+
+#endif /* __UCLIBC_HAS_XLOCALE__ */
/* We know wide char support is enabled. We wouldn't be here otherwise. */
/* Define this if you want to unify the towupper and towlower code in the
* towctrans function. */
-/* #define SMALL_UPLOW */
+/* #define SMALL_UPLOW */
-#ifndef __LOCALE_C_ONLY
-#define __WCTYPE_WITH_LOCALE
+/**********************************************************************/
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_iswspace
+/* generates one warning */
+#warning TODO: Fix the __CTYPE_* codes!
+#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#if 1
+/* Taking advantage of the C99 mutual-exclusion guarantees for the various
+ * (w)ctype classes, including the descriptions of printing and control
+ * (w)chars, we can place each in one of the following mutually-exlusive
+ * subsets. Since there are less than 16, we can store the data for
+ * each (w)chars in a nibble. In contrast, glibc uses an unsigned int
+ * per (w)char, with one bit flag for each is* type. While this allows
+ * a simple '&' operation to determine the type vs. a range test and a
+ * little special handling for the "blank" and "xdigit" types in my
+ * approach, it also uses 8 times the space for the tables on the typical
+ * 32-bit archs we supported.*/
+enum {
+ __CTYPE_unclassified = 0,
+ __CTYPE_alpha_nonupper_nonlower,
+ __CTYPE_alpha_lower,
+ __CTYPE_alpha_upper_lower,
+ __CTYPE_alpha_upper,
+ __CTYPE_digit,
+ __CTYPE_punct,
+ __CTYPE_graph,
+ __CTYPE_print_space_nonblank,
+ __CTYPE_print_space_blank,
+ __CTYPE_space_nonblank_noncntrl,
+ __CTYPE_space_blank_noncntrl,
+ __CTYPE_cntrl_space_nonblank,
+ __CTYPE_cntrl_space_blank,
+ __CTYPE_cntrl_nonspace
+};
#endif
-/**********************************************************************/
-#ifndef __PASTE
-#define __PASTE(X,Y) X ## Y
+/* The following is used to implement wctype(), but it is defined
+ * here because the ordering must agree with that of the enumeration
+ * below (ignoring unclassified). */
+#define __CTYPE_TYPESTRING \
+ "\6alnum\0\6alpha\0\6blank\0\6cntrl\0\6digit\0\6graph\0\6lower\0" \
+ "\6print\0\6punct\0\6space\0\6upper\0\7xdigit\0\0"
+
+
+/* The values for wctype_t. */
+enum {
+ _CTYPE_unclassified = 0,
+ _CTYPE_isalnum,
+ _CTYPE_isalpha,
+ _CTYPE_isblank,
+ _CTYPE_iscntrl,
+ _CTYPE_isdigit,
+ _CTYPE_isgraph,
+ _CTYPE_islower,
+ _CTYPE_isprint,
+ _CTYPE_ispunct,
+ _CTYPE_isspace,
+ _CTYPE_isupper,
+ _CTYPE_isxdigit /* _MUST_ be last of the standard classes! */
+};
+
+/* The following is used to implement wctrans(). */
+
+#define __CTYPE_TRANSTRING "\10tolower\0\10toupper\0\10totitle\0\0"
+
+enum {
+ _CTYPE_tolower = 1,
+ _CTYPE_toupper,
+ _CTYPE_totitle
+};
+
+/*--------------------------------------------------------------------*/
+
+#define _CTYPE_iswxdigit (_CTYPE_isxdigit)
+
+/*--------------------------------------------------------------------*/
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_iswspace
+/* generates one warning */
+#warning TODO: Fix WC* defines!
#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
-#define C_MACRO(X) __PASTE(__C_,X)(wc)
+#define ENCODING ((__UCLIBC_CURLOCALE_DATA).encoding)
-#define CT_MACRO(X) __PASTE(__ctype_,X)(wc)
+#define WCctype ((__UCLIBC_CURLOCALE_DATA).tblwctype)
+#define WCuplow ((__UCLIBC_CURLOCALE_DATA).tblwuplow)
+#define WCcmob ((__UCLIBC_CURLOCALE_DATA).tblwcomb)
+#define WCuplow_diff ((__UCLIBC_CURLOCALE_DATA).tblwuplow_diff)
+
+
+#define WC_TABLE_DOMAIN_MAX __LOCALE_DATA_WC_TABLE_DOMAIN_MAX
+
+#define WCctype_II_LEN __LOCALE_DATA_WCctype_II_LEN
+#define WCctype_TI_LEN __LOCALE_DATA_WCctype_TI_LEN
+#define WCctype_UT_LEN __LOCALE_DATA_WCctype_UT_LEN
+#define WCctype_II_SHIFT __LOCALE_DATA_WCctype_II_SHIFT
+#define WCctype_TI_SHIFT __LOCALE_DATA_WCctype_TI_SHIFT
+
+#define WCuplow_II_LEN __LOCALE_DATA_WCuplow_II_LEN
+#define WCuplow_TI_LEN __LOCALE_DATA_WCuplow_TI_LEN
+#define WCuplow_UT_LEN __LOCALE_DATA_WCuplow_UT_LEN
+#define WCuplow_II_SHIFT __LOCALE_DATA_WCuplow_II_SHIFT
+#define WCuplow_TI_SHIFT __LOCALE_DATA_WCuplow_TI_SHIFT
+
+
+#define WCctype_TI_MASK ((1 << (WCctype_TI_SHIFT)) - 1)
+#define WCctype_II_MASK ((1 << (WCctype_II_SHIFT)) - 1)
/**********************************************************************/
-/* TODO: fix this! */
-#ifdef __WCTYPE_WITH_LOCALE
+#undef __PASTE2
+#undef __PASTE3
+#define __PASTE2(X,Y) X ## Y
+#define __PASTE3(X,Y,Z) X ## Y ## Z
-#define WCctype (__global_locale.tblwctype)
-#define WCuplow (__global_locale.tblwuplow)
-#define WCcmob (__global_locale.tblwcomb)
-#define WCuplow_diff (__global_locale.tblwuplow_diff)
+#ifdef __UCLIBC_DO_XLOCALE
-#define ENCODING (__global_locale.encoding)
+extern int __iswctype_l (wint_t __wc, wctype_t __desc, __locale_t __locale)
+ __THROW;
#define ISW_FUNC_BODY(NAME) \
-int NAME (wint_t wc) \
+int __PASTE3(__isw,NAME,_l) (wint_t wc, __locale_t l) \
{ \
- return iswctype(wc, __PASTE(_CTYPE_,NAME)); \
-}
+ return __iswctype_l(wc, __PASTE2(_CTYPE_is,NAME), l); \
+} \
+weak_alias(__PASTE3(__isw,NAME,_l), __PASTE3(isw,NAME,_l))
+
+#else /* __UCLIBC_DO_XLOCALE */
-#else /* __WCTYPE_WITH_LOCALE */
+extern int __iswctype (wint_t __wc, wctype_t __desc) __THROW;
#define ISW_FUNC_BODY(NAME) \
-int NAME (wint_t wc) \
+int __PASTE2(isw,NAME) (wint_t wc) \
{ \
- return C_MACRO(NAME); \
+ return __iswctype(wc, __PASTE2(_CTYPE_is,NAME)); \
}
-#endif /* __WCTYPE_WITH_LOCALE */
-
+#endif /* __UCLIBC_DO_XLOCALE */
/**********************************************************************/
-#ifdef L_iswalnum
+#if defined(L_iswalnum) || defined(L_iswalnum_l)
-ISW_FUNC_BODY(iswalnum);
+ISW_FUNC_BODY(alnum);
#endif
/**********************************************************************/
-#ifdef L_iswalpha
+#if defined(L_iswalpha) || defined(L_iswalpha_l)
-ISW_FUNC_BODY(iswalpha);
+ISW_FUNC_BODY(alpha);
#endif
/**********************************************************************/
-#ifdef L_iswblank
+#if defined(L_iswblank) || defined(L_iswblank_l)
-ISW_FUNC_BODY(iswblank);
+ISW_FUNC_BODY(blank);
#endif
/**********************************************************************/
-#ifdef L_iswcntrl
+#if defined(L_iswcntrl) || defined(L_iswcntrl_l)
-ISW_FUNC_BODY(iswcntrl);
+ISW_FUNC_BODY(cntrl);
#endif
/**********************************************************************/
-#ifdef L_iswdigit
+#if defined(L_iswdigit) || defined(L_iswdigit_l)
-int iswdigit(wint_t wc)
-{
- return __C_iswdigit(wc);
-}
+ISW_FUNC_BODY(digit);
#endif
/**********************************************************************/
-#ifdef L_iswgraph
+#if defined(L_iswgraph) || defined(L_iswgraph_l)
-ISW_FUNC_BODY(iswgraph);
+ISW_FUNC_BODY(graph);
#endif
/**********************************************************************/
-#ifdef L_iswlower
+#if defined(L_iswlower) || defined(L_iswlower_l)
-ISW_FUNC_BODY(iswlower);
+ISW_FUNC_BODY(lower);
#endif
/**********************************************************************/
-#ifdef L_iswprint
+#if defined(L_iswprint) || defined(L_iswprint_l)
-ISW_FUNC_BODY(iswprint);
+ISW_FUNC_BODY(print);
#endif
/**********************************************************************/
-#ifdef L_iswpunct
+#if defined(L_iswpunct) || defined(L_iswpunct_l)
-ISW_FUNC_BODY(iswpunct);
+ISW_FUNC_BODY(punct);
#endif
/**********************************************************************/
-#ifdef L_iswspace
+#if defined(L_iswspace) || defined(L_iswspace_l)
-ISW_FUNC_BODY(iswspace);
+ISW_FUNC_BODY(space);
#endif
/**********************************************************************/
-#ifdef L_iswupper
+#if defined(L_iswupper) || defined(L_iswupper_l)
-ISW_FUNC_BODY(iswupper);
+ISW_FUNC_BODY(upper);
#endif
/**********************************************************************/
-#ifdef L_iswxdigit
+#if defined(L_iswxdigit) || defined(L_iswxdigit_l)
-int iswxdigit(wint_t wc)
-{
- return __C_iswxdigit(wc);
-}
+ISW_FUNC_BODY(xdigit);
#endif
/**********************************************************************/
+#if defined(L_towlower) || defined(L_towlower_l)
+
#ifdef L_towlower
+#define TOWLOWER(w) towlower(w)
+#else /* L_towlower */
+#define TOWLOWER(w) __towlower_l(w, __locale_t locale)
+#undef __UCLIBC_CURLOCALE_DATA
+#undef __UCLIBC_CURLOCALE
+#define __UCLIBC_CURLOCALE_DATA (*locale)
+#define __UCLIBC_CURLOCALE (locale)
+#endif /* L_towlower */
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+#define TOWCTRANS(w,d) __towctrans_l(w,d, __UCLIBC_CURLOCALE)
+#else /* __UCLIBC_HAS_XLOCALE__ */
+#define TOWCTRANS(w,d) towctrans(w,d)
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+#define __C_towlower(wc) \
+ ((((__uwchar_t)(wc)) <= 0x7f) ? (__C_ctype_tolower)[(wc)] : (wc))
+
+#ifdef __LOCALE_C_ONLY
-#ifdef __WCTYPE_WITH_LOCALE
+wint_t towlower(wint_t wc)
+{
+ return __C_towlower(wc);
+}
+
+#else /* __LOCALE_C_ONLY */
#ifdef SMALL_UPLOW
+#if defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__)
+
wint_t towlower(wint_t wc)
{
- return towctrans(wc, _CTYPE_tolower);
+ return __towctrans_l(wc, _CTYPE_tolower, __UCLIBC_CURLOCALE);
}
-#else
+#else /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+wint_t TOWLOWER(wint_t wc)
+{
+ return TOWCTRANS(wc, _CTYPE_tolower);
+}
+
+#endif /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+#else /* SMALL_UPLOW */
+
+#if defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__)
wint_t towlower(wint_t wc)
{
+ return __towlower_l(wc, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+wint_t TOWLOWER(wint_t wc)
+{
unsigned int sc, n, i;
__uwchar_t u = wc;
@@ -202,34 +362,79 @@ wint_t towlower(wint_t wc)
return wc;
}
-#endif
+#endif /* defined(L_towlower) && defined(__UCLIBC_HAS_XLOCALE__) */
-#else /* __WCTYPE_WITH_LOCALE */
+#endif /* SMALL_UPLOW */
-wint_t towlower(wint_t wc)
-{
- return __C_towlower(wc);
-}
+#ifdef L_towlower_l
+weak_alias(__towlower_l, towlower_l)
+#endif /* L_towlower_l */
-#endif /* __WCTYPE_WITH_LOCALE */
+#endif /* __LOCALE_C_ONLY */
#endif
/**********************************************************************/
+#if defined(L_towupper) || defined(L_towupper_l)
+
#ifdef L_towupper
+#define TOWUPPER(w) towupper(w)
+#else /* L_towupper */
+#define TOWUPPER(w) __towupper_l(w, __locale_t locale)
+#undef __UCLIBC_CURLOCALE_DATA
+#undef __UCLIBC_CURLOCALE
+#define __UCLIBC_CURLOCALE_DATA (*locale)
+#define __UCLIBC_CURLOCALE (locale)
+#endif /* L_towupper */
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+#define TOWCTRANS(w,d) __towctrans_l(w,d, __UCLIBC_CURLOCALE)
+#else /* __UCLIBC_HAS_XLOCALE__ */
+#define TOWCTRANS(w,d) towctrans(w,d)
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+#define __C_towupper(wc) \
+ ((((__uwchar_t)(wc)) <= 0x7f) ? (__C_ctype_toupper)[(wc)] : (wc))
+
+#ifdef __LOCALE_C_ONLY
-#ifdef __WCTYPE_WITH_LOCALE
+wint_t towupper(wint_t wc)
+{
+ return __C_towupper(wc);
+}
+
+#else /* __LOCALE_C_ONLY */
#ifdef SMALL_UPLOW
+#if defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__)
+
wint_t towupper(wint_t wc)
{
- return towctrans(wc, _CTYPE_toupper);
+ return __towctrans_l(wc, _CTYPE_toupper, __UCLIBC_CURLOCALE);
}
-#else
+#else /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+wint_t TOWUPPER(wint_t wc)
+{
+ return TOWCTRANS(wc, _CTYPE_toupper);
+}
+
+#endif /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+#else /* SMALL_UPLOW */
+
+#if defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__)
wint_t towupper(wint_t wc)
{
+ return __towupper_l(wc, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+wint_t TOWUPPER(wint_t wc)
+{
unsigned int sc, n, i;
__uwchar_t u = wc;
@@ -254,16 +459,15 @@ wint_t towupper(wint_t wc)
return wc;
}
-#endif
+#endif /* defined(L_towupper) && defined(__UCLIBC_HAS_XLOCALE__) */
-#else /* __WCTYPE_WITH_LOCALE */
+#endif /* SMALL_UPLOW */
-wint_t towupper(wint_t wc)
-{
- return __C_towupper(wc);
-}
+#ifdef L_towupper_l
+weak_alias(__towupper_l, towupper_l)
+#endif /* L_towupper_l */
-#endif /* __WCTYPE_WITH_LOCALE */
+#endif /* __LOCALE_C_ONLY */
#endif
/**********************************************************************/
@@ -293,33 +497,102 @@ wctype_t wctype(const char *property)
#endif
/**********************************************************************/
-#ifdef L_iswctype
+#ifdef L_wctype_l
#ifdef __UCLIBC_MJN3_ONLY__
-#warning duh... replace the range-based classification with table lookup!
-#endif
+#warning REMINDER: Currently wctype_l simply calls wctype.
+#endif /* __UCLIBC_MJN3_ONLY__ */
-#ifdef __WCTYPE_WITH_LOCALE
+wctype_t __wctype_l (const char *property, __locale_t locale)
+{
+ return wctype(property);
+}
+
+weak_alias(__wctype_l, wctype_l)
+
+#endif
+/**********************************************************************/
+#if defined(L_iswctype) || defined(L_iswctype_l)
+
+#define __C_iswdigit(c) \
+ ((sizeof(c) == sizeof(char)) \
+ ? (((unsigned char)((c) - '0')) < 10) \
+ : (((__uwchar_t)((c) - '0')) < 10))
+#define __C_iswxdigit(c) \
+ (__C_iswdigit(c) \
+ || ((sizeof(c) == sizeof(char)) \
+ ? (((unsigned char)((((c)) | 0x20) - 'a')) < 6) \
+ : (((__uwchar_t)((((c)) | 0x20) - 'a')) < 6)))
#ifdef __UCLIBC_MJN3_ONLY__
-#warning TODO: need to fix locale ctype table lookup stuff
+#ifdef L_iswctype
+#warning CONSIDER: Change to bit shift? would need to sync with wctype.h
#endif
-#if 0
-extern const char ctype_range[];
-#else
-static const char ctype_range[] = {
- __CTYPE_RANGES
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+
+#if !defined(__UCLIBC_HAS_XLOCALE__) || defined(L_iswctype_l)
+
+static const unsigned short int desc2flag[] = {
+ [_CTYPE_unclassified] = 0,
+ [_CTYPE_isalnum] = (unsigned short int) _ISwalnum,
+ [_CTYPE_isalpha] = (unsigned short int) _ISwalpha,
+ [_CTYPE_isblank] = (unsigned short int) _ISwblank,
+ [_CTYPE_iscntrl] = (unsigned short int) _ISwcntrl,
+ [_CTYPE_isdigit] = (unsigned short int) _ISwdigit,
+ [_CTYPE_isgraph] = (unsigned short int) _ISwgraph,
+ [_CTYPE_islower] = (unsigned short int) _ISwlower,
+ [_CTYPE_isprint] = (unsigned short int) _ISwprint,
+ [_CTYPE_ispunct] = (unsigned short int) _ISwpunct,
+ [_CTYPE_isspace] = (unsigned short int) _ISwspace,
+ [_CTYPE_isupper] = (unsigned short int) _ISwupper,
+ [_CTYPE_isxdigit] = (unsigned short int) _ISwxdigit,
};
-#endif
+
+#endif /* defined(L_iswctype_L) || defined(__LOCALE_C_ONLY) */
+
+#ifdef __LOCALE_C_ONLY
+
+int __iswctype(wint_t wc, wctype_t desc)
+{
+ /* Note... wctype_t is unsigned. */
+
+ if ((((__uwchar_t) wc) <= 0x7f)
+ && (desc < (sizeof(desc2flag)/sizeof(desc2flag[0])))
+ ) {
+ return __isctype(wc, desc2flag[desc]);
+ }
+ return 0;
+}
+
+#else /* __LOCALE_C_ONLY */
#ifdef __UCLIBC_MJN3_ONLY__
-#warning TODO: need to handle combining class!
+#ifdef L_iswctype
+#warning CONSIDER: Handle combining class?
#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
-#define WCctype_TI_MASK ((1 << WCctype_TI_SHIFT) - 1)
-#define WCctype_II_MASK ((1 << WCctype_II_SHIFT) - 1)
+#ifdef L_iswctype
+#define ISWCTYPE(w,d) __iswctype(w,d)
+#else /* L_iswctype */
+#define ISWCTYPE(w,d) __iswctype_l(w,d, __locale_t locale)
+#undef __UCLIBC_CURLOCALE_DATA
+#undef __UCLIBC_CURLOCALE
+#define __UCLIBC_CURLOCALE_DATA (*locale)
+#define __UCLIBC_CURLOCALE (locale)
+#endif /* L_iswctype */
+
+#if defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__)
+
+int __iswctype(wint_t wc, wctype_t desc)
+{
+ return __iswctype_l(wc, desc, __UCLIBC_CURLOCALE);
+}
-int iswctype(wint_t wc, wctype_t desc)
+#else /* defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__) */
+
+int ISWCTYPE(wint_t wc, wctype_t desc)
{
unsigned int sc, n, i0, i1;
unsigned char d = __CTYPE_unclassified;
@@ -348,122 +621,100 @@ int iswctype(wint_t wc, wctype_t desc)
d = __CTYPE_punct;
}
+#if 0
return ( ((unsigned char)(d - ctype_range[2*desc]))
<= ctype_range[2*desc + 1] )
&& ((desc != _CTYPE_iswblank) || (d & 1));
+#else
+ return (__UCLIBC_CURLOCALE_DATA).code2flag[d] & desc2flag[desc];
+#endif
}
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: xdigit really needs to be handled better. Remember only for ascii!
+#endif /* __UCLIBC_MJN3_ONLY__ */
/* TODO - Add locale-specific classifications. */
return (desc == _CTYPE_iswxdigit) ? __C_iswxdigit(wc) : 0;
}
return 0;
}
-#else
+#endif /* defined(L_iswctype) && defined(__UCLIBC_HAS_XLOCALE__) */
-static const unsigned char WCctype[] = {
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_space_blank << 4),
- __CTYPE_cntrl_space_nonblank | (__CTYPE_cntrl_space_nonblank << 4),
- __CTYPE_cntrl_space_nonblank | (__CTYPE_cntrl_space_nonblank << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_cntrl_nonspace | (__CTYPE_cntrl_nonspace << 4),
- __CTYPE_print_space_blank | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_digit | (__CTYPE_digit << 4),
- __CTYPE_digit | (__CTYPE_digit << 4),
- __CTYPE_digit | (__CTYPE_digit << 4),
- __CTYPE_digit | (__CTYPE_digit << 4),
- __CTYPE_digit | (__CTYPE_digit << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_alpha_upper << 4),
- __CTYPE_alpha_upper | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_alpha_lower << 4),
- __CTYPE_alpha_lower | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_punct << 4),
- __CTYPE_punct | (__CTYPE_cntrl_nonspace << 4),
-};
+#ifdef L_iswctype_l
+weak_alias(__iswctype_l, iswctype_l)
+#endif /* L_iswctype_l */
-static const char ctype_range[] = {
- __CTYPE_RANGES
-};
+#endif /* __LOCALE_C_ONLY */
-int iswctype(wint_t wc, wctype_t desc)
-{
- unsigned char d = __CTYPE_unclassified;
+#ifdef L_iswctype
+weak_alias(__iswctype, iswctype)
+#endif /* L_iswctype */
- if (((__uwchar_t) wc) <= 0x7f) {
- if (desc < _CTYPE_iswxdigit) {
- d = WCctype[wc >> 1];
- d = (wc & 1) ? (d >> 4) : (d & 0xf);
+#endif
+/**********************************************************************/
+#if defined(L_towctrans) || defined(L_towctrans_l)
- return ( ((unsigned char)(d - ctype_range[2*desc]))
- <= ctype_range[2*desc + 1] )
- && ((desc != _CTYPE_iswblank) || (d & 1));
- }
+#ifdef __LOCALE_C_ONLY
+
+/* Minimal support for C/POSIX locale. */
+
+#ifndef _tolower
+#warning _tolower is undefined!
+#define _tolower(c) tolower(c)
+#endif
+#ifndef _toupper
+#warning _toupper is undefined!
+#define _toupper(c) toupper(c)
+#endif
- if (desc == _CTYPE_iswxdigit) {
- return __C_isxdigit(((char) wc));
+wint_t towctrans(wint_t wc, wctrans_t desc)
+{
+ if (((unsigned int)(desc - _CTYPE_tolower))
+ <= (_CTYPE_toupper - _CTYPE_tolower)
+ ) {
+ /* Transliteration is either tolower or toupper. */
+ if (((__uwchar_t) wc) <= 0x7f) {
+ return (desc == _CTYPE_tolower) ? _tolower(wc) : _toupper(wc);
}
+ } else {
+ __set_errno(EINVAL); /* Invalid transliteration. */
}
- return 0;
+ return wc;
}
-#endif
+#else /* __LOCALE_C_ONLY */
-#endif
-/**********************************************************************/
#ifdef L_towctrans
+#define TOWCTRANS(w,d) towctrans(w,d)
+#else /* L_towctrans */
+#define TOWCTRANS(w,d) __towctrans_l(w,d, __locale_t locale)
+#undef __UCLIBC_CURLOCALE_DATA
+#undef __UCLIBC_CURLOCALE
+#define __UCLIBC_CURLOCALE_DATA (*locale)
+#define __UCLIBC_CURLOCALE (locale)
+#endif /* L_towctrans */
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+#define TOWLOWER(w,l) __towlower_l(w,l)
+#define TOWUPPER(w,l) __towupper_l(w,l)
+#else /* __UCLIBC_HAS_XLOCALE__ */
+#define TOWLOWER(w,l) towlower(w)
+#define TOWUPPER(w,l) towupper(w)
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+#if defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__)
-#ifdef __WCTYPE_WITH_LOCALE
+wint_t towctrans(wint_t wc, wctrans_t desc)
+{
+ return __towctrans_l(wc, desc, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__) */
#ifdef SMALL_UPLOW
-wint_t towctrans(wint_t wc, wctrans_t desc)
+wint_t TOWCTRANS(wint_t wc, wctrans_t desc)
{
unsigned int sc, n, i;
__uwchar_t u = wc;
@@ -499,6 +750,9 @@ wint_t towctrans(wint_t wc, wctrans_t desc)
}
wc += WCuplow_diff[i];
if (desc == _CTYPE_totitle) {
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Verify totitle special cases!
+#endif /* __UCLIBC_MJN3_ONLY__ */
/* WARNING! These special cases work for glibc 2.2.4. Changes
* may be needed if the glibc locale tables are updated. */
if ( (((__uwchar_t)(wc - 0x1c4)) <= (0x1cc - 0x1c4))
@@ -516,9 +770,9 @@ wint_t towctrans(wint_t wc, wctrans_t desc)
return wc;
}
-#else
+#else /* SMALL_UPLOW */
-wint_t towctrans(wint_t wc, wctrans_t desc)
+wint_t TOWCTRANS(wint_t wc, wctrans_t desc)
{
if (ENCODING == __ctype_encoding_7_bit) {
if ((((__uwchar_t) wc) > 0x7f)
@@ -532,12 +786,15 @@ wint_t towctrans(wint_t wc, wctrans_t desc)
}
if (desc == _CTYPE_tolower) {
- return towlower(wc);
+ return TOWLOWER(wc, __UCLIBC_CURLOCALE);
} else if (((unsigned int)(desc - _CTYPE_toupper))
<= (_CTYPE_totitle - _CTYPE_toupper)
) {
- wc = towupper(wc);
+ wc = TOWUPPER(wc, __UCLIBC_CURLOCALE);
if (desc == _CTYPE_totitle) {
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Verify totitle special cases!
+#endif /* __UCLIBC_MJN3_ONLY__ */
/* WARNING! These special cases work for glibc 2.2.4. Changes
* may be needed if the glibc locale tables are updated. */
if ( (((__uwchar_t)(wc - 0x1c4)) <= (0x1cc - 0x1c4))
@@ -553,28 +810,15 @@ wint_t towctrans(wint_t wc, wctrans_t desc)
return wc;
}
-#endif
+#endif /* SMALL_UPLOW */
-#else /* __WCTYPE_WITH_LOCALE */
+#endif /* defined(L_towctrans) && defined(__UCLIBC_HAS_XLOCALE__) */
-/* Minimal support for C/POSIX locale. */
+#ifdef L_towctrans_l
+weak_alias(__towctrans_l, towctrans_l)
+#endif /* L_towctrans_l */
-wint_t towctrans(wint_t wc, wctrans_t desc)
-{
- if (((unsigned int)(desc - _CTYPE_tolower))
- <= (_CTYPE_toupper - _CTYPE_tolower)
- ) {
- /* Transliteration is either tolower or toupper. */
- if (((__uwchar_t) wc) <= 0x7f) {
- return (desc == _CTYPE_tolower) ? _tolower(wc) : _toupper(wc);
- }
- } else {
- __set_errno(EINVAL); /* Invalid transliteration. */
- }
- return wc;
-}
-
-#endif /* __WCTYPE_WITH_LOCALE */
+#endif /* __LOCALE_C_ONLY */
#endif
/**********************************************************************/
@@ -603,3 +847,18 @@ wctrans_t wctrans(const char *property)
#endif
/**********************************************************************/
+#ifdef L_wctrans_l
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning REMINDER: Currently wctrans_l simply calls wctrans.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+wctrans_t __wctrans_l(const char *property, __locale_t locale)
+{
+ return wctrans(property);
+}
+
+weak_alias(__wctrans_l, wctrans_l)
+
+#endif
+/**********************************************************************/
diff --git a/libc/stdio/Makefile b/libc/stdio/Makefile
index 9f8af9e4c..271fe7207 100644
--- a/libc/stdio/Makefile
+++ b/libc/stdio/Makefile
@@ -51,10 +51,15 @@ MSRC2= printf.c
MOBJ2= vsnprintf.o vdprintf.o vasprintf.o vprintf.o vsprintf.o \
fprintf.o snprintf.o dprintf.o asprintf.o printf.o sprintf.o
+MSRC3=scanf.c
+MOBJ3=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o \
+ __scan_cookie.o __psfs_parse_spec.o __psfs_do_numeric.o
+
ifeq ($(UCLIBC_HAS_WCHAR),y)
MOBJ += _wstdio_fwrite.o
MOBJ2 += fwprintf.o wprintf.o swprintf.o vwprintf.o vswprintf.o \
vfwprintf.o
+ MOBJ3 += wscanf.o swscanf.o fwscanf.o vwscanf.o vswscanf.o vfwscanf.o
endif
ifneq ($(USE_OLD_VFPRINTF),y)
@@ -63,16 +68,11 @@ ifneq ($(USE_OLD_VFPRINTF),y)
_store_inttype.o _load_inttype.o \
register_printf_function.o parse_printf_format.o
endif
-# _do_one_spec.o
-
ifeq ($(UCLIBC_HAS_FLOATS),y)
- MOBJ2 += _dtostr.o
+ MOBJ2 += _fpmaxtostr.o
endif
-MSRC3=scanf.c
-MOBJ3=scanf.o sscanf.o fscanf.o vscanf.o vsscanf.o vfscanf.o
-
CSRC=popen.c tmpfile.c tmpnam.c tmpnam_r.c tempnam.c
ifeq ($(USE_OLD_VFPRINTF),y)
CSRC += old_vfprintf.c
diff --git a/libc/stdio/old_vfprintf.c b/libc/stdio/old_vfprintf.c
index 9c8970912..77e593490 100644
--- a/libc/stdio/old_vfprintf.c
+++ b/libc/stdio/old_vfprintf.c
@@ -117,7 +117,8 @@
* strerror and the corresponding string table which together are about 3.8k.
*/
-#define WANT_GNU_ERRNO 0
+/* Now controlled by uClibc_stdio.h and set below. */
+/* #define WANT_GNU_ERRNO 0 */
/**************************************************************************/
@@ -143,6 +144,12 @@
/* #define __isdigit(c) (((unsigned int)(c - '0')) < 10) */
+#ifdef __STDIO_PRINTF_M_SUPPORT
+#define WANT_GNU_ERRNO 1
+#else
+#define WANT_GNU_ERRNO 0
+#endif
+
#if defined(__UCLIBC_HAS_FLOATS__)
extern size_t _dtostr(FILE * fp, long double x, struct printf_info *info);
#endif
diff --git a/libc/stdio/printf.c b/libc/stdio/printf.c
index 945d3c38d..da0444510 100644
--- a/libc/stdio/printf.c
+++ b/libc/stdio/printf.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Manuel Novoa III
+/* Copyright (C) 2002, 2003 Manuel Novoa III
* My stdio library for linux and (soon) elks.
*
* This library is free software; you can redistribute it and/or
@@ -63,6 +63,12 @@
* Nov 21, 2002
* Add *wprintf functions. Currently they don't support floating point
* conversions. That will wait until the rewrite of _dtostr.
+ *
+ * Aug 1, 2003
+ * Optional hexadecimal float notation support for %a/%A.
+ * Floating point output now works for *wprintf.
+ * Support for glibc locale-specific digit grouping for floats.
+ * Misc bug fixes.
*/
/* TODO:
@@ -90,6 +96,7 @@
#include <assert.h>
#include <stdint.h>
#include <errno.h>
+#include <locale.h>
#define __PRINTF_INFO_NO_BITFIELD
#include <printf.h>
@@ -103,11 +110,22 @@
#include <wchar.h>
#endif /* __UCLIBC_HAS_WCHAR__ */
-/**********************************************************************/
+/* Some older or broken gcc toolchains define LONG_LONG_MAX but not
+ * LLONG_MAX. Since LLONG_MAX is part of the standard, that's what
+ * we use. So complain if we do not have it but should.
+ */
+#if !defined(LLONG_MAX) && defined(LONG_LONG_MAX)
+#error Apparently, LONG_LONG_MAX is defined but LLONG_MAX is not. You need to fix your toolchain headers to support the standard macros for (unsigned) long long.
+#endif
+/**********************************************************************/
/* These provide some control over printf's feature set */
-#define __STDIO_PRINTF_FLOAT
-#define __STDIO_PRINTF_M_SUPPORT
+
+/* This is undefined below depeding on uClibc's configuration. */
+#define __STDIO_PRINTF_FLOAT 1
+
+/* Now controlled by uClibc_stdio.h. */
+/* #define __STDIO_PRINTF_M_SUPPORT */
/**********************************************************************/
@@ -120,28 +138,59 @@
#undef __STDIO_PRINTF_FLOAT
#endif
-#ifndef __STDIO_PRINTF_FLOAT
-#undef L__dtostr
-#endif
+#ifdef __STDIO_PRINTF_FLOAT
+#include <float.h>
+#include <bits/uClibc_fpmax.h>
+#else /* __STDIO_PRINTF_FLOAT */
+#undef L__fpmaxtostr
+#endif /* __STDIO_PRINTF_FLOAT */
/**********************************************************************/
-#define __STDIO_GLIBC_CUSTOM_PRINTF
+/* Now controlled by uClibc_stdio.h. */
+/* #define __STDIO_GLIBC_CUSTOM_PRINTF */
/* TODO -- move these to a configuration section? */
#define MAX_FIELD_WIDTH 4095
-#define MAX_USER_SPEC 10
-#define MAX_POS_ARGS 10
-/* TODO - fix the defs below */
-#define MAX_ARGS_PER_SPEC (MAX_POS_ARGS-2)
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_register_printf_function
+/* emit only once */
+#warning WISHLIST: Make MAX_USER_SPEC configurable?
+#warning WISHLIST: Make MAX_ARGS_PER_SPEC configurable?
+#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
+
+#define MAX_USER_SPEC 10
+#define MAX_ARGS_PER_SPEC 5
+
+#else /* __STDIO_GLIBC_CUSTOM_PRINTF */
-#if MAX_ARGS_PER_SPEC + 2 > MAX_POS_ARGS
-#define MAX_ARGS MAX_ARGS_PER_SPEC + 2
+#undef MAX_USER_SPEC
+#define MAX_ARGS_PER_SPEC 1
+
+#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
+
+#if MAX_ARGS_PER_SPEC < 1
+#error MAX_ARGS_PER_SPEC < 1!
+#undef MAX_ARGS_PER_SPEC
+#define MAX_ARGS_PER_SPEC 1
+#endif
+
+#if defined(NL_ARGMAX) && (NL_ARGMAX < 9)
+#error NL_ARGMAX < 9!
+#endif
+
+#if defined(NL_ARGMAX) && (NL_ARGMAX >= (MAX_ARGS_PER_SPEC + 2))
+#define MAX_ARGS NL_ARGMAX
#else
-#define MAX_ARGS MAX_POS_ARGS
+/* N for spec itself, plus 1 each for width and precision */
+#define MAX_ARGS (MAX_ARGS_PER_SPEC + 2)
#endif
+
/**********************************************************************/
/* Deal with pre-C99 compilers. */
@@ -154,7 +203,7 @@
* to ensure we get the right behavior? Either that or fall back
* on the portable (but costly in size) method of using a va_list *.
* That means a pointer derefs in the va_arg() invocations... */
-#warning neither va_copy or __va_copy is defined. using a simple copy instead...
+#warning Neither va_copy (C99/SUSv3) or __va_copy is defined. Using a simple copy instead. But you should really check that this is appropriate...
/* the glibc manual suggests that this will usually suffice when
__va_copy doesn't exist. */
#define va_copy(A,B) A = B
@@ -167,9 +216,11 @@
#define __PA_FLAG_INTMASK \
(__PA_FLAG_CHAR|PA_FLAG_SHORT|__PA_FLAG_INT|PA_FLAG_LONG|PA_FLAG_LONG_LONG)
+#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
extern printf_function _custom_printf_handler[MAX_USER_SPEC];
extern printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
extern char *_custom_printf_spec;
+#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
/**********************************************************************/
@@ -282,7 +333,7 @@ enum {
#elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
#define IMS 8
#else
-#error fix QUAL_CHARS ptrdiff_t entry 't'!
+#error fix QUAL_CHARS intmax_t entry 'j'!
#endif
#define QUAL_CHARS { \
@@ -340,7 +391,9 @@ typedef union {
typedef struct {
const char *fmtpos; /* TODO: move below struct?? */
struct printf_info info;
+#ifdef NL_ARGMAX
int maxposarg; /* > 0 if args are positional, 0 if not, -1 if unknown */
+#endif /* NL_ARGMAX */
int num_data_args; /* TODO: use sentinal??? */
unsigned int conv_num;
unsigned char argnumber[4]; /* width | prec | 1st data | unused */
@@ -349,6 +402,7 @@ typedef struct {
#ifdef __va_arg_ptr
void *argptr[MAX_ARGS];
#else
+/* if defined(NL_ARGMAX) || defined(__STDIO_GLIBC_CUSTOM_PRINTF) */
/* While this is wasteful of space in the case where pos args aren't
* enabled, it is also needed to support custom printf handlers. */
argvalue_t argvalue[MAX_ARGS];
@@ -361,7 +415,11 @@ typedef struct {
only returns -1 if sets error indicator for the stream. */
#ifdef __STDIO_PRINTF_FLOAT
-extern size_t _dtostr(FILE * fp, long double x, struct printf_info *info);
+typedef void (__fp_outfunc_t)(FILE *fp, intptr_t type, intptr_t len,
+ intptr_t buf);
+
+extern size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
+ __fp_outfunc_t fp_outfunc);
#endif
extern int _ppfs_init(ppfs_t *ppfs, const char *fmt0); /* validates */
@@ -390,6 +448,7 @@ size_t parse_printf_format(register const char *template,
size_t count = 0;
if (_ppfs_init(&ppfs, template) >= 0) {
+#ifdef NL_ARGMAX
if (ppfs.maxposarg > 0) { /* Using positional args. */
count = ppfs.maxposarg;
if (n > count) {
@@ -399,6 +458,7 @@ size_t parse_printf_format(register const char *template,
*argtypes++ = ppfs.argtype[i];
}
} else { /* Not using positional args. */
+#endif /* NL_ARGMAX */
while (*template) {
if ((*template == '%') && (*++template != '%')) {
ppfs.fmtpos = template;
@@ -431,7 +491,9 @@ size_t parse_printf_format(register const char *template,
++template;
}
}
+#ifdef NL_ARGMAX
}
+#endif /* NL_ARGMAX */
}
return count;
@@ -443,17 +505,23 @@ size_t parse_printf_format(register const char *template,
int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
{
-#ifdef __UCLIBC_HAS_WCHAR__
- static const char invalid_mbs[] = "Invalid multibyte format string.";
-#endif /* __UCLIBC_HAS_WCHAR__ */
int r;
/* First, zero out everything... argnumber[], argtype[], argptr[] */
memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
+#ifdef NL_ARGMAX
--ppfs->maxposarg; /* set to -1 */
+#endif /* NL_ARGMAX */
ppfs->fmtpos = fmt0;
-#ifdef __UCLIBC_HAS_WCHAR__
- {
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Make checking of the format string in C locale an option.
+#endif
+#ifdef __UCLIBC_HAS_LOCALE__
+ /* To support old programs, don't check mb validity if in C locale. */
+ if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) {
+ /* ANSI/ISO C99 requires format string to be a valid multibyte string
+ * beginning and ending in its initial shift state. */
+ static const char invalid_mbs[] = "Invalid multibyte format string.";
mbstate_t mbstate;
const char *p;
mbstate.mask = 0; /* Initialize the mbstate. */
@@ -463,7 +531,7 @@ int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
return -1;
}
}
-#endif /* __UCLIBC_HAS_WCHAR__ */
+#endif /* __UCLIBC_HAS_LOCALE__ */
/* now set all argtypes to no-arg */
{
#if 1
@@ -506,6 +574,7 @@ int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
ppfs->fmtpos = fmt0; /* rewind */
}
+#ifdef NL_MAX_ARG
/* If we have positional args, make sure we know all the types. */
{
register int *p = ppfs->argtype;
@@ -517,6 +586,7 @@ int _ppfs_init(register ppfs_t *ppfs, const char *fmt0)
++p;
}
}
+#endif /* NL_MAX_ARG */
return 0;
}
@@ -529,12 +599,14 @@ void _ppfs_prepargs(register ppfs_t *ppfs, va_list arg)
va_copy(ppfs->arg, arg);
+#ifdef NL_ARGMAX
if ((i = ppfs->maxposarg) > 0) { /* init for positional args */
ppfs->num_data_args = i;
ppfs->info.width = ppfs->info.prec = ppfs->maxposarg = 0;
_ppfs_setargs(ppfs);
ppfs->maxposarg = i;
}
+#endif /* NL_ARGMAX */
}
#endif
/**********************************************************************/
@@ -549,7 +621,9 @@ void _ppfs_setargs(register ppfs_t *ppfs)
#endif
int i;
+#ifdef NL_ARGMAX
if (ppfs->maxposarg == 0) { /* initing for or no pos args */
+#endif /* NL_ARGMAX */
if (ppfs->info.width == INT_MIN) {
ppfs->info.width =
#ifdef __va_arg_ptr
@@ -615,6 +689,7 @@ void _ppfs_setargs(register ppfs_t *ppfs)
}
++p;
}
+#ifdef NL_ARGMAX
} else {
if (ppfs->info.width == INT_MIN) {
ppfs->info.width
@@ -625,6 +700,7 @@ void _ppfs_setargs(register ppfs_t *ppfs)
= (int) GET_ARG_VALUE(p + ppfs->argnumber[1] - 1,u,unsigned int);
}
}
+#endif /* NL_ARGMAX */
/* Now we know the width and precision. */
if (ppfs->info.width < 0) {
@@ -741,12 +817,14 @@ static int _is_equal_or_bigger_arg(int curtype, int newtype)
#endif
+#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
/* TODO - do this differently? */
static char _bss_custom_printf_spec[MAX_USER_SPEC]; /* 0-init'd for us. */
char *_custom_printf_spec = _bss_custom_printf_spec;
printf_arginfo_function *_custom_printf_arginfo[MAX_USER_SPEC];
printf_function _custom_printf_handler[MAX_USER_SPEC];
+#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
extern int _ppfs_parsespec(ppfs_t *ppfs)
{
@@ -758,12 +836,13 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
int dataargtype;
int i;
int dpoint;
+#ifdef NL_ARGMAX
int maxposarg;
+#endif /* NL_ARGMAX */
int p_m_spec_chars;
int n;
int argtype[MAX_ARGS_PER_SPEC+2];
int argnumber[3]; /* width, precision, 1st data arg */
- unsigned int conv_num; /* This does not need to be initialized. */
static const char spec_flags[] = SPEC_FLAGS;
static const char spec_chars[] = SPEC_CHARS;/* TODO: b? */
static const char spec_ranges[] = SPEC_RANGES;
@@ -781,7 +860,10 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
argnumber[1] = 0;
argtype[0] = __PA_NOARG;
argtype[1] = __PA_NOARG;
+#ifdef NL_ARGMAX
maxposarg = ppfs->maxposarg;
+#endif /* NL_ARGMAX */
+
#ifdef __UCLIBC_HAS_WCHAR__
/* This is somewhat lame, but saves a lot of code. If we're dealing with
* a wide stream, that means the format is a wchar string. So, copy it
@@ -820,7 +902,7 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
++fmt;
}
i = 0;
- while (__isdigit(*fmt)) {
+ while (isdigit(*fmt)) {
if (i < MAX_FIELD_WIDTH) { /* Avoid overflow. */
i = (i * 10) + (*fmt - '0');
}
@@ -830,6 +912,7 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
/* TODO: if val not in range, then error */
+#ifdef NL_ARGMAX
if ((*fmt == '$') && (i > 0)) {/* Positional spec. */
++fmt;
if (maxposarg == 0) {
@@ -846,7 +929,7 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
#warning TODO: Support prec and width for %m when positional args used
/* Actually, positional arg processing will fail in general
* for specifiers that don't require an arg. */
-#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
if (*fmt == 'm') {
goto PREC_WIDTH;
}
@@ -862,6 +945,18 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
fmt = p; /* Back up for possible '0's flag. */
/* Now fall through to check flags. */
}
+#else /* NL_ARGMAX */
+ if (*fmt == '$') { /* Positional spec. */
+ return -1;
+ }
+
+ if ((fmt > p) && (*p != '0')) {
+ goto PREC_WIDTH;
+ }
+
+ fmt = p; /* Back up for possible '0's flag. */
+ /* Now fall through to check flags. */
+#endif /* NL_ARGMAX */
restart_flags: /* Process flags. */
i = 1;
@@ -889,13 +984,16 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
}
PREC_WIDTH:
if (*p == '*') { /* Prec or width takes an arg. */
+#ifdef NL_ARGMAX
if (maxposarg) {
if ((*fmt++ != '$') || (i <= 0)) {
/* Using pos args and no $ or invalid arg number. */
return -1;
}
argnumber[-dpoint] = i;
- } else if (++p != fmt) {
+ } else
+#endif /* NL_ARGMAX */
+ if (++p != fmt) {
/* Not using pos args but digits followed *. */
return -1;
}
@@ -943,7 +1041,7 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
p_m_spec_chars -= 2; /* lc -> C and ls -> S */
}
- conv_num = p_m_spec_chars;
+ ppfs->conv_num = p_m_spec_chars;
p = spec_ranges-1;
while (p_m_spec_chars > *++p) {}
@@ -962,18 +1060,17 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
ppfs->num_data_args = 1;
if (!*p) {
-#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
- /* TODO -- gnu %m support build option. */
#ifdef __STDIO_PRINTF_M_SUPPORT
if (*fmt == 'm') {
- conv_num = CONV_m;
+ ppfs->conv_num = CONV_m;
ppfs->num_data_args = 0;
goto DONE;
}
#endif
+#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
/* Handle custom arg -- WARNING -- overwrites p!!! */
- conv_num = CONV_custom0;
+ ppfs->conv_num = CONV_custom0;
p = _custom_printf_spec;
do {
if (*p == *fmt) {
@@ -991,10 +1088,11 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
return -1;
}
-#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
+#if defined(__STDIO_GLIBC_CUSTOM_PRINTF) || defined(__STDIO_PRINTF_M_SUPPORT)
DONE:
#endif
+#ifdef NL_ARGMAX
if (maxposarg > 0) {
i = 0;
do {
@@ -1014,12 +1112,14 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
}
} while (++i < ppfs->num_data_args + 2);
} else {
+#endif /* NL_ARGMAX */
ppfs->argnumber[2] = 1;
memcpy(ppfs->argtype, argtype + 2, ppfs->num_data_args * sizeof(int));
+#ifdef NL_ARGMAX
}
ppfs->maxposarg = maxposarg;
- ppfs->conv_num = conv_num;
+#endif /* NL_ARGMAX */
#ifdef __UCLIBC_HAS_WCHAR__
if ((flags = ppfs->info._flags & FLAG_WIDESTREAM) == 0) {
@@ -1039,6 +1139,8 @@ extern int _ppfs_parsespec(ppfs_t *ppfs)
/**********************************************************************/
#ifdef L_register_printf_function
+#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
+
int register_printf_function(int spec, printf_function handler,
printf_arginfo_function arginfo)
{
@@ -1076,10 +1178,17 @@ int register_printf_function(int spec, printf_function handler,
}
return -1;
}
+
+#endif
+
#endif
/**********************************************************************/
#ifdef L_vsnprintf
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning WISHLIST: Implement vsnprintf for non-buffered and no custom stream case.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
#ifdef __STDIO_BUFFERS
int vsnprintf(char *__restrict buf, size_t size,
const char * __restrict format, va_list arg)
@@ -1206,7 +1315,7 @@ int vsnprintf(char *__restrict buf, size_t size,
}
#else /* __STDIO_GLIBC_CUSTOM_STREAMS */
-#warning skipping vsnprintf since no buffering and no custom streams!
+#warning Skipping vsnprintf since no buffering and no custom streams!
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
#endif /* __STDIO_BUFFERS */
#endif
@@ -1258,7 +1367,7 @@ int vdprintf(int filedes, const char * __restrict format, va_list arg)
#ifdef L_vasprintf
#if !defined(__STDIO_BUFFERS) && !defined(__STDIO_GLIBC_CUSTOM_STREAMS)
-#warning skipping vasprintf since no buffering and no custom streams!
+#warning Skipping vasprintf since no buffering and no custom streams!
#else
int vasprintf(char **__restrict buf, const char * __restrict format,
@@ -1312,7 +1421,7 @@ int vprintf(const char * __restrict format, va_list arg)
#ifdef L_vsprintf
#if !defined(__STDIO_BUFFERS) && !defined(__STDIO_GLIBC_CUSTOM_STREAMS)
-#warning skipping vsprintf since no buffering and no custom streams!
+#warning Skipping vsprintf since no buffering and no custom streams!
#else
int vsprintf(char *__restrict buf, const char * __restrict format,
@@ -1343,7 +1452,7 @@ int fprintf(FILE * __restrict stream, const char * __restrict format, ...)
#ifdef L_snprintf
#if !defined(__STDIO_BUFFERS) && !defined(__STDIO_GLIBC_CUSTOM_STREAMS)
-#warning skipping snprintf since no buffering and no custom streams!
+#warning Skipping snprintf since no buffering and no custom streams!
#else
int snprintf(char *__restrict buf, size_t size,
@@ -1380,7 +1489,7 @@ int dprintf(int filedes, const char * __restrict format, ...)
#ifdef L_asprintf
#if !defined(__STDIO_BUFFERS) && !defined(__STDIO_GLIBC_CUSTOM_STREAMS)
-#warning skipping asprintf and __asprintf since no buffering and no custom streams!
+#warning Skipping asprintf and __asprintf since no buffering and no custom streams!
#else
weak_alias(__asprintf,asprintf)
@@ -1417,7 +1526,7 @@ int printf(const char * __restrict format, ...)
#ifdef L_sprintf
#if !defined(__STDIO_BUFFERS) && !defined(__STDIO_GLIBC_CUSTOM_STREAMS)
-#warning skipping sprintf since no buffering and no custom streams!
+#warning Skipping sprintf since no buffering and no custom streams!
#else
int sprintf(char *__restrict buf, const char * __restrict format, ...)
@@ -1492,7 +1601,7 @@ int vswprintf(wchar_t *__restrict buf, size_t size,
return rv;
}
#else /* __STDIO_BUFFERS */
-#warning skipping vswprintf since no buffering!
+#warning Skipping vswprintf since no buffering!
#endif /* __STDIO_BUFFERS */
#endif
/**********************************************************************/
@@ -1512,7 +1621,7 @@ int swprintf(wchar_t *__restrict buf, size_t size,
}
#else /* __STDIO_BUFFERS */
-#warning skipping vsWprintf since no buffering!
+#warning Skipping vsWprintf since no buffering!
#endif /* __STDIO_BUFFERS */
#endif
/**********************************************************************/
@@ -1553,174 +1662,249 @@ int wprintf(const wchar_t * __restrict format, ...)
}
#endif
/**********************************************************************/
-#ifdef L__dtostr
-/*
- * Copyright (C) 2000, 2001 Manuel Novoa III
+#ifdef L__fpmaxtostr
+
+/* Copyright (C) 2000, 2001, 2003 Manuel Novoa III
+ *
+ * Function:
*
- * Function: size_t _dtostr(FILE *fp, long double x, struct printf_info *info)
+ * size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
+ * __fp_outfunc_t fp_outfunc);
*
- * This was written for uClibc to provide floating point support for
- * the printf functions. It handles +/- infinity and nan on i386.
+ * This is derived from the old _dtostr, whic I wrote for uClibc to provide
+ * floating point support for the printf functions. It handles +/- infinity,
+ * nan, and signed 0 assuming you have ieee arithmetic. It also now handles
+ * digit grouping (for the uClibc supported locales) and hexadecimal float
+ * notation. Finally, via the fp_outfunc parameter, it now supports wide
+ * output.
*
* Notes:
*
- * At most MAX_DIGITS significant digits are kept. Any trailing digits
+ * At most DECIMAL_DIG significant digits are kept. Any trailing digits
* are treated as 0 as they are really just the results of rounding noise
* anyway. If you want to do better, use an arbitary precision arithmetic
* package. ;-)
*
- * It should also be fairly portable, as not assumptions are made about the
- * bit-layout of doubles.
- *
- * It should be too difficult to convert this to handle long doubles on i386.
- * For information, see the comments below.
+ * It should also be fairly portable, as no assumptions are made about the
+ * bit-layout of doubles. Of course, that does make it less efficient than
+ * it could be.
*
- * TODO:
- * long double and/or float version? (note: for float can trim code some).
- *
- * Decrease the size. This is really much bigger than I'd like.
*/
/*****************************************************************************/
/* Don't change anything that follows unless you know what you're doing. */
/*****************************************************************************/
-
-/*
- * Configuration for the scaling power table. Ignoring denormals, you
- * should have 2**EXP_TABLE_SIZE >= LDBL_MAX_EXP >= 2**(EXP_TABLE_SIZE-1).
- * The minimum for standard C is 6. For IEEE 8bit doubles, 9 suffices.
- * For long doubles on i386, use 13.
+/* Fairly portable nan check. Bitwise for i386 generated larger code.
+ * If you have a better version, comment this out.
*/
-#define EXP_TABLE_SIZE 13
+#define isnan(x) ((x) != (x))
-/*
- * Set this to the maximum number of digits you want converted.
- * Conversion is done in blocks of DIGITS_PER_BLOCK (9 by default) digits.
- * (20) 17 digits suffices to uniquely determine a (long) double on i386.
+/* Without seminumerical functions to examine the sign bit, this is
+ * about the best we can do to test for '-0'.
*/
-#define MAX_DIGITS 20
+#define zeroisnegative(x) ((1./(x)) < 0)
-/*
- * Set this to the smallest integer type capable of storing a pointer.
- */
-#define INT_OR_PTR int
+/*****************************************************************************/
+/* Don't change anything that follows peroid!!! ;-) */
+/*****************************************************************************/
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+#if FLT_RADIX != 2
+#error FLT_RADIX != 2 is not currently supported
+#endif
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
-/*
- * This is really only used to check for infinities. The macro produces
- * smaller code for i386 and, since this is tested before any floating point
- * calculations, it doesn't appear to suffer from the excess precision problem
- * caused by the FPU that strtod had. If it causes problems, call the function
- * and compile zoicheck.c with -ffloat-store.
- */
-#define _zero_or_inf_check(x) ( x == (x/4) )
+#define NUM_HEX_DIGITS ((FPMAX_MANT_DIG + 3)/ 4)
-/*
- * Fairly portable nan check. Bitwise for i386 generated larger code.
- * If you have a better version, comment this out.
+/* WARNING: Adjust _fp_out_wide() below if this changes! */
+/* With 32 bit ints, we can get 9 decimal digits per block. */
+#define DIGITS_PER_BLOCK 9
+#define HEX_DIGITS_PER_BLOCK 8
+
+/* Maximum number of subcases to output double is...
+ * 0 - sign
+ * 1 - padding and initial digit
+ * 2 - digits left of the radix
+ * 3 - 0s left of the radix or radix
+ * 4 - radix or digits right of the radix
+ * 5 - 0s right of the radix
+ * 6 - exponent
+ * 7 - trailing space padding
+ * although not all cases may occur.
*/
-#define isnan(x) (x != x)
+#define MAX_CALLS 8
/*****************************************************************************/
-/* Don't change anything that follows peroid!!! ;-) */
-/*****************************************************************************/
-#include <float.h>
+#define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
+#define NUM_HEX_DIGIT_BLOCKS \
+ ((NUM_HEX_DIGITS+HEX_DIGITS_PER_BLOCK-1)/HEX_DIGITS_PER_BLOCK)
-/*****************************************************************************/
+/* WARNING: Adjust _fp_out_wide() below if this changes! */
-/*
- * Set things up for the scaling power table.
- */
+/* extra space for '-', '.', 'e+###', and nul */
+#define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
-#if EXP_TABLE_SIZE < 6
-#error EXP_TABLE_SIZE should be at least 6 to comply with standards
-#endif
+/*****************************************************************************/
-#define EXP_TABLE_MAX (1U<<(EXP_TABLE_SIZE-1))
+static const char fmt[] = "inf\0INF\0nan\0NAN\0.\0,";
-/*
- * Only bother checking if this is too small.
- */
+#define INF_OFFSET 0 /* must be 1st */
+#define NAN_OFFSET 8 /* must be 2nd.. see hex sign handling */
+#define DECPT_OFFSET 16
+#define THOUSEP_OFFSET 18
-#if LDBL_MAX_10_EXP/2 > EXP_TABLE_MAX
-#error larger EXP_TABLE_SIZE needed
-#endif
+#define EMPTY_STRING_OFFSET 3
-/*
- * With 32 bit ints, we can get 9 digits per block.
- */
-#define DIGITS_PER_BLOCK 9
+/*****************************************************************************/
+#if FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP
+#error scaling code can not handle FPMAX_MAX_10_EXP < -FPMAX_MIN_10_EXP
+#endif
-#if INT_MAX >= 2147483647L
-#define DIGIT_BLOCK_TYPE int
-#define DB_FMT "%.*d"
-#elif LONG_MAX >= 2147483647L
-#define DIGIT_BLOCK_TYPE long
-#define DB_FMT "%.*ld"
-#else
-#warning need at least 32 bit longs
+static const __fpmax_t exp10_table[] =
+{
+ 1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, /* floats */
+#if FPMAX_MAX_10_EXP < 32
+#error unsupported FPMAX_MAX_10_EXP (< 32). ANSI/ISO C requires >= 37.
+#endif
+#if FPMAX_MAX_10_EXP >= 64
+ 1e64L,
#endif
+#if FPMAX_MAX_10_EXP >= 128
+ 1e128L,
+#endif
+#if FPMAX_MAX_10_EXP >= 256
+ 1e256L,
+#endif
+#if FPMAX_MAX_10_EXP >= 512
+ 1e512L,
+#endif
+#if FPMAX_MAX_10_EXP >= 1024
+ 1e1024L,
+#endif
+#if FPMAX_MAX_10_EXP >= 2048
+ 1e2048L,
+#endif
+#if FPMAX_MAX_10_EXP >= 4096
+ 1e4096L
+#endif
+#if FPMAX_MAX_10_EXP >= 8192
+#error unsupported FPMAX_MAX_10_EXP. please increase table
+#endif
+};
-/* Maximum number of calls to fnprintf to output double. */
-#define MAX_CALLS 8
+#define EXP10_TABLE_SIZE (sizeof(exp10_table)/sizeof(exp10_table[0]))
+#define EXP10_TABLE_MAX (1U<<(EXP10_TABLE_SIZE-1))
/*****************************************************************************/
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
-#define NUM_DIGIT_BLOCKS ((MAX_DIGITS+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
+#if FLT_RADIX != 2
+#error FLT_RADIX != 2 is not currently supported
+#endif
-/* extra space for '-', '.', 'e+###', and nul */
-#define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
-/*****************************************************************************/
+#if FPMAX_MAX_EXP < -FPMAX_MIN_EXP
+#error scaling code can not handle FPMAX_MAX_EXP < -FPMAX_MIN_EXP
+#endif
-static const char *fmts[] = {
- "%0*d", "%.*s", ".", "inf", "INF", "nan", "NAN", "%*s"
+static const __fpmax_t exp16_table[] = {
+ 0x1.0p4L, 0x1.0p8L, 0x1.0p16L, 0x1.0p32L, 0x1.0p64L,
+#if FPMAX_MAX_EXP >= 128
+ 0x1.0p128L,
+#endif
+#if FPMAX_MAX_EXP >= 256
+ 0x1.0p256L,
+#endif
+#if FPMAX_MAX_EXP >= 512
+ 0x1.0p512L,
+#endif
+#if FPMAX_MAX_EXP >= 1024
+ 0x1.0p1024L,
+#endif
+#if FPMAX_MAX_EXP >= 2048
+ 0x1.0p2048L,
+#endif
+#if FPMAX_MAX_EXP >= 4096
+ 0x1.0p4096L,
+#endif
+#if FPMAX_MAX_EXP >= 8192
+ 0x1.0p8192L,
+#endif
+#if FPMAX_MAX_EXP >= 16384
+ 0x1.0p16384L
+#endif
+#if FPMAX_MAX_EXP >= 32768
+#error unsupported FPMAX_MAX_EXP. please increase table
+#endif
};
-/*****************************************************************************/
-#include <locale.h>
+#define EXP16_TABLE_SIZE (sizeof(exp16_table)/sizeof(exp16_table[0]))
+#define EXP16_TABLE_MAX (1U<<(EXP16_TABLE_SIZE-1))
-#ifdef __UCLIBC_MJN3_ONLY__
-#warning REMINDER: implement grouping for floating point
-#endif
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+/*****************************************************************************/
-#ifndef __LOCALE_C_ONLY
-#define CUR_LOCALE (__global_locale)
-#endif /* __LOCALE_C_ONLY */
+#define FPO_ZERO_PAD (0x80 | '0')
+#define FPO_STR_WIDTH (0x80 | ' ');
+#define FPO_STR_PREC 'p'
-size_t _dtostr(FILE * fp, long double x, struct printf_info *info)
+size_t _fpmaxtostr(FILE * fp, __fpmax_t x, struct printf_info *info,
+ __fp_outfunc_t fp_outfunc)
{
- long double exp_table[EXP_TABLE_SIZE];
- long double p10;
- DIGIT_BLOCK_TYPE digit_block; /* int of at least 32 bits */
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ __fpmax_t lower_bnd;
+ __fpmax_t upper_bnd = 1e9;
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+ uint_fast32_t digit_block;
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ uint_fast32_t base = 10;
+ const __fpmax_t *power_table;
+ int dpb = DIGITS_PER_BLOCK;
+ int ndb = NUM_DIGIT_BLOCKS;
+ int nd = DECIMAL_DIG;
+ int sufficient_precision = 0;
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+ int num_groups = 0;
+ int initial_group; /* This does not need to be initialized. */
+ int tslen; /* This does not need to be initialized. */
+ int nblk2; /* This does not need to be initialized. */
+ const char *ts; /* This does not need to be initialized. */
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
int i, j;
int round, o_exp;
int exp, exp_neg;
int width, preci;
+ int cnt;
char *s;
char *e;
+ intptr_t pc_fwi[3*MAX_CALLS];
+ intptr_t *ppc;
+ intptr_t *ppc_last;
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: The size of exp_buf[] should really be determined by the float constants.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+ char exp_buf[16];
char buf[BUF_SIZE];
- INT_OR_PTR pc_fwi[2*MAX_CALLS];
- INT_OR_PTR *ppc;
- char exp_buf[8];
- char drvr[8];
- char *pdrvr;
- int npc;
- int cnt;
- char sign_str[2];
+ char sign_str[6]; /* Last 2 are for 1st digit + nul. */
char o_mode;
char mode;
- /* check that INT_OR_PTR is sufficiently large */
- assert( sizeof(INT_OR_PTR) == sizeof(char *) );
width = info->width;
preci = info->prec;
mode = info->spec;
- if (mode == 'a') {
- mode = 'g'; /* TODO -- fix */
- }
- if (mode == 'A') {
- mode = 'G'; /* TODO -- fix */
+
+ *exp_buf = 'e';
+ if ((mode|0x20) == 'a') {
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ *exp_buf = 'p';
+ if (preci < 0) {
+ preci = NUM_HEX_DIGITS;
+ sufficient_precision = 1;
+ }
+#else
+ mode += ('g' - 'a');
+#endif
}
if (preci < 0) {
@@ -1733,134 +1917,196 @@ size_t _dtostr(FILE * fp, long double x, struct printf_info *info)
} else if (PRINT_INFO_FLAG_VAL(info,space)) {
*sign_str = ' ';
}
-/* *sign_str = flag[FLAG_PLUS]; */
+
*(sign_str+1) = 0;
- if (isnan(x)) { /* nan check */
- pdrvr = drvr + 1;
- *pdrvr++ = 5 + (mode < 'a');
- pc_fwi[2] = 3;
- info->pad = ' ';
-/* flag[FLAG_0_PAD] = 0; */
- goto EXIT_SPECIAL;
+ pc_fwi[5] = INF_OFFSET;
+ if (isnan(x)) { /* First, check for nan. */
+ pc_fwi[5] = NAN_OFFSET;
+ goto INF_NAN;
}
- if (x == 0) { /* handle 0 now to avoid false positive */
+ if (x == 0) { /* Handle 0 now to avoid false positive. */
+#if 1
+ if (zeroisnegative(x)) { /* Handle 'signed' zero. */
+ *sign_str = '-';
+ }
+#endif
exp = -1;
goto GENERATE_DIGITS;
}
- if (x < 0) { /* convert negatives to positives */
+ if (x < 0) { /* Convert negatives to positives. */
*sign_str = '-';
x = -x;
}
- if (_zero_or_inf_check(x)) { /* must be inf since zero handled above */
- pdrvr = drvr + 1;
- *pdrvr++ = 3 + + (mode < 'a');
- pc_fwi[2] = 3;
+ if (__FPMAX_ZERO_OR_INF_CHECK(x)) { /* Inf since zero handled above. */
+ INF_NAN:
info->pad = ' ';
-/* flag[FLAG_0_PAD] = 0; */
+ ppc = pc_fwi + 6;
+ pc_fwi[3] = FPO_STR_PREC;
+ pc_fwi[4] = 3;
+ if (mode < 'a') {
+ pc_fwi[5] += 4;
+ }
+ pc_fwi[5] = (intptr_t)(fmt + pc_fwi[5]);
goto EXIT_SPECIAL;
}
- /* need to build the scaling table */
- for (i = 0, p10 = 10 ; i < EXP_TABLE_SIZE ; i++) {
- exp_table[i] = p10;
- p10 *= p10;
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Clean up defines when hexadecimal float notation is unsupported.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+
+ if ((mode|0x20) == 'a') {
+ lower_bnd = 0x1.0p31L;
+ upper_bnd = 0x1.0p32L;
+ power_table = exp16_table;
+ exp = HEX_DIGITS_PER_BLOCK - 1;
+ i = EXP16_TABLE_SIZE;
+ j = EXP16_TABLE_MAX;
+ dpb = HEX_DIGITS_PER_BLOCK;
+ ndb = NUM_HEX_DIGIT_BLOCKS;
+ nd = NUM_HEX_DIGITS;
+ base = 16;
+ } else {
+ lower_bnd = 1e8;
+/* upper_bnd = 1e9; */
+ power_table = exp10_table;
+ exp = DIGITS_PER_BLOCK - 1;
+ i = EXP10_TABLE_SIZE;
+ j = EXP10_TABLE_MAX;
+/* dpb = DIGITS_PER_BLOCK; */
+/* ndb = NUM_DIGIT_BLOCKS; */
+/* base = 10; */
}
+
+
+#else /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+#define lower_bnd 1e8
+#define upper_bnd 1e9
+#define power_table exp10_table
+#define dpb DIGITS_PER_BLOCK
+#define base 10
+#define ndb NUM_DIGIT_BLOCKS
+#define nd DECIMAL_DIG
+
+ exp = DIGITS_PER_BLOCK - 1;
+ i = EXP10_TABLE_SIZE;
+ j = EXP10_TABLE_MAX;
+
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
exp_neg = 0;
- if (x < 1e8) { /* do we need to scale up or down? */
+ if (x < lower_bnd) { /* Do we need to scale up or down? */
exp_neg = 1;
}
- exp = DIGITS_PER_BLOCK - 1;
-
- i = EXP_TABLE_SIZE;
- j = EXP_TABLE_MAX;
- while ( i-- ) { /* scale x such that 1e8 <= x < 1e9 */
+ do {
+ --i;
if (exp_neg) {
- if (x * exp_table[i] < 1e9) {
- x *= exp_table[i];
+ if (x * power_table[i] < upper_bnd) {
+ x *= power_table[i];
exp -= j;
}
} else {
- if (x / exp_table[i] >= 1e8) {
- x /= exp_table[i];
+ if (x / power_table[i] >= lower_bnd) {
+ x /= power_table[i];
exp += j;
}
}
j >>= 1;
- }
- if (x >= 1e9) { /* handle bad rounding case */
- x /= 10;
+ } while (i);
+ if (x >= upper_bnd) { /* Handle bad rounding case. */
+ x /= power_table[0];
++exp;
}
- assert(x < 1e9);
+ assert(x < upper_bnd);
GENERATE_DIGITS:
- s = buf + 2; /* leave space for '\0' and '0' */
-#if 1
-#define ONE_E_NINE 1000000000L
-#else
-#define ONE_E_NINE 1e9
-#endif
- for (i = 0 ; i < NUM_DIGIT_BLOCKS ; ++i ) {
- digit_block = (DIGIT_BLOCK_TYPE) x;
- x = (x - digit_block) * ONE_E_NINE;
- s += sprintf(s, DB_FMT, DIGITS_PER_BLOCK, digit_block);
- }
+ s = buf + 2; /* Leave space for '\0' and '0'. */
+ i = 0;
+ do {
+ digit_block = (uint_fast32_t) x;
+ assert(digit_block < upper_bnd);
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Can rounding be a problem?
+#endif /* __UCLIBC_MJN3_ONLY__ */
+ x = (x - digit_block) * upper_bnd;
+ s += dpb;
+ j = 0;
+ do {
+ s[- ++j] = '0' + (digit_block % base);
+ digit_block /= base;
+ } while (j < dpb);
+ } while (++i < ndb);
/*************************************************************************/
- *exp_buf = 'e';
if (mode < 'a') {
- *exp_buf = 'E';
+ *exp_buf -= ('a' - 'A'); /* e->E and p->P */
mode += ('a' - 'A');
}
o_mode = mode;
-
- round = preci;
-
- if ((mode == 'g') && (round > 0)){
- --round;
+ if ((mode == 'g') && (preci > 0)){
+ --preci;
}
+ round = preci;
if (mode == 'f') {
round += exp;
if (round < -1) {
- memset(buf, '0', MAX_DIGITS);
+ memset(buf, '0', DECIMAL_DIG); /* OK, since 'f' -> decimal case. */
exp = -1;
round = -1;
}
}
s = buf;
- *s++ = 0; /* terminator for rounding and 0-triming */
- *s = '0'; /* space to round */
+ *s++ = 0; /* Terminator for rounding and 0-triming. */
+ *s = '0'; /* Space to round. */
i = 0;
- e = s + MAX_DIGITS + 1;
- if (round < MAX_DIGITS) {
+ e = s + nd + 1;
+ if (round < nd) {
e = s + round + 2;
- if (*e >= '5') {
+ if (*e >= '0' + (base/2)) { /* NOTE: We always round away from 0! */
i = 1;
}
}
- do { /* handle rounding and trim trailing 0s */
- *--e += i; /* add the carry */
- } while ((*e == '0') || (*e > '9'));
+ do { /* Handle rounding and trim trailing 0s. */
+ *--e += i; /* Add the carry. */
+ } while ((*e == '0') || (*e > '0' - 1 + base));
+
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ if ((mode|0x20) == 'a') {
+ char *q;
+
+ for (q = e ; *q ; --q) {
+ if (*q > '9') {
+ *q += (*exp_buf - ('p' - 'a') - '9' - 1);
+ }
+ }
+
+ if (e > s) {
+ exp *= 4; /* Change from base 16 to base 2. */
+ }
+ }
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
o_exp = exp;
- if (e <= s) { /* we carried into extra digit */
+ if (e <= s) { /* We carried into an extra digit. */
++o_exp;
- e = s; /* needed if all 0s */
+ e = s; /* Needed if all 0s. */
} else {
++s;
}
- *++e = 0; /* ending nul char */
+ *++e = 0; /* Terminating nul char. */
if ((mode == 'g') && ((o_exp >= -4) && (o_exp <= round))) {
mode = 'f';
@@ -1871,34 +2117,73 @@ size_t _dtostr(FILE * fp, long double x, struct printf_info *info)
o_exp = 0;
}
- if (o_exp < 0) {
- *--s = '0'; /* fake the first digit */
+ if (o_exp < 0) { /* Exponent is < 0, so */
+ *--s = '0'; /* fake the first 0 digit. */
}
- pdrvr = drvr+1;
- ppc = pc_fwi+2;
-
- *pdrvr++ = 0;
- *ppc++ = 1;
- *ppc++ = (INT_OR_PTR)(*s++ - '0');
+ pc_fwi[3] = FPO_ZERO_PAD;
+ pc_fwi[4] = 1;
+ pc_fwi[5] = (intptr_t)(sign_str + 4);
+ sign_str[4] = *s++;
+ sign_str[5] = 0;
+ ppc = pc_fwi + 6;
- i = e - s; /* total digits */
+ i = e - s; /* Total digits is 'i'. */
if (o_exp >= 0) {
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+
+ const char *p;
+
+ if (PRINT_INFO_FLAG_VAL(info,group)
+ && *(p = __UCLIBC_CURLOCALE_DATA.grouping)
+ ) {
+ int nblk1;
+
+ nblk2 = nblk1 = *p;
+ if (*++p) {
+ nblk2 = *p;
+ assert(!*++p);
+ }
+
+ if (o_exp >= nblk1) {
+ num_groups = (o_exp - nblk1) / nblk2 + 1;
+ initial_group = (o_exp - nblk1) % nblk2;
+
+#ifdef __UCLIBC_HAS_WCHAR__
+ if (PRINT_INFO_FLAG_VAL(info,wide)) {
+ /* _fp_out_wide() will fix this up. */
+ ts = fmt + THOUSEP_OFFSET;
+ tslen = 1;
+ } else {
+#endif /* __UCLIBC_HAS_WCHAR__ */
+ ts = __UCLIBC_CURLOCALE_DATA.thousands_sep;
+ tslen = __UCLIBC_CURLOCALE_DATA.thousands_sep_len;
+#ifdef __UCLIBC_HAS_WCHAR__
+ }
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+ width -= num_groups * tslen;
+ }
+ }
+
+
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+ ppc[0] = FPO_STR_PREC;
+ ppc[2] = (intptr_t)(s);
if (o_exp >= i) { /* all digit(s) left of decimal */
- *pdrvr++ = 1;
- *ppc++ = i;
- *ppc++ = (INT_OR_PTR)(s);
+ ppc[1] = i;
+ ppc += 3;
o_exp -= i;
i = 0;
if (o_exp>0) { /* have 0s left of decimal */
- *pdrvr++ = 0;
- *ppc++ = o_exp;
- *ppc++ = 0;
+ ppc[0] = FPO_ZERO_PAD;
+ ppc[1] = o_exp;
+ ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
+ ppc += 3;
}
} else if (o_exp > 0) { /* decimal between digits */
- *pdrvr++ = 1;
- *ppc++ = o_exp;
- *ppc++ = (INT_OR_PTR)(s);
+ ppc[1] = o_exp;
+ ppc += 3;
s += o_exp;
i -= o_exp;
}
@@ -1906,105 +2191,221 @@ size_t _dtostr(FILE * fp, long double x, struct printf_info *info)
}
if (PRINT_INFO_FLAG_VAL(info,alt)
-/* flag[FLAG_HASH] */
- || (i) || ((o_mode != 'g') && (preci > 0))) {
+ || (i)
+ || ((o_mode != 'g')
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ && (o_mode != 'a')
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+ && (preci > 0))
+ ) {
+ ppc[0] = FPO_STR_PREC;
#ifdef __LOCALE_C_ONLY
- *pdrvr++ = 2; /* need decimal */
- *ppc++ = 1; /* needed for width calc */
- ppc++;
+ ppc[1] = 1;
+ ppc[2] = (intptr_t)(fmt + DECPT_OFFSET);
#else /* __LOCALE_C_ONLY */
- *pdrvr++ = 1;
- *ppc++ = strlen(CUR_LOCALE.decimal_point);
- *ppc++ = (INT_OR_PTR)(CUR_LOCALE.decimal_point);
+#ifdef __UCLIBC_HAS_WCHAR__
+ if (PRINT_INFO_FLAG_VAL(info,wide)) {
+ /* _fp_out_wide() will fix this up. */
+ ppc[1] = 1;
+ ppc[2] = (intptr_t)(fmt + DECPT_OFFSET);
+ } else {
+#endif /* __UCLIBC_HAS_WCHAR__ */
+ ppc[1] = __UCLIBC_CURLOCALE_DATA.decimal_point_len;
+ ppc[2] = (intptr_t)(__UCLIBC_CURLOCALE_DATA.decimal_point);
+#ifdef __UCLIBC_HAS_WCHAR__
+ }
+#endif /* __UCLIBC_HAS_WCHAR__ */
#endif /* __LOCALE_C_ONLY */
+ ppc += 3;
}
- if (++o_exp < 0) { /* have 0s right of decimal */
- *pdrvr++ = 0;
- *ppc++ = -o_exp;
- *ppc++ = 0;
+ if (++o_exp < 0) { /* Have 0s right of decimal. */
+ ppc[0] = FPO_ZERO_PAD;
+ ppc[1] = -o_exp;
+ ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
+ ppc += 3;
}
- if (i) { /* have digit(s) right of decimal */
- *pdrvr++ = 1;
- *ppc++ = i;
- *ppc++ = (INT_OR_PTR)(s);
+ if (i) { /* Have digit(s) right of decimal. */
+ ppc[0] = FPO_STR_PREC;
+ ppc[1] = i;
+ ppc[2] = (intptr_t)(s);
+ ppc += 3;
}
- if (o_mode != 'g') {
+ if (((o_mode != 'g') || PRINT_INFO_FLAG_VAL(info,alt))
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ && !sufficient_precision
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+ ) {
i -= o_exp;
- if (i < preci) { /* have 0s right of digits */
+ if (i < preci) { /* Have 0s right of digits. */
i = preci - i;
- *pdrvr++ = 0;
- *ppc++ = i;
- *ppc++ = 0;
+ ppc[0] = FPO_ZERO_PAD;
+ ppc[1] = i;
+ ppc[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
+ ppc += 3;
}
}
- /* build exponent string */
+ /* Build exponent string. */
if (mode != 'f') {
- *pdrvr++ = 1;
- *ppc++ = sprintf(exp_buf,"%c%+.2d", *exp_buf, exp);
- *ppc++ = (INT_OR_PTR) exp_buf;
+ char *p = exp_buf + sizeof(exp_buf);
+ char exp_char = *exp_buf;
+ char exp_sign = '+';
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ int min_exp_dig_plus_2 = ((o_mode != 'a') ? (2+2) : (2+1));
+#else /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+#define min_exp_dig_plus_2 (2+2)
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+ if (exp < 0) {
+ exp_sign = '-';
+ exp = -exp;
+ }
+
+ *--p = 0; /* nul-terminate */
+ j = 2; /* Count exp_char and exp_sign. */
+ do {
+ *--p = '0' + (exp % 10);
+ exp /= 10;
+ } while ((++j < min_exp_dig_plus_2) || exp); /* char+sign+mindigits */
+ *--p = exp_sign;
+ *--p = exp_char;
+
+ ppc[0] = FPO_STR_PREC;
+ ppc[1] = j;
+ ppc[2] = (intptr_t)(p);
+ ppc += 3;
}
EXIT_SPECIAL:
- npc = pdrvr - drvr;
- ppc = pc_fwi + 2;
- for (i=1 ; i< npc ; i++) {
- width -= *(ppc++);
- ppc++;
- }
- i = 0;
- if (*sign_str) {
- i = 1;
- }
- width -= i;
- if (width <= 0) {
- width = 0;
- } else {
- if (PRINT_INFO_FLAG_VAL(info,left)) { /* padding on right */
-/* flag[FLAG_MINUS_LJUSTIFY] */
- ++npc;
- *pdrvr++ = 7;
- *ppc = width;
- *++ppc = (INT_OR_PTR)("");
- width = 0;
+ ppc_last = ppc;
+ ppc = pc_fwi + 4; /* Need width fields starting with second. */
+ do {
+ width -= *ppc;
+ ppc += 3;
+ } while (ppc < ppc_last);
+
+ ppc = pc_fwi;
+ ppc[0] = FPO_STR_WIDTH;
+ ppc[1] = i = ((*sign_str) != 0);
+ ppc[2] = (intptr_t) sign_str;
+
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ if (((mode|0x20) == 'a') && (pc_fwi[3] >= 16)) { /* Hex sign handling. */
+ /* Hex and not inf or nan, so prefix with 0x. */
+ char *h = sign_str + i;
+ *h = '0';
+ *++h = 'x' - 'p' + *exp_buf;
+ *++h = 0;
+ ppc[1] = (i += 2);
+ }
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+ if ((width -= i) > 0) {
+ if (PRINT_INFO_FLAG_VAL(info,left)) { /* Left-justified. */
+ ppc_last[0] = FPO_STR_WIDTH;
+ ppc_last[1] = width;
+ ppc_last[2] = (intptr_t)(fmt + EMPTY_STRING_OFFSET);
+ ppc_last += 3;
} else if (info->pad == '0') { /* 0 padding */
-/* (flag[FLAG_0_PAD] == '0') */
- pc_fwi[2] += width;
- width = 0;
+ ppc[4] += width; /* Pad second field. */
+ } else {
+ ppc[1] += width; /* Pad first (sign) field. */
}
}
- *drvr = 7;
- ppc = pc_fwi;
- *ppc++ = width + i;
- *ppc = (INT_OR_PTR) sign_str;
- pdrvr = drvr;
- ppc = pc_fwi;
cnt = 0;
- for (i=0 ; i<npc ; i++) {
-#if 1
- fprintf(fp, fmts[(int)(*pdrvr++)], (INT_OR_PTR)(*(ppc)),
- (INT_OR_PTR)(*(ppc+1)));
-#else
- j = fprintf(fp, fmts[(int)(*pdrvr++)], (INT_OR_PTR)(*(ppc)),
- (INT_OR_PTR)(*(ppc+1)));
- assert(j == *ppc);
-#endif
-/* if (size > *ppc) { */
-/* size -= *ppc; */
-/* } */
- cnt += *ppc; /* to avoid problems if j == -1 */
- ppc += 2;
- }
+
+ do {
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+
+ if ((ppc == pc_fwi + 6) && num_groups) {
+ const char *gp = (const char *) ppc[2];
+ int len = ppc[1];
+ int blk = initial_group;
+
+ cnt += num_groups * tslen; /* Adjust count now for sep chars. */
+
+/* printf("\n"); */
+ do {
+ if (!blk) { /* Initial group could be 0 digits long! */
+ blk = nblk2;
+ } else if (len >= blk) { /* Enough digits for a group. */
+/* printf("norm: len=%d blk=%d \"%.*s\"\n", len, blk, blk, gp); */
+ fp_outfunc(fp, *ppc, blk, (intptr_t) gp);
+ assert(gp);
+ if (*gp) {
+ gp += blk;
+ }
+ len -= blk;
+ } else { /* Transition to 0s. */
+/* printf("trans: len=%d blk=%d \"%.*s\"\n", len, blk, len, gp); */
+ if (len) {
+/* printf("len\n"); */
+ fp_outfunc(fp, *ppc, len, (intptr_t) gp);
+ gp += len;
+ }
+
+ if (ppc[3] == FPO_ZERO_PAD) { /* Need to group 0s */
+/* printf("zeropad\n"); */
+ cnt += ppc[1];
+ ppc += 3;
+ gp = (const char *) ppc[2];
+ blk -= len; /* blk > len, so blk still > 0. */
+ len = ppc[1];
+ continue; /* Don't decrement num_groups here. */
+ } else {
+ assert(num_groups == 0);
+ break;
+ }
+ }
+
+ if (num_groups <= 0) {
+ break;
+ }
+ --num_groups;
+
+ fp_outfunc(fp, FPO_STR_PREC, tslen, (intptr_t) ts);
+ blk = nblk2;
+
+/* printf("num_groups=%d blk=%d\n", num_groups, blk); */
+
+ } while (1);
+ } else
+
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+
+ fp_outfunc(fp, *ppc, ppc[1], ppc[2]); /* NOTE: Remember 'else' above! */
+
+ cnt += ppc[1];
+ ppc += 3;
+ } while (ppc < ppc_last);
return cnt;
}
+
#endif
/**********************************************************************/
#ifdef L__store_inttype
-/* TODO -- right now, assumes intmax_t is either long or long long */
+
+/* Right now, we assume intmax_t is either long or long long */
+
+#ifdef INTMAX_MAX
+
+#ifdef LLONG_MAX
+
+#if INTMAX_MAX > LLONG_MAX
+#error INTMAX_MAX > LLONG_MAX! The printf code needs to be updated!
+#endif
+
+#elif INTMAX_MAX > LONG_MAX
+
+#error No LLONG_MAX and INTMAX_MAX > LONG_MAX! The printf code needs to be updated!
+
+#endif /* LLONG_MAX */
+
+#endif /* INTMAX_MAX */
/* We assume int may be short or long, but short and long are different. */
@@ -2107,6 +2508,7 @@ extern uintmax_t _load_inttype(int desttype, register const void *src,
* In other words, we don't currently support glibc's 'I' flag.
* We do accept it, but it is currently ignored. */
+static void _charpad(FILE * __restrict stream, int padchar, size_t numpad);
#ifdef L_vfprintf
@@ -2117,6 +2519,23 @@ extern uintmax_t _load_inttype(int desttype, register const void *src,
#define _PPFS_init _ppfs_init
#define OUTPUT(F,S) fputs(S,F)
#define _outnstr(stream, string, len) _stdio_fwrite(string, len, stream)
+#define FP_OUT _fp_out_narrow
+
+#ifdef __STDIO_PRINTF_FLOAT
+
+static void _fp_out_narrow(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
+{
+ if (type & 0x80) { /* Some type of padding needed. */
+ int buflen = strlen((const char *) buf);
+ if ((len -= buflen) > 0) {
+ _charpad(fp, (type & 0x7f), len);
+ }
+ len = buflen;
+ }
+ OUTNSTR(fp, (const char *) buf, len);
+}
+
+#endif /* __STDIO_PRINTF_FLOAT */
#else /* L_vfprintf */
@@ -2127,6 +2546,7 @@ extern uintmax_t _load_inttype(int desttype, register const void *src,
#define _PPFS_init _ppwfs_init
#define OUTPUT(F,S) fputws(S,F)
#define _outnwcs(stream, wstring, len) _wstdio_fwrite(wstring, len, stream)
+#define FP_OUT _fp_out_wide
static void _outnstr(FILE *stream, const char *s, size_t wclen)
{
@@ -2139,13 +2559,69 @@ static void _outnstr(FILE *stream, const char *s, size_t wclen)
todo = wclen;
while (todo) {
- r = mbsrtowcs(wbuf, &s, sizeof(wbuf)/sizeof(wbuf[0]), &mbstate);
+ r = mbsrtowcs(wbuf, &s,
+ ((todo <= sizeof(wbuf)/sizeof(wbuf[0]))
+ ? todo
+ : sizeof(wbuf)/sizeof(wbuf[0])),
+ &mbstate);
assert(((ssize_t)r) > 0);
_outnwcs(stream, wbuf, r);
todo -= r;
}
}
+#ifdef __STDIO_PRINTF_FLOAT
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Move defines from _fpmaxtostr. Put them in a common header.
+#endif
+
+/* The following defines are from _fpmaxtostr.*/
+#define DIGITS_PER_BLOCK 9
+#define NUM_DIGIT_BLOCKS ((DECIMAL_DIG+DIGITS_PER_BLOCK-1)/DIGITS_PER_BLOCK)
+#define BUF_SIZE ( 3 + NUM_DIGIT_BLOCKS * DIGITS_PER_BLOCK )
+
+static void _fp_out_wide(FILE *fp, intptr_t type, intptr_t len, intptr_t buf)
+{
+ wchar_t wbuf[BUF_SIZE];
+ const char *s = (const char *) buf;
+ int i;
+
+ if (type & 0x80) { /* Some type of padding needed */
+ int buflen = strlen(s);
+ if ((len -= buflen) > 0) {
+ _charpad(fp, (type & 0x7f), len);
+ }
+ len = buflen;
+ }
+
+ if (len > 0) {
+ i = 0;
+ do {
+#ifdef __LOCALE_C_ONLY
+ wbuf[i] = s[i];
+#else /* __LOCALE_C_ONLY */
+
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+ if (s[i] == ',') {
+ wbuf[i] = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc;
+ } else
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+ if (s[i] == '.') {
+ wbuf[i] = __UCLIBC_CURLOCALE_DATA.decimal_point_wc;
+ } else {
+ wbuf[i] = s[i];
+ }
+#endif /* __LOCALE_C_ONLY */
+
+ } while (++i < len);
+
+ OUTNSTR(fp, wbuf, len);
+ }
+}
+
+#endif /* __STDIO_PRINTF_FLOAT */
+
static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
{
static const wchar_t invalid_wcs[] = L"Invalid wide format string.";
@@ -2153,7 +2629,9 @@ static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
/* First, zero out everything... argnumber[], argtype[], argptr[] */
memset(ppfs, 0, sizeof(ppfs_t)); /* TODO: nonportable???? */
+#ifdef NL_ARGMAX
--ppfs->maxposarg; /* set to -1 */
+#endif /* NL_ARGMAX */
ppfs->fmtpos = (const char *) fmt0;
ppfs->info._flags = FLAG_WIDESTREAM;
@@ -2210,6 +2688,7 @@ static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
ppfs->fmtpos = (const char *) fmt0; /* rewind */
}
+#ifdef NL_ARGMAX
/* If we have positional args, make sure we know all the types. */
{
register int *p = ppfs->argtype;
@@ -2221,6 +2700,7 @@ static int _ppwfs_init(register ppfs_t *ppfs, const wchar_t *fmt0)
++p;
}
}
+#endif /* NL_ARGMAX */
return 0;
}
@@ -2283,8 +2763,8 @@ static int _do_one_spec(FILE * __restrict stream,
int prefix_num = PREFIX_NONE;
char padchar = ' ';
#ifdef __UCLIBC_MJN3_ONLY__
-#warning REMINDER: buf size
-#endif
+#warning TODO: Determine appropriate buf size.
+#endif /* __UCLIBC_MJN3_ONLY__ */
/* TODO: buf needs to be big enough for any possible error return strings
* and also for any locale-grouped long long integer strings generated.
* This should be large enough for any of the current archs/locales, but
@@ -2304,24 +2784,28 @@ static int _do_one_spec(FILE * __restrict stream,
/* Deal with the argptr vs argvalue issue. */
#ifdef __va_arg_ptr
argptr = (const void * const *) ppfs->argptr;
+#ifdef NL_ARGMAX
if (ppfs->maxposarg > 0) { /* Using positional args... */
argptr += ppfs->argnumber[2] - 1;
}
+#endif /* NL_ARGMAX */
#else
/* Need to build a local copy... */
{
register argvalue_t *p = ppfs->argvalue;
int i;
+#ifdef NL_ARGMAX
if (ppfs->maxposarg > 0) { /* Using positional args... */
p += ppfs->argnumber[2] - 1;
}
+#endif /* NL_ARGMAX */
for (i = 0 ; i < ppfs->num_data_args ; i++ ) {
argptr[i] = (void *) p++;
}
}
#endif
{
- register char *s; /* TODO: Should s be unsigned char * ? */
+ register char *s = NULL; /* TODO: Should s be unsigned char * ? */
if (ppfs->conv_num == CONV_n) {
_store_inttype(*(void **)*argptr,
@@ -2331,7 +2815,12 @@ static int _do_one_spec(FILE * __restrict stream,
}
if (ppfs->conv_num <= CONV_i) { /* pointer or (un)signed int */
alphacase = __UIM_LOWER;
-#ifndef __LOCALE_C_ONLY
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_vfprintf
+#warning CONSIDER: Should we ignore these flags if stub locale? What about custom specs?
+#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
if ((base = spec_base[(int)(ppfs->conv_num - CONV_p)]) == 10) {
if (PRINT_INFO_FLAG_VAL(&(ppfs->info),group)) {
alphacase = __UIM_GROUP;
@@ -2340,7 +2829,7 @@ static int _do_one_spec(FILE * __restrict stream,
alphacase |= 0x80;
}
}
-#endif /* __LOCALE_C_ONLY */
+
if (ppfs->conv_num <= CONV_u) { /* pointer or unsigned int */
if (ppfs->conv_num == CONV_X) {
alphacase = __UIM_UPPER;
@@ -2356,8 +2845,10 @@ static int _do_one_spec(FILE * __restrict stream,
padchar = ppfs->info.pad;
}
#ifdef __UCLIBC_MJN3_ONLY__
-#warning if using outdigits and/or grouping, how should we interpret precision?
+#ifdef L_vfprintf
+#warning CONSIDER: If using outdigits and/or grouping, how should we interpret precision?
#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
s = _uintmaxtostr(buf + sizeof(buf) - 1,
(uintmax_t)
_load_inttype(*argtype & __PA_INTMASK,
@@ -2413,23 +2904,18 @@ static int _do_one_spec(FILE * __restrict stream,
}
numfill = ((numfill > SLEN) ? numfill - SLEN : 0);
} else if (ppfs->conv_num <= CONV_A) { /* floating point */
-#ifdef L_vfwprintf
-#ifdef __UCLIBC_MJN3_ONLY__
-#warning fix dtostr
-#endif
- return -1;
-#else /* L_vfwprintf */
#ifdef __STDIO_PRINTF_FLOAT
- *count += _dtostr(stream,
- (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
- ? *(long double *) *argptr
- : (long double) (* (double *) *argptr)),
- &ppfs->info);
+ *count +=
+ _fpmaxtostr(stream,
+ (__fpmax_t)
+ (PRINT_INFO_FLAG_VAL(&(ppfs->info),is_long_double)
+ ? *(long double *) *argptr
+ : (long double) (* (double *) *argptr)),
+ &ppfs->info, FP_OUT );
return 0;
#else /* __STDIO_PRINTF_FLOAT */
return -1; /* TODO -- try to continue? */
#endif /* __STDIO_PRINTF_FLOAT */
-#endif /* L_vfwprintf */
} else if (ppfs->conv_num <= CONV_S) { /* wide char or string */
#ifdef L_vfprintf
@@ -2467,7 +2953,9 @@ static int _do_one_spec(FILE * __restrict stream,
if (ppfs->conv_num == CONV_s) { /* string */
s = *((char **) (*argptr));
if (s) {
+#ifdef __STDIO_PRINTF_M_SUPPORT
SET_STRING_LEN:
+#endif
slen = strnlen(s, ((ppfs->info.prec >= 0)
? ppfs->info.prec : SIZE_MAX));
} else {
@@ -2505,11 +2993,13 @@ static int _do_one_spec(FILE * __restrict stream,
if (ppfs->conv_num == CONV_s) { /* string */
#ifdef __UCLIBC_MJN3_ONLY__
-#warning Fix %s for vfwprintf... output upto illegal sequence?
-#endif
+#warning TODO: Fix %s for vfwprintf... output upto illegal sequence?
+#endif /* __UCLIBC_MJN3_ONLY__ */
s = *((char **) (*argptr));
if (s) {
+#ifdef __STDIO_PRINTF_M_SUPPORT
SET_STRING_LEN:
+#endif
/* We use an awful uClibc-specific hack here, passing
* (wchar_t*) &mbstate as the conversion destination.
* This signals uClibc's mbsrtowcs that we want a
@@ -2544,6 +3034,7 @@ static int _do_one_spec(FILE * __restrict stream,
goto SET_STRING_LEN;
#endif
} else {
+#ifdef __STDIO_GLIBC_CUSTOM_PRINTF
assert(ppfs->conv_num == CONV_custom0);
s = _custom_printf_spec;
@@ -2561,13 +3052,16 @@ static int _do_one_spec(FILE * __restrict stream,
return 0;
}
} while (++s < (_custom_printf_spec + MAX_USER_SPEC));
+#endif /* __STDIO_GLIBC_CUSTOM_PRINTF */
assert(0);
return -1;
}
#ifdef __UCLIBC_MJN3_ONLY__
-#warning if using outdigits and/or grouping, how should we pad?
+#ifdef L_vfprintf
+#warning CONSIDER: If using outdigits and/or grouping, how should we pad?
#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
{
size_t t;
@@ -2595,6 +3089,7 @@ static int _do_one_spec(FILE * __restrict stream,
#ifdef __UCLIBC_HAS_WCHAR__
if (!ws) {
+ assert(s);
_outnstr(stream, s, slen);
} else { /* wide string */
size_t t;
@@ -2606,7 +3101,6 @@ static int _do_one_spec(FILE * __restrict stream,
_outnstr(stream, buf, t);
slen -= t;
}
- ws = NULL; /* Reset ws. */
}
#else /* __UCLIBC_HAS_WCHAR__ */
_outnstr(stream, s, slen);
@@ -2615,10 +3109,10 @@ static int _do_one_spec(FILE * __restrict stream,
#else /* L_vfprintf */
if (!ws) {
+ assert(s);
_outnstr(stream, s, SLEN);
} else {
_outnwcs(stream, ws, SLEN);
- ws = NULL; /* Reset ws. */
}
#endif /* L_vfprintf */
@@ -2644,6 +3138,9 @@ int VFPRINTF (FILE * __restrict stream,
if (_PPFS_init(&ppfs, format) < 0) { /* Bad format string. */
OUTNSTR(stream, (const FMT_TYPE *) ppfs.fmtpos,
STRLEN((const FMT_TYPE *)(ppfs.fmtpos)));
+#if defined(L_vfprintf) && !defined(NDEBUG)
+ fprintf(stderr,"\nIMbS: \"%s\"\n\n", format);
+#endif
count = -1;
} else {
_ppfs_prepargs(&ppfs, arg); /* This did a va_copy!!! */
diff --git a/libc/stdio/scanf.c b/libc/stdio/scanf.c
index 9ac3d3c9c..48e9344c0 100644
--- a/libc/stdio/scanf.c
+++ b/libc/stdio/scanf.c
@@ -1,130 +1,178 @@
-
-/*
- * Modified by Manuel Novoa III Mar 13, 2001
- *
- * The vfscanf routine was completely rewritten to add features and remove
- * bugs. The function __strtold, based on my strtod code in stdlib, was
- * added to provide floating point support for the scanf functions.
- *
- * So far they pass the test cases from glibc-2.1.3, except in two instances.
- * In one case, the test appears to be broken. The other case is something
- * I need to research further. This version of scanf assumes it can only
- * peek one character ahead. Apparently, glibc looks further. The difference
- * can be seen when parsing a floating point value in the character
- * sequence "100ergs". glibc is able to back up before the 'e' and return
- * a value of 100, whereas this scanf reports a bad match with the stream
- * pointer at 'r'. A similar situation can also happen when parsing hex
- * values prefixed by 0x or 0X; a failure would occur for "0xg". In order to
- * fix this, I need to rework the "ungetc" machinery in stdio.c again.
- * I do have one reference though, that seems to imply scanf has a single
- * character of lookahead.
- *
- * May 20, 2001
+/* Copyright (C) 2002, 2003 Manuel Novoa III
*
- * Quote from ANSI/ISO C99 standard:
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
*
- * fscanf pushes back at most one input character onto the input stream.
- * Therefore, some sequences that are acceptable to strtod, strtol, etc.,
- * are unacceptable to fscanf.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
*
- * So uClibc's *scanf functions conform to the standard, and glibc's
- * implementation doesn't for the "100ergs" case mentioned above.
- *
- * Sep 6, 2002
- * Patch from Tero_Lyytikäinen <tero@paravant.fi> to fix bug in matchchar case.
- *
- * May 15, 2003
- * Hopefully fix handling of 0 bytes with %s, %c, and %[ specifiers.
- *
- * July 17, 2003
- * Bug fix from Peter Kjellerstedt <peter.kjellerstedt@axis.com>. vfscanf was
- * not setting the FILE bufread member to flag the end of the buffer.
- * Also, do not set bufgetc member if getc macro support is disabled.
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Aug 1, 2003
+ * New *scanf implementation with lots of bug fixes and *wscanf support.
+ * Also now optionally supports hexadecimal float notation, positional
+ * args, and glibc locale-specific digit grouping. Should now be
+ * standards compliant.
*/
+
#define _ISOC99_SOURCE /* for LLONG_MAX primarily... */
#define _GNU_SOURCE
#define _STDIO_UTILITY
+#include <features.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <string.h>
#include <stdarg.h>
+#include <stdint.h>
+#include <errno.h>
+#include <printf.h>
+
+#ifdef __UCLIBC_HAS_WCHAR__
+#include <bits/uClibc_uwchar.h>
+#include <wchar.h>
+#include <wctype.h>
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+#include <langinfo.h>
+#include <locale.h>
+
+#include <assert.h>
+#include <limits.h>
#ifdef __STDIO_THREADSAFE
#include <stdio_ext.h>
#include <pthread.h>
#endif /* __STDIO_THREADSAFE */
-#ifdef L_scanf
-#ifdef __STDC__
-int scanf(const char *fmt, ...)
+#ifdef __UCLIBC_HAS_FLOATS__
+#include <float.h>
+#include <bits/uClibc_fpmax.h>
+#endif /* __UCLIBC_HAS_FLOATS__ */
+
+#ifdef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__
+#ifdef L_vfscanf
+/* only emit this once */
+#warning Forcing undef of __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ until implemented!
+#endif
+#undef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__
+#endif
+
+extern void _store_inttype(void *dest, int desttype, uintmax_t val);
+
+#ifdef LLONG_MAX
+
+extern unsigned long long
+_stdlib_strto_ll(register const char * __restrict str,
+ char ** __restrict endptr, int base, int sflag);
+#if (ULLONG_MAX == UINTMAX_MAX)
+#define STRTOUIM(s,e,b,sf) _stdlib_strto_ll(s,e,b,sf)
+#endif
+
+#else /* LLONG_MAX */
+
+extern unsigned long
+_stdlib_strto_l(register const char * __restrict str,
+ char ** __restrict endptr, int base, int sflag);
+
+#if (ULONG_MAX == UINTMAX_MAX)
+#define STRTOUIM(s,e,b,sf) _stdlib_strto_l(s,e,b,sf)
+#endif
+
+#endif /* LLONG_MAX */
+
+#ifndef STRTOUIM
+#error STRTOUIM conversion function is undefined!
+#endif
+
+/**********************************************************************/
+
+/* The standards require EOF < 0. */
+#if EOF >= CHAR_MIN
+#define __isdigit_char_or_EOF(C) __isdigit_char((C))
#else
-int scanf(fmt, va_alist)
-__const char *fmt;
-va_dcl
+#define __isdigit_char_or_EOF(C) __isdigit_int((C))
#endif
+
+/**********************************************************************/
+#ifdef L_fscanf
+
+int fscanf(FILE * __restrict stream, const char * __restrict format, ...)
{
- va_list ptr;
+ va_list arg;
int rv;
- va_start(ptr, fmt);
- rv = vfscanf(stdin, fmt, ptr);
- va_end(ptr);
+ va_start(arg, format);
+ rv = vfscanf(stream, format, arg);
+ va_end(arg);
+
return rv;
}
-#endif
-#ifdef L_sscanf
-#if !defined(__STDIO_BUFFERS) && !defined(__STDIO_GLIBC_CUSTOM_STREAMS)
-#warning skipping sscanf since no buffering and no custom streams!
-#else
+#endif
+/**********************************************************************/
+#ifdef L_scanf
-int sscanf(const char *sp, const char *fmt, ...)
+int scanf(const char * __restrict format, ...)
{
- va_list ptr;
+ va_list arg;
int rv;
- va_start(ptr, fmt);
- rv = vsscanf(sp, fmt, ptr);
- va_end(ptr);
+ va_start(arg, format);
+ rv = vfscanf(stdin, format, arg);
+ va_end(arg);
+
return rv;
}
#endif
-#endif
+/**********************************************************************/
+#ifdef L_sscanf
-#ifdef L_fscanf
-#ifdef __STDC__
-int fscanf(FILE * fp, const char *fmt, ...)
-#else
-int fscanf(fp, fmt, va_alist)
-FILE *fp;
-__const char *fmt;
-va_dcl
-#endif
+#if defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS)
+
+int sscanf(const char * __restrict str, const char * __restrict format, ...)
{
- va_list ptr;
+ va_list arg;
int rv;
- va_start(ptr, fmt);
- rv = vfscanf(fp, fmt, ptr);
- va_end(ptr);
+ va_start(arg, format);
+ rv = vsscanf(str, format, arg);
+ va_end(arg);
+
return rv;
}
-#endif
+#else /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
+#warning Skipping sscanf since no buffering and no custom streams!
+#endif /* defined(__STDIO_BUFFERS) || defined(__STDIO_GLIBC_CUSTOM_STREAMS) */
+
+#endif
+/**********************************************************************/
#ifdef L_vscanf
-int vscanf(fmt, ap)
-__const char *fmt;
-va_list ap;
+
+int vscanf(const char * __restrict format, va_list arg)
{
- return vfscanf(stdin, fmt, ap);
+ return vfscanf(stdin, format, arg);
}
-#endif
+#endif
+/**********************************************************************/
#ifdef L_vsscanf
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning WISHLIST: Implement vsscanf for non-buffered and no custom stream case.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
#ifdef __STDIO_BUFFERS
int vsscanf(__const char *sp, __const char *fmt, va_list ap)
{
@@ -165,598 +213,1866 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap)
return rv;
}
#else /* __STDIO_GLIBC_CUSTOM_STREAMS */
-#warning skipping vsscanf since no buffering and no custom streams!
+#warning Skipping vsscanf since no buffering and no custom streams!
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
#endif /* __STDIO_BUFFERS */
+
#endif
+/**********************************************************************/
+#ifdef L_fwscanf
-#ifdef L_vfscanf
+int fwscanf(FILE * __restrict stream, const wchar_t * __restrict format, ...)
+{
+ va_list arg;
+ int rv;
-#include <assert.h>
-#include <ctype.h>
-#include <limits.h>
+ va_start(arg, format);
+ rv = vfwscanf(stream, format, arg);
+ va_end(arg);
+
+ return rv;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_wscanf
-static int valid_digit(char c, char base)
+int wscanf(const wchar_t * __restrict format, ...)
{
- if (base == 16) {
- return isxdigit(c);
- } else {
- return (__isdigit(c) && (c < '0' + base));
- }
+ va_list arg;
+ int rv;
+
+ va_start(arg, format);
+ rv = vfwscanf(stdin, format, arg);
+ va_end(arg);
+
+ return rv;
}
-extern unsigned long
-_stdlib_strto_l(register const char * __restrict str,
- char ** __restrict endptr, int base, int sflag);
-#ifdef LLONG_MAX
-extern unsigned long long
-_stdlib_strto_ll(register const char * __restrict str,
- char ** __restrict endptr, int base, int sflag);
+#endif
+/**********************************************************************/
+#ifdef L_swscanf
+
+#ifdef __STDIO_BUFFERS
+
+int swscanf(const wchar_t * __restrict str, const wchar_t * __restrict format,
+ ...)
+{
+ va_list arg;
+ int rv;
+
+ va_start(arg, format);
+ rv = vswscanf(str, format, arg);
+ va_end(arg);
+
+ return rv;
+}
+#else /* __STDIO_BUFFERS */
+#warning Skipping swscanf since no buffering!
+#endif /* __STDIO_BUFFERS */
+
+#endif
+/**********************************************************************/
+#ifdef L_vwscanf
+
+int vwscanf(const wchar_t * __restrict format, va_list arg)
+{
+ return vfwscanf(stdin, format, arg);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_vswscanf
+
+#ifdef __STDIO_BUFFERS
+
+int vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict format,
+ va_list arg)
+{
+ FILE f;
+
+ f.filedes = -3; /* FAKE STREAM TO SUPPORT *wscanf! */
+ f.modeflags = (__FLAG_WIDE|__FLAG_READONLY|__FLAG_READING);
+ f.bufpos = (char *) str;
+ f.bufend = (char *)(str + wcslen(str));
+ f.ungot_width[0] = 0;
+#ifdef __STDIO_THREADSAFE
+ f.user_locking = 0;
+ __stdio_init_mutex(&f.lock);
+#endif
+
+
+ return vfwscanf(&f, format, arg);
+}
+#else /* __STDIO_BUFFERS */
+#warning Skipping vswscanf since no buffering!
+#endif /* __STDIO_BUFFERS */
+
+#endif
+/**********************************************************************/
+/**********************************************************************/
+
+
+
+/* float layout 0123456789012345678901 repeat n for "l[" */
+#define SPEC_CHARS "npxXoudifFeEgGaACSncs["
+/* npxXoudif eEgG CS cs[ */
+
+/* NOTE: Ordering is important! In particular, CONV_LEFTBRACKET
+ * must immediately precede CONV_c. */
+
+enum {
+ CONV_n = 0,
+ CONV_p,
+ CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i,
+ CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A,
+ CONV_C, CONV_S, CONV_LEFTBRACKET, CONV_c, CONV_s, CONV_leftbracket,
+ CONV_percent, CONV_whitespace /* not in SPEC_* and no flags */
+};
+
+#ifdef __UCLIBC_HAS_FLOATS__
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+/* p x X o u d i f F e E g G a A */
+#define SPEC_BASE { 16, 16, 16, 8, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
+#else
+/* p x X o u d i f F e E g G a A */
+#define SPEC_BASE { 16, 16, 16, 8, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, 10 }
+#endif
+#else /* __UCLIBC_HAS_FLOATS__ */
+/* p x X o u d i f F e E g G a A */
+#define SPEC_BASE { 16, 16, 16, 8, 10, 10, 0 }
+#endif /* __UCLIBC_HAS_FLOATS__ */
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_vfscanf
+/* emit once */
+#warning CONSIDER: Add a '0' flag to eat 0 padding when grouping?
+#endif
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#define SPEC_FLAGS "*'I"
+
+enum {
+ FLAG_SURPRESS = 0x10, /* MUST BE 1ST!! See DO_FLAGS. */
+ FLAG_THOUSANDS = 0x20,
+ FLAG_I18N = 0x40, /* only works for d, i, u */
+ FLAG_MALLOC = 0x80, /* only works for s, S, and [ (and l[)*/
+};
+
+
+#define SPEC_RANGES { CONV_n, CONV_p, CONV_i, CONV_A, \
+ CONV_C, CONV_LEFTBRACKET, \
+ CONV_c, CONV_leftbracket }
+
+/* Note: We treat L and ll as synonymous... for ints and floats. */
+
+#define SPEC_ALLOWED_FLAGS { \
+ /* n */ (0x0f|FLAG_SURPRESS), \
+ /* p */ ( 0|FLAG_SURPRESS), \
+ /* oxXudi */ (0x0f|FLAG_SURPRESS|FLAG_THOUSANDS|FLAG_I18N), \
+ /* fFeEgGaA */ (0x0c|FLAG_SURPRESS|FLAG_THOUSANDS|FLAG_I18N), \
+ /* C */ ( 0|FLAG_SURPRESS), \
+ /* S and l[ */ ( 0|FLAG_SURPRESS|FLAG_MALLOC), \
+ /* c */ (0x04|FLAG_SURPRESS), \
+ /* s and [ */ (0x04|FLAG_SURPRESS|FLAG_MALLOC), \
+}
+
+
+/**********************************************************************/
+/*
+ * In order to ease translation to what arginfo and _print_info._flags expect,
+ * we map: 0:int 1:char 2:longlong 4:long 8:short
+ * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701)
+ */
+
+/* TODO -- Fix the table below to take into account stdint.h. */
+/* #ifndef LLONG_MAX */
+/* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. */
+/* #else */
+/* #if LLONG_MAX != INTMAX_MAX */
+/* #error fix QUAL_CHARS intmax_t entry 'j'! */
+/* #endif */
+/* #endif */
+
+#ifdef PDS
+#error PDS already defined!
+#endif
+#ifdef SS
+#error SS already defined!
+#endif
+#ifdef IMS
+#error IMS already defined!
+#endif
+
+#if PTRDIFF_MAX == INT_MAX
+#define PDS 0
+#elif PTRDIFF_MAX == LONG_MAX
+#define PDS 4
+#elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)
+#define PDS 8
+#else
+#error fix QUAL_CHARS ptrdiff_t entry 't'!
+#endif
+
+#if SIZE_MAX == UINT_MAX
+#define SS 0
+#elif SIZE_MAX == ULONG_MAX
+#define SS 4
+#elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
+#define SS 8
+#else
+#error fix QUAL_CHARS size_t entries 'z', 'Z'!
+#endif
+
+#if INTMAX_MAX == INT_MAX
+#define IMS 0
+#elif INTMAX_MAX == LONG_MAX
+#define IMS 4
+#elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)
+#define IMS 8
+#else
+#error fix QUAL_CHARS ptrdiff_t entry 't'!
+#endif
+
+#define QUAL_CHARS { \
+ /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int q:long_long */ \
+ 'h', 'l', 'L', 'j', 'z', 't', 'q', 0, \
+ 2, 4, 8, IMS, SS, PDS, 8, 0, /* TODO -- fix!!! */\
+ 1, 8 }
+
+
+/**********************************************************************/
+
+#ifdef L_vfwscanf
+#if WINT_MIN > EOF
+#error Unfortunately, we currently need wint_t to be able to store EOF. Sorry.
+#endif
+#define W_EOF WEOF
+#define Wint wint_t
+#define Wchar wchar_t
+#define Wuchar __uwchar_t
+#define ISSPACE(C) iswspace((C))
+#define VFSCANF vfwscanf
+#define GETC(SC) (SC)->sc_getc((SC))
+#else
+typedef unsigned char __uchar_t;
+#define W_EOF EOF
+#define Wint int
+#define Wchar char
+#define Wuchar __uchar_t
+#define ISSPACE(C) isspace((C))
+#define VFSCANF vfscanf
+#ifdef __UCLIBC_HAS_WCHAR__
+#define GETC(SC) (SC)->sc_getc((SC))
+#else /* __UCLIBC_HAS_WCHAR__ */
+#define GETC(SC) getc_unlocked((SC)->fp)
+#endif /* __UCLIBC_HAS_WCHAR__ */
#endif
struct scan_cookie {
+ Wint cc;
+ Wint ungot_char;
FILE *fp;
int nread;
int width;
- int width_flag;
- int ungot_char;
- int ungot_flag;
- int app_ungot;
+
+#ifdef __UCLIBC_HAS_WCHAR__
+ wchar_t app_ungot; /* Match FILE struct member type. */
+ unsigned char ungot_wchar_width;
+#else /* __UCLIBC_HAS_WCHAR__ */
+ unsigned char app_ungot; /* Match FILE struct member type. */
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+ char ungot_flag;
+
+#ifdef __UCLIBC_HAS_WCHAR__
+ char ungot_wflag; /* vfwscanf */
+ char mb_fail; /* vfscanf */
+ mbstate_t mbstate; /* vfscanf */
+ wint_t wc;
+ wint_t ungot_wchar; /* to support __scan_getc */
+ int (*sc_getc)(struct scan_cookie *);
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+ const char *grouping;
+ const unsigned char *thousands_sep;
+ int tslen;
+#ifdef __UCLIBC_HAS_WCHAR__
+ wchar_t thousands_sep_wc;
+#endif /* __UCLIBC_HAS_WCHAR__ */
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+
+#ifdef __UCLIBC_HAS_FLOATS__
+ const unsigned char *decpt;
+ int decpt_len;
+#ifdef __UCLIBC_HAS_WCHAR__
+ wchar_t decpt_wc;
+#endif /* __UCLIBC_HAS_WCHAR__ */
+ const unsigned char *fake_decpt;
+#endif /* __UCLIBC_HAS_FLOATS__ */
+
};
-static const char qual[] = "hl" /* "jtz" */ "Lq";
-/* char = -2, short = -1, int = 0, long = 1, long long = 2 */
-static const char qsz[] = { -1, 1, 2, 2 };
+typedef struct {
+#if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
+#if NL_ARGMAX > 10
+#warning NL_ARGMAX > 10, and space is allocated on the stack for positional args.
+#endif
+ void *pos_args[NL_ARGMAX];
+ int num_pos_args; /* Must start at -1. */
+ int cur_pos_arg;
+#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
+ void *cur_ptr;
+ const unsigned char *fmt;
+ int cnt, dataargtype, conv_num, max_width;
+ unsigned char store, flags;
+} psfs_t; /* parse scanf format state */
+
+
+/**********************************************************************/
+/**********************************************************************/
+
+extern void __init_scan_cookie(register struct scan_cookie *sc,
+ register FILE *fp);
+extern int __scan_getc(register struct scan_cookie *sc);
+extern void __scan_ungetc(register struct scan_cookie *sc);
#ifdef __UCLIBC_HAS_FLOATS__
-static int __strtold(long double *ld, struct scan_cookie *sc);
- /*01234567890123456 */
-static const char spec[] = "%n[csoupxXidfeEgG";
-#else
-static const char spec[] = "%n[csoupxXid";
+extern int __scan_strtold(long double *ld, struct scan_cookie *sc);
+#endif /* __UCLIBC_HAS_FLOATS__ */
+
+extern int __psfs_parse_spec(psfs_t *psfs);
+extern int __psfs_do_numeric(psfs_t *psfs, struct scan_cookie *sc);
+
+/**********************************************************************/
+#ifdef L___scan_cookie
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Remove dependence on decpt_str and fake_decpt in stub locale mode.
+#endif
+#ifndef __UCLIBC_HAS_LOCALE__
+static const char decpt_str[] = ".";
#endif
-/* radix[i] <-> spec[i+5] o u p x X i d */
-static const char radix[] = { 8, 10, 16, 16, 16, 0, 10 };
-static void init_scan_cookie(register struct scan_cookie *sc,
- register FILE *fp)
+void __init_scan_cookie(register struct scan_cookie *sc,
+ register FILE *fp)
{
sc->fp = fp;
sc->nread = 0;
- sc->width_flag = 0;
sc->ungot_flag = 0;
sc->app_ungot = ((fp->modeflags & __MASK_UNGOT) ? fp->ungot[1] : 0);
-}
+#ifdef __UCLIBC_HAS_WCHAR__
+ sc->ungot_wflag = 0; /* vfwscanf */
+ sc->mb_fail = 0;
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+ if (*(sc->grouping = __UCLIBC_CURLOCALE_DATA.grouping)) {
+ sc->thousands_sep = __UCLIBC_CURLOCALE_DATA.thousands_sep;
+ sc->tslen = __UCLIBC_CURLOCALE_DATA.thousands_sep_len;
+#ifdef __UCLIBC_HAS_WCHAR__
+ sc->thousands_sep_wc = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc;
+#endif /* __UCLIBC_HAS_WCHAR__ */
+ }
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+
+#ifdef __UCLIBC_HAS_FLOATS__
+#ifdef __UCLIBC_HAS_LOCALE__
+ sc->decpt = __UCLIBC_CURLOCALE_DATA.decimal_point;
+ sc->decpt_len = __UCLIBC_CURLOCALE_DATA.decimal_point_len;
+#else /* __UCLIBC_HAS_LOCALE__ */
+ sc->fake_decpt = sc->decpt = decpt_str;
+ sc->decpt_len = 1;
+#endif /* __UCLIBC_HAS_LOCALE__ */
+#ifdef __UCLIBC_HAS_WCHAR__
+#ifdef __UCLIBC_HAS_LOCALE__
+ sc->decpt_wc = __UCLIBC_CURLOCALE_DATA.decimal_point_wc;
+#else
+ sc->decpt_wc = '.';
+#endif
+#endif /* __UCLIBC_HAS_WCHAR__ */
+#endif /* __UCLIBC_HAS_FLOATS__ */
-/* TODO -- what about literal '\0' chars in a file??? */
+}
-static int scan_getc_nw(register struct scan_cookie *sc)
+int __scan_getc(register struct scan_cookie *sc)
{
+ int c;
+
+#ifdef __UCLIBC_HAS_WCHAR__
+ assert(!sc->mb_fail);
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+ sc->cc = EOF;
+
+ if (--sc->width < 0) {
+ sc->ungot_flag |= 2;
+ return -1;
+ }
+
if (sc->ungot_flag == 0) {
- sc->ungot_char = getc(sc->fp);
+ if ((c = GETC(sc)) == EOF) {
+ sc->ungot_flag |= 2;
+ return -1;
+ }
+ sc->ungot_char = c;
} else {
+ assert(sc->ungot_flag == 1);
sc->ungot_flag = 0;
}
- if (sc->ungot_char > 0) {
- ++sc->nread;
+
+ ++sc->nread;
+ return sc->cc = sc->ungot_char;
+}
+
+void __scan_ungetc(register struct scan_cookie *sc)
+{
+ ++sc->width;
+ if (sc->ungot_flag == 2) { /* last was EOF */
+ sc->ungot_flag = 0;
+ sc->cc = sc->ungot_char;
+ } else if (sc->ungot_flag == 0) {
+ sc->ungot_flag = 1;
+ --sc->nread;
+ } else {
+ assert(0);
}
- sc->width_flag = 0;
- return sc->ungot_char;
}
-static int scan_getc(register struct scan_cookie *sc)
+#endif
+/**********************************************************************/
+#ifdef L___psfs_parse_spec
+
+#ifdef SPEC_FLAGS
+static const unsigned char spec_flags[] = SPEC_FLAGS;
+#endif /* SPEC_FLAGS */
+static const unsigned char spec_chars[] = SPEC_CHARS;
+static const unsigned char qual_chars[] = QUAL_CHARS;
+static const unsigned char spec_ranges[] = SPEC_RANGES;
+static const unsigned short spec_allowed[] = SPEC_ALLOWED_FLAGS;
+
+int __psfs_parse_spec(register psfs_t *psfs)
{
- if (sc->ungot_flag == 0) {
- sc->ungot_char = getc(sc->fp);
+ const unsigned char *p;
+ const unsigned char *fmt0 = psfs->fmt;
+ int i;
+#ifdef SPEC_FLAGS
+ int j;
+#endif
+#if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
+ unsigned char fail = 0;
+
+ i = 0; /* Do this here to avoid a warning. */
+
+ if (!__isdigit_char(*psfs->fmt)) { /* Not a positional arg. */
+ fail = 1;
+ goto DO_FLAGS;
+ }
+
+ /* parse the positional arg (or width) value */
+ do {
+ if (i <= ((INT_MAX - 9)/10)) {
+ i = (i * 10) + (*psfs->fmt++ - '0');
+ }
+ } while (__isdigit_char(*psfs->fmt));
+
+ if (*psfs->fmt != '$') { /* This is a max field width. */
+ if (psfs->num_pos_args >= 0) { /* Already saw a pos arg! */
+ goto ERROR_EINVAL;
+ }
+ psfs->max_width = i;
+ psfs->num_pos_args = -2;
+ goto DO_QUALIFIER;
+ }
+ ++psfs->fmt; /* Advance past '$'. */
+#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
+
+#if defined(SPEC_FLAGS) || (defined(NL_ARGMAX) && (NL_ARGMAX > 0))
+ DO_FLAGS:
+#endif /* defined(SPEC_FLAGS) || (defined(NL_ARGMAX) && (NL_ARGMAX > 0)) */
+#ifdef SPEC_FLAGS
+ p = spec_flags;
+ j = FLAG_SURPRESS;
+ do {
+ if (*p == *psfs->fmt) {
+ ++psfs->fmt;
+ psfs->flags |= j;
+ goto DO_FLAGS;
+ }
+ j += j;
+ } while (*++p);
+
+ if (psfs->flags & FLAG_SURPRESS) { /* Suppress assignment. */
+ psfs->store = 0;
+ goto DO_WIDTH;
+ }
+#else /* SPEC_FLAGS */
+ if (*psfs->fmt == '*') { /* Suppress assignment. */
+ ++psfs->fmt;
+ psfs->store = 0;
+ goto DO_WIDTH;
+ }
+#endif /* SPEC_FLAGS */
+
+
+#if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
+ if (fail) {
+ /* Must be a non-positional arg */
+ if (psfs->num_pos_args >= 0) { /* Already saw a pos arg! */
+ goto ERROR_EINVAL;
+ }
+ psfs->num_pos_args = -2;
+ } else {
+ if ((psfs->num_pos_args == -2) || (((unsigned int)(--i)) >= NL_ARGMAX)) {
+ /* Already saw a non-pos arg or (0-based) num too large. */
+ goto ERROR_EINVAL;
+ }
+ psfs->cur_pos_arg = i;
}
- sc->width_flag = 1;
+#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
+
+ DO_WIDTH:
+ for (i = 0 ; __isdigit_char(*psfs->fmt) ; ) {
+ if (i <= ((INT_MAX - 9)/10)) {
+ i = (i * 10) + (*psfs->fmt++ - '0');
+ psfs->max_width = i;
+ }
+ }
+
+#if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
+ DO_QUALIFIER:
+#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
+ p = qual_chars;
+ do {
+ if (*psfs->fmt == *p) {
+ ++psfs->fmt;
+ break;
+ }
+ } while (*++p);
+ if ((p - qual_chars < 2) && (*psfs->fmt == *p)) {
+ p += ((sizeof(qual_chars)-2) / 2);
+ ++psfs->fmt;
+ }
+ psfs->dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Should we validate that psfs->max_width > 0 in __psfs_parse_spec()? It would avoid whitespace consumption...
+#warning CONSIDER: Should INT_MAX be a valid width (%c/%C)? See __psfs_parse_spec().
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+ p = spec_chars;
+ do {
+ if (*psfs->fmt == *p) {
+ int p_m_spec_chars = p - spec_chars;
+
+#ifdef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__
+#error implement gnu a flag
+ if ((*p == 'a')
+ && ((psfs->fmt[1] == '[') || ((psfs->fmt[1]|0x20) == 's'))
+ ) { /* Assumes ascii for 's' and 'S' test. */
+ psfs->flags |= FLAG_MALLOC;
+ ++psfs->fmt;
+ ++p;
+ continue; /* The related conversions follow 'a'. */
+ }
+#endif /* __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ */
+
+ for (p = spec_ranges; p_m_spec_chars > *p ; ++p) {}
+ if (((psfs->dataargtype >> 8) | psfs->flags)
+ & ~spec_allowed[(int)(p - spec_ranges)]
+ ) {
+ goto ERROR_EINVAL;
+ }
+
+ if ((p_m_spec_chars >= CONV_c)
+ && (psfs->dataargtype & PA_FLAG_LONG)) {
+ p_m_spec_chars -= 3; /* lc -> C, ls -> S, l[ -> ?? */
+ }
+
+ psfs->conv_num = p_m_spec_chars;
+ return psfs->fmt - fmt0;
+ }
+ if (!*++p) {
+ ERROR_EINVAL:
+ __set_errno(EINVAL);
+ return -1;
+ }
+ } while(1);
+
+ assert(0);
+}
+
+#endif
+/**********************************************************************/
+#if defined(L_vfscanf) || defined(L_vfwscanf)
+
+#ifdef __UCLIBC_HAS_WCHAR__
+#ifdef L_vfscanf
+static int sc_getc(register struct scan_cookie *sc)
+{
+ return getc(sc->fp);
+}
+
+static int scan_getwc(register struct scan_cookie *sc)
+{
+ size_t r;
+ int width;
+ wchar_t wc[1];
+ char b[1];
+
if (--sc->width < 0) {
- sc->ungot_flag = 1;
+ sc->ungot_flag |= 2;
return -1;
}
- sc->ungot_flag = 0;
- if (sc->ungot_char > 0) {
- ++sc->nread;
+
+ width = sc->width; /* Preserve width. */
+ sc->width = INT_MAX; /* MB_CUR_MAX can invoke a function. */
+
+ r = (size_t)(-1);
+ while (__scan_getc(sc) >= 0) {
+ *b = sc->cc;
+
+ r = mbrtowc(wc, b, 1, &sc->mbstate);
+ if (((ssize_t) r) >= 0) { /* Successful completion of a wc. */
+ sc->wc = *wc;
+ goto SUCCESS;
+ } else if (r == ((size_t) -2)) {
+ /* Potentially valid but incomplete. */
+ continue;
+ }
+ break;
}
- return sc->ungot_char;
+
+ /* If we reach here, either r == ((size_t)-1) and
+ * mbrtowc set errno to EILSEQ, or r == ((size_t)-2)
+ * and stream is in an error state or at EOF with a
+ * partially complete wchar. */
+ __set_errno(EILSEQ); /* In case of incomplete conversion. */
+ sc->mb_fail = 1;
+
+ SUCCESS:
+ sc->width = width; /* Restore width. */
+
+ return (int)((ssize_t) r);
}
-static void scan_ungetc(register struct scan_cookie *sc)
+#endif /* L_vfscanf */
+
+#ifdef L_vfwscanf
+
+/* This gets called by __scan_getc. __scan_getc is called by vfwscanf
+ * when the next wide char is expected to be valid ascii (digits).
+ */
+static int sc_getc(register struct scan_cookie *sc)
{
- if (sc->ungot_flag != 0) {
- assert(sc->width < 0);
- return;
+ wint_t wc;
+
+ if (sc->fp->filedes == -3) {
+ if (sc->fp->bufpos < sc->fp->bufend) {
+ wc = *((wchar_t *)(sc->fp->bufpos));
+ sc->fp->bufpos += sizeof(wchar_t);
+ } else {
+ sc->fp->modeflags |= __FLAG_EOF;
+ return EOF;
+ }
+ } else if ((wc = fgetwc_unlocked(sc->fp)) == WEOF) {
+ return EOF;
}
- if (sc->width_flag) {
- ++sc->width;
+
+ sc->ungot_wflag = 1;
+ sc->ungot_wchar = wc;
+ sc->ungot_wchar_width = sc->fp->ungot_width[0];
+
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+ if (wc == sc->thousands_sep_wc) {
+ wc = ',';
+ } else
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+#ifdef __UCLIBC_HAS_FLOATS__
+ if (wc == sc->decpt_wc) {
+ wc = '.';
+ } else
+#endif /* __UCLIBC_HAS_FLOATS__ */
+ if (!__isascii(wc)) {
+ wc = '?';
}
- sc->ungot_flag = 1;
- if (sc->ungot_char > 0) { /* not EOF or EOS */
- --sc->nread;
+ sc->wc = sc->ungot_char = wc;
+
+ return (int) wc;
+}
+
+static int scan_getwc(register struct scan_cookie *sc)
+{
+ wint_t wc;
+
+ sc->wc = WEOF;
+
+ if (--sc->width < 0) {
+ sc->ungot_flag |= 2;
+ return -1;
}
+
+ if (sc->ungot_flag == 0) {
+
+ if (sc->fp->filedes == -3) {
+ if (sc->fp->bufpos < sc->fp->bufend) {
+ wc = *((wchar_t *)(sc->fp->bufpos));
+ sc->fp->bufpos += sizeof(wchar_t);
+ } else {
+ sc->ungot_flag |= 2;
+ return -1;
+ }
+ } else if ((wc = fgetwc_unlocked(sc->fp)) == WEOF) {
+ sc->ungot_flag |= 2;
+ return -1;
+ }
+ sc->ungot_wflag = 1;
+ sc->ungot_char = wc;
+ sc->ungot_wchar_width = sc->fp->ungot_width[0];
+ } else {
+ assert(sc->ungot_flag == 1);
+ sc->ungot_flag = 0;
+ }
+
+ ++sc->nread;
+ sc->wc = sc->ungot_char;
+
+ return 0;
}
-static void kill_scan_cookie(register struct scan_cookie *sc)
+
+#endif /* L_vfwscanf */
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+static __inline void kill_scan_cookie(register struct scan_cookie *sc)
{
- if (sc->ungot_flag) {
- ungetc(sc->ungot_char,sc->fp);
+#ifdef L_vfscanf
+
+ if (sc->ungot_flag & 1) {
+ ungetc(sc->ungot_char, sc->fp);
+ /* Deal with distiction between user and scanf ungots. */
+ if (sc->nread == 0) { /* Only one char was read... app ungot? */
+ sc->fp->ungot[1] = sc->app_ungot; /* restore ungot state. */
+ } else {
+ sc->fp->ungot[1] = 0;
+ }
+ }
+
+#else
+
+ if ((sc->ungot_wflag & 1) && (sc->fp->filedes != -3) && (sc->fp->state.mask == 0)) {
+ ungetwc(sc->ungot_char, sc->fp);
/* Deal with distiction between user and scanf ungots. */
if (sc->nread == 0) { /* Only one char was read... app ungot? */
sc->fp->ungot[1] = sc->app_ungot; /* restore ungot state. */
+ } else {
+ sc->fp->ungot[1] = 0;
}
+ sc->fp->ungot_width[1] = sc->ungot_wchar_width;
}
+
+#endif
}
-int vfscanf(FILE *fp, const char *format, va_list ap)
-{
-#define STRTO_L_(s,e,b,sf) _stdlib_strto_ll(s,e,b,sf)
-#define MAX_DIGITS 64
-#define UV_TYPE unsigned long long
-#define V_TYPE long long
+#ifdef L_vfwscanf
#ifdef __UCLIBC_HAS_FLOATS__
- long double ld;
+static const char fake_decpt_str[] = ".";
+#endif
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+static const char fake_thousands_sep_str[] = ",";
#endif
- UV_TYPE uv;
+#endif /* L_vfwscanf */
+
+
+int VFSCANF (FILE *__restrict fp, const Wchar *__restrict format, va_list arg)
+{
+ const Wuchar *fmt;
+ unsigned char *b;
+
+
+#ifdef L_vfwscanf
+ wchar_t wbuf[1];
+ wchar_t *wb;
+#endif /* L_vfwscanf */
+
+#ifdef __UCLIBC_HAS_WCHAR__
+ mbstate_t mbstate;
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
struct scan_cookie sc;
- register unsigned const char *fmt;
- const char *p;
- register unsigned char *b;
- void *vp;
- int cc, i, cnt;
- signed char lval;
- unsigned char store, usflag, base, invert, r0, r1;
+ psfs_t psfs;
+
+ int i;
+
+#warning fix MAX_DIGITS. we do not do binary, so...!
+#define MAX_DIGITS 65 /* Allow one leading 0. */
unsigned char buf[MAX_DIGITS+2];
+#ifdef L_vfscanf
unsigned char scanset[UCHAR_MAX + 1];
+ unsigned char invert; /* Careful! Meaning changes. */
+#endif /* L_vfscanf */
+ unsigned char fail;
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Make checking of the format string in C locale an option.
+#endif
+ /* To support old programs, don't check mb validity if in C locale. */
+#if defined(__UCLIBC_HAS_LOCALE__) && !defined(L_vfwscanf)
+ /* ANSI/ISO C99 requires format string to be a valid multibyte string
+ * beginning and ending in its initial shift state. */
+ if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) {
+ mbstate.mask = 0; /* Initialize the mbstate. */
+ const char *p = format;
+ if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) {
+ __set_errno(EINVAL); /* Format string is invalid. */
+ return 0;
+ }
+ }
+#endif /* defined(__UCLIBC_HAS_LOCALE__) && !defined(L_vfwscanf) */
+
+#if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
+ psfs.num_pos_args = -1; /* Must start at -1. */
+ /* Initialize positional arg ptrs to NULL. */
+ memset(psfs.pos_args, 0, sizeof(psfs.pos_args));
+#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
__STDIO_THREADLOCK(fp);
- init_scan_cookie(&sc,fp);
+ __init_scan_cookie(&sc,fp);
+#ifdef __UCLIBC_HAS_WCHAR__
+ sc.sc_getc = sc_getc;
+ sc.ungot_wchar_width = sc.fp->ungot_width[1];
- fmt = (unsigned const char *) format;
- cnt = 0;
+#ifdef L_vfwscanf
- while (*fmt) {
- store = 1;
- lval = 0;
- sc.width = INT_MAX;
- if (*fmt == '%') { /* Conversion specification. */
- ++fmt;
- if (*fmt == '*') { /* Suppress assignment. */
- store = 0;
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+ if (*sc.grouping) {
+ sc.thousands_sep = fake_thousands_sep_str;
+ sc.tslen = 1;
+ }
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+
+#ifdef __UCLIBC_HAS_FLOATS__
+ sc.fake_decpt = fake_decpt_str;
+#endif /* __UCLIBC_HAS_FLOATS__ */
+
+#else /* L_vfwscanf */
+
+#ifdef __UCLIBC_HAS_FLOATS__
+ sc.fake_decpt = sc.decpt;
+#endif /* __UCLIBC_HAS_FLOATS__ */
+
+#endif /* L_vfwscanf */
+
+#endif /* __UCLIBC_HAS_WCHAR__ */
+ psfs.cnt = 0;
+
+ /* Note: If we ever wanted to support non-nice codesets, we
+ * would really need to do a mb->wc conversion here in the
+ * vfscanf case. Related changes would have to be made in
+ * the code that follows... basicly wherever fmt appears. */
+ for (fmt = (const Wuchar *) format ; *fmt ; /* ++fmt */) {
+
+ psfs.store = 1;
+ psfs.flags = 0;
+#ifndef NDEBUG
+ psfs.cur_ptr = NULL; /* Debugging aid. */
+#endif /* NDEBUG */
+
+
+ sc.ungot_flag &= 1; /* Clear (possible fake) EOF. */
+ sc.width = psfs.max_width = INT_MAX;
+
+ /* Note: According to the standards, vfscanf does use isspace
+ * here. So, if we did a mb->wc conversion, we would have to do
+ * something like
+ * ((((__uwchar_t)wc) < UCHAR_MAX) && isspace(wc))
+ * because wc might not be in the allowed domain. */
+ if (ISSPACE(*fmt)) {
+ do {
++fmt;
+ } while (ISSPACE(*fmt));
+ --fmt;
+ psfs.conv_num = CONV_whitespace;
+ goto DO_WHITESPACE;
+ }
+
+ if (*fmt == '%') { /* Conversion specification. */
+ if (*++fmt == '%') { /* Remember, '%' eats whitespace too. */
+ psfs.conv_num = CONV_percent;
+ goto DO_CONVERSION;
}
- for (i = 0 ; __isdigit(*fmt) ; sc.width = i) {
- i = (i * 10) + (*fmt++ - '0'); /* Get specified width. */
+
+
+#ifdef L_vfscanf
+ psfs.fmt = fmt;
+#else /* L_vfscanf */
+ {
+ const __uwchar_t *wf = fmt;
+ psfs.fmt = b = buf;
+
+ while (*wf && __isascii(*wf) && (b < buf + sizeof(buf) - 1)) {
+ *b++ = *wf++;
+ }
+#ifdef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__
+#error this is wrong... we need to ched in __psfs_parse_spec instead since this checks last char in buffer and conversion my have stopped before it.
+ if ((*b == 'a') && ((*wf == '[') || ((*wf|0x20) == 's'))) {
+ goto DONE; /* Spec was excessively long. */
+ }
+#endif /* __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ */
+ *b = 0;
+ if (b == buf) { /* Bad conversion specifier! */
+ goto DONE;
+ }
}
- for (i = 0 ; i < sizeof(qual) ; i++) { /* Optional qualifier. */
- if (qual[i] == *fmt) {
- ++fmt;
- lval += qsz[i];
- if ((i < 2) && (qual[i] == *fmt)) { /* Double h or l. */
- ++fmt;
- lval += qsz[i];
+#endif /* L_vfscanf */
+ if ((i = __psfs_parse_spec(&psfs)) < 0) { /* Bad conversion specifier! */
+ goto DONE;
+ }
+ fmt += i;
+
+#if defined(NL_ARGMAX) && (NL_ARGMAX > 0)
+ if (psfs.store) {
+ if (psfs.num_pos_args == -2) {
+ psfs.cur_ptr = va_arg(arg, void *);
+ } else {
+ while (psfs.cur_pos_arg > psfs.num_pos_args) {
+ psfs.pos_args[++psfs.num_pos_args] = va_arg(arg, void *);
}
- break;
+ psfs.cur_ptr = psfs.pos_args[psfs.cur_pos_arg];
+ }
+ }
+#else /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
+ psfs.cur_ptr = va_arg(arg, void *);
+#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */
+
+ DO_CONVERSION:
+ /* First, consume white-space if not n, c, [, C, or l[. */
+ if ((((1L << CONV_n)|(1L << CONV_C)|(1L << CONV_c)
+ |(1L << CONV_LEFTBRACKET)|(1L << CONV_leftbracket))
+ & (1L << psfs.conv_num)) == 0
+ ) {
+ DO_WHITESPACE:
+ while ((__scan_getc(&sc) >= 0)
+#ifdef L_vfscanf
+ && isspace(sc.cc)
+#else /* L_vfscanf */
+ && iswspace(sc.wc)
+#endif /* L_vfscanf */
+ ) {}
+ __scan_ungetc(&sc);
+ if (psfs.conv_num == CONV_whitespace) {
+ goto NEXT_FMT;
+ }
+ }
+
+ sc.width = psfs.max_width; /* Now limit the max width. */
+
+ if (sc.width == 0) { /* 0 width is forbidden. */
+ goto DONE;
+ }
+
+
+ if (psfs.conv_num == CONV_percent) {
+ goto MATCH_CHAR;
+ }
+
+ if (psfs.conv_num == CONV_n) {
+ if (psfs.store) {
+ _store_inttype(psfs.cur_ptr, psfs.dataargtype,
+ (uintmax_t) sc.nread);
}
+ goto NEXT_FMT;
}
- for (p = spec ; *p ; p++) { /* Process format specifier. */
- if (*fmt != *p) continue;
- if (p-spec < 1) { /* % - match a '%'*/
- goto matchchar;
+
+ if (psfs.conv_num <= CONV_A) { /* pointer, integer, or float spec */
+#ifdef L_vfscanf
+ if (__psfs_do_numeric(&psfs, &sc) < 0) { /* Num conv failed! */
+ goto DONE;
}
- if (p-spec < 2) { /* n - store number of chars read */
- *(va_arg(ap, int *)) = sc.nread;
- scan_getc_nw(&sc);
- goto nextfmt;
+ goto NEXT_FMT;
+#else
+ int r = __psfs_do_numeric(&psfs, &sc);
+ if (sc.ungot_wflag == 1) { /* fix up '?', '.', and ',' hacks */
+ sc.cc = sc.ungot_char = sc.ungot_wchar;
+ }
+ if (r < 0) {
+ goto DONE;
}
- if (p-spec > 3) { /* skip white space if not c or [ */
- do {
- i = scan_getc_nw(&sc);
- } while (__isspace(i));
- scan_ungetc(&sc);
+ goto NEXT_FMT;
+#endif
+ }
+
+ /* Do string conversions here since they are not common code. */
+
+
+#ifdef L_vfscanf
+
+ if
+#ifdef __UCLIBC_HAS_WCHAR__
+ (psfs.conv_num >= CONV_LEFTBRACKET)
+#else /* __UCLIBC_HAS_WCHAR__ */
+ (psfs.conv_num >= CONV_c)
+#endif /* __UCLIBC_HAS_WCHAR__ */
+ {
+ b = (psfs.store ? ((unsigned char *) psfs.cur_ptr) : buf);
+ fail = 1;
+
+
+ if (psfs.conv_num == CONV_c) {
+ if (sc.width == INT_MAX) {
+ sc.width = 1;
+ }
+
+ while (__scan_getc(&sc) >= 0) {
+ *b = sc.cc;
+ b += psfs.store;
+ }
+ __scan_ungetc(&sc);
+ if (sc.width > 0) { /* Failed to read all required. */
+ goto DONE;
+ }
+ psfs.cnt += psfs.store;
+ goto NEXT_FMT;
}
- if (p-spec < 5) { /* [,c,s - string conversions */
+
+ if (psfs.conv_num == CONV_s) {
+ /* Yes, believe it or not, a %s conversion can store nuls. */
+ while ((__scan_getc(&sc) >= 0) && !isspace(sc.cc)) {
+ *b = sc.cc;
+ b += psfs.store;
+ fail = 0;
+ }
+ } else {
+#ifdef __UCLIBC_HAS_WCHAR__
+ assert((psfs.conv_num == CONV_LEFTBRACKET) || \
+ (psfs.conv_num == CONV_leftbracket));
+#else /* __UCLIBC_HAS_WCHAR__ */
+ assert((psfs.conv_num == CONV_leftbracket));
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
invert = 0;
- if (*p == 'c') {
+
+ if (*++fmt == '^') {
+ ++fmt;
invert = 1;
- if (sc.width == INT_MAX) {
- sc.width = 1;
- }
- }
- for (i=0 ; i<= UCHAR_MAX ; i++) {
- scanset[i] = ((*p == 's') ? (__isspace(i) == 0) : 0);
+ }
+ memset(scanset, invert, sizeof(scanset));
+ invert = 1-invert;
+
+ if (*fmt == ']') {
+ scanset[(int)(']')] = invert;
+ ++fmt;
}
- if (*p == '[') { /* need to build a scanset */
- if (*++fmt == '^') {
- invert = 1;
- ++fmt;
- }
- if (*fmt == ']') {
- scanset[(int)']'] = 1;
- ++fmt;
+
+ while (*fmt != ']') {
+ if (!*fmt) { /* No closing ']'. */
+ goto DONE;
}
- r0 = 0;
- while (*fmt && *fmt !=']') { /* build scanset */
- if ((*fmt == '-') && r0 && (fmt[1] != ']')) {
- /* range */
- ++fmt;
- if (*fmt < r0) {
- r1 = r0;
- r0 = *fmt;
- } else {
- r1 = *fmt;
- }
- for (i=r0 ; i<= r1 ; i++) {
- scanset[i] = 1;
- }
- r0 = 0;
- } else {
- r0 = *fmt;
- scanset[r0] = 1;
- }
+ if ((*fmt == '-') && (fmt[1] != ']')
+ && (fmt[-1] < fmt[1]) /* sorted? */
+ ) { /* range */
++fmt;
+ i = fmt[-2];
+ /* Note: scanset[i] should already have been done
+ * in the previous iteration. */
+ do {
+ scanset[++i] = invert;
+ } while (i < *fmt);
+ /* Safe to fall through, and a bit smaller. */
}
- if (!*fmt) { /* format string exhausted! */
- goto done;
- }
+ /* literal char */
+ scanset[(int) *fmt] = invert;
+ ++fmt;
}
- /* ok -- back to common work */
- if (sc.width <= 0) {
- goto done;
+
+#ifdef __UCLIBC_HAS_WCHAR__
+ if (psfs.conv_num == CONV_LEFTBRACKET) {
+ goto DO_LEFTBRACKET;
}
- if (store) {
- b = va_arg(ap, unsigned char *);
- } else {
- b = buf;
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+
+ while (__scan_getc(&sc) >= 0) {
+ if (!scanset[sc.cc]) {
+ break;
+ }
+ *b = sc.cc;
+ b += psfs.store;
+ fail = 0;
}
- cc = scan_getc(&sc);
- if (cc < 0) {
- scan_ungetc(&sc);
- goto done; /* return EOF if cnt == 0 */
+ }
+ /* Common tail for processing of %s and %[. */
+
+ __scan_ungetc(&sc);
+ if (fail) { /* nothing stored! */
+ goto DONE;
+ }
+ *b = 0; /* Nul-terminate string. */
+ psfs.cnt += psfs.store;
+ goto NEXT_FMT;
+ }
+
+#ifdef __UCLIBC_HAS_WCHAR__
+ DO_LEFTBRACKET: /* Need to do common wide init. */
+ if (psfs.conv_num >= CONV_C) {
+ wchar_t wbuf[1];
+ wchar_t *wb;
+
+ sc.mbstate.mask = 0;
+
+ wb = (psfs.store ? ((wchar_t *) psfs.cur_ptr) : wbuf);
+ fail = 1;
+
+ if (psfs.conv_num == CONV_C) {
+ if (sc.width == INT_MAX) {
+ sc.width = 1;
}
- if (*p == 'c') {
- goto c_spec;
+
+ while (scan_getwc(&sc) >= 0) {
+ assert(sc.width >= 0);
+ *wb = sc.wc;
+ wb += psfs.store;
}
- i = 0;
- while ((cc>=0) && (scanset[cc] != invert)) {
- c_spec:
- i = 1; /* yes, we stored something */
- *b = cc;
- b += store;
- cc = scan_getc(&sc);
+
+ __scan_ungetc(&sc);
+ if (sc.width > 0) { /* Failed to read all required. */
+ goto DONE;
}
- if (i==0) {
- scan_ungetc(&sc);
- goto done; /* return cnt */
+ psfs.cnt += psfs.store;
+ goto NEXT_FMT;
+ }
+
+
+ if (psfs.conv_num == CONV_S) {
+ /* Yes, believe it or not, a %s conversion can store nuls. */
+ while ((scan_getwc(&sc) >= 0)
+ && ((((__uwchar_t)(sc.wc)) > UCHAR_MAX)
+ || !isspace(sc.wc))
+ ) {
+ *wb = sc.wc;
+ wb += psfs.store;
+ fail = 0;
}
- if (*p != 'c') { /* nul-terminate the stored string */
- *b = 0;
+ } else {
+ assert(psfs.conv_num == CONV_LEFTBRACKET);
+
+ while (scan_getwc(&sc) >= 0) {
+ if (((__uwchar_t) sc.wc) <= UCHAR_MAX) {
+ if (!scanset[sc.wc]) {
+ break;
+ }
+ } else if (invert) {
+ break;
+ }
+ *wb = sc.wc;
+ wb += psfs.store;
+ fail = 0;
}
- cnt += store;
- goto nextfmt;
}
- if (p-spec < 12) { /* o,u,p,x,X,i,d - (un)signed integer */
- if (*p == 'p') {
- /* assume pointer same size as int or long. */
- lval = (sizeof(char *) == sizeof(long));
+ /* Common tail for processing of %ls and %l[. */
+
+ __scan_ungetc(&sc);
+ if (fail || sc.mb_fail) { /* Nothing stored or mb error. */
+ goto DONE;
+ }
+ *wb = 0; /* Nul-terminate string. */
+ psfs.cnt += psfs.store;
+ goto NEXT_FMT;
+
+ }
+
+#endif /* __UCLIBC_HAS_WCHAR__ */
+#else /* L_vfscanf */
+
+ if (psfs.conv_num >= CONV_C) {
+ b = buf;
+ wb = wbuf;
+ if (psfs.conv_num >= CONV_c) {
+ mbstate.mask = 0; /* Initialize the mbstate. */
+ if (psfs.store) {
+ b = (unsigned char *) psfs.cur_ptr;
}
- usflag = ((p-spec) < 10); /* (1)0 if (un)signed */
- base = radix[(int)(p-spec) - 5];
- b = buf;
- if (sc.width <= 0) {
- goto done;
+ } else {
+ if (psfs.store) {
+ wb = (wchar_t *) psfs.cur_ptr;
}
- cc = scan_getc(&sc);
- if ((cc == '+') || (cc == '-')) { /* Handle leading sign.*/
- *b++ = cc;
- cc = scan_getc(&sc);
+ }
+ fail = 1;
+
+
+ if ((psfs.conv_num == CONV_C) || (psfs.conv_num == CONV_c)) {
+ if (sc.width == INT_MAX) {
+ sc.width = 1;
}
- if (cc == '0') { /* Possibly set base and handle prefix. */
- if ((base == 0) || (base == 16)) {
- cc = scan_getc(&sc);
- if ((cc == 'x') || (cc == 'X')) {
- /* We're committed to base 16 now. */
- base = 16;
- cc = scan_getc(&sc);
- } else { /* oops... back up */
- scan_ungetc(&sc);
- cc = '0';
- if (base == 0) {
- base = 8;
- }
+
+ while (scan_getwc(&sc) >= 0) {
+ if (psfs.conv_num == CONV_C) {
+ *wb = sc.wc;
+ wb += psfs.store;
+ } else {
+ i = wcrtomb(b, sc.wc, &mbstate);
+ if (i < 0) { /* Conversion failure. */
+ goto DONE_DO_UNGET;
+ }
+ if (psfs.store) {
+ b += i;
}
}
}
- if (base == 0) { /* Default to base 10 */
- base = 10;
+ __scan_ungetc(&sc);
+ if (sc.width > 0) { /* Failed to read all required. */
+ goto DONE;
}
- /* At this point, we're ready to start reading digits. */
- if (cc == '0') {
- *b++ = cc; /* Store first leading 0 */
- do { /* but ignore others. */
- cc = scan_getc(&sc);
- } while (cc == '0');
- }
- while (valid_digit(cc,base)) { /* Now for nonzero digits.*/
- if (b - buf < MAX_DIGITS) {
- *b++ = cc;
+ psfs.cnt += psfs.store;
+ goto NEXT_FMT;
+ }
+
+ if ((psfs.conv_num == CONV_S) || (psfs.conv_num == CONV_s)) {
+ /* Yes, believe it or not, a %s conversion can store nuls. */
+ while ((scan_getwc(&sc) >= 0) && !iswspace(sc.wc)) {
+ if (psfs.conv_num == CONV_S) {
+ *wb = sc.wc;
+ wb += psfs.store;
+ } else {
+ i = wcrtomb(b, sc.wc, &mbstate);
+ if (i < 0) { /* Conversion failure. */
+ goto DONE_DO_UNGET;
+ }
+ if (psfs.store) {
+ b += i;
+ }
}
- cc = scan_getc(&sc);
+ fail = 0;
+ }
+ } else {
+ const wchar_t *sss;
+ const wchar_t *ssp;
+ unsigned char invert = 0;
+
+ assert((psfs.conv_num == CONV_LEFTBRACKET)
+ || (psfs.conv_num == CONV_leftbracket));
+
+ if (*++fmt == '^') {
+ ++fmt;
+ invert = 1;
}
- *b = 0; /* null-terminate */
- if ((b == buf) || (*--b == '+') || (*b == '-')) {
- scan_ungetc(&sc);
- goto done; /* No digits! */
+ sss = (const wchar_t *) fmt;
+ if (*fmt == ']') {
+ ++fmt;
}
- if (store) {
- if (*buf == '-') {
- usflag = 0;
+ while (*fmt != ']') {
+ if (!*fmt) { /* No closing ']'. */
+ goto DONE;
}
- uv = STRTO_L_(buf, NULL, base, 1-usflag);
- vp = va_arg(ap, void *);
- switch (lval) {
- case 2: /* If no long long, treat as long . */
- *((unsigned long long *)vp) = uv;
- break;
- case 1:
-#if ULONG_MAX == UINT_MAX
- case 0: /* int and long int are the same */
-#endif
- if (usflag) {
- if (uv > ULONG_MAX) {
- uv = ULONG_MAX;
- }
- } else if (((V_TYPE)uv) > LONG_MAX) {
- uv = LONG_MAX;
- } else if (((V_TYPE)uv) < LONG_MIN) {
- uv = (UV_TYPE) LONG_MIN;
- }
- *((unsigned long *)vp) = (unsigned long)uv;
- break;
-#if ULONG_MAX != UINT_MAX
- case 0: /* int and long int are different */
- if (usflag) {
- if (uv > UINT_MAX) {
- uv = UINT_MAX;
- }
- } else if (((V_TYPE)uv) > INT_MAX) {
- uv = INT_MAX;
- } else if (((V_TYPE)uv) < INT_MIN) {
- uv = (UV_TYPE) INT_MIN;
- }
- *((unsigned int *)vp) = (unsigned int)uv;
- break;
-#endif
- case (signed char)(-1):
- if (usflag) {
- if (uv > USHRT_MAX) {
- uv = USHRT_MAX;
- }
- } else if (((V_TYPE)uv) > SHRT_MAX) {
- uv = SHRT_MAX;
- } else if (((V_TYPE)uv) < SHRT_MIN) {
- uv = (UV_TYPE) SHRT_MIN;
- }
- *((unsigned short *)vp) = (unsigned short)uv;
- break;
- case (signed char)(-2):
- if (usflag) {
- if (uv > UCHAR_MAX) {
- uv = UCHAR_MAX;
+ if ((*fmt == '-') && (fmt[1] != ']')
+ && (fmt[-1] < fmt[1]) /* sorted? */
+ ) { /* range */
+ ++fmt;
+ }
+ ++fmt;
+ }
+ /* Ok... a valid scanset spec. */
+
+ while (scan_getwc(&sc) >= 0) {
+ ssp = sss;
+ do { /* We know sss < fmt. */
+ if (*ssp == '-') { /* possible range... */
+ /* Note: We accept a-c-e (ordered) as
+ * equivalent to a-e. */
+ if (ssp > sss) {
+ if ((++ssp < (const wchar_t *) fmt)
+ && (ssp[-2] < *ssp) /* sorted? */
+ ) { /* yes */
+ if ((sc.wc >= ssp[-2])
+ && (sc.wc <= *ssp)) {
+ break;
+ }
+ continue; /* not in range */
}
- } else if (((V_TYPE)uv) > CHAR_MAX) {
- uv = CHAR_MAX;
- } else if (((V_TYPE)uv) < CHAR_MIN) {
- uv = (UV_TYPE) CHAR_MIN;
+ --ssp; /* oops... '-' at end, so back up */
}
- *((unsigned char *)vp) = (unsigned char) uv;
+ /* false alarm... a literal '-' */
+ }
+ if (sc.wc == *ssp) { /* Matched literal char. */
break;
- default:
- assert(0);
+ }
+ } while (++ssp < (const wchar_t *) fmt);
+
+ if ((ssp == (const wchar_t *) fmt) ^ invert) {
+ /* no match and not inverting
+ * or match and inverting */
+ break;
}
- ++cnt;
- }
- goto nextfmt;
- }
-#ifdef __UCLIBC_HAS_FLOATS__
- else { /* floating point */
- if (sc.width <= 0) {
- goto done;
- }
- if (__strtold(&ld, &sc)) { /* Success! */
- if (store) {
- vp = va_arg(ap, void *);
- switch (lval) {
- case 2:
- *((long double *)vp) = ld;
- break;
- case 1:
- *((double *)vp) = (double) ld;
- break;
- case 0:
- *((float *)vp) = (float) ld;
- break;
- default: /* Illegal qualifier! */
- assert(0);
- goto done;
+ if (psfs.conv_num == CONV_LEFTBRACKET) {
+ *wb = sc.wc;
+ wb += psfs.store;
+ } else {
+ i = wcrtomb(b, sc.wc, &mbstate);
+ if (i < 0) { /* Conversion failure. */
+ goto DONE_DO_UNGET;
+ }
+ if (psfs.store) {
+ b += i;
}
- ++cnt;
}
- goto nextfmt;
+ fail = 0;
}
}
-#else
- assert(0);
-#endif
- goto done;
- }
- /* Unrecognized specifier! */
- goto RETURN_cnt;
- } if (__isspace(*fmt)) { /* Consume all whitespace. */
- do {
- i = scan_getc_nw(&sc);
- } while (__isspace(i));
- } else { /* Match the current fmt char. */
- matchchar:
- if (scan_getc_nw(&sc) != *fmt) {
- scan_ungetc(&sc);
- goto done;
+ /* Common tail for processing of %s and %[. */
+
+ __scan_ungetc(&sc);
+ if (fail) { /* nothing stored! */
+ goto DONE;
+ }
+ *wb = 0; /* Nul-terminate string. */
+ *b = 0;
+ psfs.cnt += psfs.store;
+ goto NEXT_FMT;
}
- scan_getc_nw(&sc);
+
+#endif /* L_vfscanf */
+
+ assert(0);
+ goto DONE;
+ } /* conversion specification */
+
+ MATCH_CHAR:
+ if (__scan_getc(&sc) != *fmt) {
+#ifdef L_vfwscanf
+ DONE_DO_UNGET:
+#endif /* L_vfwscanf */
+ __scan_ungetc(&sc);
+ goto DONE;
}
- nextfmt:
- scan_ungetc(&sc);
+
+ NEXT_FMT:
++fmt;
}
- done: /* end of scan */
- kill_scan_cookie(&sc);
-
- if ((sc.ungot_char <= 0) && (cnt == 0) && (*fmt)) {
- cnt = EOF;
+ DONE:
+ if ((psfs.cnt == 0) && (*fmt) && __FEOF_OR_FERROR(fp)) {
+ psfs.cnt = EOF; /* Yes, vfwscanf also returns EOF. */
}
- RETURN_cnt:
+ kill_scan_cookie(&sc);
+
+/* RETURN_cnt: */
__STDIO_THREADUNLOCK(fp);
- return (cnt);
+ return psfs.cnt;
}
+#endif
+/**********************************************************************/
+#ifdef L___psfs_do_numeric
-/*****************************************************************************/
+static const unsigned char spec_base[] = SPEC_BASE;
+static const unsigned char nil_string[] = "(nil)";
+
+int __psfs_do_numeric(psfs_t *psfs, struct scan_cookie *sc)
+{
+ unsigned char *b;
+ const unsigned char *p;
#ifdef __UCLIBC_HAS_FLOATS__
+ int exp_adjust = 0;
+#endif
+#warning fix MAX_DIGITS. we do not do binary, so...!
+#define MAX_DIGITS 65 /* Allow one leading 0. */
+#warning fix buf!
+ unsigned char buf[MAX_DIGITS+2+ 100];
+ unsigned char usflag, base;
+ unsigned char nonzero = 0;
+ unsigned char seendigit = 0;
+
-#include <float.h>
+#ifndef __UCLIBC_HAS_FLOATS__
+ if (psfs->conv_num > CONV_i) { /* floating point */
+ goto DONE;
+ }
+#endif
-#define MAX_SIG_DIGITS 20
-#define MAX_IGNORED_DIGITS 2000
-#define MAX_ALLOWED_EXP (MAX_SIG_DIGITS + MAX_IGNORED_DIGITS + LDBL_MAX_10_EXP)
+ base = spec_base[psfs->conv_num - CONV_p];
+ usflag = (psfs->conv_num <= CONV_u); /* (1)0 if (un)signed */
+ b = buf;
-#if LDBL_DIG > MAX_SIG_DIGITS
-#error need to adjust MAX_SIG_DIGITS
-#endif
-#include <limits.h>
-#if MAX_ALLOWED_EXP > INT_MAX
-#error size assumption violated for MAX_ALLOWED_EXP
+ if (psfs->conv_num == CONV_p) { /* Pointer */
+ p = nil_string;
+ do {
+ if ((__scan_getc(sc) < 0) || (*p != sc->cc)) {
+ __scan_ungetc(sc);
+ if (p > nil_string) { /* failed */
+ /* We matched at least the '(' so even if we
+ * are at eof, we can not match a pointer. */
+ goto DONE;
+ }
+ break;
+ }
+ if (!*++p) { /* Matched (nil), so no unget necessary. */
+ if (psfs->store) {
+ ++psfs->cnt;
+ _store_inttype(psfs->cur_ptr, psfs->dataargtype,
+ (uintmax_t) NULL);
+ }
+ return 0;
+ }
+ } while (1);
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Should we require a 0x prefix and disallow +/- for pointer %p?
+#endif /* __UCLIBC_MJN3_ONLY__ */
+ }
+
+ __scan_getc(sc);
+ if ((sc->cc == '+') || (sc->cc == '-')) { /* Handle leading sign.*/
+ *b++ = sc->cc;
+ __scan_getc(sc);
+ }
+
+ if ((base & 0xef) == 0) { /* 0xef is ~16, so 16 or 0. */
+ if (sc->cc == '0') { /* Possibly set base and handle prefix. */
+ __scan_getc(sc);
+ if ((sc->cc|0x20) == 'x') { /* Assumes ascii.. x or X. */
+ if ((__scan_getc(sc) < 0)
+#ifdef __UCLIBC_HAS_WCHAR__
+ && !sc->ungot_wflag /* wc outside char range */
+#endif /* __UCLIBC_HAS_WCHAR__ */
+ ) {
+ /* Note! 'x' at end of file|field is special.
+ * While this looks like I'm 'unget'ing twice,
+ * EOF and end of field are handled specially
+ * by the scan_* funcs. */
+ __scan_ungetc(sc);
+ goto DO_NO_0X;
+ }
+ base = 16; /* Base 16 for sure now. */
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ /* The prefix is required for hexadecimal floats. */
+ *b++ = '0';
+ *b++ = 'x';
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+ } else { /* oops... back up */
+ DO_NO_0X:
+ __scan_ungetc(sc);
+ sc->cc = '0'; /* NASTY HACK! */
+
+ base = (base >> 1) + 8; /* 0->8, 16->16. no 'if' */
+#ifdef __UCLIBC_HAS_FLOATS__
+ if (psfs->conv_num > CONV_i) { /* floating point */
+ base = 10;
+ }
#endif
+ }
+ } else if (!base) {
+ base = 10;
+ }
+ }
-int __strtold(long double *ld, struct scan_cookie *sc)
-{
- long double number;
- long double p10;
- int exponent_power;
- int exponent_temp;
- int negative;
- int num_digits;
- int since_decimal;
- int c;
+ /***************** digit grouping **********************/
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+
+ if ((psfs->flags & FLAG_THOUSANDS) && (base == 10)
+ && *(p = sc->grouping)
+ ) {
+
+ int nblk1, nblk2, nbmax, lastblock, pass, i;
- c = scan_getc(sc); /* Decrements width. */
-
- negative = 0;
- switch(c) { /* Handle optional sign. */
- case '-': negative = 1; /* Fall through to get next char. */
- case '+': c = scan_getc(sc);
- }
-
- number = 0.;
- num_digits = -1;
- exponent_power = 0;
- since_decimal = INT_MIN;
-
- LOOP:
- while (__isdigit(c)) { /* Process string of digits. */
- ++since_decimal;
- if (num_digits < 0) { /* First time through? */
- ++num_digits; /* We've now seen a digit. */
- }
- if (num_digits || (c != '0')) { /* had/have nonzero */
- ++num_digits;
- if (num_digits <= MAX_SIG_DIGITS) { /* Is digit significant? */
- number = number * 10. + (c - '0');
+
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Should we initalize the grouping blocks in __init_scan_cookie()?
+#endif /* __UCLIBC_MJN3_ONLY__ */
+ nbmax = nblk2 = nblk1 = *p;
+ if (*++p) {
+ nblk2 = *p;
+ if (nbmax < nblk2) {
+ nbmax = nblk2;
}
+ assert(!*++p);
}
- c = scan_getc(sc);
- }
-
- if ((c == '.') && (since_decimal < 0)) { /* If no previous decimal pt, */
- since_decimal = 0; /* save position of decimal point */
- c = scan_getc(sc); /* and process rest of digits */
- goto LOOP;
- }
-
- if (num_digits<0) { /* Must have at least one digit. */
- goto FAIL;
- }
-
- if (num_digits > MAX_SIG_DIGITS) { /* Adjust exp for skipped digits. */
- exponent_power += num_digits - MAX_SIG_DIGITS;
- }
-
- if (since_decimal >= 0) { /* Adjust exponent for decimal point. */
- exponent_power -= since_decimal;
- }
-
- if (negative) { /* Correct for sign. */
- number = -number;
- negative = 0; /* Reset for exponent processing below. */
- }
-
- /* Process an exponent string. */
- if (c == 'e' || c == 'E') {
- c = scan_getc(sc);
- switch(c) { /* Handle optional sign. */
- case '-': negative = 1; /* Fall through to get next char. */
- case '+': c = scan_getc(sc);
- }
-
- num_digits = 0;
- exponent_temp = 0;
- while (__isdigit(c)) { /* Process string of digits. */
- if (exponent_temp < MAX_ALLOWED_EXP) { /* overflow check */
- exponent_temp = exponent_temp * 10 + (c - '0');
+
+ /* Note: for printf, if 0 and \' flags appear then
+ * grouping is done before 0-padding. Should we
+ * strip leading 0's first? Or add a 0 flag? */
+
+ /* For vfwscanf, sc_getc translates, so the value of sc->cc is
+ * either EOF or a char. */
+
+ if (!__isdigit_char_or_EOF(sc->cc)) { /* No starting digit! */
+#ifdef __UCLIBC_HAS_FLOATS__
+ if (psfs->conv_num > CONV_i) { /* floating point */
+ goto NO_STARTING_DIGIT;
}
- c = scan_getc(sc);
- ++num_digits;
+#endif
+ goto DONE_DO_UNGET;
}
- if (num_digits == 0) { /* Were there no exp digits? */
- goto FAIL;
- } /* else */
- if (negative) {
- exponent_power -= exponent_temp;
- } else {
- exponent_power += exponent_temp;
+ if (sc->cc == '0') {
+ seendigit = 1;
+ *b++ = '0'; /* Store the first 0. */
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Should leading 0s be skipped before digit grouping? (printf 0 pad)
+#endif /* __UCLIBC_MJN3_ONLY__ */
+#if 0
+ do { /* But ignore all subsequent 0s. */
+ __scan_getc(sc);
+ } while (sc->cc == '0');
+#endif
}
- }
+ pass = 0;
+ lastblock = 0;
+ do {
+ i = 0;
+ while (__isdigit_char_or_EOF(sc->cc)) {
+ seendigit = 1;
+ if (i == nbmax) { /* too many digits for a block */
+#ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__
+ if (!pass) { /* treat as nongrouped */
+ if (nonzero) {
+ goto DO_NO_GROUP;
+ }
+ goto DO_TRIM_LEADING_ZEROS;
+ }
+#endif
+ if (nbmax > nblk1) {
+ goto DONE_DO_UNGET;
+ }
+ goto DONE_GROUPING_DO_UNGET; /* nbmax == nblk1 */
+ }
+ ++i;
+
+ if (nonzero || (sc->cc != '0')) {
+ if (b < buf + MAX_DIGITS) {
+ *b++ = sc->cc;
+ nonzero = 1;
+#ifdef __UCLIBC_HAS_FLOATS__
+ } else {
+ ++exp_adjust;
+#endif
+ }
+ }
- if (number != 0.) {
- /* Now scale the result. */
- exponent_temp = exponent_power;
- p10 = 10.;
+ __scan_getc(sc);
+ }
+
+ if (i) { /* we saw digits digits */
+ if ((i == nblk2) || ((i < nblk2) && !pass)) {
+ /* (possible) outer grp */
+ p = sc->thousands_sep;
+ if (*p == sc->cc) { /* first byte matches... */
+ /* so check if grouping mb char */
+ /* Since 1st matched, either match or fail now
+ * unless EOF (yuk) */
+ __scan_getc(sc);
+ MBG_LOOP:
+ if (!*++p) { /* is a grouping mb char */
+ lastblock = i;
+ ++pass;
+ continue;
+ }
+ if (*p == sc->cc) {
+ __scan_getc(sc);
+ goto MBG_LOOP;
+ }
+ /* bad grouping mb char! */
+ __scan_ungetc(sc);
+ if ((sc->cc >= 0) || (p > sc->thousands_sep + 1)) {
+#ifdef __UCLIBC_HAS_FLOATS__
+ /* We failed to match a thousep mb char, and
+ * we've read too much to recover. But if
+ * this is a floating point conversion and
+ * the initial portion of the decpt mb char
+ * matches, then we may still be able to
+ * recover. */
+ int k = p - sc->thousands_sep - 1;
- if (exponent_temp < 0) {
- exponent_temp = -exponent_temp;
+ if ((psfs->conv_num > CONV_i) /* float conversion */
+ && (!pass || (i == nblk1)) /* possible last */
+ && !memcmp(sc->thousands_sep, sc->fake_decpt, k)
+ /* and prefix matched, so could be decpt */
+ ) {
+ __scan_getc(sc);
+ p = sc->fake_decpt + k;
+ do {
+ if (!*++p) {
+ strcpy(b, sc->decpt);
+ b += sc->decpt_len;
+ goto GOT_DECPT;
+ }
+ if (*p != sc->cc) {
+ __scan_ungetc(sc);
+ break; /* failed */
+ }
+ __scan_getc(sc);
+ } while (1);
+ }
+#endif /* __UCLIBC_HAS_FLOATS__ */
+ goto DONE;
+ }
+ /* was EOF and 1st, so recoverable. */
+ }
+ }
+ if ((i == nblk1) || ((i < nblk1) && !pass)) {
+ /* got an inner group */
+ goto DONE_GROUPING_DO_UNGET;
+ }
+ if (i > nblk1) {
+ /* An inner group if we can back up a bit. */
+ if ((i - nblk1) <= (sc->ungot_flag ^ 1)) {
+ assert(sc->cc < 0);
+ --b;
+ goto DO_RECOVER_GROUP;
+ }
+ }
+
+ /* (0 < i < nblk1) && (pass > 0) so prev group char
+ * So we have an unrecoverable situation. */
+ goto DONE_DO_UNGET;
+ } /* i != 0 */
+
+ assert(pass);
+
+ /* No next group. Can we back up past grouping mb char? */
+ if ((pass == 1) || (nblk1 == nblk2)) {
+ if (!i && (sc->tslen == 1) && (sc->cc < 0)) {
+ /* No digits, grouping mb char is len 1, and EOF*/
+ DO_RECOVER_GROUP:
+ if (sc->ungot_flag & 2) {
+ __scan_ungetc(sc);
+ }
+ goto DONE_GROUPING_DO_UNGET;
+ }
+ }
+ goto DONE_DO_UNGET;
+ } while (1);
+
+ assert(0); /* Should never get here. */
+ }
+
+#endif /***************** digit grouping **********************/
+
+ /* Not grouping so first trim all but one leading 0. */
+#ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__
+ DO_TRIM_LEADING_ZEROS:
+#endif /* __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__ */
+ if (sc->cc == '0') {
+ seendigit = 1;
+ *b++ = '0'; /* Store the first 0. */
+ do { /* But ignore all subsequent 0s. */
+ __scan_getc(sc);
+ } while (sc->cc == '0');
+ }
+
+#ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__
+ DO_NO_GROUP:
+#endif /* __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__ */
+ /* At this point, we're ready to start reading digits. */
+
+#define valid_digit(cc,base) (isxdigit(cc) && ((base == 16) || (cc - '0' < base)))
+
+ while (valid_digit(sc->cc,base)) { /* Now for significant digits.*/
+ if (b - buf < MAX_DIGITS) {
+ nonzero = seendigit = 1; /* Set nonzero too 0s trimmed above. */
+ *b++ = sc->cc;
+#ifdef __UCLIBC_HAS_FLOATS__
+ } else {
+ ++exp_adjust;
+#endif
}
+ __scan_getc(sc);
+ }
- while (exponent_temp) {
- if (exponent_temp & 1) {
- if (exponent_power < 0) {
- number /= p10;
- } else {
- number *= p10;
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+ DONE_GROUPING_DO_UNGET:
+#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */
+ if (psfs->conv_num <= CONV_i) { /* integer conversion */
+ __scan_ungetc(sc);
+ *b = 0; /* null-terminate */
+ if (!seendigit) {
+ goto DONE; /* No digits! */
+ }
+ if (psfs->store) {
+ if (*buf == '-') {
+ usflag = 0;
+ }
+ ++psfs->cnt;
+ _store_inttype(psfs->cur_ptr, psfs->dataargtype,
+ (uintmax_t) STRTOUIM(buf, NULL, base, 1-usflag));
+ }
+ return 0;
+ }
+
+#ifdef __UCLIBC_HAS_FLOATS__
+
+ /* At this point, we have everything left of the decimal point or exponent. */
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+ NO_STARTING_DIGIT:
+#endif
+ p = sc->fake_decpt;
+ do {
+ if (!*p) {
+ strcpy(b, sc->decpt);
+ b += sc->decpt_len;
+ break;
+ }
+ if (*p != sc->cc) {
+ if (p > sc->fake_decpt) {
+ if ((sc->cc >= 0) && (p > sc->fake_decpt + 1)) {
+ goto DONE_DO_UNGET; /* failed */
}
+
+ __scan_ungetc(sc);
+
}
- exponent_temp >>= 1;
- p10 *= p10;
+ goto DO_DIGIT_CHECK;
+ }
+ ++p;
+ __scan_getc(sc);
+ } while (1);
+
+#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__
+ GOT_DECPT:
+#endif
+ if (!nonzero) {
+ if (sc->cc == '0') {
+ assert(exp_adjust == 0);
+ *b++ = '0';
+ ++exp_adjust;
+ seendigit = 1;
+ do {
+ --exp_adjust;
+ __scan_getc(sc);
+ } while (sc->cc == '0');
}
}
- *ld = number;
- return 1;
- FAIL:
- scan_ungetc(sc);
- return 0;
-}
+ while (valid_digit(sc->cc,base)) { /* Process fractional digits.*/
+ if (b - buf < MAX_DIGITS) {
+ seendigit = 1;
+ *b++ = sc->cc;
+ }
+ __scan_getc(sc);
+ }
+
+ DO_DIGIT_CHECK:
+ /* Hmm... no decimal point. */
+ if (!seendigit) {
+ static const unsigned char nan_inf_str[] = "an\0nfinity";
+
+ if (base == 16) { /* We had a prefix, but no digits! */
+ goto DONE_DO_UNGET;
+ }
+
+ /* Avoid tolower problems for INFINITY in the tr_TR locale. (yuk)*/
+#undef TOLOWER
+#define TOLOWER(C) ((C)|0x20)
+
+ switch (TOLOWER(sc->cc)) {
+ case 'i':
+ p = nan_inf_str + 3;
+ break;
+ case 'n':
+ p = nan_inf_str;
+ break;
+ default:
+ /* No digits and not inf or nan. */
+ goto DONE_DO_UNGET;
+ }
+
+ *b++ = sc->cc;
+
+ do {
+ __scan_getc(sc);
+ if (TOLOWER(sc->cc) == *p) {
+ *b++ = sc->cc;
+ ++p;
+ continue;
+ }
+ if (!*p || (p == nan_inf_str + 5)) { /* match nan/infinity or inf */
+ goto GOT_FLOAT;
+ }
+ /* Unrecoverable. Even if on 1st char, we had no digits. */
+ goto DONE_DO_UNGET;
+ } while (1);
+ }
+
+ /* If we get here, we had some digits. */
+
+ if (
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+ ((base == 16) && (((sc->cc)|0x20) == 'p')) ||
+#endif
+ (((sc->cc)|0x20) == 'e')
+ ) { /* Process an exponent. */
+ *b++ = sc->cc;
+
+ __scan_getc(sc);
+ if (sc->cc < 0) { /* EOF... recoverable */
+ --b;
+ goto GOT_FLOAT;
+ }
+
+ if ((sc->cc == '+') || (sc->cc == '-')) { /* Signed exponent? */
+ *b++ = sc->cc;
+ __scan_getc(sc);
+ }
+
+#warning fix MAX_EXP_DIGITS!
+#define MAX_EXP_DIGITS 20
+ assert(seendigit);
+ seendigit = 0;
+ nonzero = 0;
+
+ if (sc->cc == '0') {
+ seendigit = 1;
+ *b++ = '0';
+ do {
+ __scan_getc(sc);
+ } while (sc->cc == '0');
+ }
+
+ while (__isdigit_char_or_EOF(sc->cc)) { /* Exponent digits (base 10).*/
+ if (seendigit < MAX_EXP_DIGITS) {
+ ++seendigit;
+ *b++ = sc->cc;
+ }
+ __scan_getc(sc);
+ }
+
+ if (!seendigit) { /* No digits. Unrecoverable. */
+ goto DONE_DO_UNGET;
+ }
+ }
+
+
+ GOT_FLOAT:
+
+ *b = 0;
+ {
+ __fpmax_t x;
+ char *e;
+ x = __strtofpmax(buf, &e, exp_adjust);
+ assert(!*e);
+ if (psfs->store) {
+ if (psfs->dataargtype & PA_FLAG_LONG_LONG) {
+ *((long double *)psfs->cur_ptr) = (long double) x;
+ } else if (psfs->dataargtype & PA_FLAG_LONG) {
+ *((double *)psfs->cur_ptr) = (double) x;
+ } else {
+ *((float *)psfs->cur_ptr) = (float) x;
+ }
+ ++psfs->cnt;
+ }
+ __scan_ungetc(sc);
+ return 0;
+ }
#endif /* __UCLIBC_HAS_FLOATS__ */
+
+ DONE_DO_UNGET:
+ __scan_ungetc(sc);
+ DONE:
+ return -1;
+
+}
#endif
+/**********************************************************************/
diff --git a/libc/stdio/stdio.c b/libc/stdio/stdio.c
index 0d4708d97..40ac693a4 100644
--- a/libc/stdio/stdio.c
+++ b/libc/stdio/stdio.c
@@ -352,7 +352,7 @@ UNLOCKED(int,fileno,(register FILE *stream),(stream))
FILE *fdopen(int filedes, const char *mode)
{
- register char *cur_mode; /* TODO -- replace by intptr_t?? */
+ register char *cur_mode; /* TODO -- use intptr_t?? (also fopencookie) */
return (((int)(cur_mode = (char *) fcntl(filedes, F_GETFL))) != -1)
? _stdio_fopen(cur_mode, mode, NULL, filedes)
@@ -491,7 +491,10 @@ static ssize_t fmo_read(register void *cookie, char *buf, size_t bufsize)
{
size_t count = COOKIE->len - COOKIE->pos;
- /* Note: bufsize < SSIZE_MAX because of _stdio_READ. */
+ /* Note: 0 < bufsize < SSIZE_MAX because of _stdio_READ. */
+ if (!count) { /* EOF! */
+ return 0;
+ }
if (bufsize > count) {
bufsize = count;
@@ -838,8 +841,6 @@ FILE *open_memstream(char **__restrict bufloc, size_t *__restrict sizeloc)
* When compiled without large file support, the offset pointer for the
* cookie_seek function is off_t * and not off64_t * as for glibc. */
-/* TODO: rewrite _stdio_fopen() to avoid the fopencookie() kludge. */
-
/* Currently no real reentrancy issues other than a possible double close(). */
#ifndef __BCC__
@@ -848,12 +849,14 @@ FILE *fopencookie(void * __restrict cookie, const char * __restrict mode,
cookie_io_functions_t io_functions)
{
FILE *stream;
- int fd;
- if ((stream = _stdio_fopen("/dev/null", mode, NULL, -1)) != NULL) {
- fd = stream->filedes;
+ /* Fake an fdopen guaranteed to pass the _stdio_fopen basic agreement
+ * check without an fcntl call. */
+ if ((stream = _stdio_fopen(((char *)(INT_MAX-1)),
+ mode, NULL, INT_MAX)) /* TODO: use intptr_t? */
+ != NULL
+ ) {
stream->filedes = -1;
- close(fd);
stream->gcs = io_functions;
stream->cookie = cookie;
}
@@ -886,10 +889,13 @@ FILE *_fopencookie(void * __restrict cookie, const char * __restrict mode,
{
register FILE *stream;
- if ((stream = _stdio_fopen("/dev/null", mode, NULL, -1)) != NULL) {
- int fd = stream->filedes;
+ /* Fake an fdopen guaranteed to pass the _stdio_fopen basic agreement
+ * check without an fcntl call. */
+ if ((stream = _stdio_fopen(((char *)(INT_MAX-1)),
+ mode, NULL, INT_MAX)) /* TODO: use intptr_t? */
+ != NULL
+ ) {
stream->filedes = -1;
- close(fd);
stream->gcs.read = io_functions->read;
stream->gcs.write = io_functions->write;
stream->gcs.seek = io_functions->seek;
@@ -1019,7 +1025,7 @@ void __fpurge(register FILE * __restrict stream)
/* Not reentrant. */
#ifdef __STDIO_WIDE
-#warning unlike the glibc version, this __fpending returns bytes in buffer for wide streams too!
+#warning Unlike the glibc version, this __fpending returns bytes in buffer for wide streams too!
link_warning(__fpending, "This version of __fpending returns bytes remaining in buffer for both narrow and wide streams. glibc's version returns wide chars in buffer for the wide stream case.")
@@ -1220,12 +1226,17 @@ FILE *_stdio_fsfopen(const char * __restrict filename,
/* stdio internal functions */
/**********************************************************************/
#ifdef L__stdio_adjpos
-/*
- * ANSI/ISO p. 370: The file positioning indicator is unspecified after
- * a successful call to ungetwc.
+
+/* According to the ANSI/ISO C99 definition of ungetwc()
+ * For a text or binary stream, the value of its file position indicator
+ * after a successful call to the ungetwc function is unspecified until
+ * all pushed­back wide characters are read or discarded.
* Note however, that this applies only to _user_ calls to ungetwc. We
- * need to allow for internal calls by scanf. So we store the byte count
- * of the first ungot wide char in ungot0_bytes. If it is 0 (user case)
+ * need to allow for internal calls by scanf.
+
+
+ * So we store the byte count
+ * of the first ungot wide char in ungot_width. If it is 0 (user case)
* then the file position is treated as unknown.
*/
@@ -1236,16 +1247,23 @@ int _stdio_adjpos(register FILE * __restrict stream, register __offmax_t *pos)
__offmax_t r;
int cor = stream->modeflags & __MASK_UNGOT; /* handle ungots */
+ assert(cor <= 2);
+
#ifdef __STDIO_WIDE
/* Assumed narrow stream so correct if wide. */
if (cor && (stream->modeflags & __FLAG_WIDE)) {
- cor = cor - 1 + stream->ungot_width[0];
- if (((stream->modeflags & __MASK_UNGOT) > 1) || stream->ungot[1]) {
+ if ((((stream->modeflags & __MASK_UNGOT) > 1) || stream->ungot[1])) {
return -1; /* App did ungetwc, so position is indeterminate. */
}
- assert(stream->ungot_width[0] > 0);
+ if (stream->modeflags & __MASK_UNGOT) {
+ cor = cor - 1 + stream->ungot_width[1];
+ }
+ if (stream->state.mask > 0) { /* Incomplete character (possible bad) */
+ cor -= stream->ungot_width[0];
+ }
}
#endif /* __STDIO_WIDE */
+
#ifdef __STDIO_BUFFERS
if (stream->modeflags & __FLAG_WRITING) {
cor -= (stream->bufpos - stream->bufstart); /* pending writes */
@@ -1415,9 +1433,14 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, register FILE *stream)
*p++ = *stream->bufpos++;
}
- if ((bytes > 0) && (stream->filedes != -2)) {
+ if (bytes > 0) {
ssize_t len;
+ if (stream->filedes == -2) {
+ stream->modeflags |= __FLAG_EOF;
+ goto DONE;
+ }
+
/* The buffer is exhausted, but we still need chars. */
stream->bufpos = stream->bufread = stream->bufstart;
@@ -1449,6 +1472,7 @@ size_t _stdio_fread(unsigned char *buffer, size_t bytes, register FILE *stream)
}
#endif
+ DONE:
__stdio_validate_FILE(stream); /* debugging only */
return (p - (unsigned char *)buffer);
}
@@ -2086,7 +2110,9 @@ int fclose(register FILE *stream)
/* At this point, any dangling refs to the stream are the result of
* a programming bug... so free the unlocked stream. */
if (stream->modeflags & __FLAG_FREEFILE) {
+#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
stream->cookie = NULL; /* To aid debugging... */
+#endif
free(stream);
}
@@ -2118,7 +2144,9 @@ int fclose(register FILE *stream)
/* At this point, any dangling refs to the stream are the result of
* a programming bug... so free the unlocked stream. */
if (stream->modeflags & __FLAG_FREEFILE) {
+#ifdef __STDIO_GLIBC_CUSTOM_STREAMS
stream->cookie = NULL; /* To aid debugging... */
+#endif
free(stream);
}
@@ -2213,7 +2241,7 @@ int fflush_unlocked(register FILE *stream)
rv = -1; /* Not all chars written. */
}
#ifdef __UCLIBC_MJN3_ONLY__
-#warning add option to test for undefined behavior of fflush
+#warning WISHLIST: Add option to test for undefined behavior of fflush.
#endif /* __UCLIBC_MJN3_ONLY__ */
#if 0
} else if (stream->modeflags & (__FLAG_READING|__FLAG_READONLY)) {
@@ -2242,7 +2270,7 @@ int fflush_unlocked(register FILE *stream)
#endif
#ifdef __UCLIBC_MJN3_ONLY__
-#warning add option to test for undefined behavior of fflush
+#warning WISHLIST: Add option to test for undefined behavior of fflush.
#endif /* __UCLIBC_MJN3_ONLY__ */
#if 0
return ((stream != NULL)
@@ -2317,16 +2345,18 @@ FILE *_stdio_fopen(const char * __restrict filename,
open_mode |= O_RDWR;
}
-#if defined(__STDIO_GNU_FEATURE) || defined(__STDIO_FOPEN_LARGEFILE_MODE)
- while (*mode) { /* ignore everything else except ... */
+#if defined(__STDIO_FOPEN_EXCLUSIVE_MODE) || defined(__STDIO_FOPEN_LARGEFILE_MODE)
+ for ( ; *mode ; ++mode) { /* ignore everything else except ... */
#ifdef __STDIO_FOPEN_EXCLUSIVE_MODE
- if (*mode++ == 'x') { /* open exclusive -- glibc extension */
+ if (*mode == 'x') { /* open exclusive -- glibc extension */
open_mode |= O_EXCL;
+ continue;
}
#endif /* __STDIO_FOPEN_EXCLUSIVE_MODE */
#ifdef __STDIO_FOPEN_LARGEFILE_MODE
- if (*mode++ == 'F') { /* open large file */
+ if (*mode == 'F') { /* open large file */
open_mode |= O_LARGEFILE;
+ continue;
}
#endif /* __STDIO_FOPEN_LARGEFILE_MODE */
}
@@ -2371,6 +2401,7 @@ FILE *_stdio_fopen(const char * __restrict filename,
* leave it set (glibc compat). */
int i = (open_mode & (O_ACCMODE|O_LARGEFILE)) + 1;
+ /* NOTE: fopencookie needs changing if the basic check changes! */
if (((i & (((int) filename) + 1)) != i) /* Check basic agreement. */
|| (((open_mode & O_APPEND)
&& !(((int) filename) & O_APPEND)
@@ -2445,6 +2476,9 @@ FILE *_stdio_fopen(const char * __restrict filename,
stream->gcs.close = _cs_close;
#endif /* __STDIO_GLIBC_CUSTOM_STREAMS */
+#ifdef __STDIO_WIDE
+ stream->ungot_width[0] = 0;
+#endif /* __STDIO_WIDE */
#ifdef __STDIO_MBSTATE
__INIT_MBSTATE(&(stream->state));
#endif /* __STDIO_MBSTATE */
@@ -2797,6 +2831,7 @@ UNLOCKED(int,fputs,
/**********************************************************************/
#ifdef L_getc
#undef getc
+#undef getc_unlocked
/* Reentrancy handled by UNLOCKED() macro. */
@@ -2855,6 +2890,7 @@ char *gets(char *s) /* WARNING!!! UNSAFE FUNCTION!!! */
/**********************************************************************/
#ifdef L_putc
#undef putc
+#undef putc_unlocked
/* Reentrancy handled by UNLOCKED() macro. */
@@ -2931,8 +2967,7 @@ int ungetc(int c, register FILE *stream)
stream->modeflags |= __FLAG_NARROW;
#endif /* __STDIO_WIDE */
- /* If can't read or there's been an error, or c == EOF, or ungot slots
- * already filled, then return EOF */
+ /* If can't read or c == EOF or ungot slots already filled, then fail. */
if ((stream->modeflags
& (__MASK_UNGOT2|__FLAG_WRITEONLY
#ifndef __STDIO_AUTO_RW_TRANSITION
@@ -2946,14 +2981,18 @@ int ungetc(int c, register FILE *stream)
}
#ifdef __STDIO_BUFFERS
- /* TODO: shouldn't allow writing??? */
+#ifdef __STDIO_AUTO_RW_TRANSITION
if (stream->modeflags & __FLAG_WRITING) {
fflush_unlocked(stream); /* Commit any write-buffered chars. */
}
+#endif /* __STDIO_AUTO_RW_TRANSITION */
#endif /* __STDIO_BUFFERS */
/* Clear EOF and WRITING flags, and set READING FLAG */
stream->modeflags &= ~(__FLAG_EOF|__FLAG_WRITING);
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Is setting the reading flag after an ungetc necessary?
+#endif /* __UCLIBC_MJN3_ONLY__ */
stream->modeflags |= __FLAG_READING;
stream->ungot[1] = 1; /* Flag as app ungetc call; scanf fixes up. */
stream->ungot[(stream->modeflags++) & __MASK_UNGOT] = c;
@@ -3047,22 +3086,35 @@ UNLOCKED(size_t,fwrite,
int fgetpos64(FILE * __restrict stream, register fpos64_t * __restrict pos)
{
-#ifdef __STDIO_MBSTATE
- int retval;
+ int retval = -1;
- __STDIO_THREADLOCK(stream);
+#ifdef __STDIO_WIDE
- retval = ((pos != NULL) && ((pos->__pos = ftello64(stream)) >= 0))
- ? (__COPY_MBSTATE(&(pos->__mbstate), &(stream->state)), 0)
- : (__set_errno(EINVAL), -1);
+ if (pos == NULL) {
+ __set_errno(EINVAL);
+ } else {
+ __STDIO_THREADLOCK(stream);
- __STDIO_THREADUNLOCK(stream);
+ if ((pos->__pos = ftello64(stream)) >= 0) {
+ __COPY_MBSTATE(&(pos->__mbstate), &(stream->state));
+ pos->mblen_pending = stream->ungot_width[0];
+ retval = 0;
+ }
+
+ __STDIO_THREADUNLOCK(stream);
+ }
+
+#else /* __STDIO_WIDE */
+
+ if (pos == NULL) {
+ __set_errno(EINVAL);
+ } else if ((pos->__pos = ftello64(stream)) >= 0) {
+ retval = 0;
+ }
+
+#endif /* __STDIO_WIDE */
return retval;
-#else
- return ((pos != NULL) && ((pos->__pos = ftello64(stream)) >= 0))
- ? 0 : (__set_errno(EINVAL), -1);
-#endif
}
#ifndef L_fgetpos64
@@ -3137,10 +3189,19 @@ int fseeko64(register FILE *stream, __off64_t offset, int whence)
stream->modeflags &=
~(__FLAG_READING|__FLAG_WRITING|__FLAG_EOF|__MASK_UNGOT);
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: How do we deal with fseek to an ftell position for incomplete or error wide? Right now, we clear all multibyte state info. If we do not clear, then fix rewind() to do so if fseek() succeeds.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#ifdef __STDIO_WIDE
+ /* TODO: don't clear state if don't move? */
+ stream->ungot_width[0] = 0;
+#endif /* __STDIO_WIDE */
#ifdef __STDIO_MBSTATE
/* TODO: don't clear state if don't move? */
__INIT_MBSTATE(&(stream->state));
#endif /* __STDIO_MBSTATE */
+
__stdio_validate_FILE(stream); /* debugging only */
retval = 0;
@@ -3178,7 +3239,7 @@ int fsetpos64(FILE *stream, register const fpos64_t *pos)
__set_errno(EINVAL);
return EOF;
}
-#ifdef __STDIO_MBSTATE
+#ifdef __STDIO_WIDE
{
int retval;
@@ -3186,15 +3247,19 @@ int fsetpos64(FILE *stream, register const fpos64_t *pos)
if ((retval = fseeko64(stream, pos->__pos, SEEK_SET)) == 0) {
__COPY_MBSTATE(&(stream->state), &(pos->__mbstate));
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning CONSIDER: Moving mblen_pending into some mbstate field might be useful. But we would need to modify all the mb<->wc funcs.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+ stream->ungot_width[0] = pos->mblen_pending;
}
__STDIO_THREADUNLOCK(stream);
return retval;
}
-#else /* __STDIO_MBSTATE */
+#else /* __STDIO_WIDE */
return fseeko64(stream, pos->__pos, SEEK_SET);
-#endif /* __STDIO_MBSTATE */
+#endif /* __STDIO_WIDE */
}
#ifndef L_fsetpos64
@@ -3257,10 +3322,6 @@ void rewind(register FILE *stream)
__CLEARERR(stream); /* Clear errors first and then seek */
fseek(stream, 0L, SEEK_SET); /* in case there is an error seeking. */
-#ifdef __STDIO_MBSTATE
- /* TODO: Is it correct to re-init the stream's state? I think so... */
- __INIT_MBSTATE(&(stream->state));
-#endif /* __STDIO_MBSTATE */
__STDIO_THREADUNLOCK(stream);
}
@@ -3371,15 +3432,8 @@ void _stdio_fdout(int fd, ...)
#define INTERNAL_DIV_MOD
#endif
-#ifdef __UCLIBC_MJN3_ONLY__
-#warning REMINDER: move _uintmaxtostr to locale.c???
-#endif
#include <locale.h>
-#ifndef __LOCALE_C_ONLY
-#define CUR_LOCALE (__global_locale)
-#endif /* __LOCALE_C_ONLY */
-
char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
int base, __UIM_CASE alphacase)
{
@@ -3410,14 +3464,10 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
grouping = -1;
outdigit = 0x80 & alphacase;
alphacase ^= outdigit;
-#ifdef __UCLIBC_MJN3_ONLY_
-#warning implement outdigit... need digit lengths! (put it in locale struct)
-#endif
if (alphacase == __UIM_GROUP) {
assert(base == 10);
- if (*(g = CUR_LOCALE.grouping)
- && ((gslen = strlen(CUR_LOCALE.thousands_sep)) > 0)
- ) {
+ if (*(g = __UCLIBC_CURLOCALE_DATA.grouping)) {
+ gslen = strlen(__UCLIBC_CURLOCALE_DATA.thousands_sep);
grouping = *g;
}
}
@@ -3430,15 +3480,15 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
#ifndef __LOCALE_C_ONLY
if (!grouping) { /* Finished a group. */
#ifdef __UCLIBC_MJN3_ONLY__
-#warning REMINDER: decide about memcpy in _uintmaxtostr
-#endif
+#warning TODO: Decide about memcpy in _uintmaxtostr.
+#endif /* __UCLIBC_MJN3_ONLY__ */
#if 0
bufend -= gslen;
- memcpy(bufend, CUR_LOCALE.thousands_sep, gslen);
+ memcpy(bufend, __UCLIBC_CURLOCALE_DATA.thousands_sep, gslen);
#else
grouping = gslen;
do {
- *--bufend = CUR_LOCALE.thousands_sep[--grouping];
+ *--bufend = __UCLIBC_CURLOCALE_DATA.thousands_sep[--grouping];
} while (grouping);
#endif
if (g[1] != 0) { /* g[1] == 0 means repeat last grouping. */
@@ -3456,9 +3506,9 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
#ifndef __LOCALE_C_ONLY
if (outdigit) {
- outdigit = CUR_LOCALE.outdigit_length[digit];
+ outdigit = __UCLIBC_CURLOCALE_DATA.outdigit_length[digit];
do {
- *--bufend = (&CUR_LOCALE.outdigit0_mb)[digit][--outdigit];
+ *--bufend = (&__UCLIBC_CURLOCALE_DATA.outdigit0_mb)[digit][--outdigit];
} while (outdigit);
outdigit = 1;
} else
@@ -3483,15 +3533,15 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
#ifndef __LOCALE_C_ONLY
if (!grouping) { /* Finished a group. */
#ifdef __UCLIBC_MJN3_ONLY__
-#warning REMINDER: decide about memcpy in _uintmaxtostr
-#endif
+#warning TODO: Decide about memcpy in _uintmaxtostr
+#endif /* __UCLIBC_MJN3_ONLY__ */
#if 0
bufend -= gslen;
- memcpy(bufend, CUR_LOCALE.thousands_sep, gslen);
+ memcpy(bufend, __UCLIBC_CURLOCALE_DATA.thousands_sep, gslen);
#else
grouping = gslen;
do {
- *--bufend = CUR_LOCALE.thousands_sep[--grouping];
+ *--bufend = __UCLIBC_CURLOCALE_DATA.thousands_sep[--grouping];
} while (grouping);
#endif
if (g[1] != 0) { /* g[1] == 0 means repeat last grouping. */
@@ -3513,9 +3563,9 @@ char *_uintmaxtostr(register char * __restrict bufend, uintmax_t uval,
#ifndef __LOCALE_C_ONLY
if (outdigit) {
- outdigit = CUR_LOCALE.outdigit_length[digit];
+ outdigit = __UCLIBC_CURLOCALE_DATA.outdigit_length[digit];
do {
- *--bufend = (&CUR_LOCALE.outdigit0_mb)[digit][--outdigit];
+ *--bufend = (&__UCLIBC_CURLOCALE_DATA.outdigit0_mb)[digit][--outdigit];
} while (outdigit);
outdigit = 1;
} else
@@ -3548,7 +3598,7 @@ size_t _wstdio_fwrite(const wchar_t *__restrict ws, size_t n,
char buf[64];
const wchar_t *pw;
-#ifdef __STDIO_BUFFERS
+#if defined(__STDIO_WIDE) && defined(__STDIO_BUFFERS)
if (stream->filedes == -3) { /* Special case to support {v}swprintf. */
count = ((wchar_t *)(stream->bufend)) - ((wchar_t *)(stream->bufpos));
if (count > n) {
@@ -3560,7 +3610,7 @@ size_t _wstdio_fwrite(const wchar_t *__restrict ws, size_t n,
}
return n;
}
-#endif
+#endif /* defined(__STDIO_WIDE) && defined(__STDIO_BUFFERS) */
if (stream->modeflags & __FLAG_NARROW) {
stream->modeflags |= __FLAG_ERROR;
diff --git a/libc/stdlib/Makefile b/libc/stdlib/Makefile
index 59a5a6e0c..01765c1f6 100644
--- a/libc/stdlib/Makefile
+++ b/libc/stdlib/Makefile
@@ -38,31 +38,57 @@ MOBJ = abs.o labs.o atoi.o atol.o strtol.o strtoul.o _stdlib_strto_l.o \
qsort.o bsearch.o \
llabs.o atoll.o strtoll.o strtoull.o _stdlib_strto_ll.o
# (aliases) strtoq.o strtouq.o
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+
+MOBJx =
+MOBJx += strtol_l.o strtoul_l.o _stdlib_strto_l_l.o \
+ strtoll_l.o strtoull_l.o _stdlib_strto_ll_l.o
+endif
+
+MSRC1 = strtod.c
+MOBJ1 =
+MOBJ1x =
+
ifeq ($(UCLIBC_HAS_FLOATS),y)
MOBJ += atof.o
+ MOBJ1 += strtod.o strtof.o strtold.o __strtofpmax.o __fp_range_check.o
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+ MOBJ1x += strtod_l.o strtof_l.o strtold_l.o __strtofpmax_l.o
+endif
+ifeq ($(UCLIBC_HAS_WCHAR),y)
+ MOBJ1 += wcstod.o wcstof.o wcstold.o __wcstofpmax.o
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+ MOBJ1x += wcstod_l.o wcstof_l.o wcstold_l.o __wcstofpmax_l.o
+endif
+endif
endif
ifeq ($(UCLIBC_HAS_WCHAR),y)
MOBJ += mblen.o mbtowc.o wctomb.o mbstowcs.o wcstombs.o \
_stdlib_mb_cur_max.o _stdlib_wcsto_l.o _stdlib_wcsto_ll.o \
wcstol.o wcstoul.o wcstoll.o wcstoull.o
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+ MOBJx += _stdlib_wcsto_l_l.o _stdlib_wcsto_ll_l.o \
+ wcstol_l.o wcstoul_l.o wcstoll_l.o wcstoull_l.o
+endif
+endif
# (aliases) wcstoq.o wcstouq.o
# wcstod wcstof wcstold
-endif
-MSRC2=atexit.c
-MOBJ2=atexit.o on_exit.o __exit_handler.o exit.o
+MSRC2 = atexit.c
+MOBJ2 = atexit.o on_exit.o __exit_handler.o exit.o
+
CSRC = abort.c getenv.c mkdtemp.c mktemp.c realpath.c mkstemp.c mkstemp64.c \
rand.c random.c random_r.c setenv.c system.c div.c ldiv.c getpt.c \
ptsname.c grantpt.c unlockpt.c gcvt.c drand48-iter.c jrand48.c \
jrand48_r.c lrand48.c lrand48_r.c mrand48.c mrand48_r.c nrand48.c \
nrand48_r.c rand_r.c srand48.c srand48_r.c calloc.c valloc.c
ifeq ($(UCLIBC_HAS_FLOATS),y)
- CSRC += strtod.c strtof.c strtold.c drand48.c drand48_r.c erand48.c erand48_r.c
+ CSRC += drand48.c drand48_r.c erand48.c erand48_r.c
endif
COBJS=$(patsubst %.c,%.o, $(CSRC))
-OBJS=$(MOBJ) $(MOBJ2) $(COBJS)
+OBJS=$(MOBJ) $(MOBJx) $(MOBJ1) $(MOBJ1x) $(MOBJ2) $(COBJS)
all: $(OBJS) $(LIBC)
@@ -75,6 +101,18 @@ $(MOBJ): $(MSRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
+$(MOBJx): $(MSRC)
+ $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+$(MOBJ1): $(MSRC1)
+ $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+$(MOBJ1x): $(MSRC1)
+ $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
$(MOBJ2): $(MSRC2)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
diff --git a/libc/stdlib/stdlib.c b/libc/stdlib/stdlib.c
index 122289c2c..68b1af8b7 100644
--- a/libc/stdlib/stdlib.c
+++ b/libc/stdlib/stdlib.c
@@ -56,15 +56,24 @@
#define strtoull __ignore_strtoull
#define wcstoll __ignore_wcstoll
#define wcstoull __ignore_wcstoull
+#define strtoll_l __ignore_strtoll_l
+#define strtoull_l __ignore_strtoull_l
+#define wcstoll_l __ignore_wcstoll_l
+#define wcstoull_l __ignore_wcstoull_l
#endif
#include <stdlib.h>
+#include <locale.h>
#ifdef __UCLIBC_HAS_WCHAR__
-#include <locale.h>
#include <wchar.h>
#include <wctype.h>
+#include <bits/uClibc_uwchar.h>
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+#include <xlocale.h>
+#endif /* __UCLIBC_HAS_XLOCALE__ */
/* TODO: clean up the following... */
@@ -75,15 +84,23 @@
#endif
#ifdef __UCLIBC_HAS_LOCALE__
-#define ENCODING (__global_locale.encoding)
+
+#define ENCODING ((__UCLIBC_CURLOCALE_DATA).encoding)
#ifndef __CTYPE_HAS_UTF_8_LOCALES
+#ifdef L_mblen
+/* emit only once */
#warning __CTYPE_HAS_UTF_8_LOCALES not set!
#endif
-#else
+#endif
+
+#else /* __UCLIBC_HAS_LOCALE__ */
+
#ifdef __UCLIBC_MJN3_ONLY__
+#ifdef L_mblen
+/* emit only once */
#warning devel checks
#endif
-#define ENCODING (__ctype_encoding_7_bit)
+#endif
#ifdef __CTYPE_HAS_8_BIT_LOCALES
#error __CTYPE_HAS_8_BIT_LOCALES is defined!
#endif
@@ -92,7 +109,7 @@
#endif
#endif
-#endif
+#endif /* __UCLIBC_HAS_LOCALE__ */
#if UINT_MAX == ULONG_MAX
#undef atoi
@@ -105,9 +122,44 @@
#undef strtoull
#undef wcstoll
#undef wcstoull
+#undef strtoll_l
+#undef strtoull_l
+#undef wcstoll_l
+#undef wcstoull_l
#endif /* __UCLIBC_HAS_WCHAR__ */
/**********************************************************************/
+#ifdef __UCLIBC_HAS_XLOCALE__
+
+extern unsigned long
+_stdlib_strto_l_l(register const char * __restrict str,
+ char ** __restrict endptr, int base, int sflag,
+ __locale_t locale_arg);
+
+#if defined(ULLONG_MAX)
+extern unsigned long long
+_stdlib_strto_ll_l(register const char * __restrict str,
+ char ** __restrict endptr, int base, int sflag,
+ __locale_t locale_arg);
+#endif
+
+#ifdef __UCLIBC_HAS_WCHAR__
+extern unsigned long
+_stdlib_wcsto_l_l(register const wchar_t * __restrict str,
+ wchar_t ** __restrict endptr, int base, int sflag,
+ __locale_t locale_arg);
+
+#if defined(ULLONG_MAX)
+extern unsigned long long
+_stdlib_wcsto_ll_l(register const wchar_t * __restrict str,
+ wchar_t ** __restrict endptr, int base, int sflag,
+ __locale_t locale_arg);
+#endif
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+
extern unsigned long
_stdlib_strto_l(register const char * __restrict str,
@@ -130,7 +182,6 @@ _stdlib_wcsto_ll(register const wchar_t * __restrict str,
wchar_t ** __restrict endptr, int base, int sflag);
#endif
#endif /* __UCLIBC_HAS_WCHAR__ */
-
/**********************************************************************/
#ifdef L_atof
@@ -235,73 +286,82 @@ long long atoll(const char *nptr)
#endif
/**********************************************************************/
-#ifdef L_strtol
+#if defined(L_strtol) || defined(L_strtol_l)
-#if ULONG_MAX == UINTMAX_MAX
+#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtol_l)
strong_alias(strtol,strtoimax)
#endif
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
-strong_alias(strtol,strtoll)
+strong_alias(__XL(strtol),__XL(strtoll))
#endif
-long strtol(const char * __restrict str, char ** __restrict endptr, int base)
+long __XL(strtol)(const char * __restrict str, char ** __restrict endptr,
+ int base __LOCALE_PARAM )
{
- return _stdlib_strto_l(str, endptr, base, 1);
+ return __XL(_stdlib_strto_l)(str, endptr, base, 1 __LOCALE_ARG );
}
#endif
/**********************************************************************/
-#ifdef L_strtoll
+#if defined(L_strtoll) || defined(L_strtoll_l)
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
+#if !defined(L_strtoll_l)
#if (ULLONG_MAX == UINTMAX_MAX)
strong_alias(strtoll,strtoimax)
#endif
strong_alias(strtoll,strtoq)
+#endif
-long long strtoll(const char * __restrict str,
- char ** __restrict endptr, int base)
+long long __XL(strtoll)(const char * __restrict str,
+ char ** __restrict endptr, int base
+ __LOCALE_PARAM )
{
- return (long long) _stdlib_strto_ll(str, endptr, base, 1);
+ return (long long) __XL(_stdlib_strto_ll)(str, endptr, base, 1
+ __LOCALE_ARG );
}
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
#endif
/**********************************************************************/
-#ifdef L_strtoul
+#if defined(L_strtoul) || defined(L_strtoul_l)
-#if ULONG_MAX == UINTMAX_MAX
+#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_strtoul_l)
strong_alias(strtoul,strtoumax)
#endif
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
-strong_alias(strtoul,strtoull)
+strong_alias(__XL(strtoul),__XL(strtoull))
#endif
-unsigned long strtoul(const char * __restrict str,
- char ** __restrict endptr, int base)
+unsigned long __XL(strtoul)(const char * __restrict str,
+ char ** __restrict endptr, int base
+ __LOCALE_PARAM )
{
- return _stdlib_strto_l(str, endptr, base, 0);
+ return __XL(_stdlib_strto_l)(str, endptr, base, 0 __LOCALE_ARG );
}
#endif
/**********************************************************************/
-#ifdef L_strtoull
+#if defined(L_strtoull) || defined(L_strtoull_l)
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
+#if !defined(L_strtoull_l)
#if (ULLONG_MAX == UINTMAX_MAX)
strong_alias(strtoull,strtoumax)
#endif
strong_alias(strtoull,strtouq)
+#endif
-unsigned long long strtoull(const char * __restrict str,
- char ** __restrict endptr, int base)
+unsigned long long __XL(strtoull)(const char * __restrict str,
+ char ** __restrict endptr, int base
+ __LOCALE_PARAM )
{
- return _stdlib_strto_ll(str, endptr, base, 0);
+ return __XL(_stdlib_strto_ll)(str, endptr, base, 0 __LOCALE_ARG );
}
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
@@ -327,26 +387,54 @@ unsigned long long strtoull(const char * __restrict str,
#endif
/**********************************************************************/
-#ifdef L__stdlib_wcsto_l
+#if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l)
#define L__stdlib_strto_l
#endif
-#ifdef L__stdlib_strto_l
+#if defined(L__stdlib_strto_l) || defined(L__stdlib_strto_l_l)
+
+#if defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l)
-#ifdef L__stdlib_wcsto_l
#define _stdlib_strto_l _stdlib_wcsto_l
+#define _stdlib_strto_l_l _stdlib_wcsto_l_l
#define Wchar wchar_t
-#define ISSPACE iswspace
+#define Wuchar __uwchar_t
+#ifdef __UCLIBC_DO_XLOCALE
+#define ISSPACE(C) iswspace_l((C), locale_arg)
#else
+#define ISSPACE(C) iswspace((C))
+#endif
+
+#else /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */
+
#define Wchar char
-#define ISSPACE isspace
+#define Wuchar unsigned char
+#ifdef __UCLIBC_DO_XLOCALE
+#define ISSPACE(C) isspace_l((C), locale_arg)
+#else
+#define ISSPACE(C) isspace((C))
#endif
+#endif /* defined(L__stdlib_wcsto_l) || defined(L__stdlib_wcsto_l_l) */
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+unsigned long _stdlib_strto_l(register const Wchar * __restrict str,
+ Wchar ** __restrict endptr, int base,
+ int sflag)
+{
+ return _stdlib_strto_l_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE);
+}
+
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
/* This is the main work fuction which handles both strtol (sflag = 1) and
* strtoul (sflag = 0). */
-unsigned long _stdlib_strto_l(register const Wchar * __restrict str,
- Wchar ** __restrict endptr, int base, int sflag)
+unsigned long __XL(_stdlib_strto_l)(register const Wchar * __restrict str,
+ Wchar ** __restrict endptr, int base,
+ int sflag __LOCALE_PARAM )
{
unsigned long number, cutoff;
#if _STRTO_ENDPTR
@@ -361,7 +449,7 @@ unsigned long _stdlib_strto_l(register const Wchar * __restrict str,
SET_FAIL(str);
- while (ISSPACE(*str)) { /* Skip leading whitespace. */
+ while (ISSPACE(*str)) { /* Skip leading whitespace. */
++str;
}
@@ -394,7 +482,7 @@ unsigned long _stdlib_strto_l(register const Wchar * __restrict str,
cutoff_digit = ULONG_MAX % base;
cutoff = ULONG_MAX / base;
do {
- digit = (((unsigned char)(*str - '0')) <= 9)
+ digit = (((Wuchar)(*str - '0')) <= 9)
? (*str - '0')
: ((*str >= 'A')
? (((0x20|(*str)) - 'a' + 10)) /* WARNING: assumes ascii. */
@@ -436,32 +524,61 @@ unsigned long _stdlib_strto_l(register const Wchar * __restrict str,
return negative ? (unsigned long)(-((long)number)) : number;
}
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+
#endif
/**********************************************************************/
-#ifdef L__stdlib_wcsto_ll
+#if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l)
#define L__stdlib_strto_ll
#endif
-#ifdef L__stdlib_strto_ll
+#if defined(L__stdlib_strto_ll) || defined(L__stdlib_strto_ll_l)
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
-#ifdef L__stdlib_wcsto_ll
+#if defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l)
#define _stdlib_strto_ll _stdlib_wcsto_ll
+#define _stdlib_strto_ll_l _stdlib_wcsto_ll_l
#define Wchar wchar_t
-#define ISSPACE iswspace
+#define Wuchar __uwchar_t
+#ifdef __UCLIBC_DO_XLOCALE
+#define ISSPACE(C) iswspace_l((C), locale_arg)
#else
+#define ISSPACE(C) iswspace((C))
+#endif
+
+#else /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */
+
#define Wchar char
-#define ISSPACE isspace
+#define Wuchar unsigned char
+#ifdef __UCLIBC_DO_XLOCALE
+#define ISSPACE(C) isspace_l((C), locale_arg)
+#else
+#define ISSPACE(C) isspace((C))
#endif
-/* This is the main work fuction which handles both strtoll (sflag = 1) and
- * strtoull (sflag = 0). */
+#endif /* defined(L__stdlib_wcsto_ll) || defined(L__stdlib_wcsto_ll_l) */
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
unsigned long long _stdlib_strto_ll(register const Wchar * __restrict str,
Wchar ** __restrict endptr, int base,
int sflag)
{
+ return _stdlib_strto_ll_l(str, endptr, base, sflag, __UCLIBC_CURLOCALE);
+}
+
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+/* This is the main work fuction which handles both strtoll (sflag = 1) and
+ * strtoull (sflag = 0). */
+
+unsigned long long __XL(_stdlib_strto_ll)(register const Wchar * __restrict str,
+ Wchar ** __restrict endptr, int base,
+ int sflag __LOCALE_PARAM )
+{
unsigned long long number;
#if _STRTO_ENDPTR
const Wchar *fail_char;
@@ -507,7 +624,7 @@ unsigned long long _stdlib_strto_ll(register const Wchar * __restrict str,
if (((unsigned)(base - 2)) < 35) { /* Legal base. */
do {
- digit = (((unsigned char)(*str - '0')) <= 9)
+ digit = (((Wuchar)(*str - '0')) <= 9)
? (*str - '0')
: ((*str >= 'A')
? (((0x20|(*str)) - 'a' + 10)) /* WARNING: assumes ascii. */
@@ -560,6 +677,8 @@ unsigned long long _stdlib_strto_ll(register const Wchar * __restrict str,
return negative ? (unsigned long long)(-((long long)number)) : number;
}
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
#endif
@@ -715,7 +834,7 @@ void ssort (void *base,
size_t _stdlib_mb_cur_max(void)
{
#ifdef __CTYPE_HAS_UTF_8_LOCALES
- return __global_locale.mb_cur_max;
+ return __UCLIBC_CURLOCALE_DATA.mb_cur_max;
#else
#ifdef __CTYPE_HAS_8_BIT_LOCALES
#ifdef __UCLIBC_MJN3_ONLY__
@@ -824,73 +943,82 @@ size_t wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
#endif
/**********************************************************************/
-#ifdef L_wcstol
+#if defined(L_wcstol) || defined(L_wcstol_l)
-#if ULONG_MAX == UINTMAX_MAX
+#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstol_l)
strong_alias(wcstol,wcstoimax)
#endif
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
-strong_alias(wcstol,wcstoll)
+strong_alias(__XL(wcstol),__XL(wcstoll))
#endif
-long wcstol(const wchar_t * __restrict str, wchar_t ** __restrict endptr, int base)
+long __XL(wcstol)(const wchar_t * __restrict str,
+ wchar_t ** __restrict endptr, int base __LOCALE_PARAM )
{
- return _stdlib_wcsto_l(str, endptr, base, 1);
+ return __XL(_stdlib_wcsto_l)(str, endptr, base, 1 __LOCALE_ARG );
}
#endif
/**********************************************************************/
-#ifdef L_wcstoll
+#if defined(L_wcstoll) || defined(L_wcstoll_l)
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
+#if !defined(L_wcstoll_l)
#if (ULLONG_MAX == UINTMAX_MAX)
strong_alias(wcstoll,wcstoimax)
#endif
strong_alias(wcstoll,wcstoq)
+#endif
-long long wcstoll(const wchar_t * __restrict str,
- wchar_t ** __restrict endptr, int base)
+long long __XL(wcstoll)(const wchar_t * __restrict str,
+ wchar_t ** __restrict endptr, int base
+ __LOCALE_PARAM )
{
- return (long long) _stdlib_wcsto_ll(str, endptr, base, 1);
+ return (long long) __XL(_stdlib_wcsto_ll)(str, endptr, base, 1
+ __LOCALE_ARG );
}
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
#endif
/**********************************************************************/
-#ifdef L_wcstoul
+#if defined(L_wcstoul) || defined(L_wcstoul_l)
-#if ULONG_MAX == UINTMAX_MAX
+#if (ULONG_MAX == UINTMAX_MAX) && !defined(L_wcstoul_l)
strong_alias(wcstoul,wcstoumax)
#endif
#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
-strong_alias(wcstoul,wcstoull)
+strong_alias(__XL(wcstoul),__XL(wcstoull))
#endif
-unsigned long wcstoul(const wchar_t * __restrict str,
- wchar_t ** __restrict endptr, int base)
+unsigned long __XL(wcstoul)(const wchar_t * __restrict str,
+ wchar_t ** __restrict endptr, int base
+ __LOCALE_PARAM )
{
- return _stdlib_wcsto_l(str, endptr, base, 0);
+ return __XL(_stdlib_wcsto_l)(str, endptr, base, 0 __LOCALE_ARG );
}
#endif
/**********************************************************************/
-#ifdef L_wcstoull
+#if defined(L_wcstoull) || defined(L_wcstoull_l)
#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)
+#if !defined(L_wcstoull_l)
#if (ULLONG_MAX == UINTMAX_MAX)
strong_alias(wcstoull,wcstoumax)
#endif
strong_alias(wcstoull,wcstouq)
+#endif
-unsigned long long wcstoull(const wchar_t * __restrict str,
- wchar_t ** __restrict endptr, int base)
+unsigned long long __XL(wcstoull)(const wchar_t * __restrict str,
+ wchar_t ** __restrict endptr, int base
+ __LOCALE_PARAM )
{
- return _stdlib_wcsto_ll(str, endptr, base, 0);
+ return __XL(_stdlib_wcsto_ll)(str, endptr, base, 0 __LOCALE_ARG );
}
#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */
diff --git a/libc/stdlib/strtod.c b/libc/stdlib/strtod.c
index 7359d5cf9..c4d95bab1 100644
--- a/libc/stdlib/strtod.c
+++ b/libc/stdlib/strtod.c
@@ -1,263 +1,618 @@
-/*
- * Copyright (C) 2000 Manuel Novoa III
+/* Copyright (C) 2000, 2003 Manuel Novoa III
*
- * Notes:
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
*
- * The primary objective of this implementation was minimal size while
- * providing robustness and resonable accuracy.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+/* Notes:
+ *
+ * The primary objective of this implementation was minimal size and
+ * portablility, while providing robustness and resonable accuracy.
*
* This implementation depends on IEEE floating point behavior and expects
* to be able to generate +/- infinity as a result.
*
* There are a number of compile-time options below.
+ */
+
+/* July 27, 2003
+ *
+ * General cleanup and some minor size optimizations.
+ * Change implementation to support __strtofpmax() rather than strtod().
+ * Now all the strto{floating pt}() funcs are implemented in terms of
+ * of the internal __strtofpmax() function.
+ * Support "nan", "inf", and "infinity" strings (case-insensitive).
+ * Support hexadecimal floating point notation.
+ * Support wchar variants.
+ * Support xlocale variants.
+ *
+ * TODO:
*
+ * Consider accumulating blocks of digits in longs to save floating pt mults.
+ * This would likely be much better on anything that only supported floats
+ * where DECIMAL_DIG == 9. Actually, if floats have FLT_MAX_10_EXP == 38,
+ * we could calculate almost all the exponent multipliers (p_base) in
+ * long arithmetic as well.
*/
-/*****************************************************************************/
-/* OPTIONS */
-/*****************************************************************************/
+/**********************************************************************/
+/* OPTIONS */
+/**********************************************************************/
-/* Set if we want to scale with a O(log2(exp)) multiplications. */
-#define _STRTOD_LOG_SCALING 1
+/* Defined if we want to recognize "nan", "inf", and "infinity". (C99) */
+#define _STRTOD_NAN_INF_STRINGS 1
-/* Set if we want strtod to set errno appropriately. */
-/* NOTE: Implies all options below and pulls in _zero_or_inf_check. */
-#define _STRTOD_ERRNO 0
+/* Defined if we want support hexadecimal floating point notation. (C99) */
+/* Note! Now controlled by uClibc configuration. See below. */
+#define _STRTOD_HEXADECIMAL_FLOATS 1
-/* Set if we want support for the endptr arg. */
+/* Defined if we want to scale with a O(log2(exp)) multiplications.
+ * This is generally a good thing to do unless you are really tight
+ * on space and do not expect to convert values of large magnitude. */
+
+#define _STRTOD_LOG_SCALING 1
+
+/* WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!
+ *
+ * Clearing any of the options below this point is not advised (or tested).
+ *
+ * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! */
+
+/* Defined if we want strtod to set errno appropriately. */
+/* NOTE: Implies all options below. */
+#define _STRTOD_ERRNO 1
+
+/* Defined if we want support for the endptr arg. */
/* Implied by _STRTOD_ERRNO. */
-#define _STRTOD_ENDPTR 1
+#define _STRTOD_ENDPTR 1
-/* Set if we want to prevent overflow in accumulating the exponent. */
-#define _STRTOD_RESTRICT_EXP 1
+/* Defined if we want to prevent overflow in accumulating the exponent. */
+/* Implied by _STRTOD_ERRNO. */
+#define _STRTOD_RESTRICT_EXP 1
-/* Set if we want to process mantissa digits more intelligently. */
+/* Defined if we want to process mantissa digits more intelligently. */
/* Implied by _STRTOD_ERRNO. */
#define _STRTOD_RESTRICT_DIGITS 1
-/* Set if we want to skip scaling 0 for the exponent. */
+/* Defined if we want to skip scaling 0 for the exponent. */
/* Implied by _STRTOD_ERRNO. */
-#define _STRTOD_ZERO_CHECK 0
+#define _STRTOD_ZERO_CHECK 1
-/*****************************************************************************/
-/* Don't change anything that follows. */
-/*****************************************************************************/
+/**********************************************************************/
+/* Don't change anything that follows. */
+/**********************************************************************/
-#if _STRTOD_ERRNO
+#ifdef _STRTOD_ERRNO
#undef _STRTOD_ENDPTR
#undef _STRTOD_RESTRICT_EXP
#undef _STRTOD_RESTRICT_DIGITS
#undef _STRTOD_ZERO_CHECK
-#define _STRTOD_ENDPTR 1
-#define _STRTOD_RESTRICT_EXP 1
+#define _STRTOD_ENDPTR 1
+#define _STRTOD_RESTRICT_EXP 1
#define _STRTOD_RESTRICT_DIGITS 1
-#define _STRTOD_ZERO_CHECK 1
+#define _STRTOD_ZERO_CHECK 1
#endif
-/*****************************************************************************/
+/**********************************************************************/
+#define _ISOC99_SOURCE 1
+#define _GNU_SOURCE
#include <stdlib.h>
-
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
#include <float.h>
+#include <bits/uClibc_fpmax.h>
+
+#include <locale.h>
-#if _STRTOD_RESTRICT_DIGITS
-#define MAX_SIG_DIGITS 20
-#define EXP_DENORM_ADJUST MAX_SIG_DIGITS
-#define MAX_ALLOWED_EXP (MAX_SIG_DIGITS + EXP_DENORM_ADJUST - DBL_MIN_10_EXP)
+#ifdef __UCLIBC_HAS_WCHAR__
+
+#include <wchar.h>
+#include <wctype.h>
+#include <bits/uClibc_uwchar.h>
-#if DBL_DIG > MAX_SIG_DIGITS
-#error need to adjust MAX_SIG_DIGITS
#endif
-#include <limits.h>
+#ifdef __UCLIBC_HAS_XLOCALE__
+#include <xlocale.h>
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
+
+
+/* Handle _STRTOD_HEXADECIMAL_FLOATS via uClibc config now. */
+#undef _STRTOD_HEXADECIMAL_FLOATS
+#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__
+#define _STRTOD_HEXADECIMAL_FLOATS 1
+#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */
+
+/**********************************************************************/
+
+#undef _STRTOD_FPMAX
+
+#if FPMAX_TYPE == 3
+
+#define NEED_STRTOLD_WRAPPER
+#define NEED_STRTOD_WRAPPER
+#define NEED_STRTOF_WRAPPER
+
+#elif FPMAX_TYPE == 2
+
+#define NEED_STRTOD_WRAPPER
+#define NEED_STRTOF_WRAPPER
+
+#elif FPMAX_TYPE == 1
+
+#define NEED_STRTOF_WRAPPER
+
+#else
+
+#error unknown FPMAX_TYPE!
+
+#endif
+
+extern void __fp_range_check(__fpmax_t y, __fpmax_t x);
+
+/**********************************************************************/
+
+#ifdef _STRTOD_RESTRICT_DIGITS
+#define EXP_DENORM_ADJUST DECIMAL_DIG
+#define MAX_ALLOWED_EXP (DECIMAL_DIG + EXP_DENORM_ADJUST - FPMAX_MIN_10_EXP)
+
#if MAX_ALLOWED_EXP > INT_MAX
#error size assumption violated for MAX_ALLOWED_EXP
#endif
#else
/* We want some excess if we're not restricting mantissa digits. */
-#define MAX_ALLOWED_EXP ((20 - DBL_MIN_10_EXP) * 2)
+#define MAX_ALLOWED_EXP ((20 - FPMAX_MIN_10_EXP) * 2)
#endif
-#include <ctype.h>
-/* Note: For i386 the macro resulted in smaller code than the function call. */
-#if 1
-#undef isdigit
-#define isdigit(x) ( (x >= '0') && (x <= '9') )
+
+#if defined(_STRTOD_RESTRICT_DIGITS) || defined(_STRTOD_ENDPTR) || defined(_STRTOD_HEXADECIMAL_FLOATS)
+#undef _STRTOD_NEED_NUM_DIGITS
+#define _STRTOD_NEED_NUM_DIGITS 1
#endif
-#if _STRTOD_ERRNO
-#include <errno.h>
-extern int _zero_or_inf_check(double x);
+/**********************************************************************/
+#if defined(L___strtofpmax) || defined(L___strtofpmax_l) || defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
+
+#if defined(L___wcstofpmax) || defined(L___wcstofpmax_l)
+
+#define __strtofpmax __wcstofpmax
+#define __strtofpmax_l __wcstofpmax_l
+
+#define Wchar wchar_t
+#ifdef __UCLIBC_DO_XLOCALE
+#define ISSPACE(C) iswspace_l((C), locale_arg)
+#else
+#define ISSPACE(C) iswspace((C))
+#endif
+
+#else /* defined(L___wcstofpmax) || defined(L___wcstofpmax) */
+
+#define Wchar char
+#ifdef __UCLIBC_DO_XLOCALE
+#define ISSPACE(C) isspace_l((C), locale_arg)
+#else
+#define ISSPACE(C) isspace((C))
#endif
-double strtod(const char *str, char **endptr)
+#endif /* defined(L___wcstofpmax) || defined(L___wcstofpmax) */
+
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+__fpmax_t __strtofpmax(const Wchar *str, Wchar **endptr, int exponent_power)
{
- double number;
-#if _STRTOD_LOG_SCALING
- double p10;
+ return __strtofpmax_l(str, endptr, exponent_power, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+__fpmax_t __XL(__strtofpmax)(const Wchar *str, Wchar **endptr, int exponent_power
+ __LOCALE_PARAM )
+{
+ __fpmax_t number;
+ __fpmax_t p_base = 10; /* Adjusted to 16 in the hex case. */
+ Wchar *pos0;
+#ifdef _STRTOD_ENDPTR
+ Wchar *pos1;
#endif
- char *pos0;
-#if _STRTOD_ENDPTR
- char *pos1;
+ Wchar *pos = (Wchar *) str;
+ int exponent_temp;
+ int negative; /* A flag for the number, a multiplier for the exponent. */
+#ifdef _STRTOD_NEED_NUM_DIGITS
+ int num_digits;
+#endif
+#ifdef __UCLIBC_HAS_LOCALE__
+ const char *decpt = __LOCALE_PTR->decimal_point;
+#if defined(L___wcstofpmax) || defined(L___wcstofpmax)
+ wchar_t decpt_wc = __LOCALE_PTR->decimal_point;
+#else
+ int decpt_len = __LOCALE_PTR->decimal_point_len;
#endif
- char *pos = (char *) str;
- int exponent_power;
- int exponent_temp;
- int negative;
-#if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR
- int num_digits;
#endif
- while (isspace(*pos)) { /* skip leading whitespace */
- ++pos;
- }
+#ifdef _STRTOD_HEXADECIMAL_FLOATS
+ Wchar expchar = 'e';
+ Wchar *poshex = NULL;
+ __uint16_t is_mask = _ISdigit;
+#define EXPCHAR expchar
+#define IS_X_DIGIT(C) __isctype((C), is_mask)
+#else /* _STRTOD_HEXADECIMAL_FLOATS */
+#define EXPCHAR 'e'
+#define IS_X_DIGIT(C) isdigit((C))
+#endif /* _STRTOD_HEXADECIMAL_FLOATS */
+
+ while (ISSPACE(*pos)) { /* Skip leading whitespace. */
+ ++pos;
+ }
+
+ negative = 0;
+ switch(*pos) { /* Handle optional sign. */
+ case '-': negative = 1; /* Fall through to increment position. */
+ case '+': ++pos;
+ }
- negative = 0;
- switch(*pos) { /* handle optional sign */
- case '-': negative = 1; /* fall through to increment position */
- case '+': ++pos;
- }
+#ifdef _STRTOD_HEXADECIMAL_FLOATS
+ if ((*pos == '0') && (((pos[1])|0x20) == 'x')) {
+ poshex = ++pos; /* Save position of 'x' in case no digits */
+ ++pos; /* and advance past it. */
+ is_mask = _ISxdigit; /* Used by IS_X_DIGIT. */
+ expchar = 'p'; /* Adjust exponent char. */
+ p_base = 16; /* Adjust base multiplier. */
+ }
+#endif
- number = 0.;
-#if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR
- num_digits = -1;
+ number = 0.;
+#ifdef _STRTOD_NEED_NUM_DIGITS
+ num_digits = -1;
#endif
- exponent_power = 0;
- pos0 = NULL;
+/* exponent_power = 0; */
+ pos0 = NULL;
LOOP:
- while (isdigit(*pos)) { /* process string of digits */
-#if _STRTOD_RESTRICT_DIGITS
- if (num_digits < 0) { /* first time through? */
- ++num_digits; /* we've now seen a digit */
+ while (IS_X_DIGIT(*pos)) { /* Process string of (hex) digits. */
+#ifdef _STRTOD_RESTRICT_DIGITS
+ if (num_digits < 0) { /* First time through? */
+ ++num_digits; /* We've now seen a digit. */
+ }
+ if (num_digits || (*pos != '0')) { /* Had/have nonzero. */
+ ++num_digits;
+ if (num_digits <= DECIMAL_DIG) { /* Is digit significant? */
+#ifdef _STRTOD_HEXADECIMAL_FLOATS
+ number = number * p_base
+ + (isdigit(*pos)
+ ? (*pos - '0')
+ : (((*pos)|0x20) - ('a' - 10)));
+#else /* _STRTOD_HEXADECIMAL_FLOATS */
+ number = number * p_base + (*pos - '0');
+#endif /* _STRTOD_HEXADECIMAL_FLOATS */
+ }
+ }
+#else /* _STRTOD_RESTRICT_DIGITS */
+#ifdef _STRTOD_NEED_NUM_DIGITS
+ ++num_digits;
+#endif
+#ifdef _STRTOD_HEXADECIMAL_FLOATS
+ number = number * p_base
+ + (isdigit(*pos)
+ ? (*pos - '0')
+ : (((*pos)|0x20) - ('a' - 10)));
+#else /* _STRTOD_HEXADECIMAL_FLOATS */
+ number = number * p_base + (*pos - '0');
+#endif /* _STRTOD_HEXADECIMAL_FLOATS */
+#endif /* _STRTOD_RESTRICT_DIGITS */
+ ++pos;
}
- if (num_digits || (*pos != '0')) { /* had/have nonzero */
- ++num_digits;
- if (num_digits <= MAX_SIG_DIGITS) { /* is digit significant */
- number = number * 10. + (*pos - '0');
- }
+
+#ifdef __UCLIBC_HAS_LOCALE__
+#if defined(L___wcstofpmax) || defined(L___wcstofpmax)
+ if (!pos0 && (*pos == decpt_wc)) { /* First decimal point? */
+ pos0 = ++pos;
+ goto LOOP;
}
#else
-#if _STRTOD_ENDPTR
- ++num_digits;
+ if (!pos0 && !memcmp(pos, decpt, decpt_len)) { /* First decimal point? */
+ pos0 = (pos += decpt_len);
+ goto LOOP;
+ }
#endif
- number = number * 10. + (*pos - '0');
+#else /* __UCLIBC_HAS_LOCALE__ */
+ if ((*pos == '.') && !pos0) { /* First decimal point? */
+ pos0 = ++pos; /* Save position of decimal point */
+ goto LOOP; /* and process rest of digits. */
+ }
+#endif /* __UCLIBC_HAS_LOCALE__ */
+
+#ifdef _STRTOD_NEED_NUM_DIGITS
+ if (num_digits<0) { /* Must have at least one digit. */
+#ifdef _STRTOD_HEXADECIMAL_FLOATS
+ if (poshex) { /* Back up to '0' in '0x' prefix. */
+ pos = poshex;
+ goto DONE;
+ }
+#endif /* _STRTOD_HEXADECIMAL_FLOATS */
+
+#ifdef _STRTOD_NAN_INF_STRINGS
+ if (!pos0) { /* No decimal point, so check for inf/nan. */
+ /* Note: nan is the first string so 'number = i/0.;' works. */
+ static const char nan_inf_str[] = "\05nan\0\012infinity\0\05inf\0";
+ int i = 0;
+
+#ifdef __UCLIBC_HAS_LOCALE__
+ /* Avoid tolower problems for INFINITY in the tr_TR locale. (yuk)*/
+#undef _tolower
+#define _tolower(C) ((C)|0x20)
+#endif /* __UCLIBC_HAS_LOCALE__ */
+
+ do {
+ /* Unfortunately, we have no memcasecmp(). */
+ int j = 0;
+ while (_tolower(pos[j]) == nan_inf_str[i+1+j]) {
+ ++j;
+ if (!nan_inf_str[i+1+j]) {
+ number = i / 0.;
+ if (negative) { /* Correct for sign. */
+ number = -number;
+ }
+ pos += nan_inf_str[i] - 2;
+ goto DONE;
+ }
+ }
+ i += nan_inf_str[i];
+ } while (nan_inf_str[i]);
+ }
+
+#endif /* STRTOD_NAN_INF_STRINGS */
+#ifdef _STRTOD_ENDPTR
+ pos = (Wchar *) str;
#endif
- ++pos;
- }
-
- if ((*pos == '.') && !pos0) { /* is this the first decimal point? */
- pos0 = ++pos; /* save position of decimal point */
- goto LOOP; /* and process rest of digits */
- }
+ goto DONE;
+ }
+#endif /* _STRTOD_NEED_NUM_DIGITS */
-#if _STRTOD_ENDPTR
- if (num_digits<0) { /* must have at least one digit */
- pos = (char *) str;
- goto DONE;
- }
+#ifdef _STRTOD_RESTRICT_DIGITS
+ if (num_digits > DECIMAL_DIG) { /* Adjust exponent for skipped digits. */
+ exponent_power += num_digits - DECIMAL_DIG;
+ }
#endif
-#if _STRTOD_RESTRICT_DIGITS
- if (num_digits > MAX_SIG_DIGITS) { /* adjust exponent for skipped digits */
- exponent_power += num_digits - MAX_SIG_DIGITS;
- }
-#endif
+ if (pos0) {
+ exponent_power += pos0 - pos; /* Adjust exponent for decimal point. */
+ }
+
+#ifdef _STRTOD_HEXADECIMAL_FLOATS
+ if (poshex) {
+ exponent_power *= 4; /* Above is 2**4, but below is 2. */
+ p_base = 2;
+ }
+#endif /* _STRTOD_HEXADECIMAL_FLOATS */
- if (pos0) {
- exponent_power += pos0 - pos; /* adjust exponent for decimal point */
- }
+ if (negative) { /* Correct for sign. */
+ number = -number;
+ }
- if (negative) { /* correct for sign */
- number = -number;
- negative = 0; /* reset for exponent processing below */
- }
+ /* process an exponent string */
+ if (((*pos)|0x20) == EXPCHAR) {
+#ifdef _STRTOD_ENDPTR
+ pos1 = pos;
+#endif
+ negative = 1;
+ switch(*++pos) { /* Handle optional sign. */
+ case '-': negative = -1; /* Fall through to increment pos. */
+ case '+': ++pos;
+ }
+
+ pos0 = pos;
+ exponent_temp = 0;
+ while (isdigit(*pos)) { /* Process string of digits. */
+#ifdef _STRTOD_RESTRICT_EXP
+ if (exponent_temp < MAX_ALLOWED_EXP) { /* Avoid overflow. */
+ exponent_temp = exponent_temp * 10 + (*pos - '0');
+ }
+#else
+ exponent_temp = exponent_temp * 10 + (*pos - '0');
+#endif
+ ++pos;
+ }
- /* process an exponent string */
- if (*pos == 'e' || *pos == 'E') {
-#if _STRTOD_ENDPTR
- pos1 = pos;
+#ifdef _STRTOD_ENDPTR
+ if (pos == pos0) { /* No digits? */
+ pos = pos1; /* Back up to {e|E}/{p|P}. */
+ } /* else */
#endif
- switch(*++pos) { /* handle optional sign */
- case '-': negative = 1; /* fall through to increment pos */
- case '+': ++pos;
+
+ exponent_power += negative * exponent_temp;
}
- pos0 = pos;
- exponent_temp = 0;
- while (isdigit(*pos)) { /* process string of digits */
-#if _STRTOD_RESTRICT_EXP
- if (exponent_temp < MAX_ALLOWED_EXP) { /* overflow check */
- exponent_temp = exponent_temp * 10 + (*pos - '0');
- }
-#else
- exponent_temp = exponent_temp * 10 + (*pos - '0');
+#ifdef _STRTOD_ZERO_CHECK
+ if (number == 0.) {
+ goto DONE;
+ }
#endif
- ++pos;
+
+ /* scale the result */
+#ifdef _STRTOD_LOG_SCALING
+ exponent_temp = exponent_power;
+
+ if (exponent_temp < 0) {
+ exponent_temp = -exponent_temp;
}
-#if _STRTOD_ENDPTR
- if (pos == pos0) { /* were there no digits? */
- pos = pos1; /* back up to e|E */
- } /* else */
+ while (exponent_temp) {
+ if (exponent_temp & 1) {
+ if (exponent_power < 0) {
+ /* Warning... caluclating a factor for the exponent and
+ * then dividing could easily be faster. But doing so
+ * might cause problems when dealing with denormals. */
+ number /= p_base;
+ } else {
+ number *= p_base;
+ }
+ }
+ exponent_temp >>= 1;
+ p_base *= p_base;
+ }
+
+#else /* _STRTOD_LOG_SCALING */
+ while (exponent_power) {
+ if (exponent_power < 0) {
+ number /= p_base;
+ exponent_power++;
+ } else {
+ number *= p_base;
+ exponent_power--;
+ }
+ }
+#endif /* _STRTOD_LOG_SCALING */
+
+#ifdef _STRTOD_ERRNO
+ if (__FPMAX_ZERO_OR_INF_CHECK(number)) {
+ __set_errno(ERANGE);
+ }
#endif
- if (negative) {
- exponent_power -= exponent_temp;
- } else {
- exponent_power += exponent_temp;
+
+ DONE:
+#ifdef _STRTOD_ENDPTR
+ if (endptr) {
+ *endptr = pos;
}
- }
-
-#if _STRTOD_ZERO_CHECK
- if (number == 0.) {
- goto DONE;
- }
-#endif
-
- /* scale the result */
-#if _STRTOD_LOG_SCALING
- exponent_temp = exponent_power;
- p10 = 10.;
-
- if (exponent_temp < 0) {
- exponent_temp = -exponent_temp;
- }
-
- while (exponent_temp) {
- if (exponent_temp & 1) {
- if (exponent_power < 0) {
- number /= p10;
- } else {
- number *= p10;
- }
+#endif
+
+ return number;
+}
+
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+#endif
+/**********************************************************************/
+#ifdef L___fp_range_check
+#if defined(NEED_STRTOF_WRAPPER) || defined(NEED_STRTOD_WRAPPER)
+
+extern void __fp_range_check(__fpmax_t y, __fpmax_t x)
+{
+ if (__FPMAX_ZERO_OR_INF_CHECK(y) /* y is 0 or +/- infinity */
+ && (y != 0) /* y is not 0 (could have x>0, y==0 if underflow) */
+ && !__FPMAX_ZERO_OR_INF_CHECK(x) /* x is not 0 or +/- infinity */
+ ) {
+ __set_errno(ERANGE); /* Then x is not in y's range. */
}
- exponent_temp >>= 1;
- p10 *= p10;
- }
+}
+
+#endif
+#endif
+/**********************************************************************/
+#if defined(L_strtof) || defined(L_strtof_l) || defined(L_wcstof) || defined(L_wcstof_l)
+#if defined(NEED_STRTOF_WRAPPER)
+
+#if defined(L_wcstof) || defined(L_wcstof_l)
+#define strtof wcstof
+#define strtof_l wcstof_l
+#define __strtofpmax __wcstofpmax
+#define __strtofpmax_l __wcstofpmax_l
+#define Wchar wchar_t
#else
- while (exponent_power) {
- if (exponent_power < 0) {
- number /= 10.;
- exponent_power++;
- } else {
- number *= 10.;
- exponent_power--;
- }
- }
+#define Wchar char
#endif
-#if _STRTOD_ERRNO
- if (_zero_or_inf_check(number)) {
- __set_errno(ERANGE);
- }
+
+float __XL(strtof)(const Wchar *str, Wchar **endptr __LOCALE_PARAM )
+{
+#if FPMAX_TYPE == 1
+ return __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG );
+#else
+ __fpmax_t x;
+ float y;
+
+ x = __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG );
+ y = (float) x;
+
+ __fp_range_check(y, x);
+
+ return y;
#endif
+}
- DONE:
-#if _STRTOD_ENDPTR
- if (endptr) {
- *endptr = pos;
- }
#endif
+#endif
+/**********************************************************************/
+#if defined(L_strtod) || defined(L_strtod_l) || defined(L_wcstod) || defined(L_wcstod_l)
+#if defined(NEED_STRTOD_WRAPPER)
+
+#if defined(L_wcstod) || defined(L_wcstod_l)
+#define strtod wcstod
+#define strtod_l wcstod_l
+#define __strtofpmax __wcstofpmax
+#define __strtofpmax_l __wcstofpmax_l
+#define Wchar wchar_t
+#else
+#define Wchar char
+#endif
+
+double __XL(strtod)(const Wchar *str, Wchar **endptr __LOCALE_PARAM )
+{
+#if FPMAX_TYPE == 2
+ return __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG );
+#else
+ __fpmax_t x;
+ double y;
+
+ x = __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG );
+ y = (double) x;
+
+ __fp_range_check(y, x);
- return number;
+ return y;
+#endif
}
+
+#endif
+#endif
+/**********************************************************************/
+#if defined(L_strtold) || defined(L_strtold_l) || defined(L_wcstold) || defined(L_wcstold_l)
+#if defined(NEED_STRTOLD_WRAPPER)
+
+#if defined(L_wcstold) || defined(L_wcstold_l)
+#define strtold wcstold
+#define strtold_l wcstold_l
+#define __strtofpmax __wcstofpmax
+#define __strtofpmax_l __wcstofpmax_l
+#define Wchar wchar_t
+#else
+#define Wchar char
+#endif
+
+long double __XL(strtold)(const Wchar *str, Wchar **endptr __LOCALE_PARAM )
+{
+#if FPMAX_TYPE == 3
+ return __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG );
+#else
+ __fpmax_t x;
+ long double y;
+
+ x = __XL(__strtofpmax)(str, endptr, 0 __LOCALE_ARG );
+ y = (long double) x;
+
+ __fp_range_check(y, x);
+
+ return y;
+#endif
+}
+
+#endif
+#endif
+/**********************************************************************/
diff --git a/libc/string/Makefile b/libc/string/Makefile
index 5ec0924d8..1b12924d5 100644
--- a/libc/string/Makefile
+++ b/libc/string/Makefile
@@ -24,8 +24,8 @@
TOPDIR=../../
include $(TOPDIR)Rules.mak
-MSRCW= wstring.c
-MOBJW= basename.o bcopy.o bzero.o dirname.o ffs.o memccpy.o memchr.o memcmp.o \
+MSRC= wstring.c
+MOBJ= basename.o bcopy.o bzero.o dirname.o ffs.o memccpy.o memchr.o memcmp.o \
memcpy.o memmove.o mempcpy.o memrchr.o memset.o rawmemchr.o stpcpy.o \
stpncpy.o strcasecmp.o strcasestr.o strcat.o strchrnul.o strchr.o \
strcmp.o strcpy.o strcspn.o strdup.o strlen.o strncasecmp.o strncat.o \
@@ -35,17 +35,27 @@ MOBJW= basename.o bcopy.o bzero.o dirname.o ffs.o memccpy.o memchr.o memcmp.o \
_string_syssigmsgs.o sys_siglist.o strsignal.o psignal.o \
__xpg_basename.o strlcat.o strlcpy.o sys_errlist.o memmem.o
-MOBJW2= wcscasecmp.o wcscat.o wcschrnul.o wcschr.o wcscmp.o wcscpy.o wcscspn.o \
+MOBJW= wcscasecmp.o wcscat.o wcschrnul.o wcschr.o wcscmp.o wcscpy.o wcscspn.o \
wcsdup.o wcslen.o wcsncasecmp.o wcsncat.o wcsncmp.o wcsncpy.o \
wcsnlen.o wcspbrk.o wcsrchr.o wcsspn.o wcsstr.o wcstok.o wmemchr.o \
wmemcmp.o wmemcpy.o wmemmove.o wmempcpy.o wmemset.o wcpcpy.o wcpncpy.o \
__wcslcpy.o \
wcsxfrm.o strxfrm.o # wcscoll strcoll.o
-OBJS=$(MOBJ) $(MOBJ1) $(MOBJ2) $(MOBJW)
+MOBJx=
+MOBJWx=
+
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+ MOBJx += strcasecmp_l.o strncasecmp_l.o
+ MOBJWx += wcscasecmp_l.o wcsncasecmp_l.o wcsxfrm_l.o strxfrm_l.o
+endif
+
+#ffsl ffsll
+
+OBJS=$(MOBJ) $(MOBJx)
ifeq ($(UCLIBC_HAS_WCHAR),y)
- OBJS += $(MOBJW2)
+ OBJS += $(MOBJW) $(MOBJWx)
endif
all: $(OBJS) $(LIBC)
@@ -55,14 +65,22 @@ $(LIBC): ar-target
ar-target: $(OBJS)
$(AR) $(ARFLAGS) $(LIBC) $(OBJS)
-$(MOBJW): $(MSRCW)
+$(MOBJ): $(MSRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
-$(MOBJW2): $(MSRCW)
+$(MOBJx): $(MSRC)
+ $(CC) $(CFLAGS) -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+$(MOBJW): $(MSRC)
$(CC) $(CFLAGS) -DWANT_WIDE -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
+$(MOBJWx): $(MSRC)
+ $(CC) $(CFLAGS) -DWANT_WIDE -DL_$* -D__UCLIBC_DO_XLOCALE $< -c -o $*.o
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
$(COBJS): %.o : %.c
$(CC) $(CFLAGS) -c $< -o $@
$(STRIPTOOL) -x -R .note -R .comment $*.o
diff --git a/libc/string/wstring.c b/libc/string/wstring.c
index 343e82b6c..1343bf98b 100644
--- a/libc/string/wstring.c
+++ b/libc/string/wstring.c
@@ -49,6 +49,7 @@
#ifdef WANT_WIDE
#include <wchar.h>
#include <wctype.h>
+#include <bits/uClibc_uwchar.h>
#define Wvoid wchar_t
#define Wchar wchar_t
@@ -77,12 +78,22 @@ typedef unsigned char __string_uchar_t;
#define _SYS_NERR 126
#endif
+#ifdef __UCLIBC_HAS_ERRNO_MESSAGES__
#define _SYS_ERRMSG_MAXLEN 50
+#else /* __UCLIBC_HAS_ERRNO_MESSAGES__ */
+#define _SYS_ERRMSG_MAXLEN 0
+#endif /* __UCLIBC_HAS_ERRNO_MESSAGES__ */
+
extern const char _string_syserrmsgs[];
#define _SYS_NSIG 32
+
+#ifdef __UCLIBC_HAS_SIGNUM_MESSAGES__
#define _SYS_SIGMSG_MAXLEN 25
+#else /* __UCLIBC_HAS_SIGNUM_MESSAGES__ */
+#define _SYS_SIGMSG_MAXLEN 0
+#endif /* __UCLIBC_HAS_SIGNUM_MESSAGES__ */
extern const char _string_syssigmsgs[];
@@ -93,14 +104,14 @@ extern const char _string_syssigmsgs[];
#define _STRERROR_BUFSIZE _SYS_ERRMSG_MAXLEN
#endif
-#if _SYS_SIGMSG_MAXLEN < __UIM_BUFLEN_INT + 14
-#define _STRSIGNAL_BUFSIZE (__UIM_BUFLEN_INT + 14)
+#if _SYS_SIGMSG_MAXLEN < __UIM_BUFLEN_INT + 15
+#define _STRSIGNAL_BUFSIZE (__UIM_BUFLEN_INT + 15)
#else
#define _STRSIGNAL_BUFSIZE _SYS_SIGMSG_MAXLEN
#endif
/**********************************************************************/
-#ifdef L__string_syserrmsgs
+#if defined(L__string_syserrmsgs) && defined(__UCLIBC_HAS_ERRNO_MESSAGES__)
const char _string_syserrmsgs[] = {
/* 0: 0, 8 */ "Success\0"
@@ -238,7 +249,7 @@ const char _string_syserrmsgs[] = {
#endif
/**********************************************************************/
-#ifdef L_sys_errlist
+#if defined(L_sys_errlist) && defined(__UCLIBC_HAS_SYS_ERRLIST__)
link_warning(_sys_errlist, "sys_nerr and sys_errlist are obsolete and uClibc support for them (in at least some configurations) will probably be unavailable in the near future.")
@@ -1070,54 +1081,104 @@ int ffs(int i)
#endif
/**********************************************************************/
-#ifdef L_wcscasecmp
-#define L_strcasecmp
-#define Wstrcasecmp wcscasecmp
+#if defined(L_strcasecmp) || defined(L_strcasecmp_l) || defined(L_wcscasecmp) || defined(L_wcscasecmp_l)
+
+#if defined(L_wcscasecmp) || defined(L_wcscasecmp_l)
+
+#define strcasecmp wcscasecmp
+#define strcasecmp_l wcscasecmp_l
+#ifdef __UCLIBC_DO_XLOCALE
+#define TOLOWER(C) towlower_l((C), locale_arg)
+#else
+#define TOLOWER(C) towlower((C))
+#endif
+
+#else /* defined(L_wcscasecmp) || defined(L_wcscasecmp_l) */
+
+#ifdef __UCLIBC_DO_XLOCALE
+#define TOLOWER(C) tolower_l((C), locale_arg)
#else
-#define Wstrcasecmp strcasecmp
+#define TOLOWER(C) tolower((C))
#endif
-#ifdef L_strcasecmp
+#endif /* defined(L_wcscasecmp) || defined(L_wcscasecmp_l) */
+
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+int strcasecmp(register const Wchar *s1, register const Wchar *s2)
+{
+ return strcasecmp_l(s1, s2, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
-int Wstrcasecmp(register const Wchar *s1, register const Wchar *s2)
+int __XL(strcasecmp)(register const Wchar *s1, register const Wchar *s2
+ __LOCALE_PARAM )
{
#ifdef WANT_WIDE
- while ((*s1 == *s2) || (towlower(*s1) == towlower(*s2))) {
+ while ((*s1 == *s2) || (TOLOWER(*s1) == TOLOWER(*s2))) {
if (!*s1++) {
return 0;
}
++s2;
}
- return (((Wuchar)towlower(*s1)) < ((Wuchar)towlower(*s2))) ? -1 : 1;
+ return (((Wuchar)TOLOWER(*s1)) < ((Wuchar)TOLOWER(*s2))) ? -1 : 1;
/* TODO -- should wide cmp funcs do wchar or Wuchar compares? */
#else
int r = 0;
while ( ((s1 == s2) ||
- !(r = ((int)( tolower(*((Wuchar *)s1))))
- - tolower(*((Wuchar *)s2))))
+ !(r = ((int)( TOLOWER(*((Wuchar *)s1))))
+ - TOLOWER(*((Wuchar *)s2))))
&& (++s2, *s1++));
return r;
#endif
}
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
#endif
/**********************************************************************/
-#ifdef L_wcsncasecmp
-#define L_strncasecmp
-#define Wstrncasecmp wcsncasecmp
+#if defined(L_strncasecmp) || defined(L_strncasecmp_l) || defined(L_wcsncasecmp) || defined(L_wcsncasecmp_l)
+
+#if defined(L_wcsncasecmp) || defined(L_wcsncasecmp_l)
+
+#define strncasecmp wcsncasecmp
+#define strncasecmp_l wcsncasecmp_l
+#ifdef __UCLIBC_DO_XLOCALE
+#define TOLOWER(C) towlower_l((C), locale_arg)
+#else
+#define TOLOWER(C) towlower((C))
+#endif
+
+#else /* defined(L_wcsncasecmp) || defined(L_wcsncasecmp_l) */
+
+#ifdef __UCLIBC_DO_XLOCALE
+#define TOLOWER(C) tolower_l((C), locale_arg)
#else
-#define Wstrncasecmp strncasecmp
+#define TOLOWER(C) tolower((C))
#endif
-#ifdef L_strncasecmp
+#endif /* defined(L_wcsncasecmp) || defined(L_wcsncasecmp_l) */
+
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+int strncasecmp(register const Wchar *s1, register const Wchar *s2, size_t n)
+{
+ return strncasecmp_l(s1, s2, n, __UCLIBC_CURLOCALE);
+}
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
-int Wstrncasecmp(register const Wchar *s1, register const Wchar *s2, size_t n)
+int __XL(strncasecmp)(register const Wchar *s1, register const Wchar *s2,
+ size_t n __LOCALE_PARAM )
{
#ifdef WANT_WIDE
- while (n && ((*s1 == *s2) || (towlower(*s1) == towlower(*s2)))) {
+ while (n && ((*s1 == *s2) || (TOLOWER(*s1) == TOLOWER(*s2)))) {
if (!*s1++) {
return 0;
}
@@ -1127,19 +1188,22 @@ int Wstrncasecmp(register const Wchar *s1, register const Wchar *s2, size_t n)
return (n == 0)
? 0
- : ((((Wuchar)towlower(*s1)) < ((Wuchar)towlower(*s2))) ? -1 : 1);
+ : ((((Wuchar)TOLOWER(*s1)) < ((Wuchar)TOLOWER(*s2))) ? -1 : 1);
/* TODO -- should wide cmp funcs do wchar or Wuchar compares? */
#else
int r = 0;
while ( n
&& ((s1 == s2) ||
- !(r = ((int)( tolower(*((unsigned char *)s1))))
- - tolower(*((unsigned char *)s2))))
+ !(r = ((int)( TOLOWER(*((unsigned char *)s1))))
+ - TOLOWER(*((unsigned char *)s2))))
&& (--n, ++s2, *s1++));
return r;
#endif
}
+
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
#endif
/**********************************************************************/
#ifdef L_wcsnlen
@@ -1220,7 +1284,7 @@ Wchar *Wstrdup(register const Wchar *s1)
char *strerror(int errnum)
{
- static char buf[_SYS_ERRMSG_MAXLEN];
+ static char buf[_STRERROR_BUFSIZE];
_susv3_strerror_r(errnum, buf, sizeof(buf));
@@ -1233,6 +1297,7 @@ char *strerror(int errnum)
/**********************************************************************/
#ifdef L__susv3_strerror_r
+#ifdef __UCLIBC_HAS_ERRNO_MESSAGES__
#if defined(__alpha__) || defined(__mips__) || defined(__sparc__)
static const unsigned char estridx[] = {
@@ -1372,19 +1437,20 @@ static const unsigned char estridx[] = {
#endif
-
int _susv3_strerror_r(int errnum, char *strerrbuf, size_t buflen)
{
register char *s;
int i, retval;
- char buf[_SYS_ERRMSG_MAXLEN];
- static const char unknown[14] = {
+ char buf[_STRERROR_BUFSIZE];
+ static const char unknown[] = {
'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 'e', 'r', 'r', 'o', 'r', ' '
};
retval = EINVAL;
+#ifdef __UCLIBC_HAS_ERRNO_MESSAGES__
+
#if defined(__alpha__) || defined(__mips__) || defined(__sparc__)
/* Need to translate errno to string index. */
for (i = 0 ; i < sizeof(estridx)/sizeof(estridx[0]) ; i++) {
@@ -1420,6 +1486,8 @@ int _susv3_strerror_r(int errnum, char *strerrbuf, size_t buflen)
}
}
+#endif /* __UCLIBC_HAS_ERRNO_MESSAGES__ */
+
s = _int10tostr(buf+sizeof(buf)-1, errnum) - sizeof(unknown);
memcpy(s, unknown, sizeof(unknown));
@@ -1445,6 +1513,45 @@ int _susv3_strerror_r(int errnum, char *strerrbuf, size_t buflen)
return retval;
}
+#else /* __UCLIBC_HAS_ERRNO_MESSAGES__ */
+
+int _susv3_strerror_r(int errnum, char *strerrbuf, size_t buflen)
+{
+ register char *s;
+ int i, retval;
+ char buf[_STRERROR_BUFSIZE];
+ static const char unknown[] = {
+ 'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 'e', 'r', 'r', 'o', 'r', ' '
+ };
+
+ s = _int10tostr(buf+sizeof(buf)-1, errnum) - sizeof(unknown);
+ memcpy(s, unknown, sizeof(unknown));
+
+ if (!strerrbuf) { /* SUSv3 */
+ buflen = 0;
+ }
+
+ retval = EINVAL;
+
+ i = buf + sizeof(buf) - s;
+
+ if (i > buflen) {
+ i = buflen;
+ retval = ERANGE;
+ }
+
+ if (i) {
+ memcpy(strerrbuf, s, i);
+ strerrbuf[i-1] = 0; /* In case buf was too small. */
+ }
+
+ __set_errno(retval);
+
+ return retval;
+}
+
+#endif /* __UCLIBC_HAS_ERRNO_MESSAGES__ */
+
#endif
/**********************************************************************/
/* GNU extension functions. */
@@ -1993,7 +2100,7 @@ size_t Wstrlcpy(register Wchar *__restrict dst,
#endif
/**********************************************************************/
-#ifdef L__string_syssigmsgs
+#if defined(L__string_syssigmsgs) && defined(__UCLIBC_HAS_SIGNUM_MESSAGES__)
const char _string_syssigmsgs[] = {
/* 0: 0, 1 */ "\0"
@@ -2033,7 +2140,7 @@ const char _string_syssigmsgs[] = {
#endif
/**********************************************************************/
-#ifdef L_sys_siglist
+#if defined(L_sys_siglist) && defined(__UCLIBC_HAS_SYS_SIGLIST__)
const char *const sys_siglist[_NSIG] = {
NULL,
@@ -2108,12 +2215,14 @@ const char *const sys_siglist[_NSIG] = {
/* TODO: make a threadsafe version? */
+#ifdef __UCLIBC_HAS_SIGNUM_MESSAGES__
+
char *strsignal(int signum)
{
register char *s;
int i;
static char buf[_STRSIGNAL_BUFSIZE];
- static const char unknown[15] = {
+ static const char unknown[] = {
'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 's', 'i', 'g', 'n', 'a', 'l', ' '
};
@@ -2139,6 +2248,22 @@ char *strsignal(int signum)
return s;
}
+#else /* __UCLIBC_HAS_SIGNUM_MESSAGES__ */
+
+char *strsignal(int signum)
+{
+ static char buf[_STRSIGNAL_BUFSIZE];
+ static const char unknown[] = {
+ 'U', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 's', 'i', 'g', 'n', 'a', 'l', ' '
+ };
+
+ return (char *) memcpy(_int10tostr(buf+sizeof(buf)-1, signum)
+ - sizeof(unknown),
+ unknown, sizeof(unknown));
+}
+
+#endif /* __UCLIBC_HAS_SIGNUM_MESSAGES__ */
+
#endif
/**********************************************************************/
#ifdef L_psignal
@@ -2171,6 +2296,7 @@ void psignal(int signum, register const char *message)
#endif
/**********************************************************************/
#ifndef __LOCALE_C_ONLY
+#if defined(L_strxfrm) || defined(L_strxfrm_l) || defined(L_wcsxfrm) || defined(L_wcsxfrm_l)
#ifdef L_strxfrm
#ifndef WANT_WIDE
@@ -2179,11 +2305,16 @@ void psignal(int signum, register const char *message)
#ifdef L_wcsxfrm
#error L_wcsxfrm already defined for L_strxfrm
#endif
+#endif /* L_strxfrm */
-#define wcscoll strcoll
-#define L_wcsxfrm
-#undef WANT_WIDE
+#if defined(L_strxfrm) || defined(L_strxfrm_l)
+#define wcscoll strcoll
+#define wcscoll_l strcoll_l
+#define wcsxfrm strxfrm
+#define wcsxfrm_l strxfrm_l
+
+#undef WANT_WIDE
#undef Wvoid
#undef Wchar
#undef Wuchar
@@ -2191,13 +2322,28 @@ void psignal(int signum, register const char *message)
#define Wchar char
-#endif /* L_strxfrm */
+#endif /* defined(L_strxfrm) || defined(L_strxfrm_l) */
+
+#if defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE)
+
+int wcscoll (const Wchar *s0, const Wchar *s1)
+{
+ return wcscoll_l(s0, s1, __UCLIBC_CURLOCALE );
+}
+size_t wcsxfrm(Wchar *__restrict ws1, const Wchar *__restrict ws2, size_t n)
+{
+ return wcsxfrm_l(ws1, ws2, n, __UCLIBC_CURLOCALE );
+}
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
-#ifdef L_wcsxfrm
-#define CUR_COLLATE (&__global_locale.collate)
+#if 0
+#define CUR_COLLATE (&__UCLIBC_CURLOCALE_DATA.collate)
+#else
+#define CUR_COLLATE (& __LOCALE_PTR->collate)
+#endif
#define MAX_PENDING 8
@@ -2246,7 +2392,7 @@ typedef struct {
#define TRACE(X) ((void)0)
#endif
-static int lookup(wchar_t wc)
+static int lookup(wchar_t wc __LOCALE_PARAM )
{
unsigned int sc, n, i0, i1;
@@ -2276,7 +2422,7 @@ static void init_col_state(col_state_t *cs, const Wchar *wcs)
cs->bbe = cs->back_buf + (cs->bb_size -1);
}
-static void next_weight(col_state_t *cs, int pass)
+static void next_weight(col_state_t *cs, int pass __LOCALE_PARAM )
{
int r, w, ru, ri, popping_backup_stack;
ssize_t n;
@@ -2285,12 +2431,10 @@ static void next_weight(col_state_t *cs, int pass)
#define WC (*cs->s)
#define N (1)
#else /* WANT_WIDE */
- mbstate_t mbstate;
wchar_t WC;
size_t n0, nx;
#define N n0
- mbstate.mask = 0;
#endif /* WANT_WIDE */
do {
@@ -2343,15 +2487,15 @@ static void next_weight(col_state_t *cs, int pass)
BACK_LOOP:
#ifdef WANT_WIDE
n = 1;
- cs->colitem = r = lookup(*cs->s);
+ cs->colitem = r = lookup(*cs->s __LOCALE_ARG );
#else /* WANT_WIDE */
- n = n0 = mbrtowc(&WC, cs->s, SIZE_MAX, &mbstate);
+ n = n0 = __locale_mbrtowc_l(&WC, cs->s, __LOCALE_PTR);
if (n < 0) {
__set_errno(EILSEQ);
cs->weight = 0;
return;
}
- cs->colitem = r = lookup(WC);
+ cs->colitem = r = lookup(WC __LOCALE_ARG );
#endif /* WANT_WIDE */
TRACE((" r=%d WC=%#lx\n", r, (unsigned long)(WC)));
@@ -2370,7 +2514,7 @@ static void next_weight(col_state_t *cs, int pass)
}
#ifdef WANT_WIDE
/* the lookup check here is safe since we're assured that *p is a valid colidx */
- if (!cs->s[n] || (lookup(cs->s[n]) != *p)) {
+ if (!cs->s[n] || (lookup(cs->s[n] __LOCALE_ARG ) != *p)) {
do {} while (*p++);
break;
}
@@ -2378,19 +2522,19 @@ static void next_weight(col_state_t *cs, int pass)
++n;
#else /* WANT_WIDE */
if (cs->s[n]) {
- nx = mbrtowc(&WC, cs->s + n, SIZE_MAX, &mbstate);
+ nx = __locale_mbrtowc_l(&WC, cs->s + n, __LOCALE_PTR);
if (nx < 0) {
__set_errno(EILSEQ);
cs->weight = 0;
return;
}
}
- if (!cs->s[n] || (lookup(WC) != *p)) {
+ if (!cs->s[n] || (lookup(WC __LOCALE_ARG ) != *p)) {
do {} while (*p++);
break;
}
++p;
- n += nx;
+ n += nx; /* Only gets here if cs->s[n] != 0, so nx is set. */
#endif /* WANT_WIDE */
} while (1);
} while (1);
@@ -2628,7 +2772,7 @@ static void next_weight(col_state_t *cs, int pass)
} while (1);
}
-int wcscoll (const Wchar *s0, const Wchar *s1)
+int __XL(wcscoll) (const Wchar *s0, const Wchar *s1 __LOCALE_PARAM )
{
col_state_t ws[2];
int pass;
@@ -2647,8 +2791,8 @@ int wcscoll (const Wchar *s0, const Wchar *s1)
init_col_state(ws+1, s1);
do { /* loop through the strings */
/* for each string, get the next weight */
- next_weight(ws, pass);
- next_weight(ws+1, pass);
+ next_weight(ws, pass __LOCALE_ARG );
+ next_weight(ws+1, pass __LOCALE_ARG );
TRACE(("w0=%lu w1=%lu\n",
(unsigned long) ws[0].weight,
(unsigned long) ws[1].weight));
@@ -2664,7 +2808,8 @@ int wcscoll (const Wchar *s0, const Wchar *s1)
#ifdef WANT_WIDE
-size_t wcsxfrm(wchar_t *__restrict ws1, const wchar_t *__restrict ws2, size_t n)
+size_t __XL(wcsxfrm)(wchar_t *__restrict ws1, const wchar_t *__restrict ws2,
+ size_t n __LOCALE_PARAM )
{
col_state_t cs;
size_t count;
@@ -2682,7 +2827,7 @@ size_t wcsxfrm(wchar_t *__restrict ws1, const wchar_t *__restrict ws2, size_t n)
do { /* loop through the weights levels */
init_col_state(&cs, ws2);
do { /* loop through the string */
- next_weight(&cs, pass);
+ next_weight(&cs, pass __LOCALE_ARG );
TRACE(("weight=%lu (%#lx)\n", (unsigned long) cs.weight, (unsigned long) cs.weight));
if (count < n) {
ws1[count] = cs.weight +1;
@@ -2743,7 +2888,8 @@ static size_t store(unsigned char *s, size_t count, size_t n, __uwchar_t weight)
return r;
}
-size_t strxfrm(char *__restrict ws1, const char *__restrict ws2, size_t n)
+size_t __XL(strxfrm)(char *__restrict ws1, const char *__restrict ws2, size_t n
+ __LOCALE_PARAM )
{
col_state_t cs;
size_t count, inc;
@@ -2761,7 +2907,7 @@ size_t strxfrm(char *__restrict ws1, const char *__restrict ws2, size_t n)
do { /* loop through the weights levels */
init_col_state(&cs, ws2);
do { /* loop through the string */
- next_weight(&cs, pass);
+ next_weight(&cs, pass __LOCALE_ARG );
TRACE(("weight=%lu (%#lx)\n", (unsigned long) cs.weight, (unsigned long) cs.weight));
inc = store((unsigned char *)ws1, count, n, cs.weight + 1);
count += inc;
@@ -2780,11 +2926,11 @@ size_t strxfrm(char *__restrict ws1, const char *__restrict ws2, size_t n)
return count-1;
}
-
#endif /* WANT_WIDE */
-#endif /* wcscoll */
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && !defined(__UCLIBC_DO_XLOCALE) */
+
+#endif /* defined(L_strxfrm) || defined(L_strxfrm_l) || defined(L_wcsxfrm) || defined(L_wcsxfrm_l) */
#endif /* __LOCALE_C_ONLY */
/**********************************************************************/
-
diff --git a/libc/sysdeps/linux/common/bits/uClibc_ctype.h b/libc/sysdeps/linux/common/bits/uClibc_ctype.h
index 7ff62e376..294997b74 100644
--- a/libc/sysdeps/linux/common/bits/uClibc_ctype.h
+++ b/libc/sysdeps/linux/common/bits/uClibc_ctype.h
@@ -33,6 +33,8 @@
#ifndef _BITS_CTYPE_H
#define _BITS_CTYPE_H
+#warning uClibc_ctype.h is deprecated
+
/* Taking advantage of the C99 mutual-exclusion guarantees for the various
* (w)ctype classes, including the descriptions of printing and control
* (w)chars, we can place each in one of the following mutually-exlusive
diff --git a/libc/sysdeps/linux/common/bits/uClibc_fpmax.h b/libc/sysdeps/linux/common/bits/uClibc_fpmax.h
new file mode 100644
index 000000000..08d47129c
--- /dev/null
+++ b/libc/sysdeps/linux/common/bits/uClibc_fpmax.h
@@ -0,0 +1,132 @@
+/* Copyright (C) 2003 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Define a maximal floating point type, and the associated constants
+ * that are defined for the floating point types in float.h.
+ *
+ * This is to support archs that are missing long double, or even double.
+ */
+
+#ifndef _UCLIBC_FPMAX_H
+#define _UCLIBC_FPMAX_H
+
+#ifndef _ISOC99_SOURCE
+#define _ISOC99_SOURCE 1
+#endif
+
+#include <features.h>
+#include <float.h>
+
+#ifdef __UCLIBC_HAS_FLOATS__
+
+#if defined(LDBL_MANT_DIG)
+
+typedef long double __fpmax_t;
+#define FPMAX_TYPE 3
+
+#define FPMAX_MANT_DIG LDBL_MANT_DIG
+#define FPMAX_DIG LDBL_DIG
+#define FPMAX_EPSILON LDBL_EPSILON
+#define FPMAX_MIN_EXP LDBL_MIN_EXP
+#define FPMAX_MIN LDBL_MIN
+#define FPMAX_MIN_10_EXP LDBL_MIN_10_EXP
+#define FPMAX_MAX_EXP LDBL_MAX_EXP
+#define FPMAX_MAX LDBL_MAX
+#define FPMAX_MAX_10_EXP LDBL_MAX_10_EXP
+
+#elif defined(DBL_MANT_DIG)
+
+typedef double __fpmax_t;
+#define FPMAX_TYPE 2
+
+#define FPMAX_MANT_DIG DBL_MANT_DIG
+#define FPMAX_DIG DBL_DIG
+#define FPMAX_EPSILON DBL_EPSILON
+#define FPMAX_MIN_EXP DBL_MIN_EXP
+#define FPMAX_MIN DBL_MIN
+#define FPMAX_MIN_10_EXP DBL_MIN_10_EXP
+#define FPMAX_MAX_EXP DBL_MAX_EXP
+#define FPMAX_MAX DBL_MAX
+#define FPMAX_MAX_10_EXP DBL_MAX_10_EXP
+
+#elif defined(FLT_MANT_DIG)
+
+typedef float __fpmax_t;
+#define FPMAX_TYPE 1
+
+#define FPMAX_MANT_DIG FLT_MANT_DIG
+#define FPMAX_DIG FLT_DIG
+#define FPMAX_EPSILON FLT_EPSILON
+#define FPMAX_MIN_EXP FLT_MIN_EXP
+#define FPMAX_MIN FLT_MIN
+#define FPMAX_MIN_10_EXP FLT_MIN_10_EXP
+#define FPMAX_MAX_EXP FLT_MAX_EXP
+#define FPMAX_MAX FLT_MAX
+#define FPMAX_MAX_10_EXP FLT_MAX_10_EXP
+
+#else
+#error unable to determine appropriate type for __fpmax_t!
+#endif
+
+#ifndef DECIMAL_DIG
+
+#ifdef L___strtofpmax
+/* Emit warning only once. */
+#warning DECIMAL_DIG is not defined! If you are using gcc, it may not be defining __STDC_VERSION__ as it should.
+#endif
+#if !defined(FLT_RADIX) || (FLT_RADIX != 2)
+#error unable to compensate for missing DECIMAL_DIG!
+#endif
+
+/* ceil (1 + #mantissa * log10 (FLT_RADIX)) */
+#define DECIMAL_DIG (1 + (((FPMAX_MANT_DIG * 100) + 331) / 332))
+
+#endif /* DECIMAL_DIG */
+
+extern __fpmax_t __strtofpmax(const char *str, char **endptr, int exp_adjust);
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+extern __fpmax_t __strtofpmax_l(const char *str, char **endptr, int exp_adjust,
+ __locale_t locale_arg);
+#endif
+
+#ifdef __UCLIBC_HAS_WCHAR__
+extern __fpmax_t __wcstofpmax(const wchar_t *wcs, wchar_t **endptr,
+ int exp_adjust);
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+extern __fpmax_t __wcstofpmax_l(const wchar_t *wcs, wchar_t **endptr,
+ int exp_adjust, __locale_t locale_arg);
+#endif
+#endif /* __UCLIBC_HAS_WCHAR__ */
+
+/* The following checks in an __fpmax_t is either 0 or +/- infinity.
+ *
+ * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!
+ *
+ * This only works if __fpmax_t is the actual maximal floating point type used
+ * in intermediate calculations. Otherwise, excess precision in the
+ * intermediate values can cause the test to fail.
+ *
+ * WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!! WARNING!!!
+ */
+
+#define __FPMAX_ZERO_OR_INF_CHECK(x) ((x) == ((x)/4) )
+
+#endif /* __UCLIBC_HAS_FLOATS__ */
+
+#endif /* _UCLIBC_FPMAX_H */
diff --git a/libc/sysdeps/linux/common/bits/uClibc_locale.h b/libc/sysdeps/linux/common/bits/uClibc_locale.h
index 4e89188b8..56819ba62 100644
--- a/libc/sysdeps/linux/common/bits/uClibc_locale.h
+++ b/libc/sysdeps/linux/common/bits/uClibc_locale.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Manuel Novoa III
+/* Copyright (C) 2002, 2003 Manuel Novoa III
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -32,18 +32,17 @@
/**********************************************************************/
/* uClibc compatibilty stuff */
-#ifdef __UCLIBC_HAS_WCHAR__
-#define __WCHAR_ENABLED
-#endif
-
-
#ifdef __UCLIBC_HAS_LOCALE__
#undef __LOCALE_C_ONLY
#else /* __UCLIBC_HAS_LOCALE__ */
-#define __LOCALE_C_ONLY
+#define __LOCALE_C_ONLY
+
+#define __XL(N) N
+#define __LOCALE_PARAM
+#define __LOCALE_ARG
#endif /* __UCLIBC_HAS_LOCALE__ */
@@ -63,43 +62,18 @@
#define __LC_ALL 6
/**********************************************************************/
-#if defined(_LIBC) && defined(__WCHAR_ENABLED)
-
-/* TODO: This really needs to be somewhere else... */
-#include <limits.h>
-#include <stdint.h>
-
-#if WCHAR_MIN == 0
-typedef wchar_t __uwchar_t;
-#elif WCHAR_MAX <= USHRT_MAX
-typedef unsigned short __uwchar_t;
-#elif WCHAR_MAX <= UINT_MAX
-typedef unsigned int __uwchar_t;
-#elif WCHAR_MAX <= ULONG_MAX
-typedef unsigned long __uwchar_t;
-#elif defined(ULLONG_MAX) && (WCHAR_MAX <= ULLONG_MAX)
-typedef unsigned long long __uwchar_t;
-#elif WCHAR_MAX <= UINT_MAX
-typedef uintmax_t __uwchar_t;
-#else
-#error Can not determine an appropriate type for __uwchar_t!
-#endif
-
-#endif
-
-/**********************************************************************/
-#if defined(_LIBC) && !defined(__LOCALE_C_ONLY)
+/* #if defined(_LIBC) && !defined(__LOCALE_C_ONLY) */
+#ifndef __LOCALE_C_ONLY
#include <stddef.h>
#include <stdint.h>
-#include <bits/uClibc_locale_data.h>
+#include <bits/uClibc_touplow.h>
+#include <bits/uClibc_locale_data.h>
extern void _locale_set(const unsigned char *p);
extern void _locale_init(void);
-/* TODO: assumes 8-bit chars!!! */
-
enum {
__ctype_encoding_7_bit, /* C/POSIX */
__ctype_encoding_utf8, /* UTF-8 */
@@ -164,6 +138,12 @@ typedef struct {
/* static unsigned char cur_locale[LOCALE_STRING_SIZE]; */
typedef struct {
+#ifdef __UCLIBC_HAS_XLOCALE__
+ const __uint16_t *__ctype_b;
+ const __ctype_touplow_t *__ctype_tolower;
+ const __ctype_touplow_t *__ctype_toupper;
+#endif
+
/* int tables_loaded; */
/* unsigned char lctypes[LOCALE_STRING_SIZE]; */
unsigned char cur_locale[LOCALE_STRING_SIZE];
@@ -185,21 +165,30 @@ typedef struct {
const unsigned char *tbl8ctype;
const unsigned char *idx8uplow;
const unsigned char *tbl8uplow;
-#ifdef __WCHAR_ENABLED
+#ifdef __UCLIBC_HAS_WCHAR__
const unsigned char *idx8c2wc;
const uint16_t *tbl8c2wc; /* char > 0x7f to wide char */
const unsigned char *idx8wc2c;
const unsigned char *tbl8wc2c;
/* translit */
-#endif /* __WCHAR_ENABLED */
+#endif /* __UCLIBC_HAS_WCHAR__ */
#endif /* __CTYPE_HAS_8_BIT_LOCALES */
-#ifdef __WCHAR_ENABLED
+#ifdef __UCLIBC_HAS_WCHAR__
+
+ const uint16_t *code2flag;
+
const unsigned char *tblwctype;
const unsigned char *tblwuplow;
/* const unsigned char *tblwcomb; */
const int16_t *tblwuplow_diff; /* yes... signed */
/* width?? */
-#endif /* __WCHAR_ENABLED */
+
+ wchar_t decimal_point_wc;
+ wchar_t thousands_sep_wc;
+ int decimal_point_len;
+ int thousands_sep_len;
+
+#endif /* __UCLIBC_HAS_WCHAR__ */
/* ctype */
const char *outdigit0_mb;
@@ -313,10 +302,68 @@ typedef struct {
/* collate is at the end */
__collate_t collate;
-} __locale_t;
+} __uclibc_locale_t;
+
+typedef __uclibc_locale_t *__locale_t;
extern __locale_t __global_locale;
+
+extern int __locale_mbrtowc_l(wchar_t *__restrict dst,
+ const char *__restrict src,
+ __locale_t loc );
+
+#ifdef L_setlocale
+/* so we only get the warning once... */
+#warning need thread version of CUR_LOCALE!
+#endif
+/**********************************************************************/
+#ifdef __UCLIBC_HAS_XLOCALE__
+
+extern __locale_t __curlocale_var;
+
+#ifdef __UCLIBC_HAS_THREADS__
+
+extern __locale_t __curlocale(void) __THROW __attribute__ ((__const__));
+extern __locale_t __curlocale_set(__locale_t new);
+#define __UCLIBC_CURLOCALE (__curlocale())
+#define __UCLIBC_CURLOCALE_DATA (*__curlocale())
+
+#else /* __UCLIBC_HAS_THREADS__ */
+
+#define __UCLIBC_CURLOCALE (__curlocale_var)
+#define __UCLIBC_CURLOCALE_DATA (*__curlocale_var)
+
+#endif /* __UCLIBC_HAS_THREADS__ */
+
+#elif defined(__UCLIBC_HAS_LOCALE__)
+
+#define __UCLIBC_CURLOCALE (__global_locale)
+#define __UCLIBC_CURLOCALE_DATA (*__global_locale)
+
+#endif
+/**********************************************************************/
+#if defined(__UCLIBC_HAS_XLOCALE__) && defined(__UCLIBC_DO_XLOCALE)
+
+#define __XL(N) N ## _l
+#define __LOCALE_PARAM , __locale_t locale_arg
+#define __LOCALE_ARG , locale_arg
+#define __LOCALE_PTR locale_arg
+
+#else /* defined(__UCLIBC_HAS_XLOCALE__) && defined(__STDLIB_DO_XLOCALE) */
+
+#define __XL(N) N
+#define __LOCALE_PARAM
+#define __LOCALE_ARG
+#define __LOCALE_PTR __UCLIBC_CURLOCALE
+
+#endif /* defined(__UCLIBC_HAS_XLOCALE__) && defined(__STDLIB_DO_XLOCALE) */
+/**********************************************************************/
+
+extern __locale_t __newlocale(int category_mask, const char *locale, __locale_t base)
+ __THROW;
+
#endif /* defined(_LIBC) && !defined(__LOCALE_C_ONLY) */
+/**********************************************************************/
#endif /* _UCLIBC_LOCALE_H */
diff --git a/libc/sysdeps/linux/common/bits/uClibc_stdio.h b/libc/sysdeps/linux/common/bits/uClibc_stdio.h
index 59156eeea..6c0cff7ed 100644
--- a/libc/sysdeps/linux/common/bits/uClibc_stdio.h
+++ b/libc/sysdeps/linux/common/bits/uClibc_stdio.h
@@ -44,6 +44,79 @@
#define __STDIO_WIDE
#endif
+#define __STDIO_BUFFERS
+/* ANSI/ISO mandate at least 256. */
+#if defined(__UCLIBC_HAS_STDIO_BUFSIZ_NONE__)
+/* Fake this because some apps use stdio.h BUFSIZ. */
+#define _STDIO_BUFSIZ 256
+#undef __STDIO_BUFFERS
+#elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_256__)
+#define _STDIO_BUFSIZ 256
+#elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_512__)
+#define _STDIO_BUFSIZ 512
+#elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_1024__)
+#define _STDIO_BUFSIZ 1024
+#elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_2048__)
+#define _STDIO_BUFSIZ 2048
+#elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_4096__)
+#define _STDIO_BUFSIZ 4096
+#elif defined(__UCLIBC_HAS_STDIO_BUFSIZ_8192__)
+#define _STDIO_BUFSIZ 8192
+#else
+#error config seems to be out of sync regarding bufsiz options
+#endif
+
+#ifdef __UCLIBC_HAS_STDIO_GETC_MACRO__
+#define __STDIO_GETC_MACRO
+#endif
+
+#ifdef __UCLIBC_HAS_STDIO_PUTC_MACRO__
+#define __STDIO_PUTC_MACRO
+#endif
+
+#ifdef __UCLIBC_HAS_STDIO_AUTO_RW_TRANSITION__
+#define __STDIO_AUTO_RW_TRANSITION
+#endif
+
+#ifdef __UCLIBC_HAS_FOPEN_LARGEFILE_MODE__
+#define __STDIO_FOPEN_LARGEFILE_MODE
+#endif
+
+#ifdef __UCLIBC_HAS_FOPEN_LARGEFILE_MODE__
+#define __STDIO_FOPEN_EXCLUSIVE_MODE
+#endif
+
+#ifdef __UCLIBC_HAS_PRINTF_M_SPEC__
+#define __STDIO_PRINTF_M_SUPPORT
+#endif
+
+#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__
+#define __STDIO_GLIBC_CUSTOM_STREAMS
+#endif
+
+#ifdef __UCLIBC_HAS_STDIO_BUFSIZ_NONE__
+#define _STDIO_BUILTIN_BUF_SIZE 0
+#else /* __UCLIBC_HAS_STDIO_BUFSIZ_NONE__ */
+#if defined(__UCLIBC_HAS_STDIO_BUILTIN_BUFFER_NONE__)
+#define _STDIO_BUILTIN_BUF_SIZE 0
+#elif defined(__UCLIBC_HAS_STDIO_BUILTIN_BUFFER_4__)
+#define _STDIO_BUILTIN_BUF_SIZE 4
+#elif defined(__UCLIBC_HAS_STDIO_BUILTIN_BUFFER_8__)
+#define _STDIO_BUILTIN_BUF_SIZE 8
+#else
+#error config seems to be out of sync regarding builtin buffer size
+#endif
+#endif /* __UCLIBC_HAS_STDIO_BUFSIZ_NONE__ */
+
+#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_PRINTF__
+#define __STDIO_GLIBC_CUSTOM_PRINTF
+#endif
+
+
+/* Currently unimplemented/untested */
+/* #define __STDIO_FLEXIBLE_SETVBUF */
+
+
/* Make sure defines related to large files are consistent. */
#ifdef _LIBC
@@ -81,32 +154,23 @@
#include <wchar.h>
#endif
-#define __STDIO_BUFFERS
-#define __STDIO_GETC_MACRO
-#define __STDIO_PUTC_MACRO
/* For uClibc, these are currently handled above. */
-/* #define __STDIO_LARGE_FILES */
-/* #define __STDIO_THREADSAFE */
-
+/* #define __STDIO_BUFFERS */
+/* #define __STDIO_GETC_MACRO */
+/* #define __STDIO_PUTC_MACRO */
+/* #define __STDIO_LARGE_FILES */
+/* #define __STDIO_THREADSAFE */
+/* ANSI/ISO mandate at least 256. */
+/* #define _STDIO_BUFSIZ 256 */
+/* #define __STDIO_AUTO_RW_TRANSITION */
+/* #define __STDIO_FOPEN_EXCLUSIVE_MODE */
+/* #define __STDIO_PRINTF_M_SPEC */
+/* #define __STDIO_GLIBC_CUSTOM_STREAMS */
/* L mode extension for fopen. */
-#define __STDIO_FOPEN_LARGEFILE_MODE
-
+/* #define __STDIO_FOPEN_LARGEFILE_MODE */
/* size of builtin buf -- only tested with 0 */
-#define _STDIO_BUILTIN_BUF_SIZE 0
-
-/* TODO - enable features based on __STDIO_GLIBC_FEATURES */
-
-/* #define __STDIO_GLIBC_FEATURES */
-#define __STDIO_AUTO_RW_TRANSITION
-#define __STDIO_FOPEN_EXCLUSIVE_MODE
-#define __STDIO_PRINTF_M_SPEC
-#define __STDIO_GLIBC_CUSTOM_STREAMS
-
-
-/* ANSI/ISO mandate at least 256. */
-#define _STDIO_BUFSIZ 256
-
+/* #define _STDIO_BUILTIN_BUF_SIZE 0 */
/* Currently unimplemented/untested */
/* #define __STDIO_FLEXIBLE_SETVBUF */
@@ -173,7 +237,10 @@
typedef struct {
__off_t __pos;
#ifdef __STDIO_MBSTATE
- __mbstate_t __mbstate;
+ __mbstate_t __mbstate;
+#endif
+#ifdef __STDIO_WIDE
+ int mblen_pending;
#endif
} __stdio_fpos_t;
@@ -181,7 +248,10 @@ typedef struct {
typedef struct {
__off64_t __pos;
#ifdef __STDIO_MBSTATE
- __mbstate_t __mbstate;
+ __mbstate_t __mbstate;
+#endif
+#ifdef __STDIO_WIDE
+ int mblen_pending;
#endif
} __stdio_fpos64_t;
#endif
@@ -234,6 +304,7 @@ typedef _IO_cookie_io_functions_t cookie_io_functions_t;
* 0 1 one user (unused ungot is 1) or one scanf (unused ungot is 0)
* 1 0 must be scanf[0] and user[1]
* 1 1 illegal -- could be used to signal safe for setbuf
+ * but if used, need to fix _stdio_adjpos at least!
*/
#ifdef __UCLIBC__
@@ -244,8 +315,8 @@ struct __stdio_file_struct {
unsigned short modeflags;
/* There could be a hole here, but modeflags is used most.*/
#ifdef __STDIO_WIDE
- /* TOOD - ungot_width could be combined with ungot. But what about hole? */
- unsigned char ungot_width[2];
+ /* TODO - ungot_width could be combined with ungot. But what about hole? */
+ unsigned char ungot_width[2]; /* 0 is current (building) char, 1 is scanf */
wchar_t ungot[2];
#else /* __STDIO_WIDE */
unsigned char ungot[2];
diff --git a/libc/sysdeps/linux/common/bits/uClibc_touplow.h b/libc/sysdeps/linux/common/bits/uClibc_touplow.h
new file mode 100644
index 000000000..75d508546
--- /dev/null
+++ b/libc/sysdeps/linux/common/bits/uClibc_touplow.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 2003 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
+ *
+ * Besides uClibc, I'm using this code in my libc for elks, which is
+ * a 16-bit environment with a fairly limited compiler. It would make
+ * things much easier for me if this file isn't modified unnecessarily.
+ * In particular, please put any new or replacement functions somewhere
+ * else, and modify the makefile to use your version instead.
+ * Thanks. Manuel
+ *
+ * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
+
+#ifndef _UCLIBC_TOUPLOW_H
+#define _UCLIBC_TOUPLOW_H
+
+#include <features.h>
+#include <bits/types.h>
+
+/* glibc uses the equivalent of - typedef __int32_t __ctype_touplow_t; */
+
+#ifdef __UCLIBC_HAS_CTYPE_SIGNED__
+typedef __int16_t __ctype_touplow_t;
+#else /* __UCLIBC_HAS_CTYPE_SIGNED__ */
+typedef unsigned char __ctype_touplow_t;
+#endif /* __UCLIBC_HAS_CTYPE_SIGNED__ */
+
+#endif /* _UCLIBC_TOUPLOW_H */
+
diff --git a/libc/sysdeps/linux/common/bits/uClibc_uwchar.h b/libc/sysdeps/linux/common/bits/uClibc_uwchar.h
new file mode 100644
index 000000000..206191276
--- /dev/null
+++ b/libc/sysdeps/linux/common/bits/uClibc_uwchar.h
@@ -0,0 +1,56 @@
+/* Copyright (C) 2003 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
+ *
+ * Besides uClibc, I'm using this code in my libc for elks, which is
+ * a 16-bit environment with a fairly limited compiler. It would make
+ * things much easier for me if this file isn't modified unnecessarily.
+ * In particular, please put any new or replacement functions somewhere
+ * else, and modify the makefile to use your version instead.
+ * Thanks. Manuel
+ *
+ * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
+
+
+/* Define an internal unsigned int type __uwchar_t just large enough
+ * to hold a wchar_t.
+ */
+
+#ifndef _UCLIBC_UWCHAR_H
+#define _UCLIBC_UWCHAR_H
+
+#include <limits.h>
+#include <stdint.h>
+
+#if WCHAR_MIN == 0
+typedef wchar_t __uwchar_t;
+#elif WCHAR_MAX <= USHRT_MAX
+typedef unsigned short __uwchar_t;
+#elif WCHAR_MAX <= UINT_MAX
+typedef unsigned int __uwchar_t;
+#elif WCHAR_MAX <= ULONG_MAX
+typedef unsigned long __uwchar_t;
+#elif defined(ULLONG_MAX) && (WCHAR_MAX <= ULLONG_MAX)
+typedef unsigned long long __uwchar_t;
+#elif WCHAR_MAX <= UINTMAX_MAX
+typedef uintmax_t __uwchar_t;
+#else
+#error Can not determine an appropriate type for __uwchar_t!
+#endif
+
+#endif /* _UCLIBC_UWCHAR_H */
diff --git a/libc/sysdeps/linux/common/bits/xopen_lim.h b/libc/sysdeps/linux/common/bits/xopen_lim.h
index 90cb54123..c2363ab04 100644
--- a/libc/sysdeps/linux/common/bits/xopen_lim.h
+++ b/libc/sysdeps/linux/common/bits/xopen_lim.h
@@ -68,7 +68,13 @@
/* Maximum value of `digit' in calls to the `printf' and `scanf'
functions. Posix dictates this should be a minimum of 9 */
+#if !defined(__UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS__) || (__UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS__ <= 1)
+#undef NL_ARGMAX
+#elif __UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS__ < 9
#define NL_ARGMAX 9
+#else
+#define NL_ARGMAX __UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS__
+#endif
/* Maximum number of bytes in a `LANG' name. We have no limit. */
#define NL_LANGMAX _POSIX2_LINE_MAX
diff --git a/libc/unistd/getopt.c b/libc/unistd/getopt.c
index 311118853..504f3764c 100644
--- a/libc/unistd/getopt.c
+++ b/libc/unistd/getopt.c
@@ -31,6 +31,12 @@
#include <stdlib.h>
#include <libintl.h>
+#ifdef __UCLIBC_MJN3_ONLY__
+#warning TODO: Enable gettext awareness.
+#endif /* __UCLIBC_MJN3_ONLY__ */
+
+#undef _
+#define _(X) X
/* Treat '-W foo' the same as the long option '--foo',
* disabled for the moment since it costs about 2k... */
diff --git a/libpthread/linuxthreads/Makefile b/libpthread/linuxthreads/Makefile
index 748776e71..880fda291 100644
--- a/libpthread/linuxthreads/Makefile
+++ b/libpthread/linuxthreads/Makefile
@@ -45,6 +45,11 @@ CSRC=attr.c cancel.c condvar.c errno.c events.c join.c lockfile.c manager.c \
mutex.c oldsemaphore.c pt-machine.c ptfork.c pthread.c \
ptlongjmp.c rwlock.c semaphore.c signals.c specific.c spinlock.c \
wrapsyscall.c #weaks.c
+
+ifeq ($(UCLIBC_HAS_XLOCALE),y)
+ CSRC += locale.c
+endif
+
COBJS=$(patsubst %.c,%.o, $(CSRC))
OBJS=$(COBJS)
diff --git a/libpthread/linuxthreads/internals.h b/libpthread/linuxthreads/internals.h
index 528acddc3..bce6b7efe 100644
--- a/libpthread/linuxthreads/internals.h
+++ b/libpthread/linuxthreads/internals.h
@@ -28,6 +28,9 @@
#include "pt-machine.h"
#include "semaphore.h"
#include "../linuxthreads_db/thread_dbP.h"
+#ifdef __UCLIBC_HAS_XLOCALE__
+#include <bits/uClibc_locale.h>
+#endif /* __UCLIBC_HAS_XLOCALE__ */
/* Use a funky version in a probably vein attempt at preventing gdb
* from dlopen()'ing glibc's libthread_db library... */
@@ -172,6 +175,9 @@ struct _pthread_descr_struct {
pthread_readlock_info *p_readlock_free; /* Free list of structs */
int p_untracked_readlock_count; /* Readlocks not tracked by list */
/* New elements must be added at the end. */
+#ifdef __UCLIBC_HAS_XLOCALE__
+ __locale_t locale; /* thread-specific locale from uselocale() only! */
+#endif /* __UCLIBC_HAS_XLOCALE__ */
} __attribute__ ((aligned(32))); /* We need to align the structure so that
doubles are aligned properly. This is 8
bytes on MIPS and 16 bytes on MIPS64.
diff --git a/libpthread/linuxthreads/locale.c b/libpthread/linuxthreads/locale.c
new file mode 100644
index 000000000..c3ebbc285
--- /dev/null
+++ b/libpthread/linuxthreads/locale.c
@@ -0,0 +1,58 @@
+/* Copyright (C) 2003 Manuel Novoa III
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define _GNU_SOURCE
+#include <features.h>
+#include "pthread.h"
+#include "internals.h"
+#include <locale.h>
+#include <assert.h>
+#include <stdlib.h>
+
+extern struct _pthread_descr_struct __pthread_initial_thread;
+
+__locale_t __curlocale(void)
+{
+ pthread_descr self = thread_self();
+
+#ifdef NDEBUG
+ return THREAD_GETMEM (self, locale);
+#else
+ {
+ __locale_t r = THREAD_GETMEM (self, locale);
+
+ assert(r);
+
+ return r;
+ }
+#endif
+}
+
+__locale_t __curlocale_set(__locale_t newloc)
+{
+ __locale_t oldloc;
+ pthread_descr self = thread_self();
+
+ oldloc = THREAD_GETMEM (self, locale);
+
+ assert(newloc != LC_GLOBAL_LOCALE);
+ assert(oldloc);
+
+ THREAD_SETMEM (self, locale, newloc);
+
+ return oldloc;
+}
diff --git a/libpthread/linuxthreads/manager.c b/libpthread/linuxthreads/manager.c
index f1c9b93af..f7301bc52 100644
--- a/libpthread/linuxthreads/manager.c
+++ b/libpthread/linuxthreads/manager.c
@@ -134,6 +134,11 @@ int __pthread_manager(void *arg)
__pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno;
__pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno;
+#ifdef __UCLIBC_HAS_XLOCALE__
+ /* Initialize thread's locale to the global locale. */
+ __pthread_manager_thread.locale = __global_locale;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
/* Block all signals except __pthread_sig_cancel and SIGTRAP */
sigfillset(&manager_mask);
sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */
@@ -506,6 +511,10 @@ static int pthread_handle_create(pthread_t *thread, const pthread_attr_t *attr,
new_thread->p_canceltype = PTHREAD_CANCEL_DEFERRED;
new_thread->p_errnop = &new_thread->p_errno;
new_thread->p_h_errnop = &new_thread->p_h_errno;
+#ifdef __UCLIBC_HAS_XLOCALE__
+ /* Initialize thread's locale to the global locale. */
+ new_thread->locale = __global_locale;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
new_thread->p_guardaddr = guardaddr;
new_thread->p_guardsize = guardsize;
new_thread->p_self = new_thread;
diff --git a/libpthread/linuxthreads/pthread.c b/libpthread/linuxthreads/pthread.c
index 22e3f6a9c..1c24cccd8 100644
--- a/libpthread/linuxthreads/pthread.c
+++ b/libpthread/linuxthreads/pthread.c
@@ -99,6 +99,10 @@ struct _pthread_descr_struct __pthread_initial_thread = {
NULL, /* pthread_readlock_info *p_readlock_list; */
NULL, /* pthread_readlock_info *p_readlock_free; */
0 /* int p_untracked_readlock_count; */
+#ifdef __UCLIBC_HAS_XLOCALE__
+ ,
+ NULL, /* __locale_t locale; */
+#endif /* __UCLIBC_HAS_XLOCALE__ */
};
/* Descriptor of the manager thread; none of this is used but the error
@@ -151,6 +155,10 @@ struct _pthread_descr_struct __pthread_manager_thread = {
NULL, /* pthread_readlock_info *p_readlock_list; */
NULL, /* pthread_readlock_info *p_readlock_free; */
0 /* int p_untracked_readlock_count; */
+#ifdef __UCLIBC_HAS_XLOCALE__
+ ,
+ NULL, /* __locale_t locale; */
+#endif /* __UCLIBC_HAS_XLOCALE__ */
};
/* Pointer to the main thread (the father of the thread manager thread) */
@@ -318,6 +326,12 @@ static void pthread_initialize(void)
/* The errno/h_errno variable of the main thread are the global ones. */
__pthread_initial_thread.p_errnop = &_errno;
__pthread_initial_thread.p_h_errnop = &_h_errno;
+
+#ifdef __UCLIBC_HAS_XLOCALE__
+ /* The locale of the main thread is the current locale in use. */
+ __pthread_initial_thread.locale = __curlocale_var;
+#endif /* __UCLIBC_HAS_XLOCALE__ */
+
/* Play with the stack size limit to make sure that no stack ever grows
beyond STACK_SIZE minus two pages (one page for the thread descriptor
immediately beyond, and one page to act as a guard page). */