diff options
author | grehan <grehan@FreeBSD.org> | 2011-11-22 02:27:59 +0000 |
---|---|---|
committer | grehan <grehan@FreeBSD.org> | 2011-11-22 02:27:59 +0000 |
commit | f68bada80b9371e881d04b43a8ab412fa54cd5fa (patch) | |
tree | 97b668c8ce00f69d94b0237dac765c76f460638b /lib | |
parent | cdc4639328546d2b0ad5a90dd2d4e4534e874c26 (diff) | |
parent | 08ecf874bb3cc09a324985ab9315883462c59ae8 (diff) | |
download | FreeBSD-src-f68bada80b9371e881d04b43a8ab412fa54cd5fa.zip FreeBSD-src-f68bada80b9371e881d04b43a8ab412fa54cd5fa.tar.gz |
IFC @ r227804
Pull in the virtio drivers from head.
Diffstat (limited to 'lib')
177 files changed, 4927 insertions, 947 deletions
diff --git a/lib/clang/clang.build.mk b/lib/clang/clang.build.mk index ceaeb05..47b6795 100644 --- a/lib/clang/clang.build.mk +++ b/lib/clang/clang.build.mk @@ -9,7 +9,7 @@ CFLAGS+=-I${LLVM_SRCS}/include -I${CLANG_SRCS}/include \ -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS #-DNDEBUG # Correct for gcc miscompilation when compiling on PPC with -O2 -.if ${MACHINE_ARCH} == "powerpc" +.if ${MACHINE_CPUARCH} == "powerpc" CFLAGS+= -O1 .endif diff --git a/lib/clang/include/llvm/Config/config.h b/lib/clang/include/llvm/Config/config.h index 5b6761c..92c960b 100644 --- a/lib/clang/include/llvm/Config/config.h +++ b/lib/clang/include/llvm/Config/config.h @@ -552,7 +552,7 @@ /* #undef LLVM_ETCDIR */ /* Has gcc/MSVC atomic intrinsics */ -#define LLVM_HAS_ATOMICS 1 +#define LLVM_HAS_ATOMICS 0 /* Host triple we were built on */ /* #undef LLVM_HOSTTRIPLE */ diff --git a/lib/clang/include/llvm/Config/llvm-config.h b/lib/clang/include/llvm/Config/llvm-config.h index 05e17ca..1b50ab8 100644 --- a/lib/clang/include/llvm/Config/llvm-config.h +++ b/lib/clang/include/llvm/Config/llvm-config.h @@ -34,7 +34,7 @@ /* #undef LLVM_ETCDIR */ /* Has gcc/MSVC atomic intrinsics */ -#define LLVM_HAS_ATOMICS 1 +#define LLVM_HAS_ATOMICS 0 /* Host triple we were built on */ /* #undef LLVM_HOSTTRIPLE */ diff --git a/lib/libc/amd64/gen/setjmp.S b/lib/libc/amd64/gen/setjmp.S index 1409f4c..47772be 100644 --- a/lib/libc/amd64/gen/setjmp.S +++ b/lib/libc/amd64/gen/setjmp.S @@ -54,6 +54,7 @@ ENTRY(setjmp) movq $1,%rdi /* SIG_BLOCK */ movq $0,%rsi /* (sigset_t*)set */ leaq 72(%rcx),%rdx /* 9,10; (sigset_t*)oset */ + /* stack is 16-byte aligned */ call PIC_PLT(CNAME(_sigprocmask)) popq %rdi movq %rdi,%rcx @@ -81,7 +82,9 @@ ENTRY(__longjmp) movq $3,%rdi /* SIG_SETMASK */ leaq 72(%rdx),%rsi /* (sigset_t*)set */ movq $0,%rdx /* (sigset_t*)oset */ + subq $0x8,%rsp /* make the stack 16-byte aligned */ call PIC_PLT(CNAME(_sigprocmask)) + addq $0x8,%rsp popq %rsi popq %rdi /* jmpbuf */ movq %rdi,%rdx diff --git a/lib/libc/amd64/gen/sigsetjmp.S b/lib/libc/amd64/gen/sigsetjmp.S index 438d440..ef90bc6 100644 --- a/lib/libc/amd64/gen/sigsetjmp.S +++ b/lib/libc/amd64/gen/sigsetjmp.S @@ -62,6 +62,7 @@ ENTRY(sigsetjmp) movq $1,%rdi /* SIG_BLOCK */ movq $0,%rsi /* (sigset_t*)set */ leaq 72(%rcx),%rdx /* 9,10 (sigset_t*)oset */ + /* stack is 16-byte aligned */ call PIC_PLT(CNAME(_sigprocmask)) popq %rdi 2: movq %rdi,%rcx @@ -90,7 +91,9 @@ ENTRY(__siglongjmp) movq $3,%rdi /* SIG_SETMASK */ leaq 72(%rdx),%rsi /* (sigset_t*)set */ movq $0,%rdx /* (sigset_t*)oset */ + subq $0x8,%rsp /* make the stack 16-byte aligned */ call PIC_PLT(CNAME(_sigprocmask)) + addq $0x8,%rsp popq %rsi popq %rdi /* jmpbuf */ 2: movq %rdi,%rdx diff --git a/lib/libc/gdtoa/machdep_ldisQ.c b/lib/libc/gdtoa/machdep_ldisQ.c index ebcb37e..7b5c7af 100644 --- a/lib/libc/gdtoa/machdep_ldisQ.c +++ b/lib/libc/gdtoa/machdep_ldisQ.c @@ -2,6 +2,11 @@ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -38,10 +43,10 @@ __FBSDID("$FreeBSD$"); #include "gdtoaimp.h" long double -strtold(const char * __restrict s, char ** __restrict sp) +strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale) { long double result; - strtorQ(s, sp, FLT_ROUNDS, &result); + strtorQ_l(s, sp, FLT_ROUNDS, &result, locale); return result; } diff --git a/lib/libc/gdtoa/machdep_ldisd.c b/lib/libc/gdtoa/machdep_ldisd.c index e2dbb60..d5c7329 100644 --- a/lib/libc/gdtoa/machdep_ldisd.c +++ b/lib/libc/gdtoa/machdep_ldisd.c @@ -2,6 +2,11 @@ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,10 +39,11 @@ __FBSDID("$FreeBSD$"); #include "gdtoaimp.h" +#undef strtold_l long double -strtold(const char * __restrict s, char ** __restrict sp) +strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale) { - return strtod(s, sp); + return strtod_l(s, sp, locale); } diff --git a/lib/libc/gdtoa/machdep_ldisx.c b/lib/libc/gdtoa/machdep_ldisx.c index c08c85e..b8e2a05 100644 --- a/lib/libc/gdtoa/machdep_ldisx.c +++ b/lib/libc/gdtoa/machdep_ldisx.c @@ -2,6 +2,11 @@ * Copyright (c) 2003 David Schultz <das@FreeBSD.ORG> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -38,10 +43,11 @@ __FBSDID("$FreeBSD$"); #include "gdtoaimp.h" long double -strtold(const char * __restrict s, char ** __restrict sp) +strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale) { long double result; + FIX_LOCALE(locale); - strtorx(s, sp, FLT_ROUNDS, &result); + strtorx_l(s, sp, FLT_ROUNDS, &result, locale); return result; } diff --git a/lib/libc/gen/arc4random.c b/lib/libc/gen/arc4random.c index 56dfba9..a2b235f 100644 --- a/lib/libc/gen/arc4random.c +++ b/lib/libc/gen/arc4random.c @@ -1,3 +1,5 @@ +/* $OpenBSD: arc4random.c,v 1.22 2010/12/22 08:23:42 otto Exp $ */ + /* * Copyright (c) 1996, David Mazieres <dm@uun.org> * Copyright (c) 2008, Damien Miller <djm@openbsd.org> @@ -24,11 +26,6 @@ * which is a trade secret). The same algorithm is used as a stream * cipher called "arcfour" in Tatu Ylonen's ssh package. * - * Here the stream cipher has been modified always to include the time - * when initializing the state. That makes it impossible to - * regenerate the same random sequence twice, so this can't be used - * for encryption, but will generate good random numbers. - * * RC4 is a registered trademark of RSA Laboratories. */ @@ -36,16 +33,24 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" -#include <sys/types.h> -#include <sys/time.h> -#include <stdlib.h> #include <fcntl.h> +#include <limits.h> +#include <stdlib.h> #include <unistd.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> #include <pthread.h> #include "libc_private.h" #include "un-namespace.h" +#ifdef __GNUC__ +#define inline __inline +#else /* !__GNUC__ */ +#define inline +#endif /* !__GNUC__ */ + struct arc4_stream { u_int8_t i; u_int8_t j; @@ -55,22 +60,22 @@ struct arc4_stream { static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; #define RANDOMDEV "/dev/random" -#define KEYSIZE 128 -#define THREAD_LOCK() \ +#define KEYSIZE 128 +#define _ARC4_LOCK() \ do { \ if (__isthreaded) \ _pthread_mutex_lock(&arc4random_mtx); \ } while (0) -#define THREAD_UNLOCK() \ +#define _ARC4_UNLOCK() \ do { \ if (__isthreaded) \ _pthread_mutex_unlock(&arc4random_mtx); \ } while (0) -static struct arc4_stream rs; static int rs_initialized; -static int rs_stired; +static struct arc4_stream rs; +static pid_t arc4_stir_pid; static int arc4_count; static inline u_int8_t arc4_getbyte(void); @@ -107,20 +112,24 @@ arc4_addrandom(u_char *dat, int datlen) static void arc4_stir(void) { - int done, fd, n; + int done, fd, i; struct { struct timeval tv; - pid_t pid; - u_int8_t rnd[KEYSIZE]; + pid_t pid; + u_char rnd[KEYSIZE]; } rdat; + if (!rs_initialized) { + arc4_init(); + rs_initialized = 1; + } fd = _open(RANDOMDEV, O_RDONLY, 0); done = 0; if (fd >= 0) { if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) done = 1; (void)_close(fd); - } + } if (!done) { (void)gettimeofday(&rdat.tv, NULL); rdat.pid = getpid(); @@ -130,17 +139,26 @@ arc4_stir(void) arc4_addrandom((u_char *)&rdat, KEYSIZE); /* - * Throw away the first N bytes of output, as suggested in the - * paper "Weaknesses in the Key Scheduling Algorithm of RC4" - * by Fluher, Mantin, and Shamir. N=1024 is based on - * suggestions in the paper "(Not So) Random Shuffles of RC4" - * by Ilya Mironov. + * Discard early keystream, as per recommendations in: + * "(Not So) Random Shuffles of RC4" by Ilya Mironov. */ - for (n = 0; n < 1024; n++) - (void) arc4_getbyte(); + for (i = 0; i < 1024; i++) + (void)arc4_getbyte(); arc4_count = 1600000; } +static void +arc4_stir_if_needed(void) +{ + pid_t pid = getpid(); + + if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) + { + arc4_stir_pid = pid; + arc4_stir(); + } +} + static inline u_int8_t arc4_getbyte(void) { @@ -152,7 +170,6 @@ arc4_getbyte(void) sj = rs.s[rs.j]; rs.s[rs.i] = sj; rs.s[rs.j] = si; - return (rs.s[(si + sj) & 0xff]); } @@ -160,81 +177,55 @@ static inline u_int32_t arc4_getword(void) { u_int32_t val; - val = arc4_getbyte() << 24; val |= arc4_getbyte() << 16; val |= arc4_getbyte() << 8; val |= arc4_getbyte(); - - return (val); -} - -static void -arc4_check_init(void) -{ - if (!rs_initialized) { - arc4_init(); - rs_initialized = 1; - } -} - -static inline void -arc4_check_stir(void) -{ - if (!rs_stired || arc4_count <= 0) { - arc4_stir(); - rs_stired = 1; - } + return val; } void arc4random_stir(void) { - THREAD_LOCK(); - arc4_check_init(); + _ARC4_LOCK(); arc4_stir(); - rs_stired = 1; - THREAD_UNLOCK(); + _ARC4_UNLOCK(); } void arc4random_addrandom(u_char *dat, int datlen) { - THREAD_LOCK(); - arc4_check_init(); - arc4_check_stir(); + _ARC4_LOCK(); + if (!rs_initialized) + arc4_stir(); arc4_addrandom(dat, datlen); - THREAD_UNLOCK(); + _ARC4_UNLOCK(); } u_int32_t arc4random(void) { - u_int32_t rnd; - - THREAD_LOCK(); - arc4_check_init(); - arc4_check_stir(); - rnd = arc4_getword(); + u_int32_t val; + _ARC4_LOCK(); arc4_count -= 4; - THREAD_UNLOCK(); - - return (rnd); + arc4_stir_if_needed(); + val = arc4_getword(); + _ARC4_UNLOCK(); + return val; } void arc4random_buf(void *_buf, size_t n) { u_char *buf = (u_char *)_buf; - - THREAD_LOCK(); - arc4_check_init(); + _ARC4_LOCK(); + arc4_stir_if_needed(); while (n--) { - arc4_check_stir(); + if (--arc4_count <= 0) + arc4_stir(); buf[n] = arc4_getbyte(); - arc4_count--; } - THREAD_UNLOCK(); + _ARC4_UNLOCK(); } /* @@ -253,7 +244,7 @@ arc4random_uniform(u_int32_t upper_bound) u_int32_t r, min; if (upper_bound < 2) - return (0); + return 0; #if (ULONG_MAX > 0xffffffffUL) min = 0x100000000UL % upper_bound; @@ -279,7 +270,7 @@ arc4random_uniform(u_int32_t upper_bound) break; } - return (r % upper_bound); + return r % upper_bound; } #if 0 diff --git a/lib/libc/gen/fnmatch.c b/lib/libc/gen/fnmatch.c index 3acbc3b..c38aafc 100644 --- a/lib/libc/gen/fnmatch.c +++ b/lib/libc/gen/fnmatch.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Guido van Rossum. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -222,6 +227,8 @@ rangematch(pattern, test, flags, newp, patmbs) wchar_t c, c2; size_t pclen; const char *origpat; + struct xlocale_collate *table = + (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; /* * A bracket expression starting with an unquoted circumflex @@ -276,10 +283,10 @@ rangematch(pattern, test, flags, newp, patmbs) if (flags & FNM_CASEFOLD) c2 = towlower(c2); - if (__collate_load_error ? + if (table->__collate_load_error ? c <= test && test <= c2 : - __collate_range_cmp(c, test) <= 0 - && __collate_range_cmp(test, c2) <= 0 + __collate_range_cmp(table, c, test) <= 0 + && __collate_range_cmp(table, test, c2) <= 0 ) ok = 1; } else if (c == test) diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index d25aacf..e7bfae4 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 19, 2011 +.Dd October 27, 2011 .Dt GETUTXENT 3 .Os .Sh NAME @@ -301,7 +301,6 @@ The value of determines which databases are modified. .Pp Entries of type -.Dv BOOT_TIME , .Dv SHUTDOWN_TIME , .Dv OLD_TIME and @@ -335,7 +334,7 @@ In addition, entries of type .Dv BOOT_TIME and .Dv SHUTDOWN_TIME -will cause all entries in +will cause all existing entries in .Pa /var/run/utx.active to be discarded. .Pp @@ -386,10 +385,10 @@ Otherwise, -1 is returned and the global variable is set to indicate the error. .Sh ERRORS In addition to the error conditions described in +.Xr open 2 , .Xr fdopen 3 , .Xr fopen 3 , .Xr fseek 3 , -.Xr open 3 , the .Fn pututxline function can generate the following errors: diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c index c3d9f08..59663d9 100644 --- a/lib/libc/gen/glob.c +++ b/lib/libc/gen/glob.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Guido van Rossum. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -751,6 +756,8 @@ match(Char *name, Char *pat, Char *patend) { int ok, negate_range; Char c, k; + struct xlocale_collate *table = + (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; while (pat < patend) { c = *pat++; @@ -775,10 +782,10 @@ match(Char *name, Char *pat, Char *patend) ++pat; while (((c = *pat++) & M_MASK) != M_END) if ((*pat & M_MASK) == M_RNG) { - if (__collate_load_error ? + if (table->__collate_load_error ? CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) : - __collate_range_cmp(CHAR(c), CHAR(k)) <= 0 - && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0 + __collate_range_cmp(table, CHAR(c), CHAR(k)) <= 0 + && __collate_range_cmp(table, CHAR(k), CHAR(pat[1])) <= 0 ) ok = 1; pat += 2; diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c index 0cc7a01..98addee 100644 --- a/lib/libc/gen/pututxline.c +++ b/lib/libc/gen/pututxline.c @@ -86,6 +86,9 @@ utx_active_add(const struct futx *fu) return (-1); while (fread(&fe, sizeof(fe), 1, fp) == 1) { switch (fe.fu_type) { + case BOOT_TIME: + /* Leave these intact. */ + break; case USER_PROCESS: case INIT_PROCESS: case LOGIN_PROCESS: @@ -171,6 +174,19 @@ utx_active_remove(struct futx *fu) } static void +utx_active_init(const struct futx *fu) +{ + int fd; + + /* Initialize utx.active with a single BOOT_TIME record. */ + fd = _open(_PATH_UTX_ACTIVE, O_CREAT|O_RDWR|O_TRUNC, 0644); + if (fd < 0) + return; + _write(fd, fu, sizeof(*fu)); + _close(fd); +} + +static void utx_active_purge(void) { @@ -277,9 +293,11 @@ pututxline(const struct utmpx *utmpx) switch (fu.fu_type) { case BOOT_TIME: + utx_active_init(&fu); + utx_lastlogin_upgrade(); + break; case SHUTDOWN_TIME: utx_active_purge(); - utx_lastlogin_upgrade(); break; case OLD_TIME: case NEW_TIME: diff --git a/lib/libc/i386/gen/setjmp.S b/lib/libc/i386/gen/setjmp.S index 5d0ddc4..a409e35 100644 --- a/lib/libc/i386/gen/setjmp.S +++ b/lib/libc/i386/gen/setjmp.S @@ -51,12 +51,19 @@ __FBSDID("$FreeBSD$"); ENTRY(setjmp) movl 4(%esp),%ecx PIC_PROLOGUE +#ifdef PIC + subl $12,%esp /* make the stack 16-byte aligned */ +#endif leal 28(%ecx), %eax pushl %eax /* (sigset_t*)oset */ pushl $0 /* (sigset_t*)set */ pushl $1 /* SIG_BLOCK */ call PIC_PLT(CNAME(_sigprocmask)) +#ifdef PIC + addl $24,%esp +#else addl $12,%esp +#endif PIC_EPILOGUE movl 4(%esp),%ecx movl 0(%esp),%edx @@ -76,12 +83,19 @@ END(setjmp) ENTRY(__longjmp) movl 4(%esp),%edx PIC_PROLOGUE +#ifdef PIC + subl $12,%esp /* make the stack 16-byte aligned */ +#endif pushl $0 /* (sigset_t*)oset */ leal 28(%edx), %eax pushl %eax /* (sigset_t*)set */ pushl $3 /* SIG_SETMASK */ call PIC_PLT(CNAME(_sigprocmask)) +#ifdef PIC + addl $24,%esp +#else addl $12,%esp +#endif PIC_EPILOGUE movl 4(%esp),%edx movl 8(%esp),%eax diff --git a/lib/libc/i386/gen/sigsetjmp.S b/lib/libc/i386/gen/sigsetjmp.S index 6487745..936edba 100644 --- a/lib/libc/i386/gen/sigsetjmp.S +++ b/lib/libc/i386/gen/sigsetjmp.S @@ -60,12 +60,19 @@ ENTRY(sigsetjmp) testl %eax,%eax jz 2f PIC_PROLOGUE +#ifdef PIC + subl $12,%esp /* make the stack 16-byte aligned */ +#endif leal 28(%ecx), %eax pushl %eax /* (sigset_t*)oset */ pushl $0 /* (sigset_t*)set */ pushl $1 /* SIG_BLOCK */ call PIC_PLT(CNAME(_sigprocmask)) +#ifdef PIC + addl $24,%esp +#else addl $12,%esp +#endif PIC_EPILOGUE movl 4(%esp),%ecx 2: movl 0(%esp),%edx @@ -87,12 +94,19 @@ ENTRY(__siglongjmp) cmpl $0,44(%edx) jz 2f PIC_PROLOGUE +#ifdef PIC + subl $12,%esp /* make the stack 16-byte aligned */ +#endif pushl $0 /* (sigset_t*)oset */ leal 28(%edx), %eax pushl %eax /* (sigset_t*)set */ pushl $3 /* SIG_SETMASK */ call PIC_PLT(CNAME(_sigprocmask)) +#ifdef PIC + addl $24,%esp +#else addl $12,%esp +#endif PIC_EPILOGUE movl 4(%esp),%edx 2: movl 8(%esp),%eax diff --git a/lib/libc/locale/DESIGN.xlocale b/lib/libc/locale/DESIGN.xlocale new file mode 100644 index 0000000..5d998d3 --- /dev/null +++ b/lib/libc/locale/DESIGN.xlocale @@ -0,0 +1,159 @@ +$FreeBSD$ + +Design of xlocale +================= + +The xlocale APIs come from Darwin, although a subset is now part of POSIX 2008. +They fall into two broad categories: + +- Manipulation of per-thread locales (POSIX) +- Locale-aware functions taking an explicit locale argument (Darwin) + +This document describes the implementation of these APIs for FreeBSD. + +Goals +----- + +The overall goal of this implementation is to be compatible with the Darwin +version. Additionally, it should include minimal changes to the existing +locale code. A lot of the existing locale code originates with 4BSD or earlier +and has had over a decade of testing. Replacing this code, unless absolutely +necessary, gives us the potential for more bugs without much benefit. + +With this in mind, various libc-private functions have been modified to take a +locale_t parameter. This causes a compiler error if they are accidentally +called without a locale. This approach was taken, rather than adding _l +variants of these functions, to make it harder for accidental uses of the +global-locale versions to slip in. + +Locale Objects +-------------- + +A locale is encapsulated in a `locale_t`, which is an opaque type: a pointer to +a `struct _xlocale`. The name `_xlocale` is unfortunate, as it does not fit +well with existing conventions, but is used because this is the name the Darwin +implementation gives to this structure and so may be used by existing (bad) code. + +This structure should include all of the information corresponding to a locale. +A locale_t is almost immutable after creation. There are no functions that modify it, +and it can therefore be used without locking. It is the responsibility of the +caller to ensure that a locale is not deallocated during a call that uses it. + +Each locale contains a number of components, one for each of the categories +supported by `setlocale()`. These are likewise immutable after creation. This +differs from the Darwin implementation, which includes a deprecated +`setinvalidrune()` function that can modify the rune locale. + +The exception to these mutability rules is a set of `mbstate_t` flags stored +with each locale. These are used by various functions that previously had a +static local `mbstate_t` variable. + +The components are reference counted, and so can be aliased between locale +objects. This makes copying locales very cheap. + +The Global Locale +----------------- + +All locales and locale components are reference counted. The global locale, +however, is special. It, and all of its components, are static and so no +malloc() memory is required when using a single locale. + +This means that threads using the global locale are subject to the same +constraints as with the pre-xlocale libc. Calls to any locale-aware functions +in threads using the global locale, while modifying the global locale, have +undefined behaviour. + +Because of this, we have to ensure that we always copy the components of the +global locale, rather than alias them. + +It would be cleaner to simply remove the special treatment of the global locale +and have a locale_t lazily allocated for the global context. This would cost a +little more `malloc()` memory, so is not done in the initial version. + +Caching +------- + +The existing locale implementation included several ad-hoc caching layers. +None of these were thread safe. Caching is only really of use for supporting +the pattern where the locale is briefly changed to something and then changed +back. + +The current xlocale implementation removes the caching entirely. This pattern +is not one that should be encouraged. If you need to make some calls with a +modified locale, then you should use the _l suffix versions of the calls, +rather than switch the global locale. If you do need to temporarily switch the +locale and then switch it back, `uselocale()` provides a way of doing this very +easily: It returns the old locale, which can then be passed to a subsequent +call to `uselocale()` to restore it, without the need to load any locale data +from the disk. + +If, in the future, it is determined that caching is beneficial, it can be added +quite easily in xlocale.c. Given, however, that any locale-aware call is going +to be a preparation for presenting data to the user, and so is invariably going +to be part of an I/O operation, this seems like a case of premature +optimisation. + +localeconv +---------- + +The `localeconv()` function is an exception to the immutable-after-creation +rule. In the classic implementation, this function returns a pointer to some +global storage, which is initialised with the data from the current locale. +This is not possible in a multithreaded environment, with multiple locales. + +Instead, each locale contains a `struct lconv` that is lazily initialised on +calls to `localeconv()`. This is not protected by any locking, however this is +still safe on any machine where word-sized stores are atomic: two concurrent +calls will write the same data into the structure. + +Explicit Locale Calls +--------------------- + +A large number of functions have been modified to take an explicit `locale_t` +parameter. The old APIs are then reimplemented with a call to `__get_locale()` +to supply the `locale_t` parameter. This is in line with the Darwin public +APIs, but also simplifies the modifications to these functions. The +`__get_locale()` function is now the only way to access the current locale +within libc. All of the old globals have gone, so there is now a linker error +if any functions attempt to use them. + +The ctype.h functions are a little different. These are not implemented in +terms of their locale-aware versions, for performance reasons. Each of these +is implemented as a short inline function. + +Differences to Darwin APIs +-------------------------- + +`strtoq_l()` and `strtouq_l() `are not provided. These are extensions to +deprecated functions - we should not be encouraging people to use deprecated +interfaces. + +Locale Placeholders +------------------- + +The pointer values 0 and -1 have special meanings as `locale_t` values. Any +public function that accepts a `locale_t` parameter must use the `FIX_LOCALE()` +macro on it before using it. For efficiency, this can be emitted in functions +which *only* use their locale parameter as an argument to another public +function, as the callee will do the `FIX_LOCALE()` itself. + +Potential Improvements +---------------------- + +Currently, the current rune set is accessed via a function call. This makes it +fairly expensive to use any of the ctype.h functions. We could improve this +quite a lot by storing the rune locale data in a __thread-qualified variable. + +Several of the existing FreeBSD locale-aware functions appear to be wrong. For +example, most of the `strto*()` family should probably use `digittoint_l()`, +but instead they assume ASCII. These will break if using a character encoding +that does not put numbers and the letters A-F in the same location as ASCII. +Some functions, like `strcoll()` only work on single-byte encodings. No +attempt has been made to fix existing limitations in the libc functions other +than to add support for xlocale. + +Intuitively, setting a thread-local locale should ensure that all locale-aware +functions can be used safely from that thread. In fact, this is not the case +in either this implementation or the Darwin one. You must call `duplocale()` +or `newlocale()` before calling `uselocale()`. This is a bit ugly, and it +would be better if libc ensure that every thread had its own locale object. diff --git a/lib/libc/locale/Makefile.inc b/lib/libc/locale/Makefile.inc index 8fff0589..55800d0 100644 --- a/lib/libc/locale/Makefile.inc +++ b/lib/libc/locale/Makefile.inc @@ -5,7 +5,7 @@ .PATH: ${.CURDIR}/${LIBC_ARCH}/locale ${.CURDIR}/locale SRCS+= ascii.c big5.c btowc.c collate.c collcmp.c euc.c fix_grouping.c \ - gb18030.c gb2312.c gbk.c isctype.c iswctype.c \ + gb18030.c gb2312.c gbk.c ctype.c isctype.c iswctype.c \ ldpart.c lmessages.c lmonetary.c lnumeric.c localeconv.c mblen.c \ mbrlen.c \ mbrtowc.c mbsinit.c mbsnrtowcs.c \ @@ -20,7 +20,8 @@ SRCS+= ascii.c big5.c btowc.c collate.c collcmp.c euc.c fix_grouping.c \ wcstoimax.c wcstol.c wcstold.c wcstoll.c \ wcstombs.c \ wcstoul.c wcstoull.c wcstoumax.c wctob.c wctomb.c wctrans.c wctype.c \ - wcwidth.c + wcwidth.c\ + xlocale.c SYM_MAPS+=${.CURDIR}/locale/Symbol.map @@ -37,7 +38,9 @@ MAN+= btowc.3 \ wcsftime.3 \ wcrtomb.3 \ wcsrtombs.3 wcstod.3 wcstol.3 wcstombs.3 wctomb.3 \ - wctrans.3 wctype.3 wcwidth.3 + wctrans.3 wctype.3 wcwidth.3 \ + duplocale.3 freelocale.3 newlocale.3 querylocale.3 uselocale.3 xlocale.3 + MAN+= big5.5 euc.5 gb18030.5 gb2312.5 gbk.5 mskanji.5 utf8.5 MLINKS+=btowc.3 wctob.3 diff --git a/lib/libc/locale/Symbol.map b/lib/libc/locale/Symbol.map index 20d092b..01242b6 100644 --- a/lib/libc/locale/Symbol.map +++ b/lib/libc/locale/Symbol.map @@ -101,6 +101,101 @@ FBSD_1.0 { wcwidth; }; +FBSD_1.3 { + newlocale; + duplocale; + freelocale; + querylocale; + uselocale; + __getCurrentRuneLocale; + btowc_l; + localeconv_l; + mblen_l; + mbrlen_l; + mbrtowc_l; + mbsinit_l; + mbsnrtowcs_l; + mbsrtowcs_l; + mbstowcs_l; + mbtowc_l; + nl_langinfo_l; + strcoll_l; + strfmon_l; + strftime_l; + strptime_l; + strxfrm_l; + wcrtomb_l; + wcscoll_l; + wcsnrtombs_l; + wcsrtombs_l; + wcstombs_l; + wcsxfrm_l; + wctob_l; + wctomb_l; + ___tolower_l; + ___toupper_l; + ___runetype_l; + digittoint_l; + isalnum_l; + isalpha_l; + isblank_l; + iscntrl_l; + isdigit_l; + isgraph_l; + ishexnumber_l; + isideogram_l; + islower_l; + isnumber_l; + isphonogram_l; + isprint_l; + ispunct_l; + isrune_l; + isspace_l; + isspecial_l; + isupper_l; + isxdigit_l; + tolower_l; + toupper_l; + iswalnum_l; + iswalpha_l; + iswblank_l; + iswcntrl_l; + iswdigit_l; + iswgraph_l; + iswhexnumber_l; + iswideogram_l; + iswlower_l; + iswnumber_l; + iswphonogram_l; + iswprint_l; + iswpunct_l; + iswrune_l; + iswspace_l; + iswspecial_l; + iswupper_l; + iswxdigit_l; + towlower_l; + towupper_l; + iswctype_l; + wctype_l; + nextwctype_l; + ___mb_cur_max; + ___mb_cur_max_l; + towctrans_l; + wctrans_l; + wcsftime_l; + wcstod_l; + wcstof_l; + wcstoimax_l; + wcstol_l; + wcstold_l; + wcstoll_l; + wcstoul_l; + wcstoull_l; + wcstoumax_l; + __runes_for_locale; +}; + FBSDprivate_1.0 { _PathLocale; __detect_path_locale; diff --git a/lib/libc/locale/ascii.c b/lib/libc/locale/ascii.c index 493bf42..784814d 100644 --- a/lib/libc/locale/ascii.c +++ b/lib/libc/locale/ascii.c @@ -6,6 +6,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -56,17 +61,17 @@ static size_t _ascii_wcsnrtombs(char * __restrict, const wchar_t ** __restrict, size_t, size_t, mbstate_t * __restrict); int -_ascii_init(_RuneLocale *rl) +_ascii_init(struct xlocale_ctype *l,_RuneLocale *rl) { - __mbrtowc = _ascii_mbrtowc; - __mbsinit = _ascii_mbsinit; - __mbsnrtowcs = _ascii_mbsnrtowcs; - __wcrtomb = _ascii_wcrtomb; - __wcsnrtombs = _ascii_wcsnrtombs; - _CurrentRuneLocale = rl; - __mb_cur_max = 1; - __mb_sb_limit = 128; + l->__mbrtowc = _ascii_mbrtowc; + l->__mbsinit = _ascii_mbsinit; + l->__mbsnrtowcs = _ascii_mbsnrtowcs; + l->__wcrtomb = _ascii_wcrtomb; + l->__wcsnrtombs = _ascii_wcsnrtombs; + l->runes = rl; + l->__mb_cur_max = 1; + l->__mb_sb_limit = 128; return(0); } diff --git a/lib/libc/locale/big5.c b/lib/libc/locale/big5.c index 19977d0..4b37265 100644 --- a/lib/libc/locale/big5.c +++ b/lib/libc/locale/big5.c @@ -6,6 +6,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -62,15 +67,15 @@ typedef struct { } _BIG5State; int -_BIG5_init(_RuneLocale *rl) +_BIG5_init(struct xlocale_ctype *l, _RuneLocale *rl) { - __mbrtowc = _BIG5_mbrtowc; - __wcrtomb = _BIG5_wcrtomb; - __mbsinit = _BIG5_mbsinit; - _CurrentRuneLocale = rl; - __mb_cur_max = 2; - __mb_sb_limit = 128; + l->__mbrtowc = _BIG5_mbrtowc; + l->__wcrtomb = _BIG5_wcrtomb; + l->__mbsinit = _BIG5_mbsinit; + l->runes = rl; + l->__mb_cur_max = 2; + l->__mb_sb_limit = 128; return (0); } diff --git a/lib/libc/locale/btowc.c b/lib/libc/locale/btowc.c index 2c4d493..72507bc 100644 --- a/lib/libc/locale/btowc.c +++ b/lib/libc/locale/btowc.c @@ -2,6 +2,11 @@ * Copyright (c) 2002, 2003 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,12 +37,13 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" wint_t -btowc(int c) +btowc_l(int c, locale_t l) { static const mbstate_t initial; mbstate_t mbs = initial; char cc; wchar_t wc; + FIX_LOCALE(l); if (c == EOF) return (WEOF); @@ -47,7 +53,12 @@ btowc(int c) * counts. */ cc = (char)c; - if (__mbrtowc(&wc, &cc, 1, &mbs) > 1) + if (XLOCALE_CTYPE(l)->__mbrtowc(&wc, &cc, 1, &mbs) > 1) return (WEOF); return (wc); } +wint_t +btowc(int c) +{ + return btowc_l(c, __get_locale()); +} diff --git a/lib/libc/locale/collate.c b/lib/libc/locale/collate.c index 6833598..e87b6dc 100644 --- a/lib/libc/locale/collate.c +++ b/lib/libc/locale/collate.c @@ -3,6 +3,16 @@ * at Electronni Visti IA, Kiev, Ukraine. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -44,24 +54,77 @@ __FBSDID("$FreeBSD$"); #include "libc_private.h" -int __collate_load_error = 1; -int __collate_substitute_nontrivial; +/* + * To avoid modifying the original (single-threaded) code too much, we'll just + * define the old globals as fields inside the table. + * + * We also modify the collation table test functions to search the thread-local + * table first and the global table second. + */ +#define __collate_load_error (table->__collate_load_error) +#define __collate_substitute_nontrivial (table->__collate_substitute_nontrivial) +#define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr) +#define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr) +#define __collate_chain_pri_table (table->__collate_chain_pri_table) -u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN]; -struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; -struct __collate_st_chain_pri *__collate_chain_pri_table; + +struct xlocale_collate __xlocale_global_collate = { + {{0}, "C"}, 1, 0 +}; + + struct xlocale_collate __xlocale_C_collate = { + {{0}, "C"}, 1, 0 +}; void __collate_err(int ex, const char *f) __dead2; int +__collate_load_tables_l(const char *encoding, struct xlocale_collate *table); + +static void +destruct_collate(void *t) +{ + struct xlocale_collate *table = t; + if (__collate_chain_pri_table) { + free(__collate_chain_pri_table); + } + free(t); +} + +void * +__collate_load(const char *encoding, locale_t unused) +{ + if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) { + return &__xlocale_C_collate; + } + struct xlocale_collate *table = calloc(sizeof(struct xlocale_collate), 1); + table->header.header.destructor = destruct_collate; + // FIXME: Make sure that _LDP_CACHE is never returned. We should be doing + // the caching outside of this section + if (__collate_load_tables_l(encoding, table) != _LDP_LOADED) { + xlocale_release(table); + return NULL; + } + return table; +} + +/** + * Load the collation tables for the specified encoding into the global table. + */ +int __collate_load_tables(const char *encoding) { + return __collate_load_tables_l(encoding, &__xlocale_global_collate); +} + +int +__collate_load_tables_l(const char *encoding, struct xlocale_collate *table) +{ FILE *fp; int i, saverr, chains; uint32_t u32; char strbuf[STR_LEN], buf[PATH_MAX]; void *TMP_substitute_table, *TMP_char_pri_table, *TMP_chain_pri_table; - static char collate_encoding[ENCODING_LEN + 1]; /* 'encoding' must be already checked. */ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) { @@ -69,18 +132,6 @@ __collate_load_tables(const char *encoding) return (_LDP_CACHE); } - /* - * If the locale name is the same as our cache, use the cache. - */ - if (strcmp(encoding, collate_encoding) == 0) { - __collate_load_error = 0; - return (_LDP_CACHE); - } - - /* - * Slurp the locale file into the cache. - */ - /* 'PathLocale' must be already set & checked. */ /* Range checking not needed, encoding has fixed size */ (void)strcpy(buf, _PathLocale); @@ -165,7 +216,6 @@ __collate_load_tables(const char *encoding) sizeof(*__collate_chain_pri_table), chains, fp); (void)fclose(fp); - (void)strcpy(collate_encoding, encoding); if (__collate_substitute_table_ptr != NULL) free(__collate_substitute_table_ptr); __collate_substitute_table_ptr = TMP_substitute_table; @@ -201,7 +251,7 @@ __collate_load_tables(const char *encoding) } u_char * -__collate_substitute(const u_char *s) +__collate_substitute(struct xlocale_collate *table, const u_char *s) { int dest_len, len, nlen; int delta = strlen(s); @@ -228,7 +278,7 @@ __collate_substitute(const u_char *s) } void -__collate_lookup(const u_char *t, int *len, int *prim, int *sec) +__collate_lookup(struct xlocale_collate *table, const u_char *t, int *len, int *prim, int *sec) { struct __collate_st_chain_pri *p2; diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h index 2f5f5d4..ad034d4 100644 --- a/lib/libc/locale/collate.h +++ b/lib/libc/locale/collate.h @@ -3,6 +3,11 @@ * at Electronni Visti IA, Kiev, Ukraine. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,6 +38,7 @@ #include <sys/cdefs.h> #include <sys/types.h> #include <limits.h> +#include "xlocale_private.h" #define STR_LEN 10 #define TABLE_SIZE 100 @@ -47,20 +53,26 @@ struct __collate_st_chain_pri { int prim, sec; }; -extern int __collate_load_error; -extern int __collate_substitute_nontrivial; #define __collate_substitute_table (*__collate_substitute_table_ptr) -extern u_char __collate_substitute_table[UCHAR_MAX + 1][STR_LEN]; #define __collate_char_pri_table (*__collate_char_pri_table_ptr) -extern struct __collate_st_char_pri __collate_char_pri_table[UCHAR_MAX + 1]; -extern struct __collate_st_chain_pri *__collate_chain_pri_table; + +struct xlocale_collate { + struct xlocale_component header; + int __collate_load_error; + int __collate_substitute_nontrivial; + + u_char (*__collate_substitute_table_ptr)[UCHAR_MAX + 1][STR_LEN]; + struct __collate_st_char_pri (*__collate_char_pri_table_ptr)[UCHAR_MAX + 1]; + struct __collate_st_chain_pri *__collate_chain_pri_table; +}; + __BEGIN_DECLS u_char *__collate_strdup(u_char *); -u_char *__collate_substitute(const u_char *); +u_char *__collate_substitute(struct xlocale_collate *, const u_char *); int __collate_load_tables(const char *); -void __collate_lookup(const u_char *, int *, int *, int *); -int __collate_range_cmp(int, int); +void __collate_lookup(struct xlocale_collate *, const u_char *, int *, int *, int *); +int __collate_range_cmp(struct xlocale_collate *, int, int); #ifdef COLLATE_DEBUG void __collate_print_tables(void); #endif diff --git a/lib/libc/locale/collcmp.c b/lib/libc/locale/collcmp.c index 313e043..aa17afd 100644 --- a/lib/libc/locale/collcmp.c +++ b/lib/libc/locale/collcmp.c @@ -2,6 +2,11 @@ * Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -28,17 +33,20 @@ __FBSDID("$FreeBSD$"); #include <string.h> +#include <xlocale.h> #include "collate.h" /* * Compare two characters using collate */ -int __collate_range_cmp(int c1, int c2) +int __collate_range_cmp(struct xlocale_collate *table, int c1, int c2) { static char s1[2], s2[2]; s1[0] = c1; s2[0] = c2; - return (strcoll(s1, s2)); + struct _xlocale l = {{0}}; + l.components[XLC_COLLATE] = (struct xlocale_component *)table; + return (strcoll_l(s1, s2, &l)); } diff --git a/lib/libc/locale/ctype.c b/lib/libc/locale/ctype.c new file mode 100644 index 0000000..f0ec3f6 --- /dev/null +++ b/lib/libc/locale/ctype.c @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by David Chisnall under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions * are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#define _XLOCALE_INLINE +#include <ctype.h> +#include <wctype.h> +#include <xlocale.h> diff --git a/lib/libc/locale/duplocale.3 b/lib/libc/locale/duplocale.3 new file mode 100644 index 0000000..19d2569 --- /dev/null +++ b/lib/libc/locale/duplocale.3 @@ -0,0 +1,78 @@ +.\" Copyright (c) 2011 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by David Chisnall under sponsorship from +.\" the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 17 2011 +.Dt DUPLOCALE 3 +.Os +.Sh NAME +.Nm duplocale +.Nd duplicate an locale +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In xlocale.h +.Ft locale_t +.Fn duplocale "locale_t locale" +.Sh DESCRIPTION +Duplicates an existing +.Fa locale_t +returning a new +.Fa locale_t +that refers to the same locale values but has independent internal state. +Various functions, such as +.Xr mblen 3 +require presistent state. These functions formerly used static variables and +calls to them from multiple threads had undefined behavior. They now use +fields in the +.Fa locale_t +associated with the current thread by +.Xr uselocale 3 . +These calls are therefore only thread safe on threads with a unique per-thread +locale. +.Pt +The locale returned by this call must be freed with +.Xr freelocale 3 . +.Sh BUGS +Ideally, +.Xr uselocale 3 +should make a copy of the +.Fa locale_t +implicitly to ensure thread safety, and a copy of the global locale should be +installed lazily on each thread. The FreeBSD implementation does not do this, +for compatibility with Darwin. +.Sh SEE ALSO +.Xr freelocale 3 , +.Xr localeconv 3 , +.Xr newlocale 3 , +.Xr querylocale 3 , +.Xr uselocale 3 , +.Xr xlocale 3 +.Sh STANDARDS +This function, conforms to +.St -p1003.1-2008 diff --git a/lib/libc/locale/euc.c b/lib/libc/locale/euc.c index 188073e..26ad413 100644 --- a/lib/libc/locale/euc.c +++ b/lib/libc/locale/euc.c @@ -6,6 +6,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -70,7 +75,7 @@ typedef struct { } _EucState; int -_EUC_init(_RuneLocale *rl) +_EUC_init(struct xlocale_ctype *l, _RuneLocale *rl) { _EucInfo *ei; int x, new__mb_cur_max; @@ -113,12 +118,12 @@ _EUC_init(_RuneLocale *rl) } rl->__variable = ei; rl->__variable_len = sizeof(_EucInfo); - _CurrentRuneLocale = rl; - __mb_cur_max = new__mb_cur_max; - __mbrtowc = _EUC_mbrtowc; - __wcrtomb = _EUC_wcrtomb; - __mbsinit = _EUC_mbsinit; - __mb_sb_limit = 256; + l->runes = rl; + l->__mb_cur_max = new__mb_cur_max; + l->__mbrtowc = _EUC_mbrtowc; + l->__wcrtomb = _EUC_wcrtomb; + l->__mbsinit = _EUC_mbsinit; + l->__mb_sb_limit = 256; return (0); } diff --git a/lib/libc/locale/freelocale.3 b/lib/libc/locale/freelocale.3 new file mode 100644 index 0000000..cf7174d --- /dev/null +++ b/lib/libc/locale/freelocale.3 @@ -0,0 +1,61 @@ +.\" Copyright (c) 2011 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by David Chisnall under sponsorship from +.\" the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.Dd September 17 2011 +.Dt FREELOCALE 3 +.Os +.Sh NAME +.Nm freelocale +.Nd Frees a locale created with +.Xr duplocale 3 +or +.Xr newlocale 3 . +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In xlocale.h +.Ft int +.Fn freelocale "locale_t locale" +.Sh DESCRIPTION +Frees a +.Fa locale_t . +This relinquishes any resources held exclusively by this locale. Note that +locales share reference-counted components, so a call to this function is not +guaranteed to free all of the components. +.Sh RETURN VALUES +Returns 0 on success or -1 on error. +.Sh SEE ALSO +.Xr duplocale 3 , +.Xr localeconv 3 , +.Xr newlocale 3 , +.Xr querylocale 3 , +.Xr uselocale 3 , +.Xr xlocale 3 +.Sh STANDARDS +This function, conforms to +.St -p1003.1-2008 . diff --git a/lib/libc/locale/gb18030.c b/lib/libc/locale/gb18030.c index 1457d3e..9214385 100644 --- a/lib/libc/locale/gb18030.c +++ b/lib/libc/locale/gb18030.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,8 +44,6 @@ __FBSDID("$FreeBSD$"); #include <wchar.h> #include "mblocal.h" -extern int __mb_sb_limit; - static size_t _GB18030_mbrtowc(wchar_t * __restrict, const char * __restrict, size_t, mbstate_t * __restrict); static int _GB18030_mbsinit(const mbstate_t *); @@ -53,15 +56,15 @@ typedef struct { } _GB18030State; int -_GB18030_init(_RuneLocale *rl) +_GB18030_init(struct xlocale_ctype *l, _RuneLocale *rl) { - __mbrtowc = _GB18030_mbrtowc; - __wcrtomb = _GB18030_wcrtomb; - __mbsinit = _GB18030_mbsinit; - _CurrentRuneLocale = rl; - __mb_cur_max = 4; - __mb_sb_limit = 128; + l->__mbrtowc = _GB18030_mbrtowc; + l->__wcrtomb = _GB18030_wcrtomb; + l->__mbsinit = _GB18030_mbsinit; + l->runes = rl; + l->__mb_cur_max = 4; + l->__mb_sb_limit = 128; return (0); } diff --git a/lib/libc/locale/gb2312.c b/lib/libc/locale/gb2312.c index 74a7bdc..5fbc07d 100644 --- a/lib/libc/locale/gb2312.c +++ b/lib/libc/locale/gb2312.c @@ -3,6 +3,11 @@ * Copyright (c) 2003 David Xu <davidxu@freebsd.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -35,8 +40,6 @@ __FBSDID("$FreeBSD$"); #include <wchar.h> #include "mblocal.h" -extern int __mb_sb_limit; - static size_t _GB2312_mbrtowc(wchar_t * __restrict, const char * __restrict, size_t, mbstate_t * __restrict); static int _GB2312_mbsinit(const mbstate_t *); @@ -49,15 +52,15 @@ typedef struct { } _GB2312State; int -_GB2312_init(_RuneLocale *rl) +_GB2312_init(struct xlocale_ctype *l, _RuneLocale *rl) { - _CurrentRuneLocale = rl; - __mbrtowc = _GB2312_mbrtowc; - __wcrtomb = _GB2312_wcrtomb; - __mbsinit = _GB2312_mbsinit; - __mb_cur_max = 2; - __mb_sb_limit = 128; + l->runes = rl; + l->__mbrtowc = _GB2312_mbrtowc; + l->__wcrtomb = _GB2312_wcrtomb; + l->__mbsinit = _GB2312_mbsinit; + l->__mb_cur_max = 2; + l->__mb_sb_limit = 128; return (0); } diff --git a/lib/libc/locale/gbk.c b/lib/libc/locale/gbk.c index 802f78e..43269c7 100644 --- a/lib/libc/locale/gbk.c +++ b/lib/libc/locale/gbk.c @@ -6,6 +6,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -55,15 +60,15 @@ typedef struct { } _GBKState; int -_GBK_init(_RuneLocale *rl) +_GBK_init(struct xlocale_ctype *l, _RuneLocale *rl) { - __mbrtowc = _GBK_mbrtowc; - __wcrtomb = _GBK_wcrtomb; - __mbsinit = _GBK_mbsinit; - _CurrentRuneLocale = rl; - __mb_cur_max = 2; - __mb_sb_limit = 128; + l->__mbrtowc = _GBK_mbrtowc; + l->__wcrtomb = _GBK_wcrtomb; + l->__mbsinit = _GBK_mbsinit; + l->runes = rl; + l->__mb_cur_max = 2; + l->__mb_sb_limit = 128; return (0); } diff --git a/lib/libc/locale/lmessages.c b/lib/libc/locale/lmessages.c index 3498be2..a0664d0 100644 --- a/lib/libc/locale/lmessages.c +++ b/lib/libc/locale/lmessages.c @@ -2,6 +2,11 @@ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -36,6 +41,14 @@ __FBSDID("$FreeBSD$"); #define LCMESSAGES_SIZE_MIN \ (offsetof(struct lc_messages_T, yesstr) / sizeof(char *)) +struct xlocale_messages { + struct xlocale_component header; + char *buffer; + struct lc_messages_T locale; +}; + +struct xlocale_messages __xlocale_global_messages; + static char empty[] = ""; static const struct lc_messages_T _C_messages_locale = { @@ -45,33 +58,55 @@ static const struct lc_messages_T _C_messages_locale = { "no" /* nostr */ }; -static struct lc_messages_T _messages_locale; -static int _messages_using_locale; -static char *_messages_locale_buf; +static void destruct_messages(void *v) +{ + struct xlocale_messages *l = v; + if (l->buffer) + free(l->buffer); + free(l); +} -int -__messages_load_locale(const char *name) +static int +messages_load_locale(struct xlocale_messages *loc, int *using_locale, const char *name) { int ret; + struct lc_messages_T *l = &loc->locale; - ret = __part_load_locale(name, &_messages_using_locale, - &_messages_locale_buf, "LC_MESSAGES", + ret = __part_load_locale(name, using_locale, + &loc->buffer, "LC_MESSAGES", LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN, - (const char **)&_messages_locale); + (const char **)l); if (ret == _LDP_LOADED) { - if (_messages_locale.yesstr == NULL) - _messages_locale.yesstr = empty; - if (_messages_locale.nostr == NULL) - _messages_locale.nostr = empty; + if (l->yesstr == NULL) + l->yesstr = empty; + if (l->nostr == NULL) + l->nostr = empty; } return (ret); } +int +__messages_load_locale(const char *name) +{ + return messages_load_locale(&__xlocale_global_messages, + &__xlocale_global_locale.using_messages_locale, name); +} +void * +__messages_load(const char *name, locale_t l) +{ + struct xlocale_messages *new = calloc(sizeof(struct xlocale_messages), 1); + new->header.header.destructor = destruct_messages; + if (messages_load_locale(new, &l->using_messages_locale, name) == _LDP_ERROR) { + xlocale_release(new); + return NULL; + } + return new; +} struct lc_messages_T * -__get_current_messages_locale(void) +__get_current_messages_locale(locale_t loc) { - return (_messages_using_locale - ? &_messages_locale + return (loc->using_messages_locale + ? &((struct xlocale_messages *)loc->components[XLC_MESSAGES])->locale : (struct lc_messages_T *)&_C_messages_locale); } diff --git a/lib/libc/locale/lmessages.h b/lib/libc/locale/lmessages.h index 41dcfa9..ea9c57e 100644 --- a/lib/libc/locale/lmessages.h +++ b/lib/libc/locale/lmessages.h @@ -2,6 +2,11 @@ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -29,6 +34,8 @@ #ifndef _LMESSAGES_H_ #define _LMESSAGES_H_ +#include "xlocale_private.h" + struct lc_messages_T { const char *yesexpr; const char *noexpr; @@ -36,7 +43,7 @@ struct lc_messages_T { const char *nostr; }; -struct lc_messages_T *__get_current_messages_locale(void); +struct lc_messages_T *__get_current_messages_locale(locale_t); int __messages_load_locale(const char *); #endif /* !_LMESSAGES_H_ */ diff --git a/lib/libc/locale/lmonetary.c b/lib/libc/locale/lmonetary.c index 8d55ab2..a9d67d3 100644 --- a/lib/libc/locale/lmonetary.c +++ b/lib/libc/locale/lmonetary.c @@ -2,6 +2,11 @@ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,7 +39,6 @@ __FBSDID("$FreeBSD$"); #include "ldpart.h" #include "lmonetary.h" -extern int __mlocale_changed; extern const char * __fix_locale_grouping_str(const char *); #define LCMONETARY_SIZE_FULL (sizeof(struct lc_monetary_T) / sizeof(char *)) @@ -69,9 +73,7 @@ static const struct lc_monetary_T _C_monetary_locale = { numempty /* int_n_sign_posn */ }; -static struct lc_monetary_T _monetary_locale; -static int _monetary_using_locale; -static char *_monetary_locale_buf; +struct xlocale_monetary __xlocale_global_monetary; static char cnv(const char *str) @@ -83,23 +85,34 @@ cnv(const char *str) return ((char)i); } -int -__monetary_load_locale(const char *name) +static void +destruct_monetary(void *v) +{ + struct xlocale_monetary *l = v; + if (l->buffer) + free(l->buffer); + free(l); +} + +static int +monetary_load_locale_l(struct xlocale_monetary *loc, int *using_locale, + int *changed, const char *name) { int ret; + struct lc_monetary_T *l = &loc->locale; - ret = __part_load_locale(name, &_monetary_using_locale, - &_monetary_locale_buf, "LC_MONETARY", + ret = __part_load_locale(name, using_locale, + &loc->buffer, "LC_MONETARY", LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN, - (const char **)&_monetary_locale); + (const char **)l); if (ret != _LDP_ERROR) - __mlocale_changed = 1; + *changed = 1; if (ret == _LDP_LOADED) { - _monetary_locale.mon_grouping = - __fix_locale_grouping_str(_monetary_locale.mon_grouping); + l->mon_grouping = + __fix_locale_grouping_str(l->mon_grouping); -#define M_ASSIGN_CHAR(NAME) (((char *)_monetary_locale.NAME)[0] = \ - cnv(_monetary_locale.NAME)) +#define M_ASSIGN_CHAR(NAME) (((char *)l->NAME)[0] = \ + cnv(l->NAME)) M_ASSIGN_CHAR(int_frac_digits); M_ASSIGN_CHAR(frac_digits); @@ -117,9 +130,9 @@ __monetary_load_locale(const char *name) */ #define M_ASSIGN_ICHAR(NAME) \ do { \ - if (_monetary_locale.int_##NAME == NULL) \ - _monetary_locale.int_##NAME = \ - _monetary_locale.NAME; \ + if (l->int_##NAME == NULL) \ + l->int_##NAME = \ + l->NAME; \ else \ M_ASSIGN_CHAR(int_##NAME); \ } while (0) @@ -133,12 +146,32 @@ __monetary_load_locale(const char *name) } return (ret); } +int +__monetary_load_locale(const char *name) +{ + return monetary_load_locale_l(&__xlocale_global_monetary, + &__xlocale_global_locale.using_monetary_locale, + &__xlocale_global_locale.monetary_locale_changed, name); +} +void* __monetary_load(const char *name, locale_t l) +{ + struct xlocale_monetary *new = calloc(sizeof(struct xlocale_monetary), 1); + new->header.header.destructor = destruct_monetary; + if (monetary_load_locale_l(new, &l->using_monetary_locale, + &l->monetary_locale_changed, name) == _LDP_ERROR) + { + xlocale_release(new); + return NULL; + } + return new; +} + struct lc_monetary_T * -__get_current_monetary_locale(void) +__get_current_monetary_locale(locale_t loc) { - return (_monetary_using_locale - ? &_monetary_locale + return (loc->using_monetary_locale + ? &((struct xlocale_monetary*)loc->components[XLC_MONETARY])->locale : (struct lc_monetary_T *)&_C_monetary_locale); } diff --git a/lib/libc/locale/lmonetary.h b/lib/libc/locale/lmonetary.h index 45ec323..b606862 100644 --- a/lib/libc/locale/lmonetary.h +++ b/lib/libc/locale/lmonetary.h @@ -2,6 +2,11 @@ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -28,6 +33,7 @@ #ifndef _LMONETARY_H_ #define _LMONETARY_H_ +#include "xlocale_private.h" struct lc_monetary_T { const char *int_curr_symbol; @@ -52,8 +58,13 @@ struct lc_monetary_T { const char *int_p_sign_posn; const char *int_n_sign_posn; }; +struct xlocale_monetary { + struct xlocale_component header; + char *buffer; + struct lc_monetary_T locale; +}; -struct lc_monetary_T *__get_current_monetary_locale(void); +struct lc_monetary_T *__get_current_monetary_locale(locale_t loc); int __monetary_load_locale(const char *); #endif /* !_LMONETARY_H_ */ diff --git a/lib/libc/locale/lnumeric.c b/lib/libc/locale/lnumeric.c index d4ed04f..a2468f4 100644 --- a/lib/libc/locale/lnumeric.c +++ b/lib/libc/locale/lnumeric.c @@ -2,6 +2,11 @@ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,7 +37,6 @@ __FBSDID("$FreeBSD$"); #include "ldpart.h" #include "lnumeric.h" -extern int __nlocale_changed; extern const char *__fix_locale_grouping_str(const char *); #define LCNUMERIC_SIZE (sizeof(struct lc_numeric_T) / sizeof(char *)) @@ -45,37 +49,67 @@ static const struct lc_numeric_T _C_numeric_locale = { numempty /* grouping */ }; -static struct lc_numeric_T _numeric_locale; -static int _numeric_using_locale; -static char *_numeric_locale_buf; +static void +destruct_numeric(void *v) +{ + struct xlocale_numeric *l = v; + if (l->buffer) + free(l->buffer); + free(l); +} + +struct xlocale_numeric __xlocale_global_numeric; -int -__numeric_load_locale(const char *name) +static int +numeric_load_locale(struct xlocale_numeric *loc, int *using_locale, int *changed, + const char *name) { int ret; + struct lc_numeric_T *l = &loc->locale; - ret = __part_load_locale(name, &_numeric_using_locale, - &_numeric_locale_buf, "LC_NUMERIC", + ret = __part_load_locale(name, using_locale, + &loc->buffer, "LC_NUMERIC", LCNUMERIC_SIZE, LCNUMERIC_SIZE, - (const char **)&_numeric_locale); + (const char**)l); if (ret != _LDP_ERROR) - __nlocale_changed = 1; + *changed= 1; if (ret == _LDP_LOADED) { /* Can't be empty according to C99 */ - if (*_numeric_locale.decimal_point == '\0') - _numeric_locale.decimal_point = + if (*l->decimal_point == '\0') + l->decimal_point = _C_numeric_locale.decimal_point; - _numeric_locale.grouping = - __fix_locale_grouping_str(_numeric_locale.grouping); + l->grouping = + __fix_locale_grouping_str(l->grouping); } return (ret); } +int +__numeric_load_locale(const char *name) +{ + return numeric_load_locale(&__xlocale_global_numeric, + &__xlocale_global_locale.using_numeric_locale, + &__xlocale_global_locale.numeric_locale_changed, name); +} +void * +__numeric_load(const char *name, locale_t l) +{ + struct xlocale_numeric *new = calloc(sizeof(struct xlocale_numeric), 1); + new->header.header.destructor = destruct_numeric; + if (numeric_load_locale(new, &l->using_numeric_locale, + &l->numeric_locale_changed, name) == _LDP_ERROR) + { + xlocale_release(new); + return NULL; + } + return new; +} + struct lc_numeric_T * -__get_current_numeric_locale(void) +__get_current_numeric_locale(locale_t loc) { - return (_numeric_using_locale - ? &_numeric_locale + return (loc->using_numeric_locale + ? &((struct xlocale_numeric *)loc->components[XLC_NUMERIC])->locale : (struct lc_numeric_T *)&_C_numeric_locale); } diff --git a/lib/libc/locale/lnumeric.h b/lib/libc/locale/lnumeric.h index cc6965b..5088dd4 100644 --- a/lib/libc/locale/lnumeric.h +++ b/lib/libc/locale/lnumeric.h @@ -2,6 +2,11 @@ * Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -28,14 +33,20 @@ #ifndef _LNUMERIC_H_ #define _LNUMERIC_H_ +#include "xlocale_private.h" struct lc_numeric_T { const char *decimal_point; const char *thousands_sep; const char *grouping; }; +struct xlocale_numeric { + struct xlocale_component header; + char *buffer; + struct lc_numeric_T locale; +}; -struct lc_numeric_T *__get_current_numeric_locale(void); +struct lc_numeric_T *__get_current_numeric_locale(locale_t loc); int __numeric_load_locale(const char *); #endif /* !_LNUMERIC_H_ */ diff --git a/lib/libc/locale/localeconv.3 b/lib/libc/locale/localeconv.3 index c4b5746..6ebb878 100644 --- a/lib/libc/locale/localeconv.3 +++ b/lib/libc/locale/localeconv.3 @@ -44,6 +44,9 @@ .In locale.h .Ft struct lconv * .Fn localeconv "void" +.In xlocale.h +.Ft struct lconv * +.Fn localeconv_l "locale_t locale" .Sh DESCRIPTION The .Fn localeconv @@ -196,6 +199,11 @@ a value that is not in the current locale. A .Dv CHAR_MAX result similarly denotes an unavailable value. +.Pp +The +.Fn localeconv_l +function takes an explicit locale parameter. For more information, see +.Xr xlocale 3 . .Sh RETURN VALUES The .Fn localeconv @@ -204,6 +212,13 @@ which may be altered by later calls to .Xr setlocale 3 or .Fn localeconv . +The return value for +.Fn localeconv_l +is stored with the locale. It will remain valid until a subsequent call to +.Xr freelocale 3 . +If a thread-local locale is in effect then the return value from +.Fn localeconv +will remain valid until the locale is destroyed. .Sh ERRORS No errors are defined. .Sh SEE ALSO diff --git a/lib/libc/locale/localeconv.c b/lib/libc/locale/localeconv.c index fed8d35..4b19160 100644 --- a/lib/libc/locale/localeconv.c +++ b/lib/libc/locale/localeconv.c @@ -3,6 +3,11 @@ * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -48,25 +53,24 @@ __FBSDID("$FreeBSD$"); * lconv structure are computed only when the monetary or numeric * locale has been changed. */ -int __mlocale_changed = 1; -int __nlocale_changed = 1; /* * Return the current locale conversion. */ struct lconv * -localeconv() +localeconv_l(locale_t loc) { - static struct lconv ret; + FIX_LOCALE(loc); + struct lconv *ret = &loc->lconv; - if (__mlocale_changed) { + if (loc->monetary_locale_changed) { /* LC_MONETARY part */ struct lc_monetary_T * mptr; -#define M_ASSIGN_STR(NAME) (ret.NAME = (char*)mptr->NAME) -#define M_ASSIGN_CHAR(NAME) (ret.NAME = mptr->NAME[0]) +#define M_ASSIGN_STR(NAME) (ret->NAME = (char*)mptr->NAME) +#define M_ASSIGN_CHAR(NAME) (ret->NAME = mptr->NAME[0]) - mptr = __get_current_monetary_locale(); + mptr = __get_current_monetary_locale(loc); M_ASSIGN_STR(int_curr_symbol); M_ASSIGN_STR(currency_symbol); M_ASSIGN_STR(mon_decimal_point); @@ -88,21 +92,26 @@ localeconv() M_ASSIGN_CHAR(int_n_sep_by_space); M_ASSIGN_CHAR(int_p_sign_posn); M_ASSIGN_CHAR(int_n_sign_posn); - __mlocale_changed = 0; + loc->monetary_locale_changed = 0; } - if (__nlocale_changed) { + if (loc->numeric_locale_changed) { /* LC_NUMERIC part */ struct lc_numeric_T * nptr; -#define N_ASSIGN_STR(NAME) (ret.NAME = (char*)nptr->NAME) +#define N_ASSIGN_STR(NAME) (ret->NAME = (char*)nptr->NAME) - nptr = __get_current_numeric_locale(); + nptr = __get_current_numeric_locale(loc); N_ASSIGN_STR(decimal_point); N_ASSIGN_STR(thousands_sep); N_ASSIGN_STR(grouping); - __nlocale_changed = 0; + loc->numeric_locale_changed = 0; } - return (&ret); + return ret; +} +struct lconv * +localeconv(void) +{ + return localeconv_l(__get_locale()); } diff --git a/lib/libc/locale/mblen.c b/lib/libc/locale/mblen.c index 4a2cc5c..1bacf3e 100644 --- a/lib/libc/locale/mblen.c +++ b/lib/libc/locale/mblen.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,19 +37,25 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" int -mblen(const char *s, size_t n) +mblen_l(const char *s, size_t n, locale_t locale) { static const mbstate_t initial; - static mbstate_t mbs; size_t rval; + FIX_LOCALE(locale); if (s == NULL) { /* No support for state dependent encodings. */ - mbs = initial; + locale->mblen = initial; return (0); } - rval = __mbrtowc(NULL, s, n, &mbs); + rval = XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, &locale->mblen); if (rval == (size_t)-1 || rval == (size_t)-2) return (-1); return ((int)rval); } + +int +mblen(const char *s, size_t n) +{ + return mblen_l(s, n, __get_locale()); +} diff --git a/lib/libc/locale/mblocal.h b/lib/libc/locale/mblocal.h index 0faebe5..d172764 100644 --- a/lib/libc/locale/mblocal.h +++ b/lib/libc/locale/mblocal.h @@ -2,6 +2,11 @@ * Copyright (c) 2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,35 +35,45 @@ #define _MBLOCAL_H_ #include <runetype.h> +#include "xlocale_private.h" + /* - * Rune initialization function prototypes. + * Conversion function pointers for current encoding. */ -int _none_init(_RuneLocale *); -int _ascii_init(_RuneLocale *); -int _UTF8_init(_RuneLocale *); -int _EUC_init(_RuneLocale *); -int _GB18030_init(_RuneLocale *); -int _GB2312_init(_RuneLocale *); -int _GBK_init(_RuneLocale *); -int _BIG5_init(_RuneLocale *); -int _MSKanji_init(_RuneLocale *); +struct xlocale_ctype { + struct xlocale_component header; + _RuneLocale *runes; + size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict, + size_t, mbstate_t * __restrict); + int (*__mbsinit)(const mbstate_t *); + size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict, + size_t, size_t, mbstate_t * __restrict); + size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict); + size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict, + size_t, size_t, mbstate_t * __restrict); + int __mb_cur_max; + int __mb_sb_limit; +}; +#define XLOCALE_CTYPE(x) ((struct xlocale_ctype*)(x)->components[XLC_CTYPE]) +extern struct xlocale_ctype __xlocale_global_ctype; /* - * Conversion function pointers for current encoding. + * Rune initialization function prototypes. */ -extern size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict, - size_t, mbstate_t * __restrict); -extern int (*__mbsinit)(const mbstate_t *); -extern size_t (*__mbsnrtowcs)(wchar_t * __restrict, const char ** __restrict, - size_t, size_t, mbstate_t * __restrict); -extern size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict); -extern size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict, - size_t, size_t, mbstate_t * __restrict); +int _none_init(struct xlocale_ctype *, _RuneLocale *); +int _ascii_init(struct xlocale_ctype *, _RuneLocale *); +int _UTF8_init(struct xlocale_ctype *, _RuneLocale *); +int _EUC_init(struct xlocale_ctype *, _RuneLocale *); +int _GB18030_init(struct xlocale_ctype *, _RuneLocale *); +int _GB2312_init(struct xlocale_ctype *, _RuneLocale *); +int _GBK_init(struct xlocale_ctype *, _RuneLocale *); +int _BIG5_init(struct xlocale_ctype *, _RuneLocale *); +int _MSKanji_init(struct xlocale_ctype *, _RuneLocale *); extern size_t __mbsnrtowcs_std(wchar_t * __restrict, const char ** __restrict, - size_t, size_t, mbstate_t * __restrict); + size_t, size_t, mbstate_t * __restrict); extern size_t __wcsnrtombs_std(char * __restrict, const wchar_t ** __restrict, - size_t, size_t, mbstate_t * __restrict); + size_t, size_t, mbstate_t * __restrict); #endif /* _MBLOCAL_H_ */ diff --git a/lib/libc/locale/mbrlen.c b/lib/libc/locale/mbrlen.c index b4c3a04..9ce0bc0 100644 --- a/lib/libc/locale/mbrlen.c +++ b/lib/libc/locale/mbrlen.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -31,11 +36,16 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" size_t -mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps) +mbrlen_l(const char * __restrict s, size_t n, mbstate_t * __restrict ps, locale_t locale) { - static mbstate_t mbs; - + FIX_LOCALE(locale); if (ps == NULL) - ps = &mbs; - return (__mbrtowc(NULL, s, n, ps)); + ps = &locale->mbrlen; + return (XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, ps)); +} + +size_t +mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps) +{ + return mbrlen_l(s, n, ps, __get_locale()); } diff --git a/lib/libc/locale/mbrtowc.c b/lib/libc/locale/mbrtowc.c index 42d5f7a..8f1aebd 100644 --- a/lib/libc/locale/mbrtowc.c +++ b/lib/libc/locale/mbrtowc.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -31,12 +36,18 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" size_t +mbrtowc_l(wchar_t * __restrict pwc, const char * __restrict s, + size_t n, mbstate_t * __restrict ps, locale_t locale) +{ + FIX_LOCALE(locale); + if (ps == NULL) + ps = &locale->mbrtowc; + return (XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, ps)); +} + +size_t mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n, mbstate_t * __restrict ps) { - static mbstate_t mbs; - - if (ps == NULL) - ps = &mbs; - return (__mbrtowc(pwc, s, n, ps)); + return mbrtowc_l(pwc, s, n, ps, __get_locale()); } diff --git a/lib/libc/locale/mbsinit.c b/lib/libc/locale/mbsinit.c index 24408c7..be44fe5 100644 --- a/lib/libc/locale/mbsinit.c +++ b/lib/libc/locale/mbsinit.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -31,8 +36,13 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" int +mbsinit_l(const mbstate_t *ps, locale_t locale) +{ + FIX_LOCALE(locale); + return (XLOCALE_CTYPE(locale)->__mbsinit(ps)); +} +int mbsinit(const mbstate_t *ps) { - - return (__mbsinit(ps)); + return mbsinit_l(ps, __get_locale()); } diff --git a/lib/libc/locale/mbsnrtowcs.c b/lib/libc/locale/mbsnrtowcs.c index 5284087..15b48dd7 100644 --- a/lib/libc/locale/mbsnrtowcs.c +++ b/lib/libc/locale/mbsnrtowcs.c @@ -1,5 +1,10 @@ /*- * Copyright (c) 2002-2004 Tim J. Robbins. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,14 +39,19 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" size_t +mbsnrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src, + size_t nms, size_t len, mbstate_t * __restrict ps, locale_t locale) +{ + FIX_LOCALE(locale); + if (ps == NULL) + ps = &locale->mbsnrtowcs; + return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, nms, len, ps)); +} +size_t mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t nms, size_t len, mbstate_t * __restrict ps) { - static mbstate_t mbs; - - if (ps == NULL) - ps = &mbs; - return (__mbsnrtowcs(dst, src, nms, len, ps)); + return mbsnrtowcs_l(dst, src, nms, len, ps, __get_locale()); } size_t @@ -52,13 +62,14 @@ __mbsnrtowcs_std(wchar_t * __restrict dst, const char ** __restrict src, size_t nchr; wchar_t wc; size_t nb; + struct xlocale_ctype *ct = XLOCALE_CTYPE(__get_locale()); s = *src; nchr = 0; if (dst == NULL) { for (;;) { - if ((nb = __mbrtowc(&wc, s, nms, ps)) == (size_t)-1) + if ((nb = ct->__mbrtowc(&wc, s, nms, ps)) == (size_t)-1) /* Invalid sequence - mbrtowc() sets errno. */ return ((size_t)-1); else if (nb == 0 || nb == (size_t)-2) @@ -71,7 +82,7 @@ __mbsnrtowcs_std(wchar_t * __restrict dst, const char ** __restrict src, } while (len-- > 0) { - if ((nb = __mbrtowc(dst, s, nms, ps)) == (size_t)-1) { + if ((nb = ct->__mbrtowc(dst, s, nms, ps)) == (size_t)-1) { *src = s; return ((size_t)-1); } else if (nb == (size_t)-2) { diff --git a/lib/libc/locale/mbsrtowcs.c b/lib/libc/locale/mbsrtowcs.c index 1239c82..9032b94 100644 --- a/lib/libc/locale/mbsrtowcs.c +++ b/lib/libc/locale/mbsrtowcs.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,12 +39,17 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" size_t +mbsrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src, size_t len, + mbstate_t * __restrict ps, locale_t locale) +{ + FIX_LOCALE(locale); + if (ps == NULL) + ps = &locale->mbsrtowcs; + return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, SIZE_T_MAX, len, ps)); +} +size_t mbsrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t len, mbstate_t * __restrict ps) { - static mbstate_t mbs; - - if (ps == NULL) - ps = &mbs; - return (__mbsnrtowcs(dst, src, SIZE_T_MAX, len, ps)); + return mbsrtowcs_l(dst, src, len, ps, __get_locale()); } diff --git a/lib/libc/locale/mbstowcs.c b/lib/libc/locale/mbstowcs.c index 194ec2e..6905d2e 100644 --- a/lib/libc/locale/mbstowcs.c +++ b/lib/libc/locale/mbstowcs.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,13 +38,19 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" size_t -mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n) +mbstowcs_l(wchar_t * __restrict pwcs, const char * __restrict s, size_t n, locale_t locale) { static const mbstate_t initial; mbstate_t mbs; const char *sp; + FIX_LOCALE(locale); mbs = initial; sp = s; - return (__mbsnrtowcs(pwcs, &sp, SIZE_T_MAX, n, &mbs)); + return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(pwcs, &sp, SIZE_T_MAX, n, &mbs)); +} +size_t +mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n) +{ + return mbstowcs_l(pwcs, s, n, __get_locale()); } diff --git a/lib/libc/locale/mbtowc.c b/lib/libc/locale/mbtowc.c index ad5b735..70fc19e 100644 --- a/lib/libc/locale/mbtowc.c +++ b/lib/libc/locale/mbtowc.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,19 +37,24 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" int -mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n) +mbtowc_l(wchar_t * __restrict pwc, const char * __restrict s, size_t n, locale_t locale) { static const mbstate_t initial; - static mbstate_t mbs; size_t rval; + FIX_LOCALE(locale); if (s == NULL) { /* No support for state dependent encodings. */ - mbs = initial; + locale->mbtowc = initial; return (0); } - rval = __mbrtowc(pwc, s, n, &mbs); + rval = XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, &locale->mbtowc); if (rval == (size_t)-1 || rval == (size_t)-2) return (-1); return ((int)rval); } +int +mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n) +{ + return mbtowc_l(pwc, s, n, __get_locale()); +} diff --git a/lib/libc/locale/mskanji.c b/lib/libc/locale/mskanji.c index 9ee91de..9fdd080 100644 --- a/lib/libc/locale/mskanji.c +++ b/lib/libc/locale/mskanji.c @@ -6,6 +6,11 @@ * (C) Sin'ichiro MIYATANI / Phase One, Inc * May 12, 1995 * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -60,15 +65,15 @@ typedef struct { } _MSKanjiState; int -_MSKanji_init(_RuneLocale *rl) +_MSKanji_init(struct xlocale_ctype *l, _RuneLocale *rl) { - __mbrtowc = _MSKanji_mbrtowc; - __wcrtomb = _MSKanji_wcrtomb; - __mbsinit = _MSKanji_mbsinit; - _CurrentRuneLocale = rl; - __mb_cur_max = 2; - __mb_sb_limit = 256; + l->__mbrtowc = _MSKanji_mbrtowc; + l->__wcrtomb = _MSKanji_wcrtomb; + l->__mbsinit = _MSKanji_mbsinit; + l->runes = rl; + l->__mb_cur_max = 2; + l->__mb_sb_limit = 256; return (0); } diff --git a/lib/libc/locale/newlocale.3 b/lib/libc/locale/newlocale.3 new file mode 100644 index 0000000..b351f99 --- /dev/null +++ b/lib/libc/locale/newlocale.3 @@ -0,0 +1,109 @@ +.\" Copyright (c) 2011 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by David Chisnall under sponsorship from +.\" the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.Dd September 17 2011 +.Dt newlocale 3 +.Os +.Sh NAME +.Nm newlocale +.Nd Creates a new locale +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In xlocale +.Ft +.Fn newlocale "int mask" "const char * locale" "locale_t base" +.Sh DESCRIPTION +Creates a new locale, inheriting some properties from an existing locale. The +.Fa mask +defines the components that the new locale will have set to the locale with the +name specified in the +.Fa locale +parameter. Any other components will be inherited from +.Fa base . +.Pt +The +.Fa mask +is either +.Fa LC_ALL_MASK, +indicating all possible locale components, or the logical OR of some +combination of the following: +.Bl -tag -width "LC_MESSAGES_MASK" -offset indent +.It LC_COLLATE_MASK +The locale for string collation routines. This controls alphabetic ordering in +.Xr strcoll 3 + and +.Xr strxfrm 3 . +.It LC_CTYPE_MASK +The locale for the +.Xr ctype 3 +and +.Xr multibyte 3 +functions. This controls recognition of upper and lower case, alpha- betic or +non-alphabetic characters, and so on. +.It LC_MESSAGES_MASK +Set a locale for message catalogs, see +.Xr catopen 3 +function. +.It LC_MONETARY_MASK +Set a locale for formatting monetary values; this affects +the +.Xr localeconv 3 +function. +.It LC_NUMERIC_MASK +Set a locale for formatting numbers. This controls the for- +matting of decimal points in input and output of floating +point numbers in functions such as +.Xr printf 3 +and +.Xr scanf 3 , +as well as values returned by +.Xr localeconv 3 . +.It LC_TIME_MASK +Set a locale for formatting dates and times using the +.Xr strftime 3 +function. +.El + +This function uses the same rules for loading locale components as +.Xr setlocale 3 . +.Sh RETURN VALUES +Returns a new, valid, +.Fa locale_t +or NULL if an error occurs. You must free the returned locale with +.Xr freelocale 3 . +.Sh SEE ALSO +.Xr duplocale 3 , +.Xr freelocale 3 , +.Xr localeconv 3 , +.Xr querylocale 3 , +.Xr uselocale 3 , +.Xr xlocale 3 +.Sh STANDARDS +This function, conforms to +.St -p1003.1-2008 diff --git a/lib/libc/locale/nextwctype.c b/lib/libc/locale/nextwctype.c index 9363b0a..9fc8ce0 100644 --- a/lib/libc/locale/nextwctype.c +++ b/lib/libc/locale/nextwctype.c @@ -2,6 +2,11 @@ * Copyright (c) 2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,12 +35,15 @@ __FBSDID("$FreeBSD$"); #include <runetype.h> #include <wchar.h> #include <wctype.h> +#include "mblocal.h" wint_t -nextwctype(wint_t wc, wctype_t wct) +nextwctype_l(wint_t wc, wctype_t wct, locale_t locale) { size_t lim; - _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext; + FIX_LOCALE(locale); + _RuneLocale *runes = XLOCALE_CTYPE(locale)->runes; + _RuneRange *rr = &runes->__runetype_ext; _RuneEntry *base, *re; int noinc; @@ -43,7 +51,7 @@ nextwctype(wint_t wc, wctype_t wct) if (wc < _CACHED_RUNES) { wc++; while (wc < _CACHED_RUNES) { - if (_CurrentRuneLocale->__runetype[wc] & wct) + if (runes->__runetype[wc] & wct) return (wc); wc++; } @@ -88,3 +96,8 @@ found: } return (-1); } +wint_t +nextwctype(wint_t wc, wctype_t wct) +{ + return nextwctype_l(wc, wct, __get_locale()); +} diff --git a/lib/libc/locale/nl_langinfo.c b/lib/libc/locale/nl_langinfo.c index 26ca025..3e8fe7c 100644 --- a/lib/libc/locale/nl_langinfo.c +++ b/lib/libc/locale/nl_langinfo.c @@ -2,6 +2,11 @@ * Copyright (c) 2001, 2003 Alexey Zelkin <phantom@FreeBSD.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,15 +46,16 @@ __FBSDID("$FreeBSD$"); #define _REL(BASE) ((int)item-BASE) char * -nl_langinfo(nl_item item) +nl_langinfo_l(nl_item item, locale_t loc) { - char *ret, *s, *cs; - static char *csym = NULL; + char *ret, *cs; + const char *s; + FIX_LOCALE(loc); switch (item) { case CODESET: ret = ""; - if ((s = setlocale(LC_CTYPE, NULL)) != NULL) { + if ((s = querylocale(LC_CTYPE_MASK, loc)) != NULL) { if ((cs = strchr(s, '.')) != NULL) ret = cs + 1; else if (strcmp(s, "C") == 0 || @@ -58,46 +64,46 @@ nl_langinfo(nl_item item) } break; case D_T_FMT: - ret = (char *) __get_current_time_locale()->c_fmt; + ret = (char *) __get_current_time_locale(loc)->c_fmt; break; case D_FMT: - ret = (char *) __get_current_time_locale()->x_fmt; + ret = (char *) __get_current_time_locale(loc)->x_fmt; break; case T_FMT: - ret = (char *) __get_current_time_locale()->X_fmt; + ret = (char *) __get_current_time_locale(loc)->X_fmt; break; case T_FMT_AMPM: - ret = (char *) __get_current_time_locale()->ampm_fmt; + ret = (char *) __get_current_time_locale(loc)->ampm_fmt; break; case AM_STR: - ret = (char *) __get_current_time_locale()->am; + ret = (char *) __get_current_time_locale(loc)->am; break; case PM_STR: - ret = (char *) __get_current_time_locale()->pm; + ret = (char *) __get_current_time_locale(loc)->pm; break; case DAY_1: case DAY_2: case DAY_3: case DAY_4: case DAY_5: case DAY_6: case DAY_7: - ret = (char*) __get_current_time_locale()->weekday[_REL(DAY_1)]; + ret = (char*) __get_current_time_locale(loc)->weekday[_REL(DAY_1)]; break; case ABDAY_1: case ABDAY_2: case ABDAY_3: case ABDAY_4: case ABDAY_5: case ABDAY_6: case ABDAY_7: - ret = (char*) __get_current_time_locale()->wday[_REL(ABDAY_1)]; + ret = (char*) __get_current_time_locale(loc)->wday[_REL(ABDAY_1)]; break; case MON_1: case MON_2: case MON_3: case MON_4: case MON_5: case MON_6: case MON_7: case MON_8: case MON_9: case MON_10: case MON_11: case MON_12: - ret = (char*) __get_current_time_locale()->month[_REL(MON_1)]; + ret = (char*) __get_current_time_locale(loc)->month[_REL(MON_1)]; break; case ABMON_1: case ABMON_2: case ABMON_3: case ABMON_4: case ABMON_5: case ABMON_6: case ABMON_7: case ABMON_8: case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12: - ret = (char*) __get_current_time_locale()->mon[_REL(ABMON_1)]; + ret = (char*) __get_current_time_locale(loc)->mon[_REL(ABMON_1)]; break; case ALTMON_1: case ALTMON_2: case ALTMON_3: case ALTMON_4: case ALTMON_5: case ALTMON_6: case ALTMON_7: case ALTMON_8: case ALTMON_9: case ALTMON_10: case ALTMON_11: case ALTMON_12: ret = (char*) - __get_current_time_locale()->alt_month[_REL(ALTMON_1)]; + __get_current_time_locale(loc)->alt_month[_REL(ALTMON_1)]; break; case ERA: /* XXX: need to be implemented */ @@ -120,16 +126,16 @@ nl_langinfo(nl_item item) ret = ""; break; case RADIXCHAR: - ret = (char*) __get_current_numeric_locale()->decimal_point; + ret = (char*) __get_current_numeric_locale(loc)->decimal_point; break; case THOUSEP: - ret = (char*) __get_current_numeric_locale()->thousands_sep; + ret = (char*) __get_current_numeric_locale(loc)->thousands_sep; break; case YESEXPR: - ret = (char*) __get_current_messages_locale()->yesexpr; + ret = (char*) __get_current_messages_locale(loc)->yesexpr; break; case NOEXPR: - ret = (char*) __get_current_messages_locale()->noexpr; + ret = (char*) __get_current_messages_locale(loc)->noexpr; break; /* * YESSTR and NOSTR items marked with LEGACY are available, but not @@ -137,45 +143,51 @@ nl_langinfo(nl_item item) * they're subject to remove in future specification editions. */ case YESSTR: /* LEGACY */ - ret = (char*) __get_current_messages_locale()->yesstr; + ret = (char*) __get_current_messages_locale(loc)->yesstr; break; case NOSTR: /* LEGACY */ - ret = (char*) __get_current_messages_locale()->nostr; + ret = (char*) __get_current_messages_locale(loc)->nostr; break; /* * SUSv2 special formatted currency string */ case CRNCYSTR: ret = ""; - cs = (char*) __get_current_monetary_locale()->currency_symbol; + cs = (char*) __get_current_monetary_locale(loc)->currency_symbol; if (*cs != '\0') { - char pos = localeconv()->p_cs_precedes; + char pos = localeconv_l(loc)->p_cs_precedes; - if (pos == localeconv()->n_cs_precedes) { + if (pos == localeconv_l(loc)->n_cs_precedes) { char psn = '\0'; if (pos == CHAR_MAX) { - if (strcmp(cs, __get_current_monetary_locale()->mon_decimal_point) == 0) + if (strcmp(cs, __get_current_monetary_locale(loc)->mon_decimal_point) == 0) psn = '.'; } else psn = pos ? '-' : '+'; if (psn != '\0') { int clen = strlen(cs); - if ((csym = reallocf(csym, clen + 2)) != NULL) { - *csym = psn; - strcpy(csym + 1, cs); - ret = csym; + if ((loc->csym = reallocf(loc->csym, clen + 2)) != NULL) { + *loc->csym = psn; + strcpy(loc->csym + 1, cs); + ret = loc->csym; } } } } break; case D_MD_ORDER: /* FreeBSD local extension */ - ret = (char *) __get_current_time_locale()->md_order; + ret = (char *) __get_current_time_locale(loc)->md_order; break; default: ret = ""; } return (ret); } + +char * +nl_langinfo(nl_item item) +{ + return nl_langinfo_l(item, __get_locale()); +} diff --git a/lib/libc/locale/none.c b/lib/libc/locale/none.c index 22fcd20..75adffa 100644 --- a/lib/libc/locale/none.c +++ b/lib/libc/locale/none.c @@ -6,6 +6,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -64,17 +69,17 @@ int __mb_cur_max = 1; int __mb_sb_limit = 256; /* Expected to be <= _CACHED_RUNES */ int -_none_init(_RuneLocale *rl) +_none_init(struct xlocale_ctype *l, _RuneLocale *rl) { - __mbrtowc = _none_mbrtowc; - __mbsinit = _none_mbsinit; - __mbsnrtowcs = _none_mbsnrtowcs; - __wcrtomb = _none_wcrtomb; - __wcsnrtombs = _none_wcsnrtombs; - _CurrentRuneLocale = rl; - __mb_cur_max = 1; - __mb_sb_limit = 256; + l->__mbrtowc = _none_mbrtowc; + l->__mbsinit = _none_mbsinit; + l->__mbsnrtowcs = _none_mbsnrtowcs; + l->__wcrtomb = _none_wcrtomb; + l->__wcsnrtombs = _none_wcsnrtombs; + l->runes = rl; + l->__mb_cur_max = 1; + l->__mb_sb_limit = 256; return(0); } @@ -192,3 +197,26 @@ size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict) = size_t (*__wcsnrtombs)(char * __restrict, const wchar_t ** __restrict, size_t, size_t, mbstate_t * __restrict) = _none_wcsnrtombs; +struct xlocale_ctype __xlocale_global_ctype = { + {{0}, "C"}, + (_RuneLocale*)&_DefaultRuneLocale, + _none_mbrtowc, + _none_mbsinit, + _none_mbsnrtowcs, + _none_wcrtomb, + _none_wcsnrtombs, + 1, /* __mb_cur_max, */ + 256 /* __mb_sb_limit */ +}; + +const struct xlocale_ctype __xlocale_C_ctype = { + {{0}, "C"}, + (_RuneLocale*)&_DefaultRuneLocale, + _none_mbrtowc, + _none_mbsinit, + _none_mbsnrtowcs, + _none_wcrtomb, + _none_wcsnrtombs, + 1, /* __mb_cur_max, */ + 256 /* __mb_sb_limit */ +}; diff --git a/lib/libc/locale/querylocale.3 b/lib/libc/locale/querylocale.3 new file mode 100644 index 0000000..ceb4da0 --- /dev/null +++ b/lib/libc/locale/querylocale.3 @@ -0,0 +1,57 @@ +.\" Copyright (c) 2011 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by David Chisnall under sponsorship from +.\" the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 17 2011 +.Dt QUERYLOCALE 3 +.Os +.Sh NAME +.Nm querylocale +.Nd Look up the locale name for a specified category. +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In xlocale.h +.Ft const char * +.Fn querylocale "int mask" "locale_t locale" +.Sh DESCRIPTION +Returns the name of the locale for the category specified by +.Fa mask. +This possible values for the mask are the same as those in +.Xr newlocale 3 . If more than one bit in the mask is set, the returned value +is undefined. +.Sh SEE ALSO +.Xr duplocale 3 , +.Xr freelocale 3 , +.Xr localeconv 3 , +.Xr newlocale 3 , +.Xr uselocale 3 , +.Xr xlocale 3 +.Sh STANDARDS +This function, conforms to +.St -p1003.1-2008 diff --git a/lib/libc/locale/runetype.c b/lib/libc/locale/runetype.c index 5765b85..a0da47b 100644 --- a/lib/libc/locale/runetype.c +++ b/lib/libc/locale/runetype.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -36,12 +41,15 @@ __FBSDID("$FreeBSD$"); #include <ctype.h> #include <stdio.h> #include <runetype.h> +#include <wchar.h> +#include "mblocal.h" unsigned long -___runetype(__ct_rune_t c) +___runetype_l(__ct_rune_t c, locale_t locale) { size_t lim; - _RuneRange *rr = &_CurrentRuneLocale->__runetype_ext; + FIX_LOCALE(locale); + _RuneRange *rr = &(XLOCALE_CTYPE(locale)->runes->__runetype_ext); _RuneEntry *base, *re; if (c < 0 || c == EOF) @@ -64,3 +72,18 @@ ___runetype(__ct_rune_t c) return(0L); } +unsigned long +___runetype(__ct_rune_t c) +{ + return ___runetype_l(c, __get_locale()); +} + +int ___mb_cur_max(void) +{ + return XLOCALE_CTYPE(__get_locale())->__mb_cur_max; +} +int ___mb_cur_max_l(locale_t locale) +{ + FIX_LOCALE(locale); + return XLOCALE_CTYPE(locale)->__mb_cur_max; +} diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c index d6db181..8cf8fd4 100644 --- a/lib/libc/locale/setlocale.c +++ b/lib/libc/locale/setlocale.c @@ -95,7 +95,7 @@ static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)]; static char *currentlocale(void); static char *loadlocale(int); -static const char *__get_locale_env(int); +const char *__get_locale_env(int); char * setlocale(category, locale) @@ -278,13 +278,14 @@ loadlocale(category) if (func(new) != _LDP_ERROR) { (void)strcpy(old, new); + (void)strcpy(__xlocale_global_locale.components[category-1]->locale, new); return (old); } return (NULL); } -static const char * +const char * __get_locale_env(category) int category; { diff --git a/lib/libc/locale/setrunelocale.c b/lib/libc/locale/setrunelocale.c index 36d2894..61ce5d9 100644 --- a/lib/libc/locale/setrunelocale.c +++ b/lib/libc/locale/setrunelocale.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -49,68 +54,46 @@ extern int __mb_sb_limit; extern _RuneLocale *_Read_RuneMagi(FILE *); -static int __setrunelocale(const char *); +static int __setrunelocale(struct xlocale_ctype *l, const char *); + +#define __collate_load_error (table->__collate_load_error) +#define __collate_substitute_nontrivial (table->__collate_substitute_nontrivial) +#define __collate_substitute_table_ptr (table->__collate_substitute_table_ptr) +#define __collate_char_pri_table_ptr (table->__collate_char_pri_table_ptr) +#define __collate_chain_pri_table (table->__collate_chain_pri_table) + + +static void destruct_ctype(void *v) +{ + struct xlocale_ctype *l = v; + if (strcmp(l->runes->__encoding, "EUC") == 0) + free(l->runes->__variable); + if (&_DefaultRuneLocale != l->runes) + free(l->runes); + free(l); +} +_RuneLocale *__getCurrentRuneLocale(void) +{ + return XLOCALE_CTYPE(__get_locale())->runes; +} static int -__setrunelocale(const char *encoding) +__setrunelocale(struct xlocale_ctype *l, const char *encoding) { FILE *fp; char name[PATH_MAX]; _RuneLocale *rl; int saverr, ret; - size_t (*old__mbrtowc)(wchar_t * __restrict, - const char * __restrict, size_t, mbstate_t * __restrict); - size_t (*old__wcrtomb)(char * __restrict, wchar_t, - mbstate_t * __restrict); - int (*old__mbsinit)(const mbstate_t *); - size_t (*old__mbsnrtowcs)(wchar_t * __restrict, - const char ** __restrict, size_t, size_t, mbstate_t * __restrict); - size_t (*old__wcsnrtombs)(char * __restrict, - const wchar_t ** __restrict, size_t, size_t, - mbstate_t * __restrict); - static char ctype_encoding[ENCODING_LEN + 1]; - static _RuneLocale *CachedRuneLocale; - static int Cached__mb_cur_max; - static int Cached__mb_sb_limit; - static size_t (*Cached__mbrtowc)(wchar_t * __restrict, - const char * __restrict, size_t, mbstate_t * __restrict); - static size_t (*Cached__wcrtomb)(char * __restrict, wchar_t, - mbstate_t * __restrict); - static int (*Cached__mbsinit)(const mbstate_t *); - static size_t (*Cached__mbsnrtowcs)(wchar_t * __restrict, - const char ** __restrict, size_t, size_t, mbstate_t * __restrict); - static size_t (*Cached__wcsnrtombs)(char * __restrict, - const wchar_t ** __restrict, size_t, size_t, - mbstate_t * __restrict); + struct xlocale_ctype saved = *l; /* * The "C" and "POSIX" locale are always here. */ if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) { - (void) _none_init(&_DefaultRuneLocale); + (void) _none_init(l, (_RuneLocale*)&_DefaultRuneLocale); return (0); } - /* - * If the locale name is the same as our cache, use the cache. - */ - if (CachedRuneLocale != NULL && - strcmp(encoding, ctype_encoding) == 0) { - _CurrentRuneLocale = CachedRuneLocale; - __mb_cur_max = Cached__mb_cur_max; - __mb_sb_limit = Cached__mb_sb_limit; - __mbrtowc = Cached__mbrtowc; - __mbsinit = Cached__mbsinit; - __mbsnrtowcs = Cached__mbsnrtowcs; - __wcrtomb = Cached__wcrtomb; - __wcsnrtombs = Cached__wcsnrtombs; - return (0); - } - - /* - * Slurp the locale file into the cache. - */ - /* Range checking not needed, encoding length already checked before */ (void) strcpy(name, _PathLocale); (void) strcat(name, "/"); @@ -127,63 +110,47 @@ __setrunelocale(const char *encoding) } (void)fclose(fp); - old__mbrtowc = __mbrtowc; - old__mbsinit = __mbsinit; - old__mbsnrtowcs = __mbsnrtowcs; - old__wcrtomb = __wcrtomb; - old__wcsnrtombs = __wcsnrtombs; - - __mbrtowc = NULL; - __mbsinit = NULL; - __mbsnrtowcs = __mbsnrtowcs_std; - __wcrtomb = NULL; - __wcsnrtombs = __wcsnrtombs_std; + l->__mbrtowc = NULL; + l->__mbsinit = NULL; + l->__mbsnrtowcs = __mbsnrtowcs_std; + l->__wcrtomb = NULL; + l->__wcsnrtombs = __wcsnrtombs_std; rl->__sputrune = NULL; rl->__sgetrune = NULL; if (strcmp(rl->__encoding, "NONE") == 0) - ret = _none_init(rl); + ret = _none_init(l, rl); else if (strcmp(rl->__encoding, "ASCII") == 0) - ret = _ascii_init(rl); + ret = _ascii_init(l, rl); else if (strcmp(rl->__encoding, "UTF-8") == 0) - ret = _UTF8_init(rl); + ret = _UTF8_init(l, rl); else if (strcmp(rl->__encoding, "EUC") == 0) - ret = _EUC_init(rl); + ret = _EUC_init(l, rl); else if (strcmp(rl->__encoding, "GB18030") == 0) - ret = _GB18030_init(rl); + ret = _GB18030_init(l, rl); else if (strcmp(rl->__encoding, "GB2312") == 0) - ret = _GB2312_init(rl); + ret = _GB2312_init(l, rl); else if (strcmp(rl->__encoding, "GBK") == 0) - ret = _GBK_init(rl); + ret = _GBK_init(l, rl); else if (strcmp(rl->__encoding, "BIG5") == 0) - ret = _BIG5_init(rl); + ret = _BIG5_init(l, rl); else if (strcmp(rl->__encoding, "MSKanji") == 0) - ret = _MSKanji_init(rl); + ret = _MSKanji_init(l, rl); else ret = EFTYPE; if (ret == 0) { - if (CachedRuneLocale != NULL) { - /* See euc.c */ - if (strcmp(CachedRuneLocale->__encoding, "EUC") == 0) - free(CachedRuneLocale->__variable); - free(CachedRuneLocale); + /* Free the old runes if it exists. */ + /* FIXME: The "EUC" check here is a hideous abstraction violation. */ + if ((saved.runes != &_DefaultRuneLocale) && (saved.runes)) { + if (strcmp(saved.runes->__encoding, "EUC") == 0) { + free(saved.runes->__variable); + } + free(saved.runes); } - CachedRuneLocale = _CurrentRuneLocale; - Cached__mb_cur_max = __mb_cur_max; - Cached__mb_sb_limit = __mb_sb_limit; - Cached__mbrtowc = __mbrtowc; - Cached__mbsinit = __mbsinit; - Cached__mbsnrtowcs = __mbsnrtowcs; - Cached__wcrtomb = __wcrtomb; - Cached__wcsnrtombs = __wcsnrtombs; - (void)strcpy(ctype_encoding, encoding); } else { - __mbrtowc = old__mbrtowc; - __mbsinit = old__mbsinit; - __mbsnrtowcs = old__mbsnrtowcs; - __wcrtomb = old__wcrtomb; - __wcsnrtombs = old__wcsnrtombs; + /* Restore the saved version if this failed. */ + memcpy(l, &saved, sizeof(struct xlocale_ctype)); free(rl); } @@ -193,12 +160,24 @@ __setrunelocale(const char *encoding) int __wrap_setrunelocale(const char *locale) { - int ret = __setrunelocale(locale); + int ret = __setrunelocale(&__xlocale_global_ctype, locale); if (ret != 0) { errno = ret; return (_LDP_ERROR); } + __mb_cur_max = __xlocale_global_ctype.__mb_cur_max; + __mb_sb_limit = __xlocale_global_ctype.__mb_sb_limit; return (_LDP_LOADED); } - +void *__ctype_load(const char *locale, locale_t unused) +{ + struct xlocale_ctype *l = calloc(sizeof(struct xlocale_ctype), 1); + l->header.header.destructor = destruct_ctype; + if (__setrunelocale(l, locale)) + { + free(l); + return NULL; + } + return l; +} diff --git a/lib/libc/locale/table.c b/lib/libc/locale/table.c index e1f49d1..8c876e9 100644 --- a/lib/libc/locale/table.c +++ b/lib/libc/locale/table.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,7 +46,7 @@ __FBSDID("$FreeBSD$"); #include <wchar.h> #include "mblocal.h" -_RuneLocale _DefaultRuneLocale = { +const _RuneLocale _DefaultRuneLocale = { _RUNE_MAGIC_1, "NONE", NULL, @@ -245,5 +250,14 @@ _RuneLocale _DefaultRuneLocale = { }, }; -_RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale; +#undef _CurrentRuneLocale +_RuneLocale *_CurrentRuneLocale = (_RuneLocale*)&_DefaultRuneLocale; +_RuneLocale * +__runes_for_locale(locale_t locale, int *mb_sb_limit) +{ + FIX_LOCALE(locale); + struct xlocale_ctype *c = XLOCALE_CTYPE(locale); + *mb_sb_limit = c->__mb_sb_limit; + return c->runes; +} diff --git a/lib/libc/locale/tolower.c b/lib/libc/locale/tolower.c index 82a78cf..f2eb483 100644 --- a/lib/libc/locale/tolower.c +++ b/lib/libc/locale/tolower.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -36,13 +41,17 @@ __FBSDID("$FreeBSD$"); #include <ctype.h> #include <stdio.h> #include <runetype.h> +#include <wchar.h> +#include "mblocal.h" __ct_rune_t -___tolower(c) +___tolower_l(c, l) __ct_rune_t c; + locale_t l; { size_t lim; - _RuneRange *rr = &_CurrentRuneLocale->__maplower_ext; + FIX_LOCALE(l); + _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext; _RuneEntry *base, *re; if (c < 0 || c == EOF) @@ -62,3 +71,9 @@ ___tolower(c) return(c); } +__ct_rune_t +___tolower(c) + __ct_rune_t c; +{ + return ___tolower_l(c, __get_locale()); +} diff --git a/lib/libc/locale/toupper.c b/lib/libc/locale/toupper.c index 4870e8e..d3a4fa3 100644 --- a/lib/libc/locale/toupper.c +++ b/lib/libc/locale/toupper.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -36,13 +41,17 @@ __FBSDID("$FreeBSD$"); #include <ctype.h> #include <stdio.h> #include <runetype.h> +#include <wchar.h> +#include "mblocal.h" __ct_rune_t -___toupper(c) +___toupper_l(c, l) __ct_rune_t c; + locale_t l; { size_t lim; - _RuneRange *rr = &_CurrentRuneLocale->__mapupper_ext; + FIX_LOCALE(l); + _RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext; _RuneEntry *base, *re; if (c < 0 || c == EOF) @@ -53,7 +62,9 @@ ___toupper(c) for (lim = rr->__nranges; lim != 0; lim >>= 1) { re = base + (lim >> 1); if (re->__min <= c && c <= re->__max) + { return (re->__map + c - re->__min); + } else if (c > re->__max) { base = re + 1; lim--; @@ -62,3 +73,9 @@ ___toupper(c) return(c); } +__ct_rune_t +___toupper(c) + __ct_rune_t c; +{ + return ___toupper_l(c, __get_locale()); +} diff --git a/lib/libc/locale/uselocale.3 b/lib/libc/locale/uselocale.3 new file mode 100644 index 0000000..a7068b4 --- /dev/null +++ b/lib/libc/locale/uselocale.3 @@ -0,0 +1,59 @@ +.\" Copyright (c) 2011 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by David Chisnall under sponsorship from +.\" the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 17 2011 +.Dt USELOCALE 3 +.Os +.Sh NAME +.Nm uselocale +.Nd Sets a thread-local locale. +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In xlocale.h +.Ft locale_t +.Fn uselocale "locale_t locale" +.Sh DESCRIPTION +Specifies the locale for this thread to use. Specifying +.Fa LC_GLOBAL_LOCALE +disables the per-thread locale, while NULL returns the current locale without +setting a new one. +.Sh RETURN VALUES +Returns the previous locale, or LC_GLOBAL_LOCALE if this thread has no locale +associated with it. +.Sh SEE ALSO +.Xr duplocale 3 , +.Xr freelocale 3 , +.Xr localeconv 3 , +.Xr newlocale 3 , +.Xr querylocale 3 , +.Xr xlocale 3 +.Sh STANDARDS +This function, conforms to +.St -p1003.1-2008 diff --git a/lib/libc/locale/utf8.c b/lib/libc/locale/utf8.c index 0ccadd3..40f0e17 100644 --- a/lib/libc/locale/utf8.c +++ b/lib/libc/locale/utf8.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -55,22 +60,22 @@ typedef struct { } _UTF8State; int -_UTF8_init(_RuneLocale *rl) +_UTF8_init(struct xlocale_ctype *l, _RuneLocale *rl) { - __mbrtowc = _UTF8_mbrtowc; - __wcrtomb = _UTF8_wcrtomb; - __mbsinit = _UTF8_mbsinit; - __mbsnrtowcs = _UTF8_mbsnrtowcs; - __wcsnrtombs = _UTF8_wcsnrtombs; - _CurrentRuneLocale = rl; - __mb_cur_max = 6; + l->__mbrtowc = _UTF8_mbrtowc; + l->__wcrtomb = _UTF8_wcrtomb; + l->__mbsinit = _UTF8_mbsinit; + l->__mbsnrtowcs = _UTF8_mbsnrtowcs; + l->__wcsnrtombs = _UTF8_wcsnrtombs; + l->runes = rl; + l->__mb_cur_max = 6; /* * UCS-4 encoding used as the internal representation, so * slots 0x0080-0x00FF are occuped and must be excluded * from the single byte ctype by setting the limit. */ - __mb_sb_limit = 128; + l->__mb_sb_limit = 128; return (0); } diff --git a/lib/libc/locale/wcrtomb.c b/lib/libc/locale/wcrtomb.c index ef75b78..32d4df2 100644 --- a/lib/libc/locale/wcrtomb.c +++ b/lib/libc/locale/wcrtomb.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -31,11 +36,17 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" size_t -wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps) +wcrtomb_l(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps, + locale_t locale) { - static mbstate_t mbs; - + FIX_LOCALE(locale); if (ps == NULL) - ps = &mbs; - return (__wcrtomb(s, wc, ps)); + ps = &locale->wcrtomb; + return (XLOCALE_CTYPE(locale)->__wcrtomb(s, wc, ps)); +} + +size_t +wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps) +{ + return wcrtomb_l(s, wc, ps, __get_locale()); } diff --git a/lib/libc/locale/wcsftime.c b/lib/libc/locale/wcsftime.c index a546dc6..c4f6b2e 100644 --- a/lib/libc/locale/wcsftime.c +++ b/lib/libc/locale/wcsftime.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <time.h> #include <wchar.h> +#include "xlocale_private.h" /* * Convert date and time to a wide-character string. @@ -47,8 +53,9 @@ __FBSDID("$FreeBSD$"); * format specifications in the format string. */ size_t -wcsftime(wchar_t * __restrict wcs, size_t maxsize, - const wchar_t * __restrict format, const struct tm * __restrict timeptr) +wcsftime_l(wchar_t * __restrict wcs, size_t maxsize, + const wchar_t * __restrict format, const struct tm * __restrict timeptr, + locale_t locale) { static const mbstate_t initial; mbstate_t mbs; @@ -57,6 +64,7 @@ wcsftime(wchar_t * __restrict wcs, size_t maxsize, const wchar_t *formatp; size_t n, sflen; int sverrno; + FIX_LOCALE(locale); sformat = dst = NULL; @@ -66,13 +74,13 @@ wcsftime(wchar_t * __restrict wcs, size_t maxsize, */ mbs = initial; formatp = format; - sflen = wcsrtombs(NULL, &formatp, 0, &mbs); + sflen = wcsrtombs_l(NULL, &formatp, 0, &mbs, locale); if (sflen == (size_t)-1) goto error; if ((sformat = malloc(sflen + 1)) == NULL) goto error; mbs = initial; - wcsrtombs(sformat, &formatp, sflen + 1, &mbs); + wcsrtombs_l(sformat, &formatp, sflen + 1, &mbs, locale); /* * Allocate memory for longest multibyte sequence that will fit @@ -87,11 +95,11 @@ wcsftime(wchar_t * __restrict wcs, size_t maxsize, } if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL) goto error; - if (strftime(dst, maxsize, sformat, timeptr) == 0) + if (strftime_l(dst, maxsize, sformat, timeptr, locale) == 0) goto error; dstp = dst; mbs = initial; - n = mbsrtowcs(wcs, &dstp, maxsize, &mbs); + n = mbsrtowcs_l(wcs, &dstp, maxsize, &mbs, locale); if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL) goto error; @@ -106,3 +114,9 @@ error: errno = sverrno; return (0); } +size_t +wcsftime(wchar_t * __restrict wcs, size_t maxsize, + const wchar_t * __restrict format, const struct tm * __restrict timeptr) +{ + return wcsftime_l(wcs, maxsize, format, timeptr, __get_locale()); +} diff --git a/lib/libc/locale/wcsnrtombs.c b/lib/libc/locale/wcsnrtombs.c index e899698..2f3bf1e 100644 --- a/lib/libc/locale/wcsnrtombs.c +++ b/lib/libc/locale/wcsnrtombs.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,16 +39,22 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" size_t +wcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc, + size_t len, mbstate_t * __restrict ps, locale_t locale) +{ + FIX_LOCALE(locale); + if (ps == NULL) + ps = &locale->wcsnrtombs; + return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, nwc, len, ps)); +} +size_t wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc, size_t len, mbstate_t * __restrict ps) { - static mbstate_t mbs; - - if (ps == NULL) - ps = &mbs; - return (__wcsnrtombs(dst, src, nwc, len, ps)); + return wcsnrtombs_l(dst, src, nwc, len, ps, __get_locale()); } + size_t __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc, size_t len, mbstate_t * __restrict ps) @@ -53,13 +64,14 @@ __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src, const wchar_t *s; size_t nbytes; size_t nb; + struct xlocale_ctype *l = XLOCALE_CTYPE(__get_locale()); s = *src; nbytes = 0; if (dst == NULL) { while (nwc-- > 0) { - if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1) + if ((nb = l->__wcrtomb(buf, *s, ps)) == (size_t)-1) /* Invalid character - wcrtomb() sets errno. */ return ((size_t)-1); else if (*s == L'\0') @@ -73,7 +85,7 @@ __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src, while (len > 0 && nwc-- > 0) { if (len > (size_t)MB_CUR_MAX) { /* Enough space to translate in-place. */ - if ((nb = __wcrtomb(dst, *s, ps)) == (size_t)-1) { + if ((nb = l->__wcrtomb(dst, *s, ps)) == (size_t)-1) { *src = s; return ((size_t)-1); } @@ -86,7 +98,7 @@ __wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src, * character is too long for the buffer. */ mbsbak = *ps; - if ((nb = __wcrtomb(buf, *s, ps)) == (size_t)-1) { + if ((nb = l->__wcrtomb(buf, *s, ps)) == (size_t)-1) { *src = s; return ((size_t)-1); } diff --git a/lib/libc/locale/wcsrtombs.c b/lib/libc/locale/wcsrtombs.c index f3b38b7..f6d1ca0 100644 --- a/lib/libc/locale/wcsrtombs.c +++ b/lib/libc/locale/wcsrtombs.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,12 +39,18 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" size_t +wcsrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t len, + mbstate_t * __restrict ps, locale_t locale) +{ + FIX_LOCALE(locale); + if (ps == NULL) + ps = &locale->wcsrtombs; + return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, SIZE_T_MAX, len, ps)); +} + +size_t wcsrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t len, mbstate_t * __restrict ps) { - static mbstate_t mbs; - - if (ps == NULL) - ps = &mbs; - return (__wcsnrtombs(dst, src, SIZE_T_MAX, len, ps)); + return wcsrtombs_l(dst, src, len, ps, __get_locale()); } diff --git a/lib/libc/locale/wcstod.c b/lib/libc/locale/wcstod.c index 68df1ed..8bc46a7 100644 --- a/lib/libc/locale/wcstod.c +++ b/lib/libc/locale/wcstod.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <wchar.h> #include <wctype.h> +#include "xlocale_private.h" /* * Convert a string to a double-precision number. @@ -41,17 +47,22 @@ __FBSDID("$FreeBSD$"); * for at least the digits, radix character and letters. */ double -wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) +wcstod_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + locale_t locale) { static const mbstate_t initial; mbstate_t mbs; double val; char *buf, *end; - const wchar_t *wcp; + const wchar_t *wcp = nptr; size_t len; + size_t spaces = 0; + FIX_LOCALE(locale); - while (iswspace(*nptr)) - nptr++; + while (iswspace_l(*wcp, locale)) { + wcp++; + spaces++; + } /* * Convert the supplied numeric wide char. string to multibyte. @@ -63,9 +74,8 @@ wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) * duplicates a lot of strtod()'s functionality and slows down the * most common cases. */ - wcp = nptr; mbs = initial; - if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) { + if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) { if (endptr != NULL) *endptr = (wchar_t *)nptr; return (0.0); @@ -73,10 +83,10 @@ wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) if ((buf = malloc(len + 1)) == NULL) return (0.0); mbs = initial; - wcsrtombs(buf, &wcp, len + 1, &mbs); + wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale); /* Let strtod() do most of the work for us. */ - val = strtod(buf, &end); + val = strtod_l(buf, &end, locale); /* * We only know where the number ended in the _multibyte_ @@ -84,11 +94,20 @@ wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) * where it ended, count multibyte characters to find the * corresponding position in the wide char string. */ - if (endptr != NULL) + if (endptr != NULL) { /* XXX Assume each wide char is one byte. */ *endptr = (wchar_t *)nptr + (end - buf); + if (buf != end) + *endptr += spaces; + } + free(buf); return (val); } +double +wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) +{ + return wcstod_l(nptr, endptr, __get_locale()); +} diff --git a/lib/libc/locale/wcstof.c b/lib/libc/locale/wcstof.c index ba238d4..93a5af8 100644 --- a/lib/libc/locale/wcstof.c +++ b/lib/libc/locale/wcstof.c @@ -2,6 +2,11 @@ * Copyright (c) 2002, 2003 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,12 +35,14 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <wchar.h> #include <wctype.h> +#include "xlocale_private.h" /* * See wcstod() for comments as to the logic used. */ float -wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) +wcstof_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + locale_t locale) { static const mbstate_t initial; mbstate_t mbs; @@ -43,13 +50,14 @@ wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) char *buf, *end; const wchar_t *wcp; size_t len; + FIX_LOCALE(locale); - while (iswspace(*nptr)) + while (iswspace_l(*nptr, locale)) nptr++; wcp = nptr; mbs = initial; - if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) { + if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) { if (endptr != NULL) *endptr = (wchar_t *)nptr; return (0.0); @@ -57,9 +65,9 @@ wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) if ((buf = malloc(len + 1)) == NULL) return (0.0); mbs = initial; - wcsrtombs(buf, &wcp, len + 1, &mbs); + wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale); - val = strtof(buf, &end); + val = strtof_l(buf, &end, locale); if (endptr != NULL) *endptr = (wchar_t *)nptr + (end - buf); @@ -68,3 +76,8 @@ wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) return (val); } +float +wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) +{ + return wcstof_l(nptr, endptr, __get_locale()); +} diff --git a/lib/libc/locale/wcstoimax.c b/lib/libc/locale/wcstoimax.c index 66e692a..ce066a5 100644 --- a/lib/libc/locale/wcstoimax.c +++ b/lib/libc/locale/wcstoimax.c @@ -2,6 +2,11 @@ * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,19 +46,21 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <wchar.h> #include <wctype.h> +#include "xlocale_private.h" /* * Convert a wide character string to an intmax_t integer. */ intmax_t -wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, - int base) +wcstoimax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + int base, locale_t locale) { const wchar_t *s; uintmax_t acc; wchar_t c; uintmax_t cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * See strtoimax for comments as to the logic used. @@ -61,7 +68,7 @@ wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, s = nptr; do { c = *s++; - } while (iswspace(c)); + } while (iswspace_l(c, locale)); if (c == L'-') { neg = 1; c = *s++; @@ -88,8 +95,8 @@ wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, cutoff /= base; for ( ; ; c = *s++) { #ifdef notyet - if (iswdigit(c)) - c = digittoint(c); + if (iswdigit_l(c, locale)) + c = digittoint_l(c, locale); else #endif if (c >= L'0' && c <= L'9') @@ -122,3 +129,9 @@ noconv: *endptr = (wchar_t *)(any ? s - 1 : nptr); return (acc); } +intmax_t +wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + int base) +{ + return wcstoimax_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/locale/wcstol.c b/lib/libc/locale/wcstol.c index 294b6e0..2b21d12 100644 --- a/lib/libc/locale/wcstol.c +++ b/lib/libc/locale/wcstol.c @@ -2,6 +2,11 @@ * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -35,18 +40,21 @@ __FBSDID("$FreeBSD$"); #include <limits.h> #include <wchar.h> #include <wctype.h> +#include "xlocale_private.h" /* * Convert a string to a long integer. */ long -wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) +wcstol_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int + base, locale_t locale) { const wchar_t *s; unsigned long acc; wchar_t c; unsigned long cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * See strtol for comments as to the logic used. @@ -54,7 +62,7 @@ wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) s = nptr; do { c = *s++; - } while (iswspace(c)); + } while (iswspace_l(c, locale)); if (c == '-') { neg = 1; c = *s++; @@ -81,8 +89,8 @@ wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) cutoff /= base; for ( ; ; c = *s++) { #ifdef notyet - if (iswdigit(c)) - c = digittoint(c); + if (iswdigit_l(c, locale)) + c = digittoint_l(c, locale); else #endif if (c >= L'0' && c <= L'9') @@ -115,3 +123,8 @@ noconv: *endptr = (wchar_t *)(any ? s - 1 : nptr); return (acc); } +long +wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) +{ + return wcstol_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/locale/wcstold.c b/lib/libc/locale/wcstold.c index cf9d874..fcfd48f 100644 --- a/lib/libc/locale/wcstold.c +++ b/lib/libc/locale/wcstold.c @@ -2,6 +2,11 @@ * Copyright (c) 2002, 2003 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,26 +35,32 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <wchar.h> #include <wctype.h> +#include "xlocale_private.h" /* * See wcstod() for comments as to the logic used. */ long double -wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) +wcstold_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + locale_t locale) { static const mbstate_t initial; mbstate_t mbs; long double val; char *buf, *end; - const wchar_t *wcp; + const wchar_t *wcp = nptr; size_t len; + size_t spaces = 0; + FIX_LOCALE(locale); - while (iswspace(*nptr)) - nptr++; + while (iswspace_l(*wcp, locale)) { + wcp++; + spaces++; + } wcp = nptr; mbs = initial; - if ((len = wcsrtombs(NULL, &wcp, 0, &mbs)) == (size_t)-1) { + if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) { if (endptr != NULL) *endptr = (wchar_t *)nptr; return (0.0); @@ -57,14 +68,23 @@ wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) if ((buf = malloc(len + 1)) == NULL) return (0.0); mbs = initial; - wcsrtombs(buf, &wcp, len + 1, &mbs); + wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale); - val = strtold(buf, &end); + val = strtold_l(buf, &end, locale); - if (endptr != NULL) + if (endptr != NULL) { + /* XXX Assume each wide char is one byte. */ *endptr = (wchar_t *)nptr + (end - buf); + if (buf != end) + *endptr += spaces; + } free(buf); return (val); } +long double +wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr) +{ + return wcstold_l(nptr, endptr, __get_locale()); +} diff --git a/lib/libc/locale/wcstoll.c b/lib/libc/locale/wcstoll.c index 19b285f..f246502 100644 --- a/lib/libc/locale/wcstoll.c +++ b/lib/libc/locale/wcstoll.c @@ -2,6 +2,11 @@ * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,18 +46,21 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <wchar.h> #include <wctype.h> +#include "xlocale_private.h" /* * Convert a wide character string to a long long integer. */ long long -wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) +wcstoll_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + int base, locale_t locale) { const wchar_t *s; unsigned long long acc; wchar_t c; unsigned long long cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * See strtoll for comments as to the logic used. @@ -60,7 +68,7 @@ wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) s = nptr; do { c = *s++; - } while (iswspace(c)); + } while (iswspace_l(c, locale)); if (c == L'-') { neg = 1; c = *s++; @@ -87,8 +95,8 @@ wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) cutoff /= base; for ( ; ; c = *s++) { #ifdef notyet - if (iswdigit(c)) - c = digittoint(c); + if (iswdigit_l(c, locale)) + c = digittoint_l(c, locale); else #endif if (c >= L'0' && c <= L'9') @@ -121,3 +129,8 @@ noconv: *endptr = (wchar_t *)(any ? s - 1 : nptr); return (acc); } +long long +wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) +{ + return wcstoll_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/locale/wcstombs.c b/lib/libc/locale/wcstombs.c index 250d2b9..8d4ae1c 100644 --- a/lib/libc/locale/wcstombs.c +++ b/lib/libc/locale/wcstombs.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,13 +38,21 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" size_t -wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n) +wcstombs_l(char * __restrict s, const wchar_t * __restrict pwcs, size_t n, + locale_t locale) { static const mbstate_t initial; mbstate_t mbs; const wchar_t *pwcsp; + FIX_LOCALE(locale); mbs = initial; pwcsp = pwcs; - return (__wcsnrtombs(s, &pwcsp, SIZE_T_MAX, n, &mbs)); + return (XLOCALE_CTYPE(locale)->__wcsnrtombs(s, &pwcsp, SIZE_T_MAX, n, &mbs)); +} +size_t +wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n) +{ + return wcstombs_l(s, pwcs, n, __get_locale()); } + diff --git a/lib/libc/locale/wcstoul.c b/lib/libc/locale/wcstoul.c index f50e7a7..54e6b4f 100644 --- a/lib/libc/locale/wcstoul.c +++ b/lib/libc/locale/wcstoul.c @@ -2,6 +2,11 @@ * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -35,18 +40,21 @@ __FBSDID("$FreeBSD$"); #include <limits.h> #include <wchar.h> #include <wctype.h> +#include "xlocale_private.h" /* * Convert a wide character string to an unsigned long integer. */ unsigned long -wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) +wcstoul_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + int base, locale_t locale) { const wchar_t *s; unsigned long acc; wchar_t c; unsigned long cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * See strtol for comments as to the logic used. @@ -54,7 +62,7 @@ wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) s = nptr; do { c = *s++; - } while (iswspace(c)); + } while (iswspace_l(c, locale)); if (c == L'-') { neg = 1; c = *s++; @@ -79,8 +87,8 @@ wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) cutlim = ULONG_MAX % base; for ( ; ; c = *s++) { #ifdef notyet - if (iswdigit(c)) - c = digittoint(c); + if (iswdigit_l(c, locale)) + c = digittoint_l(c, locale); else #endif if (c >= L'0' && c <= L'9') @@ -113,3 +121,8 @@ noconv: *endptr = (wchar_t *)(any ? s - 1 : nptr); return (acc); } +unsigned long +wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base) +{ + return wcstoul_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/locale/wcstoull.c b/lib/libc/locale/wcstoull.c index d840424..c56ee77 100644 --- a/lib/libc/locale/wcstoull.c +++ b/lib/libc/locale/wcstoull.c @@ -2,6 +2,11 @@ * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,19 +46,21 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <wchar.h> #include <wctype.h> +#include "xlocale_private.h" /* * Convert a wide character string to an unsigned long long integer. */ unsigned long long -wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, - int base) +wcstoull_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + int base, locale_t locale) { const wchar_t *s; unsigned long long acc; wchar_t c; unsigned long long cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * See strtoull for comments as to the logic used. @@ -61,7 +68,7 @@ wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, s = nptr; do { c = *s++; - } while (iswspace(c)); + } while (iswspace_l(c, locale)); if (c == L'-') { neg = 1; c = *s++; @@ -86,8 +93,8 @@ wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, cutlim = ULLONG_MAX % base; for ( ; ; c = *s++) { #ifdef notyet - if (iswdigit(c)) - c = digittoint(c); + if (iswdigit_l(c, locale)) + c = digittoint_l(c, locale); else #endif if (c >= L'0' && c <= L'9') @@ -120,3 +127,9 @@ noconv: *endptr = (wchar_t *)(any ? s - 1 : nptr); return (acc); } +unsigned long long +wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + int base) +{ + return wcstoull_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/locale/wcstoumax.c b/lib/libc/locale/wcstoumax.c index d643b0b..397c1e3 100644 --- a/lib/libc/locale/wcstoumax.c +++ b/lib/libc/locale/wcstoumax.c @@ -2,6 +2,11 @@ * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,19 +46,21 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <wchar.h> #include <wctype.h> +#include "xlocale_private.h" /* * Convert a wide character string to a uintmax_t integer. */ uintmax_t -wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, - int base) +wcstoumax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + int base, locale_t locale) { const wchar_t *s; uintmax_t acc; wchar_t c; uintmax_t cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * See strtoimax for comments as to the logic used. @@ -61,7 +68,7 @@ wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, s = nptr; do { c = *s++; - } while (iswspace(c)); + } while (iswspace_l(c, locale)); if (c == L'-') { neg = 1; c = *s++; @@ -86,8 +93,8 @@ wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, cutlim = UINTMAX_MAX % base; for ( ; ; c = *s++) { #ifdef notyet - if (iswdigit(c)) - c = digittoint(c); + if (iswdigit_l(c, locale)) + c = digittoint_l(c, locale); else #endif if (c >= L'0' && c <= L'9') @@ -120,3 +127,9 @@ noconv: *endptr = (wchar_t *)(any ? s - 1 : nptr); return (acc); } +uintmax_t +wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, + int base) +{ + return wcstoumax_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/locale/wctob.c b/lib/libc/locale/wctob.c index cb39adc..96e8b73 100644 --- a/lib/libc/locale/wctob.c +++ b/lib/libc/locale/wctob.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,13 +38,19 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" int -wctob(wint_t c) +wctob_l(wint_t c, locale_t locale) { static const mbstate_t initial; mbstate_t mbs = initial; char buf[MB_LEN_MAX]; + FIX_LOCALE(locale); - if (c == WEOF || __wcrtomb(buf, c, &mbs) != 1) + if (c == WEOF || XLOCALE_CTYPE(locale)->__wcrtomb(buf, c, &mbs) != 1) return (EOF); return ((unsigned char)*buf); } +int +wctob(wint_t c) +{ + return wctob_l(c, __get_locale()); +} diff --git a/lib/libc/locale/wctomb.c b/lib/libc/locale/wctomb.c index 77b9043..da3d263 100644 --- a/lib/libc/locale/wctomb.c +++ b/lib/libc/locale/wctomb.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,18 +37,23 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" int -wctomb(char *s, wchar_t wchar) +wctomb_l(char *s, wchar_t wchar, locale_t locale) { static const mbstate_t initial; - static mbstate_t mbs; size_t rval; + FIX_LOCALE(locale); if (s == NULL) { /* No support for state dependent encodings. */ - mbs = initial; + locale->wctomb = initial; return (0); } - if ((rval = __wcrtomb(s, wchar, &mbs)) == (size_t)-1) + if ((rval = XLOCALE_CTYPE(locale)->__wcrtomb(s, wchar, &locale->wctomb)) == (size_t)-1) return (-1); return ((int)rval); } +int +wctomb(char *s, wchar_t wchar) +{ + return wctomb_l(s, wchar, __get_locale()); +} diff --git a/lib/libc/locale/wctrans.c b/lib/libc/locale/wctrans.c index 6813e33..0831146 100644 --- a/lib/libc/locale/wctrans.c +++ b/lib/libc/locale/wctrans.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <string.h> #include <wctype.h> +#include "xlocale_private.h" enum { _WCT_ERROR = 0, @@ -38,15 +44,14 @@ enum { }; wint_t -towctrans(wint_t wc, wctrans_t desc) +towctrans_l(wint_t wc, wctrans_t desc, locale_t locale) { - switch (desc) { case _WCT_TOLOWER: - wc = towlower(wc); + wc = towlower_l(wc, locale); break; case _WCT_TOUPPER: - wc = towupper(wc); + wc = towupper_l(wc, locale); break; case _WCT_ERROR: default: @@ -56,9 +61,18 @@ towctrans(wint_t wc, wctrans_t desc) return (wc); } +wint_t +towctrans(wint_t wc, wctrans_t desc) +{ + return towctrans_l(wc, desc, __get_locale()); +} +/* + * wctrans() calls this will a 0 locale. If this is ever modified to actually + * use the locale, wctrans() must be modified to call __get_locale(). + */ wctrans_t -wctrans(const char *charclass) +wctrans_l(const char *charclass, locale_t locale) { struct { const char *name; @@ -78,3 +92,10 @@ wctrans(const char *charclass) errno = EINVAL; return (ccls[i].trans); } + +wctrans_t +wctrans(const char *charclass) +{ + return wctrans_l(charclass, 0); +} + diff --git a/lib/libc/locale/wctype.c b/lib/libc/locale/wctype.c index f94a735..5ffbb79 100644 --- a/lib/libc/locale/wctype.c +++ b/lib/libc/locale/wctype.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,17 +35,27 @@ __FBSDID("$FreeBSD$"); #include <ctype.h> #include <string.h> #include <wctype.h> +#include <xlocale.h> #undef iswctype int iswctype(wint_t wc, wctype_t charclass) { - return (__istype(wc, charclass)); } +int +iswctype_l(wint_t wc, wctype_t charclass, locale_t locale) +{ + return __istype_l(wc, charclass, locale); +} +/* + * IMPORTANT: The 0 in the call to this function in wctype() must be changed to + * __get_locale() if wctype_l() is ever modified to actually use the locale + * parameter. + */ wctype_t -wctype(const char *property) +wctype_l(const char *property, locale_t locale) { static const struct { const char *name; @@ -72,3 +87,8 @@ wctype(const char *property) return (props[i].mask); } + +wctype_t wctype(const char *property) +{ + return wctype_l(property, 0); +} diff --git a/lib/libc/locale/wcwidth.c b/lib/libc/locale/wcwidth.c index 7a5d2ed..9e74217 100644 --- a/lib/libc/locale/wcwidth.c +++ b/lib/libc/locale/wcwidth.c @@ -10,6 +10,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,12 +44,18 @@ __FBSDID("$FreeBSD$"); #include <wchar.h> +#include <wctype.h> +#include <xlocale.h> #undef wcwidth int wcwidth(wchar_t wc) { - return (__wcwidth(wc)); } +int +wcwidth_l(wchar_t wc, locale_t locale) +{ + return (__wcwidth_l(wc, locale)); +} diff --git a/lib/libc/locale/xlocale.3 b/lib/libc/locale/xlocale.3 new file mode 100644 index 0000000..ecfbb4c --- /dev/null +++ b/lib/libc/locale/xlocale.3 @@ -0,0 +1,270 @@ +.\" Copyright (c) 2011 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by David Chisnall under sponsorship from +.\" the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 17 2011 +.Dt XLOCALE 3 +.Os +.Sh NAME +.Nm xlocale +.Nd Thread-safe extended locale support. +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In xlocale.h +.Sh DESCRIPTION +The extended locale support includes a set of functions for setting +thread-local locales, as well convenience functions for performing locale-aware +calls with a specified locale. +.Pp +The core of the xlocale API is the +.Fa locale_t +type. This is an opaque type encapsulating a locale. Instances of this can be +either set as the locale for a specific thread or passed directly to the +.Fa _l +suffixed variants of various standard C functions. Two special +.Fa locale_t +values are available: +.Bl -bullet -offset indent +.It +NULL refers to the current locale for the thread, or to the global locale if no +locale has been set for this thread. +.It +LC_GLOBAL_LOCALE refers to the global locale. +.El +.Pp +The global locale is the locale set with the +.Xr setlocale 3 +function. +.Sh CAVEATS +The +.Xr setlocale 3 +function, and others in the family, refer to the global locale. Other +functions that depend on the locale, however, will take the thread-local locale +if one has been set. This means that the idiom of setting the locale using +.Xr setlocale 3 , +calling a locale-dependent function, and then restoring the locale will not +have the expected behavior if the current thread has had a locale set using +.Xr uselocale 3 . +You should avoid this idiom and prefer to use the +.Fa _l +suffixed versions instead. +.Sh SEE ALSO +.Xr duplocale 3 , +.Xr freelocale 3 , +.Xr localeconv 3 , +.Xr newlocale 3 , +.Xr querylocale 3 , +.Xr uselocale 3 , +.Sh CONVENIENCE FUNCTIONS +The xlocale API includes a number of +.Fa _l +suffixed convenience functions. These are variants of standard C functions +that have been modified to take an explicit +.Fa locale_t +parameter as the final argument or, in the case of variadic functions, as an +additional argument directly before the format string. Each of these functions +accepts either NULL or LC_GLOBAL_LOCALE. In these functions, NULL refers to +the C locale, rather than the thread's current locale. If you wish to use the +thread's current locale, then use the unsuffixed version of the function. +.Pp +These functions are exposed by including +.In xlocale.h +.Em after +including the relevant headers for the standard variant. For example, the +.Xr strtol_l 3 +function is exposed by including +.In xlocale.h +after +.In stdlib.h , +which defines +.Xr strtol 3 . +.Pp +For reference, a complete list of the locale-aware functions that are available +in this form, along with the headers that expose them, is provided here: +.Pp +.Bl -tag -width "<monetary.h> " +.It In wctype.h +.Xr iswalnum_l 3 , +.Xr iswalpha_l 3 , +.Xr iswcntrl_l 3 , +.Xr iswctype_l 3 , +.Xr iswdigit_l 3 , +.Xr iswgraph_l 3 , +.Xr iswlower_l 3 , +.Xr iswprint_l 3 , +.Xr iswpunct_l 3 , +.Xr iswspace_l 3 , +.Xr iswupper_l 3 , +.Xr iswxdigit_l 3 , +.Xr towlower_l 3 , +.Xr towupper_l 3 , +.Xr wctype_l 3 , +.It In ctype.h +.Xr digittoint_l 3 , +.Xr isalnum_l 3 , +.Xr isalpha_l 3 , +.Xr isblank_l 3 , +.Xr iscntrl_l 3 , +.Xr isdigit_l 3 , +.Xr isgraph_l 3 , +.Xr ishexnumber_l 3 , +.Xr isideogram_l 3 , +.Xr islower_l 3 , +.Xr isnumber_l 3 , +.Xr isphonogram_l 3 , +.Xr isprint_l 3 , +.Xr ispunct_l 3 , +.Xr isrune_l 3 , +.Xr isspace_l 3 , +.Xr isspecial_l 3 , +.Xr isupper_l 3 , +.Xr isxdigit_l 3 , +.Xr tolower_l 3 , +.Xr toupper_l 3 +.It In inttypes.h +.Xr strtoimax_l 3 , +.Xr strtoumax_l 3 , +.Xr wcstoimax_l 3 , +.Xr wcstoumax_l 3 +.It In langinfo.h +.Xr nl_langinfo_l 3 +.It In monetary.h +.Xr strfmon_l 3 +.It In stdio.h +.Xr asprintf_l 3 , +.Xr fprintf_l 3 , +.Xr fscanf_l 3 , +.Xr printf_l 3 , +.Xr scanf_l 3 , +.Xr snprintf_l 3 , +.Xr sprintf_l 3 , +.Xr sscanf_l 3 , +.Xr vasprintf_l 3 , +.Xr vfprintf_l 3 , +.Xr vfscanf_l 3 , +.Xr vprintf_l 3 , +.Xr vscanf_l 3 , +.Xr vsnprintf_l 3 , +.Xr vsprintf_l 3 , +.Xr vsscanf_l 3 +.It In stdlib.h +.Xr atof_l 3 , +.Xr atoi_l 3 , +.Xr atol_l 3 , +.Xr atoll_l 3 , +.Xr mblen_l 3 , +.Xr mbstowcs_l 3 , +.Xr mbtowc_l 3 , +.Xr strtod_l 3 , +.Xr strtof_l 3 , +.Xr strtol_l 3 , +.Xr strtold_l 3 , +.Xr strtoll_l 3 , +.Xr strtoq_l 3 , +.Xr strtoul_l 3 , +.Xr strtoull_l 3 , +.Xr strtouq_l 3 , +.Xr wcstombs_l 3 , +.Xr wctomb_l 3 +.It In string.h +.Xr strcoll_l 3 , +.Xr strxfrm_l 3 , +.Xr strcasecmp_l 3 , +.Xr strcasestr_l 3 , +.Xr strncasecmp_l 3 +.It In time.h +.Xr strftime_l 3 +.Xr strptime_l 3 +.It In wchar.h +.Xr btowc_l 3 , +.Xr fgetwc_l 3 , +.Xr fgetws_l 3 , +.Xr fputwc_l 3 , +.Xr fputws_l 3 , +.Xr fwprintf_l 3 , +.Xr fwscanf_l 3 , +.Xr getwc_l 3 , +.Xr getwchar_l 3 , +.Xr mbrlen_l 3 , +.Xr mbrtowc_l 3 , +.Xr mbsinit_l 3 , +.Xr mbsnrtowcs_l 3 , +.Xr mbsrtowcs_l 3 , +.Xr putwc_l 3 , +.Xr putwchar_l 3 , +.Xr swprintf_l 3 , +.Xr swscanf_l 3 , +.Xr ungetwc_l 3 , +.Xr vfwprintf_l 3 , +.Xr vfwscanf_l 3 , +.Xr vswprintf_l 3 , +.Xr vswscanf_l 3 , +.Xr vwprintf_l 3 , +.Xr vwscanf_l 3 , +.Xr wcrtomb_l 3 , +.Xr wcscoll_l 3 , +.Xr wcsftime_l 3 , +.Xr wcsnrtombs_l 3 , +.Xr wcsrtombs_l 3 , +.Xr wcstod_l 3 , +.Xr wcstof_l 3 , +.Xr wcstol_l 3 , +.Xr wcstold_l 3 , +.Xr wcstoll_l 3 , +.Xr wcstoul_l 3 , +.Xr wcstoull_l 3 , +.Xr wcswidth_l 3 , +.Xr wcsxfrm_l 3 , +.Xr wctob_l 3 , +.Xr wcwidth_l 3 , +.Xr wprintf_l 3 , +.Xr wscanf_l 3 +.It In wctype.h +.Xr iswblank_l 3 , +.Xr iswhexnumber_l 3 , +.Xr iswideogram_l 3 , +.Xr iswnumber_l 3 , +.Xr iswphonogram_l 3 , +.Xr iswrune_l 3 , +.Xr iswspecial_l 3 , +.Xr nextwctype_l 3 , +.Xr towctrans_l 3 , +.Xr wctrans_l 3 +.It In xlocale.h +.Xr localeconv_l 3 +.El +.Sh STANDARDS +The functions +conform to +.St -p1003.1-2008 . +.Sh HISTORY +The xlocale APIs first appeared in Darwin 8.0. This implementation was +written by David Chisnall, under sponsorship from the FreeBSD Foundation and +first appeared in +.Fx 9.1 . diff --git a/lib/libc/locale/xlocale.c b/lib/libc/locale/xlocale.c new file mode 100644 index 0000000..f14f952 --- /dev/null +++ b/lib/libc/locale/xlocale.c @@ -0,0 +1,334 @@ +/*- + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by David Chisnall under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions * are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include "libc_private.h" +#include "xlocale_private.h" + +/** + * Each locale loader declares a global component. This is used by setlocale() + * and also by xlocale with LC_GLOBAL_LOCALE.. + */ +extern struct xlocale_component __xlocale_global_collate; +extern struct xlocale_component __xlocale_global_ctype; +extern struct xlocale_component __xlocale_global_monetary; +extern struct xlocale_component __xlocale_global_numeric; +extern struct xlocale_component __xlocale_global_time; +extern struct xlocale_component __xlocale_global_messages; +/* + * And another version for the statically-allocated C locale. We only have + * components for the parts that are expected to be sensible. + */ +extern struct xlocale_component __xlocale_C_collate; +extern struct xlocale_component __xlocale_C_ctype; +/* + * Private functions in setlocale.c. + */ +const char * +__get_locale_env(int category); +int +__detect_path_locale(void); + +struct _xlocale __xlocale_global_locale = { + {0}, + { + &__xlocale_global_collate, + &__xlocale_global_ctype, + &__xlocale_global_monetary, + &__xlocale_global_numeric, + &__xlocale_global_time, + &__xlocale_global_messages + }, + 1, + 0, + 1, + 0 +}; + +struct _xlocale __xlocale_C_locale = { + {0}, + { + &__xlocale_C_collate, + &__xlocale_C_ctype, + 0, 0, 0, 0 + }, + 1, + 0, + 1, + 0 +}; + +static void*(*constructors[])(const char*, locale_t) = +{ + __collate_load, + __ctype_load, + __monetary_load, + __numeric_load, + __time_load, + __messages_load +}; + +static pthread_key_t locale_info_key; +static int fake_tls; +static locale_t thread_local_locale; + +static void init_key(void) +{ + pthread_key_create(&locale_info_key, xlocale_release); + pthread_setspecific(locale_info_key, (void*)42); + if (pthread_getspecific(locale_info_key) == (void*)42) { + pthread_setspecific(locale_info_key, 0); + } else { + fake_tls = 1; + } + __detect_path_locale(); +} + +static pthread_once_t once_control = PTHREAD_ONCE_INIT; + +static locale_t +get_thread_locale(void) +{ + _once(&once_control, init_key); + + return (fake_tls ? thread_local_locale : + pthread_getspecific(locale_info_key)); +} + +locale_t +__get_locale(void) +{ + locale_t l = get_thread_locale(); + return (l ? l : &__xlocale_global_locale); + +} + +static void +set_thread_locale(locale_t loc) +{ + pthread_once(&once_control, init_key); + + if (NULL != loc) { + xlocale_retain((struct xlocale_refcounted*)loc); + } + locale_t old = pthread_getspecific(locale_info_key); + if ((NULL != old) && (loc != old)) { + xlocale_release((struct xlocale_refcounted*)old); + } + if (fake_tls) { + thread_local_locale = loc; + } else { + pthread_setspecific(locale_info_key, loc); + } +} + +/** + * Clean up a locale, once its reference count reaches zero. This function is + * called by xlocale_release(), it should not be called directly. + */ +static void +destruct_locale(void *l) +{ + locale_t loc = l; + for (int type=0 ; type<XLC_LAST ; type++) { + if (loc->components[type]) { + xlocale_release(loc->components[type]); + } + } + if (loc->csym) { + free(loc->csym); + } + free(l); +} + +/** + * Allocates a new, uninitialised, locale. + */ +static locale_t +alloc_locale(void) +{ + locale_t new = calloc(sizeof(struct _xlocale), 1); + new->header.destructor = destruct_locale; + new->monetary_locale_changed = 1; + new->numeric_locale_changed = 1; + return (new); +} +static void +copyflags(locale_t new, locale_t old) +{ + new->using_monetary_locale = old->using_monetary_locale; + new->using_numeric_locale = old->using_numeric_locale; + new->using_time_locale = old->using_time_locale; + new->using_messages_locale = old->using_messages_locale; +} + +static int dupcomponent(int type, locale_t base, locale_t new) +{ + /* Always copy from the global locale, since it has mutable components. */ + struct xlocale_component *src = base->components[type]; + if (&__xlocale_global_locale == base) { + new->components[type] = constructors[type](src->locale, new); + if (new->components[type]) { + strncpy(new->components[type]->locale, src->locale, ENCODING_LEN); + } + } else { + new->components[type] = xlocale_retain(base->components[type]); + } + return (0 != new->components[type]); +} + +/* + * Public interfaces. These are the five public functions described by the + * xlocale interface. + */ + +locale_t newlocale(int mask, const char *locale, locale_t base) +{ + int type; + const char *realLocale = locale; + int useenv = 0; + int success = 1; + + _once(&once_control, init_key); + + locale_t new = alloc_locale(); + if (NULL == new) { + return (NULL); + } + + FIX_LOCALE(base); + copyflags(new, base); + + if (NULL == locale) { + realLocale = "C"; + } else if ('\0' == locale[0]) { + useenv = 1; + } + + for (type=0 ; type<XLC_LAST ; type++) { + if (mask & 1) { + if (useenv) { + realLocale = __get_locale_env(type); + } + new->components[type] = constructors[type](realLocale, new); + if (new->components[type]) { + strncpy(new->components[type]->locale, realLocale, ENCODING_LEN); + } else { + success = 0; + break; + } + } else { + if (!dupcomponent(type, base, new)) { + success = 0; + break; + } + } + mask >>= 1; + } + if (0 == success) { + xlocale_release(new); + new = NULL; + } + + return (new); +} + +locale_t duplocale(locale_t base) +{ + locale_t new = alloc_locale(); + int type; + + _once(&once_control, init_key); + + if (NULL == new) { + return (NULL); + } + + FIX_LOCALE(base); + copyflags(new, base); + + for (type=0 ; type<XLC_LAST ; type++) { + dupcomponent(type, base, new); + } + + return (new); +} + +/* + * Free a locale_t. This is quite a poorly named function. It actually + * disclaims a reference to a locale_t, rather than freeing it. + */ +int +freelocale(locale_t loc) +{ + /* Fail if we're passed something that isn't a locale. */ + if ((NULL == loc) || (LC_GLOBAL_LOCALE == loc)) { + return (-1); + } + /* If we're passed the global locale, pretend that we freed it but don't + * actually do anything. */ + if (&__xlocale_global_locale == loc) { + return (0); + } + xlocale_release(loc); + return (0); +} + +/* + * Returns the name of the locale for a particular component of a locale_t. + */ +const char *querylocale(int mask, locale_t loc) +{ + int type = ffs(mask) - 1; + FIX_LOCALE(loc); + if (type >= XLC_LAST) + return (NULL); + if (loc->components[type]) + return (loc->components[type]->locale); + return "C"; +} + +/* + * Installs the specified locale_t as this thread's locale. + */ +locale_t uselocale(locale_t loc) +{ + locale_t old = get_thread_locale(); + if (NULL != loc) { + if (LC_GLOBAL_LOCALE == loc) { + loc = NULL; + } + set_thread_locale(loc); + } + return (old ? old : LC_GLOBAL_LOCALE); +} + diff --git a/lib/libc/locale/xlocale_private.h b/lib/libc/locale/xlocale_private.h new file mode 100644 index 0000000..272d15e --- /dev/null +++ b/lib/libc/locale/xlocale_private.h @@ -0,0 +1,198 @@ +/*- + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by David Chisnall under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _XLOCALE_PRIVATE__H_ +#define _XLOCALE_PRIVATE__H_ + +#include <xlocale.h> +#include <locale.h> +#include <stdlib.h> +#include <stdint.h> +#include <sys/types.h> +#include <machine/atomic.h> +#include "setlocale.h" + +enum { + XLC_COLLATE = 0, + XLC_CTYPE, + XLC_MONETARY, + XLC_NUMERIC, + XLC_TIME, + XLC_MESSAGES, + XLC_LAST +}; + + +/** + * Header used for objects that are reference counted. Objects may optionally + * have a destructor associated, which is responsible for destroying the + * structure. Global / static versions of the structure should have no + * destructor set - they can then have their reference counts manipulated as + * normal, but will not do anything with them. + * + * The header stores a retain count - objects are assumed to have a reference + * count of 1 when they are created, but the retain count is 0. When the + * retain count is less than 0, they are freed. + */ +struct xlocale_refcounted { + /** Number of references to this component. */ + long retain_count; + /** Function used to destroy this component, if one is required*/ + void(*destructor)(void*); +}; +/** + * Header for a locale component. All locale components must begin with this + * header. + */ +struct xlocale_component { + struct xlocale_refcounted header; + /** Name of the locale used for this component. */ + char locale[ENCODING_LEN+1]; +}; + +/** + * xlocale structure, stores per-thread locale information. + */ +struct _xlocale { + struct xlocale_refcounted header; + /** Components for the locale. */ + struct xlocale_component *components[XLC_LAST]; + /** Flag indicating if components[XLC_MONETARY] has changed since the last + * call to localeconv_l() with this locale. */ + int monetary_locale_changed; + /** Flag indicating whether this locale is actually using a locale for + * LC_MONETARY (1), or if it should use the C default instead (0). */ + int using_monetary_locale; + /** Flag indicating if components[XLC_NUMERIC] has changed since the last + * call to localeconv_l() with this locale. */ + int numeric_locale_changed; + /** Flag indicating whether this locale is actually using a locale for + * LC_NUMERIC (1), or if it should use the C default instead (0). */ + int using_numeric_locale; + /** Flag indicating whether this locale is actually using a locale for + * LC_TIME (1), or if it should use the C default instead (0). */ + int using_time_locale; + /** Flag indicating whether this locale is actually using a locale for + * LC_MESSAGES (1), or if it should use the C default instead (0). */ + int using_messages_locale; + /** The structure to be returned from localeconv_l() for this locale. */ + struct lconv lconv; + /** Persistent state used by mblen() calls. */ + __mbstate_t mblen; + /** Persistent state used by mbrlen() calls. */ + __mbstate_t mbrlen; + /** Persistent state used by mbrtowc() calls. */ + __mbstate_t mbrtowc; + /** Persistent state used by mbsnrtowcs() calls. */ + __mbstate_t mbsnrtowcs; + /** Persistent state used by mbsrtowcs() calls. */ + __mbstate_t mbsrtowcs; + /** Persistent state used by mbtowc() calls. */ + __mbstate_t mbtowc; + /** Persistent state used by wcrtomb() calls. */ + __mbstate_t wcrtomb; + /** Persistent state used by wcsnrtombs() calls. */ + __mbstate_t wcsnrtombs; + /** Persistent state used by wcsrtombs() calls. */ + __mbstate_t wcsrtombs; + /** Persistent state used by wctomb() calls. */ + __mbstate_t wctomb; + /** Buffer used by nl_langinfo_l() */ + char *csym; +}; + +/** + * Increments the reference count of a reference-counted structure. + */ +__attribute__((unused)) static void* +xlocale_retain(void *val) +{ + struct xlocale_refcounted *obj = val; + atomic_add_long(&(obj->retain_count), 1); + return (val); +} +/** + * Decrements the reference count of a reference-counted structure, freeing it + * if this is the last reference, calling its destructor if it has one. + */ +__attribute__((unused)) static void +xlocale_release(void *val) +{ + struct xlocale_refcounted *obj = val; + long count = atomic_fetchadd_long(&(obj->retain_count), -1) - 1; + if (count < 0) { + if (0 != obj->destructor) { + obj->destructor(obj); + } + } +} + +/** + * Load functions. Each takes the name of a locale and a pointer to the data + * to be initialised as arguments. Two special values are allowed for the + */ +extern void* __collate_load(const char*, locale_t); +extern void* __ctype_load(const char*, locale_t); +extern void* __messages_load(const char*, locale_t); +extern void* __monetary_load(const char*, locale_t); +extern void* __numeric_load(const char*, locale_t); +extern void* __time_load(const char*, locale_t); + +extern struct _xlocale __xlocale_global_locale; +extern struct _xlocale __xlocale_C_locale; + +/** + * Returns the current locale for this thread, or the global locale if none is + * set. The caller does not have to free the locale. The return value from + * this call is not guaranteed to remain valid after the locale changes. As + * such, this should only be called within libc functions. + */ +locale_t __get_locale(void); + +/** + * Two magic values are allowed for locale_t objects. NULL and -1. This + * function maps those to the real locales that they represent. + */ +static inline locale_t get_real_locale(locale_t locale) +{ + switch ((intptr_t)locale) { + case 0: return (&__xlocale_C_locale); + case -1: return (&__xlocale_global_locale); + default: return (locale); + } +} + +/** + * Replace a placeholder locale with the real global or thread-local locale_t. + */ +#define FIX_LOCALE(l) (l = get_real_locale(l)) + +#endif diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c index 0d721d5..72e9883 100644 --- a/lib/libc/net/sctp_sys_calls.c +++ b/lib/libc/net/sctp_sys_calls.c @@ -413,6 +413,9 @@ sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size) case SCTP_PEER_ADDR_THLDS: ((struct sctp_paddrthlds *)arg)->spt_assoc_id = id; break; + case SCTP_REMOTE_UDP_ENCAPS_PORT: + ((struct sctp_udpencaps *)arg)->sue_assoc_id = id; + break; case SCTP_MAX_BURST: ((struct sctp_assoc_value *)arg)->assoc_id = id; break; diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c index 39ae1d4..c24b382 100644 --- a/lib/libc/regex/regcomp.c +++ b/lib/libc/regex/regcomp.c @@ -3,9 +3,19 @@ * Copyright (c) 1992, 1993, 1994 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * This code is derived from software contributed to Berkeley by * Henry Spencer. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -81,10 +91,10 @@ extern "C" { #endif /* === regcomp.c === */ -static void p_ere(struct parse *p, wint_t stop); +static void p_ere(struct parse *p, int stop); static void p_ere_exp(struct parse *p); static void p_str(struct parse *p); -static void p_bre(struct parse *p, wint_t end1, wint_t end2); +static void p_bre(struct parse *p, int end1, int end2); static int p_simp_re(struct parse *p, int starordinary); static int p_count(struct parse *p); static void p_bracket(struct parse *p); @@ -109,7 +119,7 @@ static sopno dupl(struct parse *p, sopno start, sopno finish); static void doemit(struct parse *p, sop op, size_t opnd); static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos); static void dofwd(struct parse *p, sopno pos, sop value); -static void enlarge(struct parse *p, sopno size); +static int enlarge(struct parse *p, sopno size); static void stripsnug(struct parse *p, struct re_guts *g); static void findmust(struct parse *p, struct re_guts *g); static int altoffset(sop *scan, int offset); @@ -285,7 +295,7 @@ regcomp(regex_t * __restrict preg, /* - p_ere - ERE parser top level, concatenation and alternation - == static void p_ere(struct parse *p, int stop); + == static void p_ere(struct parse *p, int_t stop); */ static void p_ere(struct parse *p, @@ -493,7 +503,7 @@ p_str(struct parse *p) /* - p_bre - BRE parser top level, anchoring and concatenation - == static void p_bre(struct parse *p, int end1, \ + == static void p_bre(struct parse *p, int end1, \ == int end2); * Giving end1 as OUT essentially eliminates the end1/end2 check. * @@ -730,6 +740,8 @@ p_b_term(struct parse *p, cset *cs) char c; wint_t start, finish; wint_t i; + struct xlocale_collate *table = + (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; /* classify what we've got */ switch ((MORE()) ? PEEK() : '\0') { @@ -778,14 +790,14 @@ p_b_term(struct parse *p, cset *cs) if (start == finish) CHadd(p, cs, start); else { - if (__collate_load_error) { + if (table->__collate_load_error) { (void)REQUIRE((uch)start <= (uch)finish, REG_ERANGE); CHaddrange(p, cs, start, finish); } else { - (void)REQUIRE(__collate_range_cmp(start, finish) <= 0, REG_ERANGE); + (void)REQUIRE(__collate_range_cmp(table, start, finish) <= 0, REG_ERANGE); for (i = 0; i <= UCHAR_MAX; i++) { - if ( __collate_range_cmp(start, i) <= 0 - && __collate_range_cmp(i, finish) <= 0 + if ( __collate_range_cmp(table, start, i) <= 0 + && __collate_range_cmp(table, i, finish) <= 0 ) CHadd(p, cs, i); } @@ -840,7 +852,7 @@ p_b_eclass(struct parse *p, cset *cs) /* - p_b_symbol - parse a character or [..]ed multicharacter collating symbol - == static char p_b_symbol(struct parse *p); + == static wint_t p_b_symbol(struct parse *p); */ static wint_t /* value of symbol */ p_b_symbol(struct parse *p) @@ -859,7 +871,7 @@ p_b_symbol(struct parse *p) /* - p_b_coll_elem - parse a collating-element name and look it up - == static char p_b_coll_elem(struct parse *p, int endc); + == static wint_t p_b_coll_elem(struct parse *p, wint_t endc); */ static wint_t /* value of collating element */ p_b_coll_elem(struct parse *p, @@ -894,7 +906,7 @@ p_b_coll_elem(struct parse *p, /* - othercase - return the case counterpart of an alphabetic - == static char othercase(int ch); + == static wint_t othercase(wint_t ch); */ static wint_t /* if no counterpart, return ch */ othercase(wint_t ch) @@ -910,7 +922,7 @@ othercase(wint_t ch) /* - bothcases - emit a dualcase version of a two-case character - == static void bothcases(struct parse *p, int ch); + == static void bothcases(struct parse *p, wint_t ch); * * Boy, is this implementation ever a kludge... */ @@ -939,7 +951,7 @@ bothcases(struct parse *p, wint_t ch) /* - ordinary - emit an ordinary character - == static void ordinary(struct parse *p, int ch); + == static void ordinary(struct parse *p, wint_t ch); */ static void ordinary(struct parse *p, wint_t ch) @@ -1246,8 +1258,8 @@ dupl(struct parse *p, assert(finish >= start); if (len == 0) return(ret); - enlarge(p, p->ssize + len); /* this many unexpected additions */ - assert(p->ssize >= p->slen + len); + if (!enlarge(p, p->ssize + len)) /* this many unexpected additions */ + return(ret); (void) memcpy((char *)(p->strip + p->slen), (char *)(p->strip + start), (size_t)len*sizeof(sop)); p->slen += len; @@ -1274,8 +1286,8 @@ doemit(struct parse *p, sop op, size_t opnd) /* deal with undersized strip */ if (p->slen >= p->ssize) - enlarge(p, (p->ssize+1) / 2 * 3); /* +50% */ - assert(p->slen < p->ssize); + if (!enlarge(p, (p->ssize+1) / 2 * 3)) /* +50% */ + return; /* finally, it's all reduced to the easy case */ p->strip[p->slen++] = SOP(op, opnd); @@ -1334,23 +1346,24 @@ dofwd(struct parse *p, sopno pos, sop value) /* - enlarge - enlarge the strip - == static void enlarge(struct parse *p, sopno size); + == static int enlarge(struct parse *p, sopno size); */ -static void +static int enlarge(struct parse *p, sopno size) { sop *sp; if (p->ssize >= size) - return; + return 1; sp = (sop *)realloc(p->strip, size*sizeof(sop)); if (sp == NULL) { SETERROR(REG_ESPACE); - return; + return 0; } p->strip = sp; p->ssize = size; + return 1; } /* diff --git a/lib/libc/stdio/Symbol.map b/lib/libc/stdio/Symbol.map index df66ab3..cafb0c6 100644 --- a/lib/libc/stdio/Symbol.map +++ b/lib/libc/stdio/Symbol.map @@ -117,6 +117,46 @@ FBSD_1.1 { vdprintf; }; +FBSD_1.3 { + asprintf_l; + fprintf_l; + fwprintf_l; + printf_l; + snprintf_l; + sprintf_l; + swprintf_l; + vasprintf_l; + vfprintf_l; + vfwprintf_l; + vprintf_l; + vsnprintf_l; + vsprintf_l; + vswprintf_l; + vwprintf_l; + wprintf_l; + fgetwc_l; + fputwc_l; + ungetwc_l; + vfwscanf_l; + vswscanf_l; + fscanf_l; + fwscanf_l; + scanf_l; + sscanf_l; + swscanf_l; + vfscanf_l; + vscanf_l; + vsscanf_l; + vwscanf_l; + wscanf_l; + fgetws_l; + fputws_l; + getwc_l; + getwchar_l; + putwc_l; + putwchar_l; +}; + FBSDprivate_1.0 { _flockfile; _flockfile_debug_stub; diff --git a/lib/libc/stdio/asprintf.c b/lib/libc/stdio/asprintf.c index 90c62bc..cd475cd 100644 --- a/lib/libc/stdio/asprintf.c +++ b/lib/libc/stdio/asprintf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -35,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdarg.h> +#include <xlocale.h> int asprintf(char ** __restrict s, char const * __restrict fmt, ...) @@ -47,3 +53,15 @@ asprintf(char ** __restrict s, char const * __restrict fmt, ...) va_end(ap); return (ret); } +int +asprintf_l(char ** __restrict s, locale_t locale, char const * __restrict fmt, + ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vasprintf_l(s, locale, fmt, ap); + va_end(ap); + return (ret); +} diff --git a/lib/libc/stdio/fgetwc.c b/lib/libc/stdio/fgetwc.c index 3a5b09b..0e87753 100644 --- a/lib/libc/stdio/fgetwc.c +++ b/lib/libc/stdio/fgetwc.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -36,31 +41,39 @@ __FBSDID("$FreeBSD$"); #include "libc_private.h" #include "local.h" #include "mblocal.h" +#include "xlocale_private.h" /* * MT-safe version. */ wint_t -fgetwc(FILE *fp) +fgetwc_l(FILE *fp, locale_t locale) { wint_t r; + FIX_LOCALE(locale); FLOCKFILE(fp); ORIENT(fp, 1); - r = __fgetwc(fp); + r = __fgetwc(fp, locale); FUNLOCKFILE(fp); return (r); } +wint_t +fgetwc(FILE *fp) +{ + return fgetwc_l(fp, __get_locale()); +} /* * Non-MT-safe version. */ wint_t -__fgetwc(FILE *fp) +__fgetwc(FILE *fp, locale_t locale) { wchar_t wc; size_t nconv; + struct xlocale_ctype *l = XLOCALE_CTYPE(locale); if (fp->_r <= 0 && __srefill(fp)) return (WEOF); @@ -71,7 +84,7 @@ __fgetwc(FILE *fp) return (wc); } do { - nconv = __mbrtowc(&wc, fp->_p, fp->_r, &fp->_mbstate); + nconv = l->__mbrtowc(&wc, fp->_p, fp->_r, &fp->_mbstate); if (nconv == (size_t)-1) break; else if (nconv == (size_t)-2) diff --git a/lib/libc/stdio/fgetwln.c b/lib/libc/stdio/fgetwln.c index 1a1ad2d..6d9087b 100644 --- a/lib/libc/stdio/fgetwln.c +++ b/lib/libc/stdio/fgetwln.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,18 +38,20 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "libc_private.h" #include "local.h" +#include "xlocale_private.h" wchar_t * -fgetwln(FILE * __restrict fp, size_t *lenp) +fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale) { wint_t wc; size_t len; + FIX_LOCALE(locale); FLOCKFILE(fp); ORIENT(fp, 1); len = 0; - while ((wc = __fgetwc(fp)) != WEOF) { + while ((wc = __fgetwc(fp, locale)) != WEOF) { #define GROW 512 if (len * sizeof(wchar_t) >= fp->_lb._size && __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) @@ -65,3 +72,8 @@ error: *lenp = 0; return (NULL); } +wchar_t * +fgetwln(FILE * __restrict fp, size_t *lenp) +{ + return fgetwln_l(fp, lenp, __get_locale()); +} diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/fgetws.c index 550843d..f7a63fe 100644 --- a/lib/libc/stdio/fgetws.c +++ b/lib/libc/stdio/fgetws.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -38,12 +43,14 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" wchar_t * -fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp) +fgetws_l(wchar_t * __restrict ws, int n, FILE * __restrict fp, locale_t locale) { wchar_t *wsp; size_t nconv; const char *src; unsigned char *nl; + FIX_LOCALE(locale); + struct xlocale_ctype *l = XLOCALE_CTYPE(locale); FLOCKFILE(fp); ORIENT(fp, 1); @@ -60,7 +67,7 @@ fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp) do { src = fp->_p; nl = memchr(fp->_p, '\n', fp->_r); - nconv = __mbsnrtowcs(wsp, &src, + nconv = l->__mbsnrtowcs(wsp, &src, nl != NULL ? (nl - fp->_p + 1) : fp->_r, n - 1, &fp->_mbstate); if (nconv == (size_t)-1) @@ -86,7 +93,7 @@ fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp) if (wsp == ws) /* EOF */ goto error; - if (!__mbsinit(&fp->_mbstate)) + if (!l->__mbsinit(&fp->_mbstate)) /* Incomplete character */ goto error; *wsp = L'\0'; @@ -98,3 +105,8 @@ error: FUNLOCKFILE(fp); return (NULL); } +wchar_t * +fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp) +{ + return fgetws_l(ws, n, fp, __get_locale()); +} diff --git a/lib/libc/stdio/fprintf.c b/lib/libc/stdio/fprintf.c index bebc182..169532d 100644 --- a/lib/libc/stdio/fprintf.c +++ b/lib/libc/stdio/fprintf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -38,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdarg.h> +#include "xlocale_private.h" int fprintf(FILE * __restrict fp, const char * __restrict fmt, ...) @@ -46,7 +52,19 @@ fprintf(FILE * __restrict fp, const char * __restrict fmt, ...) va_list ap; va_start(ap, fmt); - ret = vfprintf(fp, fmt, ap); + ret = vfprintf_l(fp, __get_locale(), fmt, ap); + va_end(ap); + return (ret); +} +int +fprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt, ...) +{ + int ret; + va_list ap; + FIX_LOCALE(locale); + + va_start(ap, fmt); + ret = vfprintf_l(fp, locale, fmt, ap); va_end(ap); return (ret); } diff --git a/lib/libc/stdio/fputwc.c b/lib/libc/stdio/fputwc.c index ae92f66..7b05d4a 100644 --- a/lib/libc/stdio/fputwc.c +++ b/lib/libc/stdio/fputwc.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -42,10 +47,11 @@ __FBSDID("$FreeBSD$"); * Non-MT-safe version. */ wint_t -__fputwc(wchar_t wc, FILE *fp) +__fputwc(wchar_t wc, FILE *fp, locale_t locale) { char buf[MB_LEN_MAX]; size_t i, len; + struct xlocale_ctype *l = XLOCALE_CTYPE(locale); if (MB_CUR_MAX == 1 && wc > 0 && wc <= UCHAR_MAX) { /* @@ -56,7 +62,7 @@ __fputwc(wchar_t wc, FILE *fp) *buf = (unsigned char)wc; len = 1; } else { - if ((len = __wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) { + if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) { fp->_flags |= __SERR; return (WEOF); } @@ -73,14 +79,20 @@ __fputwc(wchar_t wc, FILE *fp) * MT-safe version. */ wint_t -fputwc(wchar_t wc, FILE *fp) +fputwc_l(wchar_t wc, FILE *fp, locale_t locale) { wint_t r; + FIX_LOCALE(locale); FLOCKFILE(fp); ORIENT(fp, 1); - r = __fputwc(wc, fp); + r = __fputwc(wc, fp, locale); FUNLOCKFILE(fp); return (r); } +wint_t +fputwc(wchar_t wc, FILE *fp) +{ + return fputwc_l(wc, fp, __get_locale()); +} diff --git a/lib/libc/stdio/fputws.c b/lib/libc/stdio/fputws.c index b4462b7..a318e2d 100644 --- a/lib/libc/stdio/fputws.c +++ b/lib/libc/stdio/fputws.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,13 +44,15 @@ __FBSDID("$FreeBSD$"); #include "mblocal.h" int -fputws(const wchar_t * __restrict ws, FILE * __restrict fp) +fputws_l(const wchar_t * __restrict ws, FILE * __restrict fp, locale_t locale) { size_t nbytes; char buf[BUFSIZ]; struct __suio uio; struct __siov iov; const wchar_t *wsp; + FIX_LOCALE(locale); + struct xlocale_ctype *l = XLOCALE_CTYPE(locale); FLOCKFILE(fp); ORIENT(fp, 1); @@ -56,7 +63,7 @@ fputws(const wchar_t * __restrict ws, FILE * __restrict fp) iov.iov_base = buf; do { wsp = ws; - nbytes = __wcsnrtombs(buf, &wsp, SIZE_T_MAX, sizeof(buf), + nbytes = l->__wcsnrtombs(buf, &wsp, SIZE_T_MAX, sizeof(buf), &fp->_mbstate); if (nbytes == (size_t)-1) goto error; @@ -71,3 +78,9 @@ error: FUNLOCKFILE(fp); return (-1); } + +int +fputws(const wchar_t * __restrict ws, FILE * __restrict fp) +{ + return fputws_l(ws, fp, __get_locale()); +} diff --git a/lib/libc/stdio/fscanf.c b/lib/libc/stdio/fscanf.c index ce3001a..c5fa85f 100644 --- a/lib/libc/stdio/fscanf.c +++ b/lib/libc/stdio/fscanf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -42,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "libc_private.h" #include "local.h" +#include "xlocale_private.h" int fscanf(FILE * __restrict fp, char const * __restrict fmt, ...) @@ -51,7 +57,21 @@ fscanf(FILE * __restrict fp, char const * __restrict fmt, ...) va_start(ap, fmt); FLOCKFILE(fp); - ret = __svfscanf(fp, fmt, ap); + ret = __svfscanf(fp, __get_locale(), fmt, ap); + va_end(ap); + FUNLOCKFILE(fp); + return (ret); +} +int +fscanf_l(FILE * __restrict fp, locale_t locale, char const * __restrict fmt, ...) +{ + int ret; + va_list ap; + FIX_LOCALE(locale); + + va_start(ap, fmt); + FLOCKFILE(fp); + ret = __svfscanf(fp, locale, fmt, ap); va_end(ap); FUNLOCKFILE(fp); return (ret); diff --git a/lib/libc/stdio/fwprintf.c b/lib/libc/stdio/fwprintf.c index a22edae..f4342ab 100644 --- a/lib/libc/stdio/fwprintf.c +++ b/lib/libc/stdio/fwprintf.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <stdarg.h> #include <stdio.h> #include <wchar.h> +#include <xlocale.h> int fwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...) @@ -43,3 +49,15 @@ fwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...) return (ret); } +int +fwprintf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vfwprintf_l(fp, locale, fmt, ap); + va_end(ap); + + return (ret); +} diff --git a/lib/libc/stdio/fwscanf.c b/lib/libc/stdio/fwscanf.c index f779c53..1756077 100644 --- a/lib/libc/stdio/fwscanf.c +++ b/lib/libc/stdio/fwscanf.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <stdarg.h> #include <stdio.h> #include <wchar.h> +#include <xlocale.h> int fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...) @@ -43,3 +49,15 @@ fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...) return (r); } +int +fwscanf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = vfwscanf_l(fp, locale, fmt, ap); + va_end(ap); + + return (r); +} diff --git a/lib/libc/stdio/getwc.c b/lib/libc/stdio/getwc.c index ba5ab60..666350b 100644 --- a/lib/libc/stdio/getwc.c +++ b/lib/libc/stdio/getwc.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include <stdio.h> #include <wchar.h> +#include <xlocale.h> #include "un-namespace.h" #include "libc_private.h" #include "local.h" @@ -46,3 +52,9 @@ getwc(FILE *fp) return (fgetwc(fp)); } +wint_t +getwc_l(FILE *fp, locale_t locale) +{ + + return (fgetwc_l(fp, locale)); +} diff --git a/lib/libc/stdio/getwchar.c b/lib/libc/stdio/getwchar.c index 79dd7bc..bc3b8a6 100644 --- a/lib/libc/stdio/getwchar.c +++ b/lib/libc/stdio/getwchar.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include <stdio.h> #include <wchar.h> +#include <xlocale.h> #include "un-namespace.h" #include "libc_private.h" #include "local.h" @@ -42,6 +48,10 @@ __FBSDID("$FreeBSD$"); wint_t getwchar(void) { - return (fgetwc(stdin)); } +wint_t +getwchar_l(locale_t locale) +{ + return (fgetwc_l(stdin, locale)); +} diff --git a/lib/libc/stdio/local.h b/lib/libc/stdio/local.h index 6380b83..8b37f0d 100644 --- a/lib/libc/stdio/local.h +++ b/lib/libc/stdio/local.h @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,6 +42,7 @@ #include <pthread.h> #include <string.h> #include <wchar.h> +#include <locale.h> /* * Information local to this implementation of stdio, @@ -50,8 +56,8 @@ extern int _ftello(FILE *, fpos_t *); extern int _fseeko(FILE *, off_t, int, int); extern int __fflush(FILE *fp); extern void __fcloseall(void); -extern wint_t __fgetwc(FILE *); -extern wint_t __fputwc(wchar_t, FILE *); +extern wint_t __fgetwc(FILE *, locale_t); +extern wint_t __fputwc(wchar_t, FILE *, locale_t); extern int __sflush(FILE *); extern FILE *__sfp(void); extern int __slbexpand(FILE *, size_t); @@ -65,15 +71,15 @@ extern void _cleanup(void); extern void __smakebuf(FILE *); extern int __swhatbuf(FILE *, size_t *, int *); extern int _fwalk(int (*)(FILE *)); -extern int __svfscanf(FILE *, const char *, __va_list); +extern int __svfscanf(FILE *, locale_t, const char *, __va_list); extern int __swsetup(FILE *); extern int __sflags(const char *, int *); extern int __ungetc(int, FILE *); -extern wint_t __ungetwc(wint_t, FILE *); -extern int __vfprintf(FILE *, const char *, __va_list); +extern wint_t __ungetwc(wint_t, FILE *, locale_t); +extern int __vfprintf(FILE *, locale_t, const char *, __va_list); extern int __vfscanf(FILE *, const char *, __va_list); -extern int __vfwprintf(FILE *, const wchar_t *, __va_list); -extern int __vfwscanf(FILE * __restrict, const wchar_t * __restrict, +extern int __vfwprintf(FILE *, locale_t, const wchar_t *, __va_list); +extern int __vfwscanf(FILE * __restrict, locale_t, const wchar_t * __restrict, __va_list); extern size_t __fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp); diff --git a/lib/libc/stdio/printf.c b/lib/libc/stdio/printf.c index df290fa..f623f2f 100644 --- a/lib/libc/stdio/printf.c +++ b/lib/libc/stdio/printf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -38,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdarg.h> +#include <xlocale.h> int printf(char const * __restrict fmt, ...) @@ -50,3 +56,14 @@ printf(char const * __restrict fmt, ...) va_end(ap); return (ret); } +int +printf_l(locale_t locale, char const * __restrict fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vfprintf_l(stdout, locale, fmt, ap); + va_end(ap); + return (ret); +} diff --git a/lib/libc/stdio/printfcommon.h b/lib/libc/stdio/printfcommon.h index 39b0003..97acc53 100644 --- a/lib/libc/stdio/printfcommon.h +++ b/lib/libc/stdio/printfcommon.h @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -79,14 +84,14 @@ io_init(struct io_state *iop, FILE *fp) * remain valid until io_flush() is called. */ static inline int -io_print(struct io_state *iop, const CHAR * __restrict ptr, int len) +io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale) { iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr; iop->iov[iop->uio.uio_iovcnt].iov_len = len; iop->uio.uio_resid += len; if (++iop->uio.uio_iovcnt >= NIOV) - return (__sprint(iop->fp, &iop->uio)); + return (__sprint(iop->fp, &iop->uio, locale)); else return (0); } @@ -107,13 +112,14 @@ static const CHAR zeroes[PADSIZE] = * or the zeroes array. */ static inline int -io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with) +io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with, + locale_t locale) { int n; while (howmany > 0) { n = (howmany >= PADSIZE) ? PADSIZE : howmany; - if (io_print(iop, with, n)) + if (io_print(iop, with, n, locale)) return (-1); howmany -= n; } @@ -126,7 +132,7 @@ io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with) */ static inline int io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, - int len, const CHAR * __restrict with) + int len, const CHAR * __restrict with, locale_t locale) { int p_len; @@ -134,19 +140,19 @@ io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep, if (p_len > len) p_len = len; if (p_len > 0) { - if (io_print(iop, p, p_len)) + if (io_print(iop, p, p_len, locale)) return (-1); } else { p_len = 0; } - return (io_pad(iop, len - p_len, with)); + return (io_pad(iop, len - p_len, with, locale)); } static inline int -io_flush(struct io_state *iop) +io_flush(struct io_state *iop, locale_t locale) { - return (__sprint(iop->fp, &iop->uio)); + return (__sprint(iop->fp, &iop->uio, locale)); } /* diff --git a/lib/libc/stdio/putwc.c b/lib/libc/stdio/putwc.c index 8fe065b..56acf50 100644 --- a/lib/libc/stdio/putwc.c +++ b/lib/libc/stdio/putwc.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "libc_private.h" #include "local.h" +#include "xlocale_private.h" #undef putwc @@ -41,8 +47,13 @@ __FBSDID("$FreeBSD$"); * macro, may evaluate `fp' more than once. */ wint_t +putwc_l(wchar_t wc, FILE *fp, locale_t locale) +{ + FIX_LOCALE(locale); + return (fputwc_l(wc, fp, locale)); +} +wint_t putwc(wchar_t wc, FILE *fp) { - - return (fputwc(wc, fp)); + return putwc_l(wc, fp, __get_locale()); } diff --git a/lib/libc/stdio/putwchar.c b/lib/libc/stdio/putwchar.c index 5503071..8673bd5 100644 --- a/lib/libc/stdio/putwchar.c +++ b/lib/libc/stdio/putwchar.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,6 +38,7 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "libc_private.h" #include "local.h" +#include "xlocale_private.h" #undef putwchar @@ -40,8 +46,13 @@ __FBSDID("$FreeBSD$"); * Synonym for fputwc(wc, stdout). */ wint_t +putwchar_l(wchar_t wc, locale_t locale) +{ + FIX_LOCALE(locale); + return (fputwc_l(wc, stdout, locale)); +} +wint_t putwchar(wchar_t wc) { - - return (fputwc(wc, stdout)); + return putwchar_l(wc, __get_locale()); } diff --git a/lib/libc/stdio/scanf.c b/lib/libc/stdio/scanf.c index 4ae88da..ba33caa 100644 --- a/lib/libc/stdio/scanf.c +++ b/lib/libc/stdio/scanf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -42,6 +47,7 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "libc_private.h" #include "local.h" +#include "xlocale_private.h" int scanf(char const * __restrict fmt, ...) @@ -51,7 +57,21 @@ scanf(char const * __restrict fmt, ...) va_start(ap, fmt); FLOCKFILE(stdin); - ret = __svfscanf(stdin, fmt, ap); + ret = __svfscanf(stdin, __get_locale(), fmt, ap); + FUNLOCKFILE(stdin); + va_end(ap); + return (ret); +} +int +scanf_l(locale_t locale, char const * __restrict fmt, ...) +{ + int ret; + va_list ap; + FIX_LOCALE(locale); + + va_start(ap, fmt); + FLOCKFILE(stdin); + ret = __svfscanf(stdin, locale, fmt, ap); FUNLOCKFILE(stdin); va_end(ap); return (ret); diff --git a/lib/libc/stdio/snprintf.c b/lib/libc/stdio/snprintf.c index e6d7115..74af42d 100644 --- a/lib/libc/stdio/snprintf.c +++ b/lib/libc/stdio/snprintf.c @@ -2,6 +2,11 @@ * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * This code is derived from software contributed to Berkeley by * Chris Torek. * @@ -39,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <limits.h> #include <stdio.h> #include <stdarg.h> +#include "xlocale_private.h" #include "local.h" @@ -59,7 +65,32 @@ snprintf(char * __restrict str, size_t n, char const * __restrict fmt, ...) f._flags = __SWR | __SSTR; f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = n; - ret = __vfprintf(&f, fmt, ap); + ret = __vfprintf(&f, __get_locale(), fmt, ap); + if (on > 0) + *f._p = '\0'; + va_end(ap); + return (ret); +} +int +snprintf_l(char * __restrict str, size_t n, locale_t locale, + char const * __restrict fmt, ...) +{ + size_t on; + int ret; + va_list ap; + FILE f = FAKE_FILE; + FIX_LOCALE(locale); + + on = n; + if (n != 0) + n--; + if (n > INT_MAX) + n = INT_MAX; + va_start(ap, fmt); + f._flags = __SWR | __SSTR; + f._bf._base = f._p = (unsigned char *)str; + f._bf._size = f._w = n; + ret = __vfprintf(&f, locale, fmt, ap); if (on > 0) *f._p = '\0'; va_end(ap); diff --git a/lib/libc/stdio/sprintf.c b/lib/libc/stdio/sprintf.c index b55bd6c..6e20e04 100644 --- a/lib/libc/stdio/sprintf.c +++ b/lib/libc/stdio/sprintf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -40,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include <stdarg.h> #include <limits.h> #include "local.h" +#include "xlocale_private.h" int sprintf(char * __restrict str, char const * __restrict fmt, ...) @@ -52,3 +58,16 @@ sprintf(char * __restrict str, char const * __restrict fmt, ...) va_end(ap); return (ret); } +int +sprintf_l(char * __restrict str, locale_t locale, char const * __restrict fmt, + ...) +{ + int ret; + va_list ap; + FIX_LOCALE(locale); + + va_start(ap, fmt); + ret = vsprintf_l(str, locale, fmt, ap); + va_end(ap); + return (ret); +} diff --git a/lib/libc/stdio/sscanf.c b/lib/libc/stdio/sscanf.c index c793b86..1c339eb 100644 --- a/lib/libc/stdio/sscanf.c +++ b/lib/libc/stdio/sscanf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <string.h> #include <stdarg.h> +#include <xlocale.h> #include "local.h" int @@ -52,3 +58,15 @@ sscanf(const char * __restrict str, char const * __restrict fmt, ...) va_end(ap); return (ret); } +int +sscanf_l(const char * __restrict str, locale_t locale, + char const * __restrict fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vsscanf_l(str, locale, fmt, ap); + va_end(ap); + return (ret); +} diff --git a/lib/libc/stdio/swprintf.c b/lib/libc/stdio/swprintf.c index d665318..1f6ecc6 100644 --- a/lib/libc/stdio/swprintf.c +++ b/lib/libc/stdio/swprintf.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <stdarg.h> #include <stdio.h> #include <wchar.h> +#include <xlocale.h> int swprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, ...) @@ -43,3 +49,16 @@ swprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, ...) return (ret); } +int +swprintf_l(wchar_t * __restrict s, size_t n, locale_t locale, + const wchar_t * __restrict fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vswprintf_l(s, n, locale, fmt, ap); + va_end(ap); + + return (ret); +} diff --git a/lib/libc/stdio/swscanf.c b/lib/libc/stdio/swscanf.c index 728a3d6..c305ac1 100644 --- a/lib/libc/stdio/swscanf.c +++ b/lib/libc/stdio/swscanf.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <stdarg.h> #include <stdio.h> #include <wchar.h> +#include <xlocale.h> int swscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, ...) @@ -43,3 +49,16 @@ swscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, ...) return (r); } +int +swscanf_l(const wchar_t * __restrict str, locale_t locale, + const wchar_t * __restrict fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = vswscanf_l(str, locale, fmt, ap); + va_end(ap); + + return (r); +} diff --git a/lib/libc/stdio/ungetwc.c b/lib/libc/stdio/ungetwc.c index 10dbbbf..78bc38d 100644 --- a/lib/libc/stdio/ungetwc.c +++ b/lib/libc/stdio/ungetwc.c @@ -2,6 +2,11 @@ * Copyright (c) 2002-2004 Tim J. Robbins. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,19 +42,21 @@ __FBSDID("$FreeBSD$"); #include "libc_private.h" #include "local.h" #include "mblocal.h" +#include "xlocale_private.h" /* * Non-MT-safe version. */ wint_t -__ungetwc(wint_t wc, FILE *fp) +__ungetwc(wint_t wc, FILE *fp, locale_t locale) { char buf[MB_LEN_MAX]; size_t len; + struct xlocale_ctype *l = XLOCALE_CTYPE(locale); if (wc == WEOF) return (WEOF); - if ((len = __wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) { + if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) { fp->_flags |= __SERR; return (WEOF); } @@ -64,14 +71,20 @@ __ungetwc(wint_t wc, FILE *fp) * MT-safe version. */ wint_t -ungetwc(wint_t wc, FILE *fp) +ungetwc_l(wint_t wc, FILE *fp, locale_t locale) { wint_t r; + FIX_LOCALE(locale); FLOCKFILE(fp); ORIENT(fp, 1); - r = __ungetwc(wc, fp); + r = __ungetwc(wc, fp, locale); FUNLOCKFILE(fp); return (r); } +wint_t +ungetwc(wint_t wc, FILE *fp) +{ + return ungetwc_l(wc, fp, __get_locale()); +} diff --git a/lib/libc/stdio/vasprintf.c b/lib/libc/stdio/vasprintf.c index a1b600a..8feb23d 100644 --- a/lib/libc/stdio/vasprintf.c +++ b/lib/libc/stdio/vasprintf.c @@ -4,6 +4,11 @@ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,13 +38,15 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdlib.h> #include <errno.h> +#include "xlocale_private.h" #include "local.h" int -vasprintf(char **str, const char *fmt, __va_list ap) +vasprintf_l(char **str, locale_t locale, const char *fmt, __va_list ap) { FILE f = FAKE_FILE; int ret; + FIX_LOCALE(locale); f._flags = __SWR | __SSTR | __SALC; f._bf._base = f._p = malloc(128); @@ -49,7 +56,7 @@ vasprintf(char **str, const char *fmt, __va_list ap) return (-1); } f._bf._size = f._w = 127; /* Leave room for the NUL */ - ret = __vfprintf(&f, fmt, ap); + ret = __vfprintf(&f, locale, fmt, ap); if (ret < 0) { free(f._bf._base); *str = NULL; @@ -60,3 +67,8 @@ vasprintf(char **str, const char *fmt, __va_list ap) *str = (char *)f._bf._base; return (ret); } +int +vasprintf(char **str, const char *fmt, __va_list ap) +{ + return vasprintf_l(str, __get_locale(), fmt, ap); +} diff --git a/lib/libc/stdio/vdprintf.c b/lib/libc/stdio/vdprintf.c index 3ad273e..454b0f9 100644 --- a/lib/libc/stdio/vdprintf.c +++ b/lib/libc/stdio/vdprintf.c @@ -2,6 +2,11 @@ * Copyright (c) 2009 David Schultz <das@FreeBSD.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -35,6 +40,7 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "local.h" +#include "xlocale_private.h" int vdprintf(int fd, const char * __restrict fmt, va_list ap) @@ -57,7 +63,7 @@ vdprintf(int fd, const char * __restrict fmt, va_list ap) f._bf._base = buf; f._bf._size = sizeof(buf); - if ((ret = __vfprintf(&f, fmt, ap)) < 0) + if ((ret = __vfprintf(&f, __get_locale(), fmt, ap)) < 0) return (ret); return (__fflush(&f) ? EOF : ret); diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c index 17ad824..bfbdc13 100644 --- a/lib/libc/stdio/vfprintf.c +++ b/lib/libc/stdio/vfprintf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -57,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include <printf.h> #include <stdarg.h> +#include "xlocale_private.h" #include "un-namespace.h" #include "libc_private.h" @@ -64,8 +70,8 @@ __FBSDID("$FreeBSD$"); #include "fvwrite.h" #include "printflocal.h" -static int __sprint(FILE *, struct __suio *); -static int __sbprintf(FILE *, const char *, va_list) __printflike(2, 0) +static int __sprint(FILE *, struct __suio *, locale_t); +static int __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0) __noinline; static char *__wcsconv(wchar_t *, int); @@ -87,11 +93,11 @@ struct grouping_state { * of bytes that will be needed. */ static int -grouping_init(struct grouping_state *gs, int ndigits) +grouping_init(struct grouping_state *gs, int ndigits, locale_t loc) { struct lconv *locale; - locale = localeconv(); + locale = localeconv_l(loc); gs->grouping = locale->grouping; gs->thousands_sep = locale->thousands_sep; gs->thousep_len = strlen(gs->thousands_sep); @@ -116,11 +122,11 @@ grouping_init(struct grouping_state *gs, int ndigits) */ static int grouping_print(struct grouping_state *gs, struct io_state *iop, - const CHAR *cp, const CHAR *ep) + const CHAR *cp, const CHAR *ep, locale_t locale) { const CHAR *cp0 = cp; - if (io_printandpad(iop, cp, ep, gs->lead, zeroes)) + if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale)) return (-1); cp += gs->lead; while (gs->nseps > 0 || gs->nrepeats > 0) { @@ -130,9 +136,9 @@ grouping_print(struct grouping_state *gs, struct io_state *iop, gs->grouping--; gs->nseps--; } - if (io_print(iop, gs->thousands_sep, gs->thousep_len)) + if (io_print(iop, gs->thousands_sep, gs->thousep_len, locale)) return (-1); - if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes)) + if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale)) return (-1); cp += *gs->grouping; } @@ -146,7 +152,7 @@ grouping_print(struct grouping_state *gs, struct io_state *iop, * then reset it so that it can be reused. */ static int -__sprint(FILE *fp, struct __suio *uio) +__sprint(FILE *fp, struct __suio *uio, locale_t locale) { int err; @@ -166,7 +172,7 @@ __sprint(FILE *fp, struct __suio *uio) * worries about ungetc buffers and so forth. */ static int -__sbprintf(FILE *fp, const char *fmt, va_list ap) +__sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap) { int ret; FILE fake = FAKE_FILE; @@ -190,7 +196,7 @@ __sbprintf(FILE *fp, const char *fmt, va_list ap) fake._lbfsize = 0; /* not actually used, but Just In Case */ /* do the work, then copy any error status */ - ret = __vfprintf(&fake, fmt, ap); + ret = __vfprintf(&fake, locale, fmt, ap); if (ret >= 0 && __fflush(&fake)) ret = EOF; if (fake._flags & __SERR) @@ -261,21 +267,27 @@ __wcsconv(wchar_t *wcsarg, int prec) * MT-safe version */ int -vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) - +vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0, + va_list ap) { int ret; + FIX_LOCALE(locale); FLOCKFILE(fp); /* optimise fprintf(stderr) (and other unbuffered Unix files) */ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && fp->_file >= 0) - ret = __sbprintf(fp, fmt0, ap); + ret = __sbprintf(fp, locale, fmt0, ap); else - ret = __vfprintf(fp, fmt0, ap); + ret = __vfprintf(fp, locale, fmt0, ap); FUNLOCKFILE(fp); return (ret); } +int +vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) +{ + return vfprintf_l(fp, __get_locale(), fmt0, ap); +} /* * The size of the buffer we use as scratch space for integer @@ -292,7 +304,7 @@ vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap) * Non-MT-safe version */ int -__vfprintf(FILE *fp, const char *fmt0, va_list ap) +__vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) { char *fmt; /* format string */ int ch; /* character from fmt */ @@ -357,19 +369,19 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) /* BEWARE, these `goto error' on error. */ #define PRINT(ptr, len) { \ - if (io_print(&io, (ptr), (len))) \ + if (io_print(&io, (ptr), (len), locale)) \ goto error; \ } #define PAD(howmany, with) { \ - if (io_pad(&io, (howmany), (with))) \ + if (io_pad(&io, (howmany), (with), locale)) \ goto error; \ } #define PRINTANDPAD(p, ep, len, with) { \ - if (io_printandpad(&io, (p), (ep), (len), (with))) \ + if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \ goto error; \ } #define FLUSH() { \ - if (io_flush(&io)) \ + if (io_flush(&io, locale)) \ goto error; \ } @@ -454,7 +466,7 @@ __vfprintf(FILE *fp, const char *fmt0, va_list ap) ret = 0; #ifndef NO_FLOATING_POINT dtoaresult = NULL; - decimal_point = localeconv()->decimal_point; + decimal_point = localeconv_l(locale)->decimal_point; /* The overwhelmingly common case is decpt_len == 1. */ decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point)); #endif @@ -750,7 +762,7 @@ fp_common: if (prec || flags & ALT) size += prec + decpt_len; if ((flags & GROUPING) && expt > 0) - size += grouping_init(&gs, expt); + size += grouping_init(&gs, expt, locale); } break; #endif /* !NO_FLOATING_POINT */ @@ -887,7 +899,7 @@ number: if ((dprec = prec) >= 0) if (size > BUF) /* should never happen */ abort(); if ((flags & GROUPING) && size != 0) - size += grouping_init(&gs, size); + size += grouping_init(&gs, size, locale); break; default: /* "%?" prints ?, unless ? is NUL */ if (ch == '\0') @@ -950,7 +962,7 @@ number: if ((dprec = prec) >= 0) /* leading zeroes from decimal precision */ PAD(dprec - size, zeroes); if (gs.grouping) { - if (grouping_print(&gs, &io, cp, buf+BUF) < 0) + if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0) goto error; } else { PRINT(cp, size); @@ -968,7 +980,7 @@ number: if ((dprec = prec) >= 0) } else { if (gs.grouping) { n = grouping_print(&gs, &io, - cp, dtoaend); + cp, dtoaend, locale); if (n < 0) goto error; cp += n; diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c index bce4481..0e78949 100644 --- a/lib/libc/stdio/vfscanf.c +++ b/lib/libc/stdio/vfscanf.c @@ -2,6 +2,11 @@ * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * This code is derived from software contributed to Berkeley by * Chris Torek. * @@ -51,6 +56,7 @@ __FBSDID("$FreeBSD$"); #include "collate.h" #include "libc_private.h" #include "local.h" +#include "xlocale_private.h" #ifndef NO_FLOATING_POINT #include <locale.h> @@ -95,7 +101,7 @@ __FBSDID("$FreeBSD$"); static const u_char *__sccl(char *, const u_char *); #ifndef NO_FLOATING_POINT -static int parsefloat(FILE *, char *, char *); +static int parsefloat(FILE *, char *, char *, locale_t); #endif __weak_reference(__vfscanf, vfscanf); @@ -109,7 +115,18 @@ __vfscanf(FILE *fp, char const *fmt0, va_list ap) int ret; FLOCKFILE(fp); - ret = __svfscanf(fp, fmt0, ap); + ret = __svfscanf(fp, __get_locale(), fmt0, ap); + FUNLOCKFILE(fp); + return (ret); +} +int +vfscanf_l(FILE *fp, locale_t locale, char const *fmt0, va_list ap) +{ + int ret; + FIX_LOCALE(locale); + + FLOCKFILE(fp); + ret = __svfscanf(fp, locale, fmt0, ap); FUNLOCKFILE(fp); return (ret); } @@ -118,7 +135,7 @@ __vfscanf(FILE *fp, char const *fmt0, va_list ap) * __svfscanf - non-MT-safe version of __vfscanf */ int -__svfscanf(FILE *fp, const char *fmt0, va_list ap) +__svfscanf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) { const u_char *fmt = (const u_char *)fmt0; int c; /* character from format, or conversion */ @@ -733,9 +750,9 @@ literal: *p = 0; if ((flags & UNSIGNED) == 0) - res = strtoimax(buf, (char **)NULL, base); + res = strtoimax_l(buf, (char **)NULL, base, locale); else - res = strtoumax(buf, (char **)NULL, base); + res = strtoumax_l(buf, (char **)NULL, base, locale); if (flags & POINTER) *va_arg(ap, void **) = (void *)(uintptr_t)res; @@ -766,17 +783,17 @@ literal: /* scan a floating point number as if by strtod */ if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1; - if ((width = parsefloat(fp, buf, buf + width)) == 0) + if ((width = parsefloat(fp, buf, buf + width, locale)) == 0) goto match_failure; if ((flags & SUPPRESS) == 0) { if (flags & LONGDBL) { - long double res = strtold(buf, &p); + long double res = strtold_l(buf, &p, locale); *va_arg(ap, long double *) = res; } else if (flags & LONG) { - double res = strtod(buf, &p); + double res = strtod_l(buf, &p, locale); *va_arg(ap, double *) = res; } else { - float res = strtof(buf, &p); + float res = strtof_l(buf, &p, locale); *va_arg(ap, float *) = res; } nassigned++; @@ -805,6 +822,8 @@ __sccl(tab, fmt) const u_char *fmt; { int c, n, v, i; + struct xlocale_collate *table = + (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; /* first `clear' the whole table */ c = *fmt++; /* first char hat => negated scanset */ @@ -858,8 +877,8 @@ doswitch: */ n = *fmt; if (n == ']' - || (__collate_load_error ? n < c : - __collate_range_cmp (n, c) < 0 + || (table->__collate_load_error ? n < c : + __collate_range_cmp (table, n, c) < 0 ) ) { c = '-'; @@ -867,14 +886,14 @@ doswitch: } fmt++; /* fill in the range */ - if (__collate_load_error) { + if (table->__collate_load_error) { do { tab[++c] = v; } while (c < n); } else { for (i = 0; i < 256; i ++) - if ( __collate_range_cmp (c, i) < 0 - && __collate_range_cmp (i, n) <= 0 + if ( __collate_range_cmp (table, c, i) < 0 + && __collate_range_cmp (table, i, n) <= 0 ) tab[i] = v; } @@ -908,7 +927,7 @@ doswitch: #ifndef NO_FLOATING_POINT static int -parsefloat(FILE *fp, char *buf, char *end) +parsefloat(FILE *fp, char *buf, char *end, locale_t locale) { char *commit, *p; int infnanpos = 0, decptpos = 0; @@ -917,7 +936,7 @@ parsefloat(FILE *fp, char *buf, char *end) S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS } state = S_START; unsigned char c; - const char *decpt = localeconv()->decimal_point; + const char *decpt = localeconv_l(locale)->decimal_point; _Bool gotmantdig = 0, ishex = 0; /* diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c index d34f559..73e37c9 100644 --- a/lib/libc/stdio/vfwprintf.c +++ b/lib/libc/stdio/vfwprintf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -65,10 +70,11 @@ __FBSDID("$FreeBSD$"); #include "local.h" #include "fvwrite.h" #include "printflocal.h" +#include "xlocale_private.h" -static int __sprint(FILE *, struct __suio *); -static int __sbprintf(FILE *, const wchar_t *, va_list) __noinline; -static wint_t __xfputwc(wchar_t, FILE *); +static int __sprint(FILE *, struct __suio *, locale_t); +static int __sbprintf(FILE *, locale_t, const wchar_t *, va_list) __noinline; +static wint_t __xfputwc(wchar_t, FILE *, locale_t); static wchar_t *__mbsconv(char *, int); #define CHAR wchar_t @@ -85,28 +91,28 @@ struct grouping_state { static const mbstate_t initial_mbs; static inline wchar_t -get_decpt(void) +get_decpt(locale_t locale) { mbstate_t mbs; wchar_t decpt; int nconv; mbs = initial_mbs; - nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs); + nconv = mbrtowc(&decpt, localeconv_l(locale)->decimal_point, MB_CUR_MAX, &mbs); if (nconv == (size_t)-1 || nconv == (size_t)-2) decpt = '.'; /* failsafe */ return (decpt); } static inline wchar_t -get_thousep(void) +get_thousep(locale_t locale) { mbstate_t mbs; wchar_t thousep; int nconv; mbs = initial_mbs; - nconv = mbrtowc(&thousep, localeconv()->thousands_sep, + nconv = mbrtowc(&thousep, localeconv_l(locale)->thousands_sep, MB_CUR_MAX, &mbs); if (nconv == (size_t)-1 || nconv == (size_t)-2) thousep = '\0'; /* failsafe */ @@ -119,11 +125,11 @@ get_thousep(void) * of wide characters that will be printed. */ static int -grouping_init(struct grouping_state *gs, int ndigits) +grouping_init(struct grouping_state *gs, int ndigits, locale_t locale) { - gs->grouping = localeconv()->grouping; - gs->thousands_sep = get_thousep(); + gs->grouping = localeconv_l(locale)->grouping; + gs->thousands_sep = get_thousep(locale); gs->nseps = gs->nrepeats = 0; gs->lead = ndigits; @@ -145,11 +151,11 @@ grouping_init(struct grouping_state *gs, int ndigits) */ static int grouping_print(struct grouping_state *gs, struct io_state *iop, - const CHAR *cp, const CHAR *ep) + const CHAR *cp, const CHAR *ep, locale_t locale) { const CHAR *cp0 = cp; - if (io_printandpad(iop, cp, ep, gs->lead, zeroes)) + if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale)) return (-1); cp += gs->lead; while (gs->nseps > 0 || gs->nrepeats > 0) { @@ -159,9 +165,9 @@ grouping_print(struct grouping_state *gs, struct io_state *iop, gs->grouping--; gs->nseps--; } - if (io_print(iop, &gs->thousands_sep, 1)) + if (io_print(iop, &gs->thousands_sep, 1, locale)) return (-1); - if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes)) + if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale)) return (-1); cp += *gs->grouping; } @@ -180,7 +186,7 @@ grouping_print(struct grouping_state *gs, struct io_state *iop, * string eclipses the benefits of buffering. */ static int -__sprint(FILE *fp, struct __suio *uio) +__sprint(FILE *fp, struct __suio *uio, locale_t locale) { struct __siov *iov; wchar_t *p; @@ -191,7 +197,7 @@ __sprint(FILE *fp, struct __suio *uio) p = (wchar_t *)iov->iov_base; len = iov->iov_len; for (i = 0; i < len; i++) { - if (__xfputwc(p[i], fp) == WEOF) + if (__xfputwc(p[i], fp, locale) == WEOF) return (-1); } } @@ -205,7 +211,7 @@ __sprint(FILE *fp, struct __suio *uio) * worries about ungetc buffers and so forth. */ static int -__sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) +__sbprintf(FILE *fp, locale_t locale, const wchar_t *fmt, va_list ap) { int ret; FILE fake; @@ -229,7 +235,7 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) fake._lbfsize = 0; /* not actually used, but Just In Case */ /* do the work, then copy any error status */ - ret = __vfwprintf(&fake, fmt, ap); + ret = __vfwprintf(&fake, locale, fmt, ap); if (ret >= 0 && __fflush(&fake)) ret = WEOF; if (fake._flags & __SERR) @@ -242,7 +248,7 @@ __sbprintf(FILE *fp, const wchar_t *fmt, va_list ap) * File must already be locked. */ static wint_t -__xfputwc(wchar_t wc, FILE *fp) +__xfputwc(wchar_t wc, FILE *fp, locale_t locale) { mbstate_t mbs; char buf[MB_LEN_MAX]; @@ -251,7 +257,7 @@ __xfputwc(wchar_t wc, FILE *fp) size_t len; if ((fp->_flags & __SSTR) == 0) - return (__fputwc(wc, fp)); + return (__fputwc(wc, fp, locale)); mbs = initial_mbs; if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) { @@ -343,21 +349,27 @@ __mbsconv(char *mbsarg, int prec) * MT-safe version */ int -vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap) +vfwprintf_l(FILE * __restrict fp, locale_t locale, + const wchar_t * __restrict fmt0, va_list ap) { int ret; - + FIX_LOCALE(locale); FLOCKFILE(fp); /* optimise fprintf(stderr) (and other unbuffered Unix files) */ if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) && fp->_file >= 0) - ret = __sbprintf(fp, fmt0, ap); + ret = __sbprintf(fp, locale, fmt0, ap); else - ret = __vfwprintf(fp, fmt0, ap); + ret = __vfwprintf(fp, locale, fmt0, ap); FUNLOCKFILE(fp); return (ret); } +int +vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap) +{ + return vfwprintf_l(fp, __get_locale(), fmt0, ap); +} /* * The size of the buffer we use as scratch space for integer @@ -374,7 +386,7 @@ vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap) * Non-MT-safe version */ int -__vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) +__vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap) { wchar_t *fmt; /* format string */ wchar_t ch; /* character from fmt */ @@ -437,19 +449,19 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) /* BEWARE, these `goto error' on error. */ #define PRINT(ptr, len) do { \ - if (io_print(&io, (ptr), (len))) \ + if (io_print(&io, (ptr), (len), locale)) \ goto error; \ } while (0) #define PAD(howmany, with) { \ - if (io_pad(&io, (howmany), (with))) \ + if (io_pad(&io, (howmany), (with), locale)) \ goto error; \ } #define PRINTANDPAD(p, ep, len, with) { \ - if (io_printandpad(&io, (p), (ep), (len), (with))) \ + if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \ goto error; \ } #define FLUSH() { \ - if (io_flush(&io)) \ + if (io_flush(&io, locale)) \ goto error; \ } @@ -529,7 +541,7 @@ __vfwprintf(FILE *fp, const wchar_t *fmt0, va_list ap) io_init(&io, fp); ret = 0; #ifndef NO_FLOATING_POINT - decimal_point = get_decpt(); + decimal_point = get_decpt(locale); #endif /* @@ -816,7 +828,7 @@ fp_common: if (prec || flags & ALT) size += prec + 1; if ((flags & GROUPING) && expt > 0) - size += grouping_init(&gs, expt); + size += grouping_init(&gs, expt, locale); } break; #endif /* !NO_FLOATING_POINT */ @@ -955,7 +967,7 @@ number: if ((dprec = prec) >= 0) if (size > BUF) /* should never happen */ abort(); if ((flags & GROUPING) && size != 0) - size += grouping_init(&gs, size); + size += grouping_init(&gs, size, locale); break; default: /* "%?" prints ?, unless ? is NUL */ if (ch == '\0') @@ -1018,7 +1030,7 @@ number: if ((dprec = prec) >= 0) /* leading zeroes from decimal precision */ PAD(dprec - size, zeroes); if (gs.grouping) { - if (grouping_print(&gs, &io, cp, buf+BUF) < 0) + if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0) goto error; } else { PRINT(cp, size); @@ -1036,7 +1048,7 @@ number: if ((dprec = prec) >= 0) } else { if (gs.grouping) { n = grouping_print(&gs, &io, - cp, convbuf + ndig); + cp, convbuf + ndig, locale); if (n < 0) goto error; cp += n; diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c index 60c7c71..22b0827 100644 --- a/lib/libc/stdio/vfwscanf.c +++ b/lib/libc/stdio/vfwscanf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -53,10 +58,7 @@ __FBSDID("$FreeBSD$"); #include "libc_private.h" #include "local.h" - -#ifndef NO_FLOATING_POINT -#include <locale.h> -#endif +#include "xlocale_private.h" #define BUF 513 /* Maximum length of numeric string. */ @@ -96,7 +98,7 @@ __FBSDID("$FreeBSD$"); #define CT_FLOAT 4 /* %[efgEFG] conversion */ #ifndef NO_FLOATING_POINT -static int parsefloat(FILE *, wchar_t *, wchar_t *); +static int parsefloat(FILE *, wchar_t *, wchar_t *, locale_t); #endif #define INCCL(_c) \ @@ -109,22 +111,30 @@ static const mbstate_t initial_mbs; * MT-safe version. */ int -vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) +vfwscanf_l(FILE * __restrict fp, locale_t locale, + const wchar_t * __restrict fmt, va_list ap) { int ret; + FIX_LOCALE(locale); FLOCKFILE(fp); ORIENT(fp, 1); - ret = __vfwscanf(fp, fmt, ap); + ret = __vfwscanf(fp, locale, fmt, ap); FUNLOCKFILE(fp); return (ret); } +int +vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) +{ + return vfwscanf_l(fp, __get_locale(), fmt, ap); +} /* * Non-MT-safe version. */ int -__vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) +__vfwscanf(FILE * __restrict fp, locale_t locale, + const wchar_t * __restrict fmt, va_list ap) { wint_t c; /* character from format, or conversion */ size_t width; /* field width, or 0 */ @@ -159,11 +169,11 @@ __vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap) if (c == 0) return (nassigned); if (iswspace(c)) { - while ((c = __fgetwc(fp)) != WEOF && - iswspace(c)) + while ((c = __fgetwc(fp, locale)) != WEOF && + iswspace_l(c, locale)) ; if (c != WEOF) - __ungetwc(c, fp); + __ungetwc(c, fp, locale); continue; } if (c != '%') @@ -178,10 +188,10 @@ again: c = *fmt++; switch (c) { case '%': literal: - if ((wi = __fgetwc(fp)) == WEOF) + if ((wi = __fgetwc(fp, locale)) == WEOF) goto input_failure; if (wi != c) { - __ungetwc(wi, fp); + __ungetwc(wi, fp, locale); goto input_failure; } nread++; @@ -341,11 +351,11 @@ literal: * that suppress this. */ if ((flags & NOSKIP) == 0) { - while ((wi = __fgetwc(fp)) != WEOF && iswspace(wi)) + while ((wi = __fgetwc(fp, locale)) != WEOF && iswspace(wi)) nread++; if (wi == WEOF) goto input_failure; - __ungetwc(wi, fp); + __ungetwc(wi, fp, locale); } /* @@ -362,7 +372,7 @@ literal: p = va_arg(ap, wchar_t *); n = 0; while (width-- != 0 && - (wi = __fgetwc(fp)) != WEOF) { + (wi = __fgetwc(fp, locale)) != WEOF) { if (!(flags & SUPPRESS)) *p++ = (wchar_t)wi; n++; @@ -378,7 +388,7 @@ literal: n = 0; mbs = initial_mbs; while (width != 0 && - (wi = __fgetwc(fp)) != WEOF) { + (wi = __fgetwc(fp, locale)) != WEOF) { if (width >= MB_CUR_MAX && !(flags & SUPPRESS)) { nconv = wcrtomb(mbp, wi, &mbs); @@ -390,7 +400,7 @@ literal: if (nconv == (size_t)-1) goto input_failure; if (nconv > width) { - __ungetwc(wi, fp); + __ungetwc(wi, fp, locale); break; } if (!(flags & SUPPRESS)) @@ -418,20 +428,20 @@ literal: /* take only those things in the class */ if ((flags & SUPPRESS) && (flags & LONG)) { n = 0; - while ((wi = __fgetwc(fp)) != WEOF && + while ((wi = __fgetwc(fp, locale)) != WEOF && width-- != 0 && INCCL(wi)) n++; if (wi != WEOF) - __ungetwc(wi, fp); + __ungetwc(wi, fp, locale); if (n == 0) goto match_failure; } else if (flags & LONG) { p0 = p = va_arg(ap, wchar_t *); - while ((wi = __fgetwc(fp)) != WEOF && + while ((wi = __fgetwc(fp, locale)) != WEOF && width-- != 0 && INCCL(wi)) *p++ = (wchar_t)wi; if (wi != WEOF) - __ungetwc(wi, fp); + __ungetwc(wi, fp, locale); n = p - p0; if (n == 0) goto match_failure; @@ -442,7 +452,7 @@ literal: mbp = va_arg(ap, char *); n = 0; mbs = initial_mbs; - while ((wi = __fgetwc(fp)) != WEOF && + while ((wi = __fgetwc(fp, locale)) != WEOF && width != 0 && INCCL(wi)) { if (width >= MB_CUR_MAX && !(flags & SUPPRESS)) { @@ -466,7 +476,7 @@ literal: n++; } if (wi != WEOF) - __ungetwc(wi, fp); + __ungetwc(wi, fp, locale); if (!(flags & SUPPRESS)) { *mbp = 0; nassigned++; @@ -481,29 +491,29 @@ literal: if (width == 0) width = (size_t)~0; if ((flags & SUPPRESS) && (flags & LONG)) { - while ((wi = __fgetwc(fp)) != WEOF && + while ((wi = __fgetwc(fp, locale)) != WEOF && width-- != 0 && !iswspace(wi)) nread++; if (wi != WEOF) - __ungetwc(wi, fp); + __ungetwc(wi, fp, locale); } else if (flags & LONG) { p0 = p = va_arg(ap, wchar_t *); - while ((wi = __fgetwc(fp)) != WEOF && + while ((wi = __fgetwc(fp, locale)) != WEOF && width-- != 0 && !iswspace(wi)) { *p++ = (wchar_t)wi; nread++; } if (wi != WEOF) - __ungetwc(wi, fp); + __ungetwc(wi, fp, locale); *p = '\0'; nassigned++; } else { if (!(flags & SUPPRESS)) mbp = va_arg(ap, char *); mbs = initial_mbs; - while ((wi = __fgetwc(fp)) != WEOF && + while ((wi = __fgetwc(fp, locale)) != WEOF && width != 0 && !iswspace(wi)) { if (width >= MB_CUR_MAX && @@ -528,7 +538,7 @@ literal: nread++; } if (wi != WEOF) - __ungetwc(wi, fp); + __ungetwc(wi, fp, locale); if (!(flags & SUPPRESS)) { *mbp = 0; nassigned++; @@ -544,7 +554,7 @@ literal: width = sizeof(buf) / sizeof(*buf) - 1; flags |= SIGNOK | NDIGITS | NZDIGITS; for (p = buf; width; width--) { - c = __fgetwc(fp); + c = __fgetwc(fp, locale); /* * Switch on the character; `goto ok' * if we accept it as a part of number. @@ -628,7 +638,7 @@ literal: * for a number. Stop accumulating digits. */ if (c != WEOF) - __ungetwc(c, fp); + __ungetwc(c, fp, locale); break; ok: /* @@ -644,13 +654,13 @@ literal: */ if (flags & NDIGITS) { if (p > buf) - __ungetwc(*--p, fp); + __ungetwc(*--p, fp, locale); goto match_failure; } c = p[-1]; if (c == 'x' || c == 'X') { --p; - __ungetwc(c, fp); + __ungetwc(c, fp, locale); } if ((flags & SUPPRESS) == 0) { uintmax_t res; @@ -691,7 +701,7 @@ literal: if (width == 0 || width > sizeof(buf) / sizeof(*buf) - 1) width = sizeof(buf) / sizeof(*buf) - 1; - if ((width = parsefloat(fp, buf, buf + width)) == 0) + if ((width = parsefloat(fp, buf, buf + width, locale)) == 0) goto match_failure; if ((flags & SUPPRESS) == 0) { if (flags & LONGDBL) { @@ -720,7 +730,7 @@ match_failure: #ifndef NO_FLOATING_POINT static int -parsefloat(FILE *fp, wchar_t *buf, wchar_t *end) +parsefloat(FILE *fp, wchar_t *buf, wchar_t *end, locale_t locale) { mbstate_t mbs; size_t nconv; @@ -751,7 +761,7 @@ parsefloat(FILE *fp, wchar_t *buf, wchar_t *end) commit = buf - 1; c = WEOF; for (p = buf; p < end; ) { - if ((c = __fgetwc(fp)) == WEOF) + if ((c = __fgetwc(fp, locale)) == WEOF) break; reswitch: switch (state) { @@ -871,9 +881,9 @@ reswitch: parsedone: if (c != WEOF) - __ungetwc(c, fp); + __ungetwc(c, fp, locale); while (commit < --p) - __ungetwc(*p, fp); + __ungetwc(*p, fp, locale); *++commit = '\0'; return (commit - buf); } diff --git a/lib/libc/stdio/vprintf.c b/lib/libc/stdio/vprintf.c index a610b7d..c15ef4d 100644 --- a/lib/libc/stdio/vprintf.c +++ b/lib/libc/stdio/vprintf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,10 +42,15 @@ static char sccsid[] = "@(#)vprintf.c 8.1 (Berkeley) 6/4/93"; __FBSDID("$FreeBSD$"); #include <stdio.h> +#include <xlocale.h> int vprintf(const char * __restrict fmt, __va_list ap) { - return (vfprintf(stdout, fmt, ap)); } +int +vprintf_l(locale_t locale, const char * __restrict fmt, __va_list ap) +{ + return (vfprintf_l(stdout, locale, fmt, ap)); +} diff --git a/lib/libc/stdio/vscanf.c b/lib/libc/stdio/vscanf.c index 25bce72..d56bb3b 100644 --- a/lib/libc/stdio/vscanf.c +++ b/lib/libc/stdio/vscanf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Donn Seeley at UUNET Technologies, Inc. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,16 +46,26 @@ __FBSDID("$FreeBSD$"); #include "un-namespace.h" #include "libc_private.h" #include "local.h" +#include "xlocale_private.h" int -vscanf(fmt, ap) +vscanf_l(locale, fmt, ap) + locale_t locale; const char * __restrict fmt; __va_list ap; { int retval; + FIX_LOCALE(locale); FLOCKFILE(stdin); - retval = __svfscanf(stdin, fmt, ap); + retval = __svfscanf(stdin, locale, fmt, ap); FUNLOCKFILE(stdin); return (retval); } +int +vscanf(fmt, ap) + const char * __restrict fmt; + __va_list ap; +{ + return vscanf_l(__get_locale(), fmt, ap); +} diff --git a/lib/libc/stdio/vsnprintf.c b/lib/libc/stdio/vsnprintf.c index 70e4c53..d2bad0f 100644 --- a/lib/libc/stdio/vsnprintf.c +++ b/lib/libc/stdio/vsnprintf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,15 +44,17 @@ __FBSDID("$FreeBSD$"); #include <limits.h> #include <stdio.h> #include "local.h" +#include "xlocale_private.h" int -vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt, - __va_list ap) +vsnprintf_l(char * __restrict str, size_t n, locale_t locale, + const char * __restrict fmt, __va_list ap) { size_t on; int ret; char dummy[2]; FILE f = FAKE_FILE; + FIX_LOCALE(locale); on = n; if (n != 0) @@ -64,8 +71,14 @@ vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt, f._flags = __SWR | __SSTR; f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = n; - ret = __vfprintf(&f, fmt, ap); + ret = __vfprintf(&f, locale, fmt, ap); if (on > 0) *f._p = '\0'; return (ret); } +int +vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt, + __va_list ap) +{ + return vsnprintf_l(str, n, __get_locale(), fmt, ap); +} diff --git a/lib/libc/stdio/vsprintf.c b/lib/libc/stdio/vsprintf.c index 3890af7..04f2df3 100644 --- a/lib/libc/stdio/vsprintf.c +++ b/lib/libc/stdio/vsprintf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,17 +44,25 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <limits.h> #include "local.h" +#include "xlocale_private.h" int -vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap) +vsprintf_l(char * __restrict str, locale_t locale, + const char * __restrict fmt, __va_list ap) { int ret; FILE f = FAKE_FILE; + FIX_LOCALE(locale); f._flags = __SWR | __SSTR; f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = INT_MAX; - ret = __vfprintf(&f, fmt, ap); + ret = __vfprintf(&f, locale, fmt, ap); *f._p = 0; return (ret); } +int +vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap) +{ + return vsprintf_l(str, __get_locale(), fmt, ap); +} diff --git a/lib/libc/stdio/vsscanf.c b/lib/libc/stdio/vsscanf.c index 82429c6..5668ab5 100644 --- a/lib/libc/stdio/vsscanf.c +++ b/lib/libc/stdio/vsscanf.c @@ -2,6 +2,11 @@ * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * This code is derived from software contributed to Berkeley by * Donn Seeley at UUNET Technologies, Inc. * @@ -39,6 +44,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <string.h> #include "local.h" +#include "xlocale_private.h" static int eofread(void *, char *, int); @@ -52,14 +58,21 @@ eofread(void *cookie, char *buf, int len) } int -vsscanf(const char * __restrict str, const char * __restrict fmt, - __va_list ap) +vsscanf_l(const char * __restrict str, locale_t locale, + const char * __restrict fmt, __va_list ap) { FILE f = FAKE_FILE; + FIX_LOCALE(locale); f._flags = __SRD; f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._r = strlen(str); f._read = eofread; - return (__svfscanf(&f, fmt, ap)); + return (__svfscanf(&f, locale, fmt, ap)); +} +int +vsscanf(const char * __restrict str, const char * __restrict fmt, + __va_list ap) +{ + return vsscanf_l(str, __get_locale(), fmt, ap); } diff --git a/lib/libc/stdio/vswprintf.c b/lib/libc/stdio/vswprintf.c index 2cfe724..023c537 100644 --- a/lib/libc/stdio/vswprintf.c +++ b/lib/libc/stdio/vswprintf.c @@ -4,6 +4,11 @@ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -38,10 +43,11 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> #include <wchar.h> #include "local.h" +#include "xlocale_private.h" int -vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, - __va_list ap) +vswprintf_l(wchar_t * __restrict s, size_t n, locale_t locale, + const wchar_t * __restrict fmt, __va_list ap) { static const mbstate_t initial; mbstate_t mbs; @@ -49,6 +55,7 @@ vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, char *mbp; int ret, sverrno; size_t nwc; + FIX_LOCALE(locale); if (n == 0) { errno = EINVAL; @@ -62,7 +69,7 @@ vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, return (-1); } f._bf._size = f._w = 127; /* Leave room for the NUL */ - ret = __vfwprintf(&f, fmt, ap); + ret = __vfwprintf(&f, locale, fmt, ap); if (ret < 0) { sverrno = errno; free(f._bf._base); @@ -76,7 +83,7 @@ vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, * fputwc() did in __vfwprintf(). */ mbs = initial; - nwc = mbsrtowcs(s, (const char **)&mbp, n, &mbs); + nwc = mbsrtowcs_l(s, (const char **)&mbp, n, &mbs, locale); free(f._bf._base); if (nwc == (size_t)-1) { errno = EILSEQ; @@ -90,3 +97,9 @@ vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, return (ret); } +int +vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, + __va_list ap) +{ + return vswprintf_l(s, n, __get_locale(), fmt, ap); +} diff --git a/lib/libc/stdio/vswscanf.c b/lib/libc/stdio/vswscanf.c index f06fc02..f646e85 100644 --- a/lib/libc/stdio/vswscanf.c +++ b/lib/libc/stdio/vswscanf.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Donn Seeley at UUNET Technologies, Inc. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -46,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <wchar.h> #include "local.h" +#include "xlocale_private.h" static int eofread(void *, char *, int); @@ -57,8 +63,8 @@ eofread(void *cookie, char *buf, int len) } int -vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, - va_list ap) +vswscanf_l(const wchar_t * __restrict str, locale_t locale, + const wchar_t * __restrict fmt, va_list ap) { static const mbstate_t initial; mbstate_t mbs; @@ -67,6 +73,7 @@ vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, size_t mlen; int r; const wchar_t *strp; + FIX_LOCALE(locale); /* * XXX Convert the wide character string to multibyte, which @@ -76,7 +83,7 @@ vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, return (EOF); mbs = initial; strp = str; - if ((mlen = wcsrtombs(mbstr, &strp, SIZE_T_MAX, &mbs)) == (size_t)-1) { + if ((mlen = wcsrtombs_l(mbstr, &strp, SIZE_T_MAX, &mbs, locale)) == (size_t)-1) { free(mbstr); return (EOF); } @@ -84,8 +91,14 @@ vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, f._bf._base = f._p = (unsigned char *)mbstr; f._bf._size = f._r = mlen; f._read = eofread; - r = __vfwscanf(&f, fmt, ap); + r = __vfwscanf(&f, locale, fmt, ap); free(mbstr); return (r); } +int +vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, + va_list ap) +{ + return vswscanf_l(str, __get_locale(), fmt, ap); +} diff --git a/lib/libc/stdio/vwprintf.c b/lib/libc/stdio/vwprintf.c index 91212a8..e09a30e 100644 --- a/lib/libc/stdio/vwprintf.c +++ b/lib/libc/stdio/vwprintf.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,10 +35,15 @@ __FBSDID("$FreeBSD$"); #include <stdarg.h> #include <stdio.h> #include <wchar.h> +#include <xlocale.h> int vwprintf(const wchar_t * __restrict fmt, va_list ap) { - return (vfwprintf(stdout, fmt, ap)); } +int +vwprintf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap) +{ + return (vfwprintf_l(stdout, locale, fmt, ap)); +} diff --git a/lib/libc/stdio/vwscanf.c b/lib/libc/stdio/vwscanf.c index 4a21af2..730beee 100644 --- a/lib/libc/stdio/vwscanf.c +++ b/lib/libc/stdio/vwscanf.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,10 +35,15 @@ __FBSDID("$FreeBSD$"); #include <stdarg.h> #include <stdio.h> #include <wchar.h> +#include <xlocale.h> int vwscanf(const wchar_t * __restrict fmt, va_list ap) { - return (vfwscanf(stdin, fmt, ap)); } +int +vwscanf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap) +{ + return (vfwscanf_l(stdin, locale, fmt, ap)); +} diff --git a/lib/libc/stdio/wprintf.c b/lib/libc/stdio/wprintf.c index 92426f6..fdffa86 100644 --- a/lib/libc/stdio/wprintf.c +++ b/lib/libc/stdio/wprintf.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <stdarg.h> #include <stdio.h> #include <wchar.h> +#include <xlocale.h> int wprintf(const wchar_t * __restrict fmt, ...) @@ -43,3 +49,15 @@ wprintf(const wchar_t * __restrict fmt, ...) return (ret); } +int +wprintf_l(locale_t locale, const wchar_t * __restrict fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = vfwprintf_l(stdout, locale, fmt, ap); + va_end(ap); + + return (ret); +} diff --git a/lib/libc/stdio/wscanf.c b/lib/libc/stdio/wscanf.c index 5e27b40..22ce9bd 100644 --- a/lib/libc/stdio/wscanf.c +++ b/lib/libc/stdio/wscanf.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -30,6 +35,7 @@ __FBSDID("$FreeBSD$"); #include <stdarg.h> #include <stdio.h> #include <wchar.h> +#include <xlocale.h> int wscanf(const wchar_t * __restrict fmt, ...) @@ -43,3 +49,15 @@ wscanf(const wchar_t * __restrict fmt, ...) return (r); } +int +wscanf_l(locale_t locale, const wchar_t * __restrict fmt, ...) +{ + va_list ap; + int r; + + va_start(ap, fmt); + r = vfwscanf_l(stdin, locale, fmt, ap); + va_end(ap); + + return (r); +} diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map index d159bed..c268ab9 100644 --- a/lib/libc/stdlib/Symbol.map +++ b/lib/libc/stdlib/Symbol.map @@ -92,6 +92,24 @@ FBSD_1.0 { twalk; }; +FBSD_1.3 { + atof_l; + atoi_l; + atol_l; + atoll_l; + strtod_l; + strtol_l; + strtoll_l; + strtof_l; + strtoimax_l; + strtold_l; + strtoq_l; + strtoul_l; + strtoull_l; + strtoumax_l; + strtouq_l; +}; + FBSDprivate_1.0 { _malloc_thread_cleanup; _malloc_prefork; diff --git a/lib/libc/stdlib/atof.c b/lib/libc/stdlib/atof.c index 51e482e..746ceac 100644 --- a/lib/libc/stdlib/atof.c +++ b/lib/libc/stdlib/atof.c @@ -2,6 +2,11 @@ * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,6 +39,7 @@ static char sccsid[] = "@(#)atof.c 8.1 (Berkeley) 6/4/93"; __FBSDID("$FreeBSD$"); #include <stdlib.h> +#include <xlocale.h> double atof(ascii) @@ -41,3 +47,11 @@ atof(ascii) { return strtod(ascii, (char **)NULL); } + +double +atof_l(ascii, locale) + const char *ascii; + locale_t locale; +{ + return strtod_l(ascii, (char **)NULL, locale); +} diff --git a/lib/libc/stdlib/atoi.c b/lib/libc/stdlib/atoi.c index 0ffcd03..31a8676 100644 --- a/lib/libc/stdlib/atoi.c +++ b/lib/libc/stdlib/atoi.c @@ -2,6 +2,11 @@ * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,6 +39,7 @@ static char sccsid[] = "@(#)atoi.c 8.1 (Berkeley) 6/4/93"; __FBSDID("$FreeBSD$"); #include <stdlib.h> +#include <xlocale.h> int atoi(str) @@ -41,3 +47,11 @@ atoi(str) { return (int)strtol(str, (char **)NULL, 10); } + +int +atoi_l(str, locale) + const char *str; + locale_t locale; +{ + return (int)strtol_l(str, (char **)NULL, 10, locale); +} diff --git a/lib/libc/stdlib/atol.c b/lib/libc/stdlib/atol.c index c9cf2e8..7ebbe01 100644 --- a/lib/libc/stdlib/atol.c +++ b/lib/libc/stdlib/atol.c @@ -2,6 +2,11 @@ * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,6 +39,7 @@ static char sccsid[] = "@(#)atol.c 8.1 (Berkeley) 6/4/93"; __FBSDID("$FreeBSD$"); #include <stdlib.h> +#include <xlocale.h> long atol(str) @@ -41,3 +47,11 @@ atol(str) { return strtol(str, (char **)NULL, 10); } + +long +atol_l(str, locale) + const char *str; + locale_t locale; +{ + return strtol_l(str, (char **)NULL, 10, locale); +} diff --git a/lib/libc/stdlib/atoll.c b/lib/libc/stdlib/atoll.c index 203c174..cbb5459 100644 --- a/lib/libc/stdlib/atoll.c +++ b/lib/libc/stdlib/atoll.c @@ -2,6 +2,11 @@ * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -31,6 +36,7 @@ __FBSDID("$FreeBSD$"); #include <stdlib.h> +#include <xlocale.h> long long atoll(str) @@ -38,3 +44,11 @@ atoll(str) { return strtoll(str, (char **)NULL, 10); } + +long long +atoll_l(str, locale) + const char *str; + locale_t locale; +{ + return strtoll_l(str, (char **)NULL, 10, locale); +} diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c index 66bb8da..2c9562e 100644 --- a/lib/libc/stdlib/realpath.c +++ b/lib/libc/stdlib/realpath.c @@ -212,7 +212,8 @@ realpath(const char * __restrict path, char * __restrict resolved) symlink[slen] = '/'; symlink[slen + 1] = 0; } - left_len = strlcat(symlink, left, sizeof(left)); + left_len = strlcat(symlink, left, + sizeof(symlink)); if (left_len >= sizeof(left)) { if (m) free(resolved); diff --git a/lib/libc/stdlib/strfmon.c b/lib/libc/stdlib/strfmon.c index 6c28254..b82797d 100644 --- a/lib/libc/stdlib/strfmon.c +++ b/lib/libc/stdlib/strfmon.c @@ -2,6 +2,11 @@ * Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org> * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -38,6 +43,7 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "xlocale_private.h" /* internal flags */ #define NEED_GROUPING 0x01 /* print digits grouped (default) */ @@ -92,11 +98,10 @@ static void __setup_vars(int, char *, char *, char *, char **); static int __calc_left_pad(int, char *); static char *__format_grouped_double(double, int *, int, int, int); -ssize_t -strfmon(char * __restrict s, size_t maxsize, const char * __restrict format, - ...) +static ssize_t +vstrfmon_l(char * __restrict s, size_t maxsize, locale_t loc, + const char * __restrict format, va_list ap) { - va_list ap; char *dst; /* output destination pointer */ const char *fmt; /* current format poistion pointer */ struct lconv *lc; /* pointer to lconv structure */ @@ -119,10 +124,10 @@ strfmon(char * __restrict s, size_t maxsize, const char * __restrict format, char *tmpptr; /* temporary vars */ int sverrno; + FIX_LOCALE(loc); - va_start(ap, format); - lc = localeconv(); + lc = localeconv_l(loc); dst = s; fmt = format; asciivalue = NULL; @@ -380,7 +385,6 @@ strfmon(char * __restrict s, size_t maxsize, const char * __restrict format, } PRINT('\0'); - va_end(ap); free(asciivalue); free(currency_symbol); return (dst - s - 1); /* return size of put data except trailing '\0' */ @@ -399,9 +403,32 @@ end_error: if (currency_symbol != NULL) free(currency_symbol); errno = sverrno; - va_end(ap); return (-1); } +ssize_t +strfmon_l(char * __restrict s, size_t maxsize, locale_t loc, const char * __restrict format, + ...) +{ + size_t ret; + va_list ap; + va_start(ap, format); + ret = vstrfmon_l(s, maxsize, loc, format, ap); + va_end(ap); + return ret; +} + +ssize_t +strfmon(char * __restrict s, size_t maxsize, const char * __restrict format, + ...) +{ + size_t ret; + va_list ap; + va_start(ap, format); + ret = vstrfmon_l(s, maxsize, __get_locale(), format, ap); + va_end(ap); + return ret; +} + static void __setup_vars(int flags, char *cs_precedes, char *sep_by_space, diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c index 4f0063c..9be773b 100644 --- a/lib/libc/stdlib/strtoimax.c +++ b/lib/libc/stdlib/strtoimax.c @@ -2,6 +2,11 @@ * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <stdlib.h> #include <inttypes.h> +#include "xlocale_private.h" /* * Convert a string to an intmax_t integer. @@ -45,13 +51,15 @@ __FBSDID("$FreeBSD$"); * alphabets and digits are each contiguous. */ intmax_t -strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base) +strtoimax_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) { const char *s; uintmax_t acc; char c; uintmax_t cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * Skip white space and pick up leading +/- sign if any. @@ -61,7 +69,7 @@ strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base) s = nptr; do { c = *s++; - } while (isspace((unsigned char)c)); + } while (isspace_l((unsigned char)c, locale)); if (c == '-') { neg = 1; c = *s++; @@ -138,3 +146,8 @@ noconv: *endptr = (char *)(any ? s - 1 : nptr); return (acc); } +intmax_t +strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoimax_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtol.c b/lib/libc/stdlib/strtol.c index 0d6f736..f80ecb4 100644 --- a/lib/libc/stdlib/strtol.c +++ b/lib/libc/stdlib/strtol.c @@ -2,6 +2,11 @@ * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <ctype.h> #include <errno.h> #include <stdlib.h> +#include "xlocale_private.h" /* @@ -46,13 +52,15 @@ __FBSDID("$FreeBSD$"); * alphabets and digits are each contiguous. */ long -strtol(const char * __restrict nptr, char ** __restrict endptr, int base) +strtol_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) { const char *s; unsigned long acc; char c; unsigned long cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * Skip white space and pick up leading +/- sign if any. @@ -62,7 +70,7 @@ strtol(const char * __restrict nptr, char ** __restrict endptr, int base) s = nptr; do { c = *s++; - } while (isspace((unsigned char)c)); + } while (isspace_l((unsigned char)c, locale)); if (c == '-') { neg = 1; c = *s++; @@ -138,3 +146,13 @@ noconv: *endptr = (char *)(any ? s - 1 : nptr); return (acc); } +long +strtol(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtol_l(nptr, endptr, base, __get_locale()); +} +long double +strtold(const char * __restrict nptr, char ** __restrict endptr) +{ + return strtold_l(nptr, endptr, __get_locale()); +} diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c index 2e5547d..6783327 100644 --- a/lib/libc/stdlib/strtoll.c +++ b/lib/libc/stdlib/strtoll.c @@ -2,6 +2,11 @@ * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <ctype.h> #include <stdlib.h> +#include "xlocale_private.h" /* * Convert a string to a long long integer. @@ -45,13 +51,15 @@ __FBSDID("$FreeBSD$"); * alphabets and digits are each contiguous. */ long long -strtoll(const char * __restrict nptr, char ** __restrict endptr, int base) +strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) { const char *s; unsigned long long acc; char c; unsigned long long cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * Skip white space and pick up leading +/- sign if any. @@ -61,7 +69,7 @@ strtoll(const char * __restrict nptr, char ** __restrict endptr, int base) s = nptr; do { c = *s++; - } while (isspace((unsigned char)c)); + } while (isspace_l((unsigned char)c, locale)); if (c == '-') { neg = 1; c = *s++; @@ -138,3 +146,8 @@ noconv: *endptr = (char *)(any ? s - 1 : nptr); return (acc); } +long long +strtoll(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoll_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtoul.c b/lib/libc/stdlib/strtoul.c index e8d1e11..0ae0661 100644 --- a/lib/libc/stdlib/strtoul.c +++ b/lib/libc/stdlib/strtoul.c @@ -2,6 +2,11 @@ * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <ctype.h> #include <errno.h> #include <stdlib.h> +#include "xlocale_private.h" /* * Convert a string to an unsigned long integer. @@ -45,13 +51,14 @@ __FBSDID("$FreeBSD$"); * alphabets and digits are each contiguous. */ unsigned long -strtoul(const char * __restrict nptr, char ** __restrict endptr, int base) +strtoul_l(const char * __restrict nptr, char ** __restrict endptr, int base, locale_t locale) { const char *s; unsigned long acc; char c; unsigned long cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * See strtol for comments as to the logic used. @@ -59,7 +66,7 @@ strtoul(const char * __restrict nptr, char ** __restrict endptr, int base) s = nptr; do { c = *s++; - } while (isspace((unsigned char)c)); + } while (isspace_l((unsigned char)c, locale)); if (c == '-') { neg = 1; c = *s++; @@ -116,3 +123,8 @@ noconv: *endptr = (char *)(any ? s - 1 : nptr); return (acc); } +unsigned long +strtoul(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoul_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c index f11910c..4b7f1c9 100644 --- a/lib/libc/stdlib/strtoull.c +++ b/lib/libc/stdlib/strtoull.c @@ -2,6 +2,11 @@ * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <ctype.h> #include <stdlib.h> +#include "xlocale_private.h" /* * Convert a string to an unsigned long long integer. @@ -45,13 +51,15 @@ __FBSDID("$FreeBSD$"); * alphabets and digits are each contiguous. */ unsigned long long -strtoull(const char * __restrict nptr, char ** __restrict endptr, int base) +strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) { const char *s; unsigned long long acc; char c; unsigned long long cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * See strtoq for comments as to the logic used. @@ -59,7 +67,7 @@ strtoull(const char * __restrict nptr, char ** __restrict endptr, int base) s = nptr; do { c = *s++; - } while (isspace((unsigned char)c)); + } while (isspace_l((unsigned char)c, locale)); if (c == '-') { neg = 1; c = *s++; @@ -116,3 +124,8 @@ noconv: *endptr = (char *)(any ? s - 1 : nptr); return (acc); } +unsigned long long +strtoull(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoull_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c index 23050c2..d4362bb 100644 --- a/lib/libc/stdlib/strtoumax.c +++ b/lib/libc/stdlib/strtoumax.c @@ -2,6 +2,11 @@ * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -37,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <errno.h> #include <stdlib.h> #include <inttypes.h> +#include "xlocale_private.h" /* * Convert a string to a uintmax_t integer. @@ -45,13 +51,15 @@ __FBSDID("$FreeBSD$"); * alphabets and digits are each contiguous. */ uintmax_t -strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base) +strtoumax_l(const char * __restrict nptr, char ** __restrict endptr, int base, + locale_t locale) { const char *s; uintmax_t acc; char c; uintmax_t cutoff; int neg, any, cutlim; + FIX_LOCALE(locale); /* * See strtoimax for comments as to the logic used. @@ -59,7 +67,7 @@ strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base) s = nptr; do { c = *s++; - } while (isspace((unsigned char)c)); + } while (isspace_l((unsigned char)c, locale)); if (c == '-') { neg = 1; c = *s++; @@ -116,3 +124,8 @@ noconv: *endptr = (char *)(any ? s - 1 : nptr); return (acc); } +uintmax_t +strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base) +{ + return strtoumax_l(nptr, endptr, base, __get_locale()); +} diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c index dac910b..d3571ad 100644 --- a/lib/libc/stdtime/strftime.c +++ b/lib/libc/stdtime/strftime.c @@ -2,6 +2,11 @@ * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, @@ -43,7 +48,7 @@ __FBSDID("$FreeBSD$"); static char * _add(const char *, char *, const char *); static char * _conv(int, const char *, char *, const char *); static char * _fmt(const char *, const struct tm *, char *, const char *, - int *); + int *, locale_t); static char * _yconv(int, int, int, int, char *, const char *); extern char * tzname[]; @@ -82,29 +87,30 @@ static const char* fmt_padding[][4] = { }; size_t -strftime(char * __restrict s, size_t maxsize, const char * __restrict format, - const struct tm * __restrict t) +strftime_l(char * __restrict s, size_t maxsize, const char * __restrict format, + const struct tm * __restrict t, locale_t loc) { char * p; int warn; + FIX_LOCALE(loc); tzset(); warn = IN_NONE; - p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn); + p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, loc); #ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) { - (void) fprintf(stderr, "\n"); + (void) fprintf_l(stderr, loc, "\n"); if (format == NULL) - (void) fprintf(stderr, "NULL strftime format "); - else (void) fprintf(stderr, "strftime format \"%s\" ", + (void) fprintf_l(stderr, loc, "NULL strftime format "); + else (void) fprintf_l(stderr, loc, "strftime format \"%s\" ", format); - (void) fprintf(stderr, "yields only two digits of years in "); + (void) fprintf_l(stderr, loc, "yields only two digits of years in "); if (warn == IN_SOME) - (void) fprintf(stderr, "some locales"); + (void) fprintf_l(stderr, loc, "some locales"); else if (warn == IN_THIS) - (void) fprintf(stderr, "the current locale"); - else (void) fprintf(stderr, "all locales"); - (void) fprintf(stderr, "\n"); + (void) fprintf_l(stderr, loc, "the current locale"); + else (void) fprintf_l(stderr, loc, "all locales"); + (void) fprintf_l(stderr, loc, "\n"); } #endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */ if (p == s + maxsize) @@ -113,16 +119,24 @@ strftime(char * __restrict s, size_t maxsize, const char * __restrict format, return p - s; } +size_t +strftime(char * __restrict s, size_t maxsize, const char * __restrict format, + const struct tm * __restrict t) +{ + return strftime_l(s, maxsize, format, t, __get_locale()); +} + static char * -_fmt(format, t, pt, ptlim, warnp) +_fmt(format, t, pt, ptlim, warnp, loc) const char * format; const struct tm * const t; char * pt; const char * const ptlim; int * warnp; +locale_t loc; { int Ealternative, Oalternative, PadIndex; - struct lc_time_T *tptr = __get_current_time_locale(); + struct lc_time_T *tptr = __get_current_time_locale(loc); for ( ; *format; ++format) { if (*format == '%') { @@ -175,7 +189,7 @@ label: { int warn2 = IN_SOME; - pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2); + pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2, loc); if (warn2 == IN_ALL) warn2 = IN_THIS; if (warn2 > *warnp) @@ -183,7 +197,7 @@ label: } continue; case 'D': - pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp); + pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, loc); continue; case 'd': pt = _conv(t->tm_mday, fmt_padding[PAD_FMT_DAYOFMONTH][PadIndex], @@ -216,7 +230,7 @@ label: fmt_padding[PAD_FMT_SDAYOFMONTH][PadIndex], pt, ptlim); continue; case 'F': - pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp); + pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, loc); continue; case 'H': pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_HMS][PadIndex], @@ -285,11 +299,11 @@ label: pt, ptlim); continue; case 'R': - pt = _fmt("%H:%M", t, pt, ptlim, warnp); + pt = _fmt("%H:%M", t, pt, ptlim, warnp, loc); continue; case 'r': pt = _fmt(tptr->ampm_fmt, t, pt, ptlim, - warnp); + warnp, loc); continue; case 'S': pt = _conv(t->tm_sec, fmt_padding[PAD_FMT_HMS][PadIndex], @@ -313,7 +327,7 @@ label: } continue; case 'T': - pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp); + pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, loc); continue; case 't': pt = _add("\t", pt, ptlim); @@ -428,7 +442,7 @@ label: ** "date as dd-bbb-YYYY" ** (ado, 1993-05-24) */ - pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp); + pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, loc); continue; case 'W': pt = _conv((t->tm_yday + DAYSPERWEEK - @@ -441,13 +455,13 @@ label: pt = _conv(t->tm_wday, "%d", pt, ptlim); continue; case 'X': - pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp); + pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp, loc); continue; case 'x': { int warn2 = IN_SOME; - pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2); + pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2, loc); if (warn2 == IN_ALL) warn2 = IN_THIS; if (warn2 > *warnp) @@ -534,7 +548,7 @@ label: continue; case '+': pt = _fmt(tptr->date_fmt, t, pt, ptlim, - warnp); + warnp, loc); continue; case '-': if (PadIndex != PAD_DEFAULT) diff --git a/lib/libc/stdtime/strptime.c b/lib/libc/stdtime/strptime.c index 401350e..fb94dcd 100644 --- a/lib/libc/stdtime/strptime.c +++ b/lib/libc/stdtime/strptime.c @@ -22,6 +22,11 @@ /* * Copyright (c) 1994 Powerdog Industries. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -72,19 +77,20 @@ __FBSDID("$FreeBSD$"); #include "libc_private.h" #include "timelocal.h" -static char * _strptime(const char *, const char *, struct tm *, int *); +static char * _strptime(const char *, const char *, struct tm *, int *, locale_t); #define asizeof(a) (sizeof (a) / sizeof ((a)[0])) static char * -_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp) +_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, + locale_t locale) { char c; const char *ptr; int i, len; int Ealternative, Oalternative; - struct lc_time_T *tptr = __get_current_time_locale(); + struct lc_time_T *tptr = __get_current_time_locale(locale); ptr = fmt; while (*ptr != 0) { @@ -94,8 +100,9 @@ _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp) c = *ptr++; if (c != '%') { - if (isspace((unsigned char)c)) - while (*buf != 0 && isspace((unsigned char)*buf)) + if (isspace_l((unsigned char)c, locale)) + while (*buf != 0 && + isspace_l((unsigned char)*buf, locale)) buf++; else if (c != *buf++) return 0; @@ -114,18 +121,19 @@ label: break; case '+': - buf = _strptime(buf, tptr->date_fmt, tm, GMTp); + buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale); if (buf == 0) return 0; break; case 'C': - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, locale)) return 0; /* XXX This will break for 3-digit centuries. */ len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && + isdigit_l((unsigned char)*buf, locale); buf++) { i *= 10; i += *buf - '0'; len--; @@ -137,13 +145,13 @@ label: break; case 'c': - buf = _strptime(buf, tptr->c_fmt, tm, GMTp); + buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale); if (buf == 0) return 0; break; case 'D': - buf = _strptime(buf, "%m/%d/%y", tm, GMTp); + buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale); if (buf == 0) return 0; break; @@ -161,47 +169,48 @@ label: goto label; case 'F': - buf = _strptime(buf, "%Y-%m-%d", tm, GMTp); + buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale); if (buf == 0) return 0; break; case 'R': - buf = _strptime(buf, "%H:%M", tm, GMTp); + buf = _strptime(buf, "%H:%M", tm, GMTp, locale); if (buf == 0) return 0; break; case 'r': - buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp); + buf = _strptime(buf, tptr->ampm_fmt, tm, GMTp, locale); if (buf == 0) return 0; break; case 'T': - buf = _strptime(buf, "%H:%M:%S", tm, GMTp); + buf = _strptime(buf, "%H:%M:%S", tm, GMTp, locale); if (buf == 0) return 0; break; case 'X': - buf = _strptime(buf, tptr->X_fmt, tm, GMTp); + buf = _strptime(buf, tptr->X_fmt, tm, GMTp, locale); if (buf == 0) return 0; break; case 'x': - buf = _strptime(buf, tptr->x_fmt, tm, GMTp); + buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale); if (buf == 0) return 0; break; case 'j': - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, locale)) return 0; len = 3; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && + isdigit_l((unsigned char)*buf, locale); buf++){ i *= 10; i += *buf - '0'; len--; @@ -214,14 +223,16 @@ label: case 'M': case 'S': - if (*buf == 0 || isspace((unsigned char)*buf)) + if (*buf == 0 || + isspace_l((unsigned char)*buf, locale)) break; - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, locale)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && + isdigit_l((unsigned char)*buf, locale); buf++){ i *= 10; i += *buf - '0'; len--; @@ -237,8 +248,10 @@ label: tm->tm_sec = i; } - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && + isspace_l((unsigned char)*buf, locale)) + while (*ptr != 0 && + !isspace_l((unsigned char)*ptr, locale)) ptr++; break; @@ -254,11 +267,12 @@ label: * XXX The %l specifier may gobble one too many * digits if used incorrectly. */ - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, locale)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && + isdigit_l((unsigned char)*buf, locale); buf++) { i *= 10; i += *buf - '0'; len--; @@ -271,8 +285,10 @@ label: tm->tm_hour = i; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && + isspace_l((unsigned char)*buf, locale)) + while (*ptr != 0 && + !isspace_l((unsigned char)*ptr, locale)) ptr++; break; @@ -282,7 +298,7 @@ label: * specifiers. */ len = strlen(tptr->am); - if (strncasecmp(buf, tptr->am, len) == 0) { + if (strncasecmp_l(buf, tptr->am, len, locale) == 0) { if (tm->tm_hour > 12) return 0; if (tm->tm_hour == 12) @@ -292,7 +308,7 @@ label: } len = strlen(tptr->pm); - if (strncasecmp(buf, tptr->pm, len) == 0) { + if (strncasecmp_l(buf, tptr->pm, len, locale) == 0) { if (tm->tm_hour > 12) return 0; if (tm->tm_hour != 12) @@ -307,12 +323,12 @@ label: case 'a': for (i = 0; i < asizeof(tptr->weekday); i++) { len = strlen(tptr->weekday[i]); - if (strncasecmp(buf, tptr->weekday[i], - len) == 0) + if (strncasecmp_l(buf, tptr->weekday[i], + len, locale) == 0) break; len = strlen(tptr->wday[i]); - if (strncasecmp(buf, tptr->wday[i], - len) == 0) + if (strncasecmp_l(buf, tptr->wday[i], + len, locale) == 0) break; } if (i == asizeof(tptr->weekday)) @@ -330,11 +346,12 @@ label: * point to calculate a real value, so just check the * range for now. */ - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, locale)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && + isdigit_l((unsigned char)*buf, locale); buf++) { i *= 10; i += *buf - '0'; len--; @@ -342,13 +359,15 @@ label: if (i > 53) return 0; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && + isspace_l((unsigned char)*buf, locale)) + while (*ptr != 0 && + !isspace_l((unsigned char)*ptr, locale)) ptr++; break; case 'w': - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, locale)) return 0; i = *buf - '0'; @@ -357,8 +376,10 @@ label: tm->tm_wday = i; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && + isspace_l((unsigned char)*buf, locale)) + while (*ptr != 0 && + !isspace_l((unsigned char)*ptr, locale)) ptr++; break; @@ -372,11 +393,12 @@ label: * XXX The %e specifier may gobble one too many * digits if used incorrectly. */ - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, locale)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && + isdigit_l((unsigned char)*buf, locale); buf++) { i *= 10; i += *buf - '0'; len--; @@ -386,8 +408,10 @@ label: tm->tm_mday = i; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && + isspace_l((unsigned char)*buf, locale)) + while (*ptr != 0 && + !isspace_l((unsigned char)*ptr, locale)) ptr++; break; @@ -398,15 +422,15 @@ label: if (Oalternative) { if (c == 'B') { len = strlen(tptr->alt_month[i]); - if (strncasecmp(buf, + if (strncasecmp_l(buf, tptr->alt_month[i], - len) == 0) + len, locale) == 0) break; } } else { len = strlen(tptr->month[i]); - if (strncasecmp(buf, tptr->month[i], - len) == 0) + if (strncasecmp_l(buf, tptr->month[i], + len, locale) == 0) break; } } @@ -417,8 +441,8 @@ label: if (i == asizeof(tptr->month) && !Oalternative) { for (i = 0; i < asizeof(tptr->month); i++) { len = strlen(tptr->mon[i]); - if (strncasecmp(buf, tptr->mon[i], - len) == 0) + if (strncasecmp_l(buf, tptr->mon[i], + len, locale) == 0) break; } } @@ -430,11 +454,12 @@ label: break; case 'm': - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, locale)) return 0; len = 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && + isdigit_l((unsigned char)*buf, locale); buf++) { i *= 10; i += *buf - '0'; len--; @@ -444,8 +469,10 @@ label: tm->tm_mon = i - 1; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && + isspace_l((unsigned char)*buf, locale)) + while (*ptr != 0 && + !isspace_l((unsigned char)*ptr, locale)) ptr++; break; @@ -458,7 +485,7 @@ label: sverrno = errno; errno = 0; - n = strtol(buf, &cp, 10); + n = strtol_l(buf, &cp, 10, locale); if (errno == ERANGE || (long)(t = n) != n) { errno = sverrno; return 0; @@ -472,14 +499,16 @@ label: case 'Y': case 'y': - if (*buf == 0 || isspace((unsigned char)*buf)) + if (*buf == 0 || + isspace_l((unsigned char)*buf, locale)) break; - if (!isdigit((unsigned char)*buf)) + if (!isdigit_l((unsigned char)*buf, locale)) return 0; len = (c == 'Y') ? 4 : 2; - for (i = 0; len && *buf != 0 && isdigit((unsigned char)*buf); buf++) { + for (i = 0; len && *buf != 0 && + isdigit_l((unsigned char)*buf, locale); buf++) { i *= 10; i += *buf - '0'; len--; @@ -493,8 +522,10 @@ label: tm->tm_year = i; - if (*buf != 0 && isspace((unsigned char)*buf)) - while (*ptr != 0 && !isspace((unsigned char)*ptr)) + if (*buf != 0 && + isspace_l((unsigned char)*buf, locale)) + while (*ptr != 0 && + !isspace_l((unsigned char)*ptr, locale)) ptr++; break; @@ -503,7 +534,9 @@ label: const char *cp; char *zonestr; - for (cp = buf; *cp && isupper((unsigned char)*cp); ++cp) {/*empty*/} + for (cp = buf; *cp && + isupper_l((unsigned char)*cp, locale); ++cp) { + /*empty*/} if (cp - buf) { zonestr = alloca(cp - buf + 1); strncpy(zonestr, buf, cp - buf); @@ -537,7 +570,7 @@ label: buf++; i = 0; for (len = 4; len > 0; len--) { - if (isdigit((unsigned char)*buf)) { + if (isdigit_l((unsigned char)*buf, locale)) { i *= 10; i += *buf - '0'; buf++; @@ -557,14 +590,15 @@ label: char * -strptime(const char * __restrict buf, const char * __restrict fmt, - struct tm * __restrict tm) +strptime_l(const char * __restrict buf, const char * __restrict fmt, + struct tm * __restrict tm, locale_t loc) { char *ret; int gmt; + FIX_LOCALE(loc); gmt = 0; - ret = _strptime(buf, fmt, tm, &gmt); + ret = _strptime(buf, fmt, tm, &gmt, loc); if (ret && gmt) { time_t t = timegm(tm); localtime_r(&t, tm); @@ -572,3 +606,9 @@ strptime(const char * __restrict buf, const char * __restrict fmt, return (ret); } +char * +strptime(const char * __restrict buf, const char * __restrict fmt, + struct tm * __restrict tm) +{ + return strptime_l(buf, fmt, tm, __get_locale()); +} diff --git a/lib/libc/stdtime/timelocal.c b/lib/libc/stdtime/timelocal.c index 6917e6b..3d9d096 100644 --- a/lib/libc/stdtime/timelocal.c +++ b/lib/libc/stdtime/timelocal.c @@ -3,6 +3,11 @@ * Copyright (c) 1997 FreeBSD Inc. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,9 +38,13 @@ __FBSDID("$FreeBSD$"); #include "ldpart.h" #include "timelocal.h" -static struct lc_time_T _time_locale; -static int _time_using_locale; -static char *time_locale_buf; +struct xlocale_time { + struct xlocale_component header; + char *buffer; + struct lc_time_T locale; +}; + +struct xlocale_time __xlocale_global_time; #define LCTIME_SIZE (sizeof(struct lc_time_T) / sizeof(char *)) @@ -99,19 +108,47 @@ static const struct lc_time_T _C_time_locale = { "%I:%M:%S %p" }; +static void destruct_time(void *v) +{ + struct xlocale_time *l = v; + if (l->buffer) + free(l->buffer); + free(l); +} + +#include <stdio.h> struct lc_time_T * -__get_current_time_locale(void) +__get_current_time_locale(locale_t loc) { - return (_time_using_locale - ? &_time_locale + return (loc->using_time_locale + ? &((struct xlocale_time *)loc->components[XLC_TIME])->locale : (struct lc_time_T *)&_C_time_locale); } +static int +time_load_locale(struct xlocale_time *l, int *using_locale, const char *name) +{ + struct lc_time_T *time_locale = &l->locale; + return (__part_load_locale(name, using_locale, + &l->buffer, "LC_TIME", + LCTIME_SIZE, LCTIME_SIZE, + (const char **)time_locale)); +} int __time_load_locale(const char *name) { - return (__part_load_locale(name, &_time_using_locale, - &time_locale_buf, "LC_TIME", - LCTIME_SIZE, LCTIME_SIZE, - (const char **)&_time_locale)); + return time_load_locale(&__xlocale_global_time, + &__xlocale_global_locale.using_time_locale, name); } +void* __time_load(const char* name, locale_t loc) +{ + struct xlocale_time *new = calloc(sizeof(struct xlocale_time), 1); + new->header.header.destructor = destruct_time; + if (time_load_locale(new, &loc->using_time_locale, name) == _LDP_ERROR) + { + xlocale_release(new); + return NULL; + } + return new; +} + diff --git a/lib/libc/stdtime/timelocal.h b/lib/libc/stdtime/timelocal.h index 5d26bf9..2e44415 100644 --- a/lib/libc/stdtime/timelocal.h +++ b/lib/libc/stdtime/timelocal.h @@ -2,6 +2,11 @@ * Copyright (c) 1997-2002 FreeBSD Project. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -28,6 +33,7 @@ #ifndef _TIMELOCAL_H_ #define _TIMELOCAL_H_ +#include "xlocale_private.h" /* * Private header file for the strftime and strptime localization @@ -49,7 +55,7 @@ struct lc_time_T { const char *ampm_fmt; }; -struct lc_time_T *__get_current_time_locale(void); +struct lc_time_T *__get_current_time_locale(locale_t); int __time_load_locale(const char *); #endif /* !_TIMELOCAL_H_ */ diff --git a/lib/libc/string/Symbol.map b/lib/libc/string/Symbol.map index 19f3382..ef23465 100644 --- a/lib/libc/string/Symbol.map +++ b/lib/libc/string/Symbol.map @@ -91,6 +91,14 @@ FBSD_1.1 { wcsnlen; }; +FBSD_1.3 { + strcasecmp_l; + strcasestr_l; + strncasecmp_l; + wcswidth_l; + wcwidth_l; +}; + FBSDprivate_1.0 { __strtok_r; }; diff --git a/lib/libc/string/strcasecmp.c b/lib/libc/string/strcasecmp.c index 4a474fe..e173f6d 100644 --- a/lib/libc/string/strcasecmp.c +++ b/lib/libc/string/strcasecmp.c @@ -2,6 +2,11 @@ * Copyright (c) 1987, 1993 * The Regents of the University of California. All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -35,36 +40,50 @@ __FBSDID("$FreeBSD$"); #include <strings.h> #include <ctype.h> +#include "xlocale_private.h" typedef unsigned char u_char; int -strcasecmp(const char *s1, const char *s2) +strcasecmp_l(const char *s1, const char *s2, locale_t locale) { const u_char *us1 = (const u_char *)s1, *us2 = (const u_char *)s2; + FIX_LOCALE(locale); - while (tolower(*us1) == tolower(*us2++)) + while (tolower_l(*us1, locale) == tolower_l(*us2++, locale)) if (*us1++ == '\0') return (0); - return (tolower(*us1) - tolower(*--us2)); + return (tolower_l(*us1, locale) - tolower_l(*--us2, locale)); +} +int +strcasecmp(const char *s1, const char *s2) +{ + return strcasecmp_l(s1, s2, __get_locale()); } int -strncasecmp(const char *s1, const char *s2, size_t n) +strncasecmp_l(const char *s1, const char *s2, size_t n, locale_t locale) { + FIX_LOCALE(locale); if (n != 0) { const u_char *us1 = (const u_char *)s1, *us2 = (const u_char *)s2; do { - if (tolower(*us1) != tolower(*us2++)) - return (tolower(*us1) - tolower(*--us2)); + if (tolower_l(*us1, locale) != tolower_l(*us2++, locale)) + return (tolower_l(*us1, locale) - tolower_l(*--us2, locale)); if (*us1++ == '\0') break; } while (--n != 0); } return (0); } + +int +strncasecmp(const char *s1, const char *s2, size_t n) +{ + return strncasecmp_l(s1, s2, n, __get_locale()); +} diff --git a/lib/libc/string/strcasestr.c b/lib/libc/string/strcasestr.c index 9b28bf5..5f39648 100644 --- a/lib/libc/string/strcasestr.c +++ b/lib/libc/string/strcasestr.c @@ -5,6 +5,11 @@ * This code is derived from software contributed to Berkeley by * Chris Torek. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -35,26 +40,33 @@ __FBSDID("$FreeBSD$"); #include <ctype.h> #include <string.h> +#include "xlocale_private.h" /* * Find the first occurrence of find in s, ignore case. */ char * -strcasestr(const char *s, const char *find) +strcasestr_l(const char *s, const char *find, locale_t locale) { char c, sc; size_t len; + FIX_LOCALE(locale); if ((c = *find++) != 0) { - c = tolower((unsigned char)c); + c = tolower_l((unsigned char)c, locale); len = strlen(find); do { do { if ((sc = *s++) == 0) return (NULL); - } while ((char)tolower((unsigned char)sc) != c); - } while (strncasecmp(s, find, len) != 0); + } while ((char)tolower_l((unsigned char)sc, locale) != c); + } while (strncasecmp_l(s, find, len, locale) != 0); s--; } return ((char *)s); } +char * +strcasestr(const char *s, const char *find) +{ + return strcasestr_l(s, find, __get_locale()); +} diff --git a/lib/libc/string/strcoll.c b/lib/libc/string/strcoll.c index 0da5c57..a918fca 100644 --- a/lib/libc/string/strcoll.c +++ b/lib/libc/string/strcoll.c @@ -3,6 +3,11 @@ * at Electronni Visti IA, Kiev, Ukraine. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -32,21 +37,26 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include "collate.h" +#include <stdio.h> + int -strcoll(const char *s, const char *s2) +strcoll_l(const char *s, const char *s2, locale_t locale) { int len, len2, prim, prim2, sec, sec2, ret, ret2; const char *t, *t2; char *tt, *tt2; + FIX_LOCALE(locale); + struct xlocale_collate *table = + (struct xlocale_collate*)locale->components[XLC_COLLATE]; - if (__collate_load_error) + if (table->__collate_load_error) return strcmp(s, s2); len = len2 = 1; ret = ret2 = 0; - if (__collate_substitute_nontrivial) { - t = tt = __collate_substitute(s); - t2 = tt2 = __collate_substitute(s2); + if (table->__collate_substitute_nontrivial) { + t = tt = __collate_substitute(table, s); + t2 = tt2 = __collate_substitute(table, s2); } else { tt = tt2 = NULL; t = s; @@ -55,11 +65,11 @@ strcoll(const char *s, const char *s2) while(*t && *t2) { prim = prim2 = 0; while(*t && !prim) { - __collate_lookup(t, &len, &prim, &sec); + __collate_lookup(table, t, &len, &prim, &sec); t += len; } while(*t2 && !prim2) { - __collate_lookup(t2, &len2, &prim2, &sec2); + __collate_lookup(table, t2, &len2, &prim2, &sec2); t2 += len2; } if(!prim || !prim2) @@ -83,3 +93,10 @@ strcoll(const char *s, const char *s2) return ret; } + +int +strcoll(const char *s, const char *s2) +{ + return strcoll_l(s, s2, __get_locale()); +} + diff --git a/lib/libc/string/strxfrm.c b/lib/libc/string/strxfrm.c index a4c8019..b758b0c 100644 --- a/lib/libc/string/strxfrm.c +++ b/lib/libc/string/strxfrm.c @@ -3,6 +3,11 @@ * at Electronni Visti IA, Kiev, Ukraine. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -33,11 +38,22 @@ __FBSDID("$FreeBSD$"); #include "collate.h" size_t +strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t loc); +size_t strxfrm(char * __restrict dest, const char * __restrict src, size_t len) { + return strxfrm_l(dest, src, len, __get_locale()); +} + +size_t +strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t locale) +{ int prim, sec, l; size_t slen; char *s, *ss; + FIX_LOCALE(locale); + struct xlocale_collate *table = + (struct xlocale_collate*)locale->components[XLC_COLLATE]; if (!*src) { if (len > 0) @@ -45,15 +61,15 @@ strxfrm(char * __restrict dest, const char * __restrict src, size_t len) return 0; } - if (__collate_load_error) + if (table->__collate_load_error) return strlcpy(dest, src, len); slen = 0; prim = sec = 0; - ss = s = __collate_substitute(src); + ss = s = __collate_substitute(table, src); while (*s) { while (*s && !prim) { - __collate_lookup(s, &l, &prim, &sec); + __collate_lookup(table, s, &l, &prim, &sec); s += l; } if (prim) { diff --git a/lib/libc/string/wcscoll.c b/lib/libc/string/wcscoll.c index dbfbcfa..3c51015 100644 --- a/lib/libc/string/wcscoll.c +++ b/lib/libc/string/wcscoll.c @@ -2,6 +2,11 @@ * Copyright (c) 2002 Tim J. Robbins * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -41,12 +46,15 @@ static char *__mbsdup(const wchar_t *); * with extended character sets. */ int -wcscoll(const wchar_t *ws1, const wchar_t *ws2) +wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale) { char *mbs1, *mbs2; int diff, sverrno; + FIX_LOCALE(locale); + struct xlocale_collate *table = + (struct xlocale_collate*)locale->components[XLC_COLLATE]; - if (__collate_load_error || MB_CUR_MAX > 1) + if (table->__collate_load_error || MB_CUR_MAX > 1) /* * Locale has no special collating order, could not be * loaded, or has an extended character set; do a fast binary @@ -67,7 +75,7 @@ wcscoll(const wchar_t *ws1, const wchar_t *ws2) return (wcscmp(ws1, ws2)); } - diff = strcoll(mbs1, mbs2); + diff = strcoll_l(mbs1, mbs2, locale); sverrno = errno; free(mbs1); free(mbs2); @@ -76,6 +84,12 @@ wcscoll(const wchar_t *ws1, const wchar_t *ws2) return (diff); } +int +wcscoll(const wchar_t *ws1, const wchar_t *ws2) +{ + return wcscoll_l(ws1, ws2, __get_locale()); +} + static char * __mbsdup(const wchar_t *ws) { diff --git a/lib/libc/string/wcswidth.c b/lib/libc/string/wcswidth.c index b142074..4095c8d 100644 --- a/lib/libc/string/wcswidth.c +++ b/lib/libc/string/wcswidth.c @@ -10,6 +10,11 @@ * This code is derived from software contributed to Berkeley by * Paul Borman at Krystal Technologies. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -39,19 +44,26 @@ __FBSDID("$FreeBSD$"); #include <wchar.h> +#include "xlocale_private.h" int -wcswidth(const wchar_t *pwcs, size_t n) +wcswidth_l(const wchar_t *pwcs, size_t n, locale_t locale) { wchar_t wc; int len, l; + FIX_LOCALE(locale); len = 0; while (n-- > 0 && (wc = *pwcs++) != L'\0') { - if ((l = wcwidth(wc)) < 0) + if ((l = wcwidth_l(wc, locale)) < 0) return (-1); len += l; } return (len); } +int +wcswidth(const wchar_t *pwcs, size_t n) +{ + return wcswidth_l(pwcs, n, __get_locale()); +} diff --git a/lib/libc/string/wcsxfrm.c b/lib/libc/string/wcsxfrm.c index 5e47ad9..cea667e 100644 --- a/lib/libc/string/wcsxfrm.c +++ b/lib/libc/string/wcsxfrm.c @@ -3,6 +3,11 @@ * at Electronni Visti IA, Kiev, Ukraine. * All rights reserved. * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -43,11 +48,14 @@ static char *__mbsdup(const wchar_t *); * the logic used. */ size_t -wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len) +wcsxfrm_l(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len, locale_t locale) { int prim, sec, l; size_t slen; char *mbsrc, *s, *ss; + FIX_LOCALE(locale); + struct xlocale_collate *table = + (struct xlocale_collate*)locale->components[XLC_COLLATE]; if (*src == L'\0') { if (len != 0) @@ -55,7 +63,7 @@ wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len) return (0); } - if (__collate_load_error || MB_CUR_MAX > 1) { + if (table->__collate_load_error || MB_CUR_MAX > 1) { slen = wcslen(src); if (len > 0) { if (slen < len) @@ -71,10 +79,10 @@ wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len) mbsrc = __mbsdup(src); slen = 0; prim = sec = 0; - ss = s = __collate_substitute(mbsrc); + ss = s = __collate_substitute(table, mbsrc); while (*s != '\0') { while (*s != '\0' && prim == 0) { - __collate_lookup(s, &l, &prim, &sec); + __collate_lookup(table, s, &l, &prim, &sec); s += l; } if (prim != 0) { @@ -93,6 +101,11 @@ wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len) return (slen); } +size_t +wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len) +{ + return wcsxfrm_l(dest, src, len, __get_locale()); +} static char * __mbsdup(const wchar_t *ws) diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index fe5061d..ea38b51 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -80,7 +80,7 @@ MAN+= abort2.2 accept.2 access.2 acct.2 adjtime.2 \ bind.2 brk.2 cap_enter.2 cap_new.2 chdir.2 chflags.2 \ chmod.2 chown.2 chroot.2 clock_gettime.2 close.2 closefrom.2 \ connect.2 cpuset.2 cpuset_getaffinity.2 dup.2 execve.2 _exit.2 \ - extattr_get_file.2 fcntl.2 fhopen.2 flock.2 fork.2 fsync.2 \ + extattr_get_file.2 fcntl.2 ffclock.2 fhopen.2 flock.2 fork.2 fsync.2 \ getdirentries.2 getdtablesize.2 \ getfh.2 getfsstat.2 getgid.2 getgroups.2 getitimer.2 getlogin.2 \ getloginclass.2 getpeername.2 getpgrp.2 getpid.2 getpriority.2 \ @@ -96,7 +96,8 @@ MAN+= abort2.2 accept.2 access.2 acct.2 adjtime.2 \ mq_setattr.2 \ msgctl.2 msgget.2 msgrcv.2 msgsnd.2 \ msync.2 munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 open.2 \ - pathconf.2 pdfork.2 pipe.2 poll.2 posix_fallocate.2 posix_openpt.2 profil.2 \ + pathconf.2 pdfork.2 pipe.2 poll.2 posix_fadvise.2 posix_fallocate.2 \ + posix_openpt.2 profil.2 \ pselect.2 ptrace.2 quotactl.2 \ read.2 readlink.2 reboot.2 recv.2 rename.2 revoke.2 rfork.2 rmdir.2 \ rtprio.2 @@ -141,6 +142,8 @@ MLINKS+=extattr_get_file.2 extattr.2 \ extattr_get_file.2 extattr_set_fd.2 \ extattr_get_file.2 extattr_set_file.2 \ extattr_get_file.2 extattr_set_link.2 +MLINKS+=ffclock.2 ffclock_getcounter.2 ffclock.2 ffclock_getestimate.2 \ + ffclock.2 ffclock_setestimate.2 MLINKS+=fhopen.2 fhstat.2 fhopen.2 fhstatfs.2 MLINKS+=getdirentries.2 getdents.2 MLINKS+=getfh.2 lgetfh.2 diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index 095751a..f1c1567 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -365,6 +365,9 @@ FBSD_1.2 { cap_getmode; cap_new; cap_getrights; + ffclock_getcounter; + ffclock_getestimate; + ffclock_setestimate; getloginclass; pdfork; pdgetpid; @@ -378,6 +381,10 @@ FBSD_1.2 { setloginclass; }; +FBSD_1.3 { + posix_fadvise; +}; + FBSDprivate_1.0 { ___acl_aclcheck_fd; __sys___acl_aclcheck_fd; diff --git a/lib/libc/sys/ffclock.2 b/lib/libc/sys/ffclock.2 new file mode 100644 index 0000000..0e8f09b --- /dev/null +++ b/lib/libc/sys/ffclock.2 @@ -0,0 +1,177 @@ +.\" Copyright (c) 2011 The University of Melbourne +.\" All rights reserved. +.\" +.\" This documentation was written by Julien Ridoux at the University of +.\" Melbourne under sponsorship from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd November 21, 2011 +.Dt FFCLOCK 2 +.Os +.Sh NAME +.Nm ffclock_getcounter , +.Nm ffclock_getestimate , +.Nm ffclock_setestimate +.Nd Retrieve feed-forward counter, get and set feed-forward clock estimates. +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/timeffc.h +.Ft int +.Fn ffclock_getcounter "ffcounter *ffcount" +.Ft int +.Fn ffclock_getestimate "struct ffclock_estimate *cest" +.Ft int +.Fn ffclock_setestimate "struct ffclock_estimate *cest" +.Sh DESCRIPTION +The ffclock is an alternative method to synchronise the system clock. +The ffclock implements a feed-forward paradigm and decouples the timestamping +and timekeeping kernel functions. +This ensures that past clock errors do not affect current timekeeping, an +approach radically different from the feedback alternative implemented by the +ntpd daemon when adjusting the system clock. +The feed-forward approach has demonstrated better performance and higher +robustness than a feedback approach when synchronising over the network. +.Pp +In the feed-forward context, a +.Em timestamp +is a cumulative value of the ticks of the timecounter, which can be converted +into seconds by using the feed-forward +.Em clock estimates. +.Pp +The +.Fn ffclock_getcounter +system call allows the calling process to retrieve the current value of the +feed-forward counter maintained by the kernel. +.Pp +The +.Fn ffclock_getestimate +and +.Fn ffclock_setestimate +system calls allow the caller to get and set the kernel's feed-forward clock +parameter estimates respectively. +The +.Fn ffclock_setestimate +system call should be invoked by a single instance of a feed-forward +synchronisation daemon. +The +.Fn ffclock_getestimate +system call can be called by any process to retrieve the feed-forward clock +estimates. +.Pp +The feed-forward approach does not require that the clock estimates be retrieved +every time a timestamp is to be converted into seconds. +The number of system calls can therefore be greatly reduced if the calling +process retrieves the clock estimates from the clock synchronisation daemon +instead. +The +.Fn ffclock_getestimate +must be used when the feed-forward synchronisation daemon is not running +.Po see +.Sx USAGE +below +.Pc . +.Pp +The clock parameter estimates structure pointed to by +.Fa cest +is defined in +.In sys/timeffc.h +as: +.Bd -literal +struct ffclock_estimate { + struct bintime update_time; /* Time of last estimates update. */ + ffcounter update_ffcount; /* Counter value at last update. */ + ffcounter leapsec_next; /* Counter value of next leap second. */ + uint64_t period; /* Estimate of counter period. */ + uint32_t errb_abs; /* Bound on absolute clock error [ns]. */ + uint32_t errb_rate; /* Bound on counter rate error [ps/s]. */ + uint32_t status; /* Clock status. */ + int16_t leapsec_total; /* All leap seconds seen so far. */ + int8_t leapsec; /* Next leap second (in {-1,0,1}). */ +}; +.Ed +.Pp +Only the super-user may set the feed-forward clock estimates. +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +The following error codes may be set in +.Va errno : +.Bl -tag -width Er +.It Bq Er EFAULT +The +.Fa ffcount +or +.Fa cest +pointer referenced invalid memory. +.It Bq Er EPERM +A user other than the super-user attempted to set the feed-forward clock +parameter estimates. +.El +.Sh USAGE +The feed-forward paradigm enables the definition of specialised clock functions. +.Pp +In its simplest form, +.Fn ffclock_getcounter +can be used to establish strict order between events or to measure small time +intervals very accurately with a minimum performance cost. +.Pp +Different methods exist to access absolute time +.Po or +.Qq wall-clock time +.Pc tracked by the ffclock. +The simplest method uses the ffclock sysctl interface +.Va kern.ffclock +to make the system clock return the ffclock time. +The +.Xr clock_gettime 2 +system call can then be used to retrieve the current time seen by the +feed-forward clock. +Note that this setting affects the entire system and that a feed-forward +synchronisation daemon should be running. +.Pp +A less automated method consists of retrieving the feed-forward counter +timestamp from the kernel and using the feed-forward clock parameter estimates +to convert the timestamp into seconds. +The feed-forward clock parameter estimates can be retrieved from the kernel or +from the synchronisation daemon directly (preferred). +This method allows converting timestamps using different clock models as needed +by the application, while collecting meaningful upper bounds on current clock +error. +.Sh SEE ALSO +.Xr date 1 , +.Xr adjtime 2 , +.Xr clock_gettime 2 , +.Xr ctime 3 +.Sh HISTORY +Feed-forward clock support first appeared in +.Fx 10.0 . +.Sh AUTHORS +.An -nosplit +The feed-forward clock support was written by +.An Julien Ridoux Aq jridoux@unimelb.edu.au +in collaboration with +.An Darryl Veitch Aq dveitch@unimelb.edu.au +at the University of Melbourne under sponsorship from the FreeBSD Foundation. diff --git a/lib/libc/sys/flock.2 b/lib/libc/sys/flock.2 index 93f1f66..6106bf4 100644 --- a/lib/libc/sys/flock.2 +++ b/lib/libc/sys/flock.2 @@ -28,7 +28,7 @@ .\" @(#)flock.2 8.2 (Berkeley) 12/11/93 .\" $FreeBSD$ .\" -.Dd January 22, 2008 +.Dd November 9, 2011 .Dt FLOCK 2 .Os .Sh NAME @@ -154,6 +154,8 @@ refers to an object other than a file. The argument .Fa fd refers to an object that does not support file locking. +.It Bq Er ENOLCK +A lock was requested, but no locks are available. .El .Sh SEE ALSO .Xr close 2 , diff --git a/lib/libc/sys/getsockopt.2 b/lib/libc/sys/getsockopt.2 index 7370b6b..edd92c3 100644 --- a/lib/libc/sys/getsockopt.2 +++ b/lib/libc/sys/getsockopt.2 @@ -28,7 +28,7 @@ .\" @(#)getsockopt.2 8.4 (Berkeley) 5/2/95 .\" $FreeBSD$ .\" -.Dd June 13, 2008 +.Dd November 21, 2011 .Dt GETSOCKOPT 2 .Os .Sh NAME @@ -533,7 +533,9 @@ on a non-listening socket was attempted. .Sh HISTORY The .Fn getsockopt -system call appeared in +and +.Fn setsockopt +system calls appeared in .Bx 4.2 . .Sh BUGS Several of the socket options should be handled at lower levels of the system. diff --git a/lib/libc/sys/madvise.2 b/lib/libc/sys/madvise.2 index 48f0e5a..b5ea6b2 100644 --- a/lib/libc/sys/madvise.2 +++ b/lib/libc/sys/madvise.2 @@ -169,7 +169,8 @@ was specified and the process does not have superuser privileges. .Xr mincore 2 , .Xr mprotect 2 , .Xr msync 2 , -.Xr munmap 2 +.Xr munmap 2 , +.Xr posix_fadvise 2 .Sh STANDARDS The .Fn posix_madvise diff --git a/lib/libc/sys/posix_fadvise.2 b/lib/libc/sys/posix_fadvise.2 new file mode 100644 index 0000000..bdf321f --- /dev/null +++ b/lib/libc/sys/posix_fadvise.2 @@ -0,0 +1,139 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 4. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" @(#)madvise.2 8.1 (Berkeley) 6/9/93 +.\" $FreeBSD$ +.\" +.Dd October 26, 2011 +.Dt POSIX_FADVISE 2 +.Os +.Sh NAME +.Nm posix_fadvise +.Nd give advice about use of file data +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In fcntl.h +.Ft int +.Fn posix_fadvise "int fd" "off_t offset" "off_t len" "int advice" +.Sh DESCRIPTION +The +.Fn posix_fadvise +system call +allows a process to describe to the system its data access behavior for an +open file descriptor +.Fa fd . +The advice covers the data starting at offset +.Fa offset +and continuing for +.Fa len +bytes. +If +.Fa len +is zero, +all data from +.Fa offset +to the end of the file is covered. +.Pp +The behavior is specified by the +.Fa advice +parameter and may be one of: +.Bl -tag -width POSIX_FADV_SEQUENTIAL +.It Dv POSIX_FADV_NORMAL +Tells the system to revert to the default data access behavior. +.It Dv POSIX_FADV_RANDOM +Is a hint that file data will be accessed randomly, +and prefetching is likely not advantageous. +.It Dv POSIX_FADV_SEQUENTIAL +Tells the system that file data will be accessed sequentially. +This currently does nothing as the default behavior uses heuristics to +detect sequential behavior. +.It Dv POSIX_FADV_WILLNEED +Tells the system that the specified data will be accessed in the near future. +The system may initiate an asychronous read of the data if it is not already +present in memory. +.It Dv POSIX_FADV_DONTNEED +Tells the system that the specified data will not be accessed in the near +future. +The system may decrease the in-memory priority of clean data within the +specified range and future access to this data may require a read operation. +.It Dv POSIX_FADV_NOREUSE +Tells the system that the specified data will only be accessed once and +then not reused. +Accesses to data within the specified range are treated as if the file +descriptor has the +.Dv O_DIRECT +flag enabled. +.El +.Pp +.Sh RETURN VALUES +.Rv -std posix_fadvise +.Sh ERRORS +The +.Fn posix_fadvise +system call will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument is not a valid file descriptor. +.It Bq Er EINVAL +The +.Fa advice +argument is not valid. +.It Bq Er EINVAL +The +.Fa offset +or +.Fa len +arguments are negative, +or +.Fa offset ++ +.Fa len +is greater than the maximum file size. +.It Bq Er ENODEV +The +.Fa fd +argument does not refer to a regular file. +.It Bq Er ESPIPE +The +.Fa fd +argument is associated with a pipe or FIFO. +.El +.Sh SEE ALSO +.Xr madvise 2 +.Sh STANDARDS +The +.Fn posix_fadvise +interface conforms to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn posix_fadvise +system call first appeared in +.Fx 10.0 . diff --git a/lib/libc/sys/stat.2 b/lib/libc/sys/stat.2 index 7f6d533..b6c03ab 100644 --- a/lib/libc/sys/stat.2 +++ b/lib/libc/sys/stat.2 @@ -28,7 +28,7 @@ .\" @(#)stat.2 8.4 (Berkeley) 5/1/95 .\" $FreeBSD$ .\" -.Dd March 28, 2010 +.Dd November 17, 2011 .Dt STAT 2 .Os .Sh NAME @@ -411,7 +411,7 @@ and system calls are expected to conform to .St -p1003.1-90 . The -.Fn fchownat +.Fn fstatat system call follows The Open Group Extended API Set 2 specification. .Sh HISTORY The diff --git a/lib/libkiconv/xlat16_iconv.c b/lib/libkiconv/xlat16_iconv.c index ce06324..dc9dc86 100644 --- a/lib/libkiconv/xlat16_iconv.c +++ b/lib/libkiconv/xlat16_iconv.c @@ -74,6 +74,18 @@ kiconv_add_xlat16_cspair(const char *tocode, const char *fromcode, int flag) struct xlat16_table xt; void *data; char *p; + const char unicode[] = ENCODING_UNICODE; + + if ((flag & KICONV_WCTYPE) == 0 && + strcmp(unicode, tocode) != 0 && + strcmp(unicode, fromcode) != 0 && + kiconv_lookupconv(unicode) == 0) { + error = kiconv_add_xlat16_cspair(unicode, fromcode, flag); + if (error) + return (-1); + error = kiconv_add_xlat16_cspair(tocode, unicode, flag); + return (error); + } if (kiconv_lookupcs(tocode, fromcode) == 0) return (0); diff --git a/lib/libpam/Makefile.inc b/lib/libpam/Makefile.inc index 1c1e513..923d7bd 100644 --- a/lib/libpam/Makefile.inc +++ b/lib/libpam/Makefile.inc @@ -31,4 +31,6 @@ DEBUG_FLAGS+= -DDEBUG SHLIB_MAJOR= 5 PAM_MOD_DIR= ${LIBDIR} +STATIC_CFLAGS+= -DOPENPAM_STATIC_MODULES + .include "../Makefile.inc" diff --git a/lib/libpam/modules/Makefile.inc b/lib/libpam/modules/Makefile.inc index feb5da0..00bfbf9 100644 --- a/lib/libpam/modules/Makefile.inc +++ b/lib/libpam/modules/Makefile.inc @@ -5,20 +5,8 @@ PAMDIR= ${.CURDIR}/../../../../contrib/openpam NO_INSTALLLIB= NO_PROFILE= -CFLAGS+= -I${PAMDIR}/include -I${.CURDIR}/../../libpam +CFLAGS+= -I${PAMDIR}/include -I${.CURDIR}/../../libpam -# This is nasty. -# For the static case, libpam.a depends on the modules. -# For the dynamic case, the modules depend on libpam.so.N -.if defined(_NO_LIBPAM_SO_YET) -NO_PIC= -.else SHLIB_NAME?= ${LIB}.so.${SHLIB_MAJOR} -DPADD+= ${LIBPAM} -LDADD+= -lpam -.endif - -.c.o: - ${CC} ${CFLAGS} -DOPENPAM_STATIC_MODULES -c ${.IMPSRC} .include "../Makefile.inc" diff --git a/lib/libpam/modules/pam_lastlog/pam_lastlog.c b/lib/libpam/modules/pam_lastlog/pam_lastlog.c index 14e47b80..72bb942 100644 --- a/lib/libpam/modules/pam_lastlog/pam_lastlog.c +++ b/lib/libpam/modules/pam_lastlog/pam_lastlog.c @@ -47,6 +47,8 @@ __FBSDID("$FreeBSD$"); #define _BSD_SOURCE #include <sys/time.h> + +#include <paths.h> #include <pwd.h> #include <stdlib.h> #include <string.h> @@ -96,6 +98,9 @@ pam_sm_open_session(pam_handle_t *pamh, int flags, pam_err = PAM_SERVICE_ERR; goto err; } + /* Strip /dev/ component. */ + if (strncmp(tty, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) + tty = (const char *)tty + sizeof(_PATH_DEV) - 1; if ((flags & PAM_SILENT) == 0) { if (setutxdb(UTXDB_LASTLOGIN, NULL) != 0) { diff --git a/lib/libpam/modules/pam_ssh/pam_ssh.c b/lib/libpam/modules/pam_ssh/pam_ssh.c index bc5f522..ab4990b 100644 --- a/lib/libpam/modules/pam_ssh/pam_ssh.c +++ b/lib/libpam/modules/pam_ssh/pam_ssh.c @@ -93,7 +93,8 @@ static char *const pam_ssh_agent_envp[] = { NULL }; * struct pam_ssh_key containing the key and its comment. */ static struct pam_ssh_key * -pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase) +pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase, + int nullok) { struct pam_ssh_key *psk; char fn[PATH_MAX]; @@ -103,7 +104,21 @@ pam_ssh_load_key(const char *dir, const char *kfn, const char *passphrase) if (snprintf(fn, sizeof(fn), "%s/%s", dir, kfn) > (int)sizeof(fn)) return (NULL); comment = NULL; - key = key_load_private(fn, passphrase, &comment); + /* + * If the key is unencrypted, OpenSSL ignores the passphrase, so + * it will seem like the user typed in the right one. This allows + * a user to circumvent nullok by providing a dummy passphrase. + * Verify that the key really *is* encrypted by trying to load it + * with an empty passphrase, and if the key is not encrypted, + * accept only an empty passphrase. + */ + key = key_load_private(fn, NULL, &comment); + if (key != NULL && !(*passphrase == '\0' && nullok)) { + key_free(key); + return (NULL); + } + if (key == NULL) + key = key_load_private(fn, passphrase, &comment); if (key == NULL) { openpam_log(PAM_LOG_DEBUG, "failed to load key from %s", fn); return (NULL); @@ -170,9 +185,6 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, if (pam_err != PAM_SUCCESS) return (pam_err); - if (*passphrase == '\0' && !nullok) - goto skip_keys; - /* switch to user credentials */ pam_err = openpam_borrow_cred(pamh, pwd); if (pam_err != PAM_SUCCESS) @@ -180,7 +192,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, /* try to load keys from all keyfiles we know of */ for (kfn = pam_ssh_keyfiles; *kfn != NULL; ++kfn) { - psk = pam_ssh_load_key(pwd->pw_dir, *kfn, passphrase); + psk = pam_ssh_load_key(pwd->pw_dir, *kfn, passphrase, nullok); if (psk != NULL) { pam_set_data(pamh, *kfn, psk, pam_ssh_free_key); ++nkeys; @@ -190,7 +202,6 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, /* switch back to arbitrator credentials */ openpam_restore_cred(pamh); - skip_keys: /* * If we tried an old token and didn't get anything, and * try_first_pass was specified, try again after prompting the diff --git a/lib/libpam/modules/pam_unix/pam_unix.8 b/lib/libpam/modules/pam_unix/pam_unix.8 index 82354d5..1345e82 100644 --- a/lib/libpam/modules/pam_unix/pam_unix.8 +++ b/lib/libpam/modules/pam_unix/pam_unix.8 @@ -199,3 +199,9 @@ password database. .Xr pam 8 , .Xr pw 8 , .Xr yp 8 +.Sh BUGS +The +.Nm +module ignores the +.Dv PAM_CHANGE_EXPIRED_AUTHTOK +flag. diff --git a/lib/libpam/modules/pam_unix/pam_unix.c b/lib/libpam/modules/pam_unix/pam_unix.c index 5c6c8f7..415004a 100644 --- a/lib/libpam/modules/pam_unix/pam_unix.c +++ b/lib/libpam/modules/pam_unix/pam_unix.c @@ -81,8 +81,6 @@ static char password_hash[] = PASSWORD_HASH; #define PAM_OPT_LOCAL_PASS "local_pass" #define PAM_OPT_NIS_PASS "nis_pass" -char *tempname = NULL; - /* * authentication management */ diff --git a/lib/librt/timer.c b/lib/librt/timer.c index f02e761..90269c2 100644 --- a/lib/librt/timer.c +++ b/lib/librt/timer.c @@ -102,12 +102,14 @@ __timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) } if (__sigev_check_init()) { + free(timer); errno = EINVAL; return (-1); } sn = __sigev_alloc(SI_TIMER, evp, NULL, 0); if (sn == NULL) { + free(timer); errno = EAGAIN; return (-1); } diff --git a/lib/libthr/thread/thr_umtx.c b/lib/libthr/thread/thr_umtx.c index 33c3637..e962378 100644 --- a/lib/libthr/thread/thr_umtx.c +++ b/lib/libthr/thread/thr_umtx.c @@ -231,7 +231,7 @@ _thr_ucond_init(struct ucond *cv) int _thr_ucond_wait(struct ucond *cv, struct umutex *m, - const struct timespec *timeout, int check_unparking) + const struct timespec *timeout, int flags) { if (timeout && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 && timeout->tv_nsec <= 0))) { @@ -239,8 +239,7 @@ _thr_ucond_wait(struct ucond *cv, struct umutex *m, _thr_umutex_unlock(m, TID(curthread)); return (ETIMEDOUT); } - return _umtx_op_err(cv, UMTX_OP_CV_WAIT, - check_unparking ? UMTX_CHECK_UNPARKING : 0, + return _umtx_op_err(cv, UMTX_OP_CV_WAIT, flags, m, __DECONST(void*, timeout)); } diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile index b76618a..8d78619 100644 --- a/lib/libusb/Makefile +++ b/lib/libusb/Makefile @@ -74,6 +74,10 @@ MLINKS += libusb.3 libusb_get_config_descriptor.3 MLINKS += libusb.3 libusb_get_config_descriptor_by_value.3 MLINKS += libusb.3 libusb_free_config_descriptor.3 MLINKS += libusb.3 libusb_get_string_descriptor_ascii.3 +MLINKS += libusb.3 libusb_parse_ss_endpoint_comp.3 +MLINKS += libusb.3 libusb_free_ss_endpoint_comp.3 +MLINKS += libusb.3 libusb_parse_bos_descriptor.3 +MLINKS += libusb.3 libusb_free_bos_descriptor.3 MLINKS += libusb.3 libusb_alloc_transfer.3 MLINKS += libusb.3 libusb_free_transfer.3 MLINKS += libusb.3 libusb_submit_transfer.3 diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3 index 7255f2b..4e4dd10 100644 --- a/lib/libusb/libusb.3 +++ b/lib/libusb/libusb.3 @@ -26,7 +26,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 16, 2011 +.Dd November 9, 2011 .Dt LIBUSB 3 .Os .Sh NAME @@ -316,6 +316,40 @@ Retrieve a string descriptor in C style ASCII. Returns the positive number of bytes in the resulting ASCII string on success and a LIBUSB_ERROR code on failure. .Pp +.Ft int +.Fn libusb_parse_ss_endpoint_comp "const void *buf" "int len" "libusb_ss_endpoint_companion_descriptor **ep_comp" +This function parses the USB 3.0 endpoint companion descriptor in host endian format pointed to by +.Fa buf +and having a length of +.Fa len. +Typically these arguments are the extra and extra_length fields of the +endpoint descriptor. +On success the pointer to resulting descriptor is stored at the location given by +.Fa ep_comp. +Returns zero on success and a LIBUSB_ERROR code on failure. +On success the parsed USB 3.0 endpoint companion descriptor must be +freed using the libusb_free_ss_endpoint_comp function. +.Pp +.Ft void +.Fn libusb_free_ss_endpoint_comp "libusb_ss_endpoint_companion_descriptor *ep_comp" +This function is NULL safe and frees a parsed USB 3.0 endpoint companion descriptor. +.Pp +.Ft int +.Fn libusb_parse_bos_descriptor "const void *buf" "int len" "libusb_bos_descriptor **bos" +This function parses a Binary Object Store, BOS, descriptor into host endian format pointed to by +.Fa buf +and having a length of +.Fa len. +On success the pointer to resulting descriptor is stored at the location given by +.Fa bos. +Returns zero on success and a LIBUSB_ERROR code on failure. +On success the parsed BOS descriptor must be freed using the +libusb_free_bos_descriptor function. +.Pp +.Ft void +.Fn libusb_free_bos_descriptor "libusb_bos_descriptor *bos" +This function is NULL safe and frees a parsed BOS descriptor. +.Pp .Sh USB ASYNCHRONOUS I/O .Pp .Ft struct libusb_transfer * diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h index 63e3ebc..5a4d2df 100644 --- a/lib/libusb/libusb.h +++ b/lib/libusb/libusb.h @@ -63,6 +63,16 @@ enum libusb_descriptor_type { LIBUSB_DT_REPORT = 0x22, LIBUSB_DT_PHYSICAL = 0x23, LIBUSB_DT_HUB = 0x29, + LIBUSB_DT_BOS = 0x0f, + LIBUSB_DT_DEVICE_CAPABILITY = 0x10, + LIBUSB_DT_SS_ENDPOINT_COMPANION = 0x30, +}; + +enum libusb_device_capability_type { + LIBUSB_WIRELESS_USB_DEVICE_CAPABILITY = 0x1, + LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY = 0x2, + LIBUSB_SS_USB_DEVICE_CAPABILITY = 0x3, + LIBUSB_CONTAINER_ID_DEVICE_CAPABILITY = 0x4, }; #define LIBUSB_DT_DEVICE_SIZE 18 @@ -71,6 +81,10 @@ enum libusb_descriptor_type { #define LIBUSB_DT_ENDPOINT_SIZE 7 #define LIBUSB_DT_ENDPOINT_AUDIO_SIZE 9 #define LIBUSB_DT_HUB_NONVAR_SIZE 7 +#define LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE 6 +#define LIBUSB_DT_BOS_SIZE 5 +#define LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE 7 +#define LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE 10 #define LIBUSB_ENDPOINT_ADDRESS_MASK 0x0f #define LIBUSB_ENDPOINT_DIR_MASK 0x80 @@ -230,6 +244,14 @@ typedef struct libusb_endpoint_descriptor { int extra_length; } libusb_endpoint_descriptor __aligned(sizeof(void *)); +typedef struct libusb_ss_endpoint_companion_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bMaxBurst; + uint8_t bmAttributes; + uint16_t wBytesPerInterval; +} libusb_ss_endpoint_companion_descriptor __aligned(sizeof(void *)); + typedef struct libusb_interface_descriptor { uint8_t bLength; uint8_t bDescriptorType; @@ -264,6 +286,39 @@ typedef struct libusb_config_descriptor { int extra_length; } libusb_config_descriptor __aligned(sizeof(void *)); +typedef struct libusb_usb_2_0_device_capability_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint32_t bmAttributes; +#define LIBUSB_USB_2_0_CAPABILITY_LPM_SUPPORT (1 << 1) +} libusb_usb_2_0_device_capability_descriptor __aligned(sizeof(void *)); + +typedef struct libusb_ss_usb_device_capability_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t bmAttributes; +#define LIBUSB_SS_USB_CAPABILITY_LPM_SUPPORT (1 << 1) + uint16_t wSpeedSupported; +#define LIBUSB_CAPABILITY_LOW_SPEED_OPERATION (1) +#define LIBUSB_CAPABILITY_FULL_SPEED_OPERATION (1 << 1) +#define LIBUSB_CAPABILITY_HIGH_SPEED_OPERATION (1 << 2) +#define LIBUSB_CAPABILITY_5GBPS_OPERATION (1 << 3) + uint8_t bFunctionalitySupport; + uint8_t bU1DevExitLat; + uint16_t wU2DevExitLat; +} libusb_ss_usb_device_capability_descriptor __aligned(sizeof(void *)); + +typedef struct libusb_bos_descriptor { + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumDeviceCapabilities; + struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap; + struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap; +} libusb_bos_descriptor __aligned(sizeof(void *)); + typedef struct libusb_control_setup { uint8_t bmRequestType; uint8_t bRequest; @@ -345,6 +400,10 @@ int libusb_get_config_descriptor_by_value(libusb_device * dev, uint8_t bConfigur void libusb_free_config_descriptor(struct libusb_config_descriptor *config); int libusb_get_string_descriptor_ascii(libusb_device_handle * devh, uint8_t desc_index, uint8_t *data, int length); int libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, uint8_t desc_index, uint8_t *data, int length); +int libusb_parse_ss_endpoint_comp(const void *buf, int len, struct libusb_ss_endpoint_companion_descriptor **ep_comp); +void libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp); +int libusb_parse_bos_descriptor(const void *buf, int len, struct libusb_bos_descriptor **bos); +void libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos); /* Asynchronous device I/O */ diff --git a/lib/libusb/libusb10_desc.c b/lib/libusb/libusb10_desc.c index 3448679..6d5822e 100644 --- a/lib/libusb/libusb10_desc.c +++ b/lib/libusb/libusb10_desc.c @@ -298,7 +298,7 @@ libusb_get_string_descriptor_ascii(libusb_device_handle *pdev, uint8_t desc_index, unsigned char *data, int length) { if (pdev == NULL || data == NULL || length < 1) - return (LIBUSB20_ERROR_INVALID_PARAM); + return (LIBUSB_ERROR_INVALID_PARAM); if (length > 65535) length = 65535; @@ -318,7 +318,7 @@ libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, uint8_t desc_index, uint8_t *data, int length) { if (devh == NULL || data == NULL || length < 1) - return (LIBUSB20_ERROR_INVALID_PARAM); + return (LIBUSB_ERROR_INVALID_PARAM); if (length > 65535) length = 65535; @@ -327,3 +327,172 @@ libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, length, 1000)); } + +int +libusb_parse_ss_endpoint_comp(const void *buf, int len, + struct libusb_ss_endpoint_companion_descriptor **ep_comp) +{ + if (buf == NULL || ep_comp == NULL || len < 1) + return (LIBUSB_ERROR_INVALID_PARAM); + + if (len > 65535) + len = 65535; + + *ep_comp = NULL; + + while (len != 0) { + uint8_t dlen; + uint8_t dtype; + + dlen = ((const uint8_t *)buf)[0]; + dtype = ((const uint8_t *)buf)[1]; + + if (dlen < 2 || dlen > len) + break; + + if (dlen >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE && + dtype == LIBUSB_DT_SS_ENDPOINT_COMPANION) { + struct libusb_ss_endpoint_companion_descriptor *ptr; + + ptr = malloc(sizeof(*ptr)); + if (ptr == NULL) + return (LIBUSB_ERROR_NO_MEM); + + ptr->bLength = LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE; + ptr->bDescriptorType = dtype; + ptr->bMaxBurst = ((const uint8_t *)buf)[2]; + ptr->bmAttributes = ((const uint8_t *)buf)[3]; + ptr->wBytesPerInterval = ((const uint8_t *)buf)[4] | + (((const uint8_t *)buf)[5] << 8); + + *ep_comp = ptr; + + return (0); /* success */ + } + + buf = ((const uint8_t *)buf) + dlen; + len -= dlen; + } + return (LIBUSB_ERROR_IO); +} + +void +libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp) +{ + if (ep_comp == NULL) + return; + + free(ep_comp); +} + +int +libusb_parse_bos_descriptor(const void *buf, int len, + struct libusb_bos_descriptor **bos) +{ + struct libusb_bos_descriptor *ptr; + struct libusb_usb_2_0_device_capability_descriptor *dcap_20; + struct libusb_ss_usb_device_capability_descriptor *ss_cap; + + if (buf == NULL || bos == NULL || len < 1) + return (LIBUSB_ERROR_INVALID_PARAM); + + if (len > 65535) + len = 65535; + + *bos = ptr = NULL; + + while (len != 0) { + uint8_t dlen; + uint8_t dtype; + + dlen = ((const uint8_t *)buf)[0]; + dtype = ((const uint8_t *)buf)[1]; + + if (dlen < 2 || dlen > len) + break; + + if (dlen >= LIBUSB_DT_BOS_SIZE && + dtype == LIBUSB_DT_BOS) { + + ptr = malloc(sizeof(*ptr) + sizeof(*dcap_20) + + sizeof(*ss_cap)); + + if (ptr == NULL) + return (LIBUSB_ERROR_NO_MEM); + + *bos = ptr; + + ptr->bLength = LIBUSB_DT_BOS_SIZE; + ptr->bDescriptorType = dtype; + ptr->wTotalLength = ((const uint8_t *)buf)[2] | + (((const uint8_t *)buf)[3] << 8); + ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4]; + ptr->usb_2_0_ext_cap = NULL; + ptr->ss_usb_cap = NULL; + + dcap_20 = (void *)(ptr + 1); + ss_cap = (void *)(dcap_20 + 1); + } + if (dlen >= 3 && + ptr != NULL && + dtype == LIBUSB_DT_DEVICE_CAPABILITY) { + switch (((const uint8_t *)buf)[2]) { + case LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY: + if (ptr->usb_2_0_ext_cap != NULL) + break; + if (dlen < LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE) + break; + + ptr->usb_2_0_ext_cap = dcap_20; + + dcap_20->bLength = LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE; + dcap_20->bDescriptorType = dtype; + dcap_20->bDevCapabilityType = ((const uint8_t *)buf)[2]; + dcap_20->bmAttributes = ((const uint8_t *)buf)[3] | + (((const uint8_t *)buf)[4] << 8) | + (((const uint8_t *)buf)[5] << 16) | + (((const uint8_t *)buf)[6] << 24); + break; + + case LIBUSB_SS_USB_DEVICE_CAPABILITY: + if (ptr->ss_usb_cap != NULL) + break; + if (dlen < LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE) + break; + + ptr->ss_usb_cap = ss_cap; + + ss_cap->bLength = LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE; + ss_cap->bDescriptorType = dtype; + ss_cap->bDevCapabilityType = ((const uint8_t *)buf)[2]; + ss_cap->bmAttributes = ((const uint8_t *)buf)[3]; + ss_cap->wSpeedSupported = ((const uint8_t *)buf)[4] | + (((const uint8_t *)buf)[5] << 8); + ss_cap->bFunctionalitySupport = ((const uint8_t *)buf)[6]; + ss_cap->bU1DevExitLat = ((const uint8_t *)buf)[7]; + ss_cap->wU2DevExitLat = ((const uint8_t *)buf)[8] | + (((const uint8_t *)buf)[9] << 8); + break; + + default: + break; + } + } + + buf = ((const uint8_t *)buf) + dlen; + len -= dlen; + } + if (ptr != NULL) + return (0); /* success */ + + return (LIBUSB_ERROR_IO); +} + +void +libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) +{ + if (bos == NULL) + return; + + free(bos); +} diff --git a/lib/libusb/libusb20_desc.c b/lib/libusb/libusb20_desc.c index 5ee61b2..0781067 100644 --- a/lib/libusb/libusb20_desc.c +++ b/lib/libusb/libusb20_desc.c @@ -41,6 +41,10 @@ LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC); LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC); LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC); LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP); +LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_ENDPT_COMP_DESC); +LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_USB_20_DEVCAP_DESC); +LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_USB_DEVCAP_DESC); +LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_BOS_DESCRIPTOR); /*------------------------------------------------------------------------* * libusb20_parse_config_desc diff --git a/lib/libusb/libusb20_desc.h b/lib/libusb/libusb20_desc.h index e5e7c94..a069ee9 100644 --- a/lib/libusb/libusb20_desc.h +++ b/lib/libusb/libusb20_desc.h @@ -264,6 +264,43 @@ LIBUSB20_MAKE_STRUCT(LIBUSB20_CONFIG_DESC); LIBUSB20_MAKE_STRUCT(LIBUSB20_CONTROL_SETUP); +#define LIBUSB20_SS_ENDPT_COMP_DESC(m,n) \ + m(n, UINT8_T, bLength, ) \ + m(n, UINT8_T, bDescriptorType, ) \ + m(n, UINT8_T, bMaxBurst, ) \ + m(n, UINT8_T, bmAttributes, ) \ + m(n, UINT16_T, wBytesPerInterval, ) \ + +LIBUSB20_MAKE_STRUCT(LIBUSB20_SS_ENDPT_COMP_DESC); + +#define LIBUSB20_USB_20_DEVCAP_DESC(m,n) \ + m(n, UINT8_T, bLength, ) \ + m(n, UINT8_T, bDescriptorType, ) \ + m(n, UINT8_T, bDevCapabilityType, ) \ + m(n, UINT32_T, bmAttributes, ) \ + +LIBUSB20_MAKE_STRUCT(LIBUSB20_USB_20_DEVCAP_DESC); + +#define LIBUSB20_SS_USB_DEVCAP_DESC(m,n) \ + m(n, UINT8_T, bLength, ) \ + m(n, UINT8_T, bDescriptorType, ) \ + m(n, UINT8_T, bDevCapabilityType, ) \ + m(n, UINT8_T, bmAttributes, ) \ + m(n, UINT16_T, wSpeedSupported, ) \ + m(n, UINT8_T, bFunctionalitySupport, ) \ + m(n, UINT8_T, bU1DevExitLat, ) \ + m(n, UINT16_T, wU2DevExitLat, ) \ + +LIBUSB20_MAKE_STRUCT(LIBUSB20_SS_USB_DEVCAP_DESC); + +#define LIBUSB20_BOS_DESCRIPTOR(m,n) \ + m(n, UINT8_T, bLength, ) \ + m(n, UINT8_T, bDescriptorType, ) \ + m(n, UINT16_T, wTotalLength, ) \ + m(n, UINT8_T, bNumDeviceCapabilities, ) \ + +LIBUSB20_MAKE_STRUCT(LIBUSB20_BOS_DESCRIPTOR); + /* standard USB stuff */ /** \ingroup desc @@ -333,6 +370,24 @@ enum libusb20_descriptor_type { /** Hub descriptor */ LIBUSB20_DT_HUB = 0x29, + + /** Binary Object Store, BOS */ + LIBUSB20_DT_BOS = 0x0f, + + /** Device Capability */ + LIBUSB20_DT_DEVICE_CAPABILITY = 0x10, + + /** SuperSpeed endpoint companion */ + LIBUSB20_DT_SS_ENDPOINT_COMPANION = 0x30, +}; + +/** \ingroup desc + * Device capability types as defined by the USB specification. */ +enum libusb20_device_capability_type { + LIBUSB20_WIRELESS_USB_DEVICE_CAPABILITY = 0x1, + LIBUSB20_USB_2_0_EXTENSION_DEVICE_CAPABILITY = 0x2, + LIBUSB20_SS_USB_DEVICE_CAPABILITY = 0x3, + LIBUSB20_CONTAINER_ID_DEVICE_CAPABILITY = 0x4, }; /* Descriptor sizes per descriptor type */ @@ -342,6 +397,10 @@ enum libusb20_descriptor_type { #define LIBUSB20_DT_ENDPOINT_SIZE 7 #define LIBUSB20_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ #define LIBUSB20_DT_HUB_NONVAR_SIZE 7 +#define LIBUSB20_DT_SS_ENDPOINT_COMPANION_SIZE 6 +#define LIBUSB20_DT_BOS_SIZE 5 +#define LIBUSB20_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE 7 +#define LIBUSB20_SS_USB_DEVICE_CAPABILITY_SIZE 10 #define LIBUSB20_ENDPOINT_ADDRESS_MASK 0x0f /* in bEndpointAddress */ #define LIBUSB20_ENDPOINT_DIR_MASK 0x80 diff --git a/lib/msun/src/math.h b/lib/msun/src/math.h index 69b138e..9389dda 100644 --- a/lib/msun/src/math.h +++ b/lib/msun/src/math.h @@ -395,32 +395,32 @@ float significandf(float); * long double versions of ISO/POSIX math functions */ #if __ISO_C_VISIBLE >= 1999 -#if 0 +#if _DECLARE_C99_LDBL_MATH long double acoshl(long double); #endif long double acosl(long double); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double asinhl(long double); #endif long double asinl(long double); long double atan2l(long double, long double); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double atanhl(long double); #endif long double atanl(long double); long double cbrtl(long double); long double ceill(long double); long double copysignl(long double, long double) __pure2; -#if 0 +#if _DECLARE_C99_LDBL_MATH long double coshl(long double); #endif long double cosl(long double); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double erfcl(long double); long double erfl(long double); #endif long double exp2l(long double); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double expl(long double); long double expm1l(long double); #endif @@ -435,18 +435,18 @@ long double frexpl(long double value, int *); /* fundamentally !__pure2 */ long double hypotl(long double, long double); int ilogbl(long double) __pure2; long double ldexpl(long double, int); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double lgammal(long double); #endif long long llrintl(long double); long long llroundl(long double); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double log10l(long double); long double log1pl(long double); long double log2l(long double); #endif long double logbl(long double); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double logl(long double); #endif long lrintl(long double); @@ -458,7 +458,7 @@ long double nextafterl(long double, long double); double nexttoward(double, long double); float nexttowardf(float, long double); long double nexttowardl(long double, long double); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double powl(long double, long double); #endif long double remainderl(long double, long double); @@ -467,16 +467,16 @@ long double rintl(long double); long double roundl(long double); long double scalblnl(long double, long); long double scalbnl(long double, int); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double sinhl(long double); #endif long double sinl(long double); long double sqrtl(long double); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double tanhl(long double); #endif long double tanl(long double); -#if 0 +#if _DECLARE_C99_LDBL_MATH long double tgammal(long double); #endif long double truncl(long double); |