From efcbafce648f89687f6a68e8fb7a0a0dc1135f6a Mon Sep 17 00:00:00 2001 From: pluknet Date: Thu, 27 Oct 2011 13:17:42 +0000 Subject: Fix the manual section number for a cross-reference to open(2) and sort it. Reviewed by: ed MFC after: 3 days --- lib/libc/gen/getutxent.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index d25aacf..1fe64f1 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -386,10 +386,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: -- cgit v1.1 From cb65a7fe02e5f4f60980f6634bbc5aabffa4e33b Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 27 Oct 2011 17:05:18 +0000 Subject: Make our utmpx more like System V. When booting the system, truncate the utx.active file, but do write the BOOT_TIME record into it afterwards. This allows one to obtain the boot time of the system as follows: struct utmpx u1 = { .ut_type = BOOT_TIME }, *u2; setutxent(); u2 = getutxid(&u1); Now, the boot time is stored in u2->ut_tv, just like on Linux and other systems. We don't open the utx.active file with O_EXLOCK. It's rather unlikely that other applications use this database at the same time and I want to prevent the possibility of deadlocks in init(8). Discussed with: pluknet --- lib/libc/gen/getutxent.3 | 3 +-- lib/libc/gen/pututxline.c | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index 1fe64f1..f3d7e73 100644 --- a/lib/libc/gen/getutxent.3 +++ b/lib/libc/gen/getutxent.3 @@ -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 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: -- cgit v1.1 From 52ba57ec045a334ed9d919584faa5986771b11da Mon Sep 17 00:00:00 2001 From: ed Date: Thu, 27 Oct 2011 17:21:41 +0000 Subject: Don't forget to kick the man page date. --- lib/libc/gen/getutxent.3 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 index f3d7e73..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 -- cgit v1.1 From d5bbfd2b4a596efac124921b8eb84c0e9294fac1 Mon Sep 17 00:00:00 2001 From: kib Date: Wed, 2 Nov 2011 18:06:22 +0000 Subject: Make sure that stack is 16-byte aligned before calling a function, as it is required by amd64 ABI. Add a comment for the places were the stack is accidentally properly aligned already. PR: amd64/162214 Submitted by: yamayan MFC after: 1 week --- lib/libc/amd64/gen/setjmp.S | 3 +++ lib/libc/amd64/gen/sigsetjmp.S | 3 +++ 2 files changed, 6 insertions(+) (limited to 'lib') 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 -- cgit v1.1 From ca71676fe9906efdc910094ed5d53e6b06845789 Mon Sep 17 00:00:00 2001 From: kib Date: Wed, 2 Nov 2011 18:08:30 +0000 Subject: Despite official i386 ABI does not mandate any stack alignment besides the word alignment, some versions of gcc do require 16-byte alignment. Make sure the stack is 16-byte aligned before calling a subroutine. Inspired by: PR amd64/162214 MFC after: 1 week --- lib/libc/i386/gen/setjmp.S | 14 ++++++++++++++ lib/libc/i386/gen/sigsetjmp.S | 14 ++++++++++++++ 2 files changed, 28 insertions(+) (limited to 'lib') 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 -- cgit v1.1 From 53ee6626a3766f4f999d1db733fa9b48af5774d2 Mon Sep 17 00:00:00 2001 From: des Date: Wed, 2 Nov 2011 23:40:21 +0000 Subject: Note that pam_unix(8) does not respect PAM_CHANGE_EXPIRED_AUTHTOK. --- lib/libpam/modules/pam_unix/pam_unix.8 | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'lib') 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. -- cgit v1.1 From 78c075174e74e727279365476d0d076d6c3e3075 Mon Sep 17 00:00:00 2001 From: jhb Date: Fri, 4 Nov 2011 04:02:50 +0000 Subject: Add the posix_fadvise(2) system call. It is somewhat similar to madvise(2) except that it operates on a file descriptor instead of a memory region. It is currently only supported on regular files. Just as with madvise(2), the advice given to posix_fadvise(2) can be divided into two types. The first type provide hints about data access patterns and are used in the file read and write routines to modify the I/O flags passed down to VOP_READ() and VOP_WRITE(). These modes are thus filesystem independent. Note that to ease implementation (and since this API is only advisory anyway), only a single non-normal range is allowed per file descriptor. The second type of hints are used to hint to the OS that data will or will not be used. These hints are implemented via a new VOP_ADVISE(). A default implementation is provided which does nothing for the WILLNEED request and attempts to move any clean pages to the cache page queue for the DONTNEED request. This latter case required two other changes. First, a new V_CLEANONLY flag was added to vinvalbuf(). This requests vinvalbuf() to only flush clean buffers for the vnode from the buffer cache and to not remove any backing pages from the vnode. This is used to ensure clean pages are not wired into the buffer cache before attempting to move them to the cache page queue. The second change adds a new vm_object_page_cache() method. This method is somewhat similar to vm_object_page_remove() except that instead of freeing each page in the specified range, it attempts to move clean pages to the cache queue if possible. To preserve the ABI of struct file, the f_cdevpriv pointer is now reused in a union to point to the currently active advice region if one is present for regular files. Reviewed by: jilles, kib, arch@ Approved by: re (kib) MFC after: 1 month --- lib/libc/sys/Makefile.inc | 3 +- lib/libc/sys/Symbol.map | 4 ++ lib/libc/sys/madvise.2 | 3 +- lib/libc/sys/posix_fadvise.2 | 139 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 lib/libc/sys/posix_fadvise.2 (limited to 'lib') diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index fe5061d..6da6a00 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -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 diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index 095751a..d0c0c94 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -378,6 +378,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/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 . -- cgit v1.1 From 71aa39a47b82d48a9255b29a05fc250c40f4ed51 Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 4 Nov 2011 19:56:34 +0000 Subject: Fix a warning emitted by Clang. The size passed to strlcat() must depend on the input length, not the output length. Because the input and output buffers are equal in size, the resulting binary does not change at all. --- lib/libc/stdlib/realpath.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') 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); -- cgit v1.1 From e59eeb86a40a0b2b97663ebadb8b42fd9b01a724 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 5 Nov 2011 10:00:29 +0000 Subject: Remove an unused variable from pam_unix. This variable was added in r82352 back in 2001, but even then it didn't have any use. Because it's not marked static, the C compiler won't complain about it. Discussed with: des --- lib/libpam/modules/pam_unix/pam_unix.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') 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 */ -- cgit v1.1 From 897775d6ee89e54e447e35fd09436a65a620307d Mon Sep 17 00:00:00 2001 From: dim Date: Sun, 6 Nov 2011 14:07:23 +0000 Subject: When one attempts to compile the tree with -march=i386, which also used to be gcc's default before r198344, calls to atomic builtins will not be expanded inline. Instead, they will be generated as calls to external functions (e.g. __sync_fetch_and_add_N), leading to linking errors later on. Put in a seatbelt that disables use of atomic builtins in libstdc++ and llvm, when tuning specifically for the real i386 CPU. This does not protect against all possible issues, but it is better than nothing. --- lib/clang/include/llvm/Config/config.h | 2 ++ lib/clang/include/llvm/Config/llvm-config.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/clang/include/llvm/Config/config.h b/lib/clang/include/llvm/Config/config.h index 5b6761c..5ecb51c 100644 --- a/lib/clang/include/llvm/Config/config.h +++ b/lib/clang/include/llvm/Config/config.h @@ -552,7 +552,9 @@ /* #undef LLVM_ETCDIR */ /* Has gcc/MSVC atomic intrinsics */ +#ifndef __tune_i386__ #define LLVM_HAS_ATOMICS 1 +#endif /* 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..28837f7 100644 --- a/lib/clang/include/llvm/Config/llvm-config.h +++ b/lib/clang/include/llvm/Config/llvm-config.h @@ -34,7 +34,9 @@ /* #undef LLVM_ETCDIR */ /* Has gcc/MSVC atomic intrinsics */ +#ifndef __tune_i386__ #define LLVM_HAS_ATOMICS 1 +#endif /* Host triple we were built on */ /* #undef LLVM_HOSTTRIPLE */ -- cgit v1.1 From 518d5f51525d8e01b4befcc3f659020f16f76d4c Mon Sep 17 00:00:00 2001 From: ed Date: Mon, 7 Nov 2011 19:57:42 +0000 Subject: Ensure pam_lastlog removes the /dev/ component of the TTY name. Some consumers of PAM remove the /dev/ component (i.e. login), while others don't (i.e. su). We must ensure that the /dev/ component is removed to ensure that the utmpx entries properly work with tools such as w(1). Discussed with: des MFC after: 1 week --- lib/libpam/modules/pam_lastlog/pam_lastlog.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') 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 + +#include #include #include #include @@ -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) { -- cgit v1.1 From efcd317363664307ce1b8bfa274aa09e83b9ce79 Mon Sep 17 00:00:00 2001 From: hselasky Date: Wed, 9 Nov 2011 19:03:26 +0000 Subject: Add definition of some USB 3.0 descriptors to libusb 1.0 and libusb 2.0. Some header file parts of this patch were taken from a patch submitted by Maya Erez to the LibUSB developers list. MFC after: 1 week --- lib/libusb/Makefile | 4 ++ lib/libusb/libusb.3 | 36 +++++++++- lib/libusb/libusb.h | 59 ++++++++++++++++ lib/libusb/libusb10_desc.c | 173 ++++++++++++++++++++++++++++++++++++++++++++- lib/libusb/libusb20_desc.c | 4 ++ lib/libusb/libusb20_desc.h | 59 ++++++++++++++++ 6 files changed, 332 insertions(+), 3 deletions(-) (limited to 'lib') 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 -- cgit v1.1 From 38e063bea11d59412a237764c4bbd2ea94e306d3 Mon Sep 17 00:00:00 2001 From: kevlo Date: Thu, 10 Nov 2011 01:44:05 +0000 Subject: - Don't handle out-of-memory condition - Fix types of function arguments match their declaration Reviewed by: delphij Obtained from: NetBSD --- lib/libc/regex/regcomp.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c index 39ae1d4..80f9e97 100644 --- a/lib/libc/regex/regcomp.c +++ b/lib/libc/regex/regcomp.c @@ -109,7 +109,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,11 +285,11 @@ 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, wint_t stop); */ static void p_ere(struct parse *p, - int stop) /* character this ERE should end at */ + wint_t stop) /* character this ERE should end at */ { char c; sopno prevback; @@ -493,8 +493,8 @@ p_str(struct parse *p) /* - p_bre - BRE parser top level, anchoring and concatenation - == static void p_bre(struct parse *p, int end1, \ - == int end2); + == static void p_bre(struct parse *p, wint_t end1, \ + == wint_t end2); * Giving end1 as OUT essentially eliminates the end1/end2 check. * * This implementation is a bit of a kludge, in that a trailing $ is first @@ -503,8 +503,8 @@ p_str(struct parse *p) */ static void p_bre(struct parse *p, - int end1, /* first terminating character */ - int end2) /* second terminating character */ + wint_t end1, /* first terminating character */ + wint_t end2) /* second terminating character */ { sopno start = HERE(); int first = 1; /* first subexpression? */ @@ -840,7 +840,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 +859,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 +894,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 +910,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 +939,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 +1246,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 +1274,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 +1334,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; } /* -- cgit v1.1 From 29c48cd31f36cdf5ee8977e51331da624725b1fe Mon Sep 17 00:00:00 2001 From: dougb Date: Thu, 10 Nov 2011 06:20:18 +0000 Subject: Document that flock can return ENOLCK --- lib/libc/sys/flock.2 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') 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 , -- cgit v1.1 From 85b2830346b20c323d2332a339c06ffca315b1b0 Mon Sep 17 00:00:00 2001 From: kevlo Date: Fri, 11 Nov 2011 01:35:07 +0000 Subject: Converting int to wint_t leads to broekn comparison of raw char and encoded wint_t. Spotted by: ache --- lib/libc/regex/regcomp.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c index 80f9e97..2e9adeb 100644 --- a/lib/libc/regex/regcomp.c +++ b/lib/libc/regex/regcomp.c @@ -81,10 +81,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); @@ -285,11 +285,11 @@ regcomp(regex_t * __restrict preg, /* - p_ere - ERE parser top level, concatenation and alternation - == static void p_ere(struct parse *p, wint_t stop); + == static void p_ere(struct parse *p, int_t stop); */ static void p_ere(struct parse *p, - wint_t stop) /* character this ERE should end at */ + int stop) /* character this ERE should end at */ { char c; sopno prevback; @@ -493,8 +493,8 @@ p_str(struct parse *p) /* - p_bre - BRE parser top level, anchoring and concatenation - == static void p_bre(struct parse *p, wint_t end1, \ - == wint_t end2); + == static void p_bre(struct parse *p, int end1, \ + == int end2); * Giving end1 as OUT essentially eliminates the end1/end2 check. * * This implementation is a bit of a kludge, in that a trailing $ is first @@ -503,8 +503,8 @@ p_str(struct parse *p) */ static void p_bre(struct parse *p, - wint_t end1, /* first terminating character */ - wint_t end2) /* second terminating character */ + int end1, /* first terminating character */ + int end2) /* second terminating character */ { sopno start = HERE(); int first = 1; /* first subexpression? */ -- cgit v1.1 From cc75dec446313f522fc9482a85f2c0e9f1f6111f Mon Sep 17 00:00:00 2001 From: theraven Date: Sat, 12 Nov 2011 19:55:48 +0000 Subject: Expose the unimplemented libm functions in the math.h header. This allows C++'s to work without the compiler complaining that the C++ versions are calling implicitly-declared functions. You will still get a linker error when they are called. OpenBSD 5.0 claims to fully implement the C99 stuff, so might be worth investigating... Reviewed by: das Approved by: dim (mentor) --- lib/msun/src/math.h | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'lib') 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); -- cgit v1.1 From 811ac31232079011eb075d71c050b66c4f39f3bc Mon Sep 17 00:00:00 2001 From: das Date: Tue, 15 Nov 2011 05:45:46 +0000 Subject: Sync the style, comments, and variable names of arc4random.c with OpenBSD's version (r1.22). While some of our style changes were indeed small improvements, being able to easily track functionality changes in OpenBSD seems more useful. Also fix style bugs in the FreeBSD-specific parts of this file. No functional changes, as verified with md5. --- lib/libc/gen/arc4random.c | 72 ++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 39 deletions(-) (limited to 'lib') diff --git a/lib/libc/gen/arc4random.c b/lib/libc/gen/arc4random.c index 56dfba9..02f7814 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 * Copyright (c) 2008, Damien Miller @@ -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. */ @@ -46,6 +43,12 @@ __FBSDID("$FreeBSD$"); #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,14 +58,14 @@ 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); \ @@ -107,11 +110,11 @@ 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; fd = _open(RANDOMDEV, O_RDONLY, 0); @@ -120,7 +123,7 @@ arc4_stir(void) if (_read(fd, &rdat, KEYSIZE) == KEYSIZE) done = 1; (void)_close(fd); - } + } if (!done) { (void)gettimeofday(&rdat.tv, NULL); rdat.pid = getpid(); @@ -130,14 +133,11 @@ 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; } @@ -152,7 +152,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,13 +159,11 @@ 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); + return val; } static void @@ -190,51 +187,48 @@ arc4_check_stir(void) void arc4random_stir(void) { - THREAD_LOCK(); + _ARC4_LOCK(); arc4_check_init(); arc4_stir(); rs_stired = 1; - THREAD_UNLOCK(); + _ARC4_UNLOCK(); } void arc4random_addrandom(u_char *dat, int datlen) { - THREAD_LOCK(); + _ARC4_LOCK(); arc4_check_init(); arc4_check_stir(); arc4_addrandom(dat, datlen); - THREAD_UNLOCK(); + _ARC4_UNLOCK(); } u_int32_t arc4random(void) { - u_int32_t rnd; - - THREAD_LOCK(); + u_int32_t val; + _ARC4_LOCK(); arc4_check_init(); arc4_check_stir(); - rnd = arc4_getword(); + val = arc4_getword(); arc4_count -= 4; - THREAD_UNLOCK(); - - return (rnd); + _ARC4_UNLOCK(); + return val; } void arc4random_buf(void *_buf, size_t n) { u_char *buf = (u_char *)_buf; - - THREAD_LOCK(); + _ARC4_LOCK(); arc4_check_init(); while (n--) { arc4_check_stir(); buf[n] = arc4_getbyte(); arc4_count--; } - THREAD_UNLOCK(); + _ARC4_UNLOCK(); } /* @@ -253,7 +247,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 +273,7 @@ arc4random_uniform(u_int32_t upper_bound) break; } - return (r % upper_bound); + return r % upper_bound; } #if 0 -- cgit v1.1 From 81be7970658c5dedb97dc160f013e884b8ebda1e Mon Sep 17 00:00:00 2001 From: das Date: Tue, 15 Nov 2011 05:49:24 +0000 Subject: Further reduce diffs with OpenBSD's arc4random. The main functional change here is to ensure that when a process forks after arc4random is seeded, the parent and child don't observe the same random sequence. OpenBSD's fix introduces some additional overhead in the form of a getpid() call. This could be improved upon, e.g., by setting a flag in fork(), if it proves to be a problem. This was discussed with secteam (simon, csjp, rwatson) in 2008, shortly prior to my going out of town and forgetting all about it. The conclusion was that the problem with forks is worrisome, but it doesn't appear to have introduced an actual vulnerability for any known programs. The only significant remaining difference between our arc4random and OpenBSD's is in how we seed the generator in arc4_stir(). --- lib/libc/gen/arc4random.c | 63 ++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 33 deletions(-) (limited to 'lib') diff --git a/lib/libc/gen/arc4random.c b/lib/libc/gen/arc4random.c index 02f7814..a2b235f 100644 --- a/lib/libc/gen/arc4random.c +++ b/lib/libc/gen/arc4random.c @@ -33,11 +33,13 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" -#include -#include -#include #include +#include +#include #include +#include +#include +#include #include #include "libc_private.h" @@ -71,9 +73,9 @@ static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; _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); @@ -117,6 +119,10 @@ arc4_stir(void) u_char rnd[KEYSIZE]; } rdat; + if (!rs_initialized) { + arc4_init(); + rs_initialized = 1; + } fd = _open(RANDOMDEV, O_RDONLY, 0); done = 0; if (fd >= 0) { @@ -141,6 +147,18 @@ arc4_stir(void) 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) { @@ -166,31 +184,11 @@ arc4_getword(void) 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; - } -} - void arc4random_stir(void) { _ARC4_LOCK(); - arc4_check_init(); arc4_stir(); - rs_stired = 1; _ARC4_UNLOCK(); } @@ -198,8 +196,8 @@ void arc4random_addrandom(u_char *dat, int datlen) { _ARC4_LOCK(); - arc4_check_init(); - arc4_check_stir(); + if (!rs_initialized) + arc4_stir(); arc4_addrandom(dat, datlen); _ARC4_UNLOCK(); } @@ -209,10 +207,9 @@ arc4random(void) { u_int32_t val; _ARC4_LOCK(); - arc4_check_init(); - arc4_check_stir(); - val = arc4_getword(); arc4_count -= 4; + arc4_stir_if_needed(); + val = arc4_getword(); _ARC4_UNLOCK(); return val; } @@ -222,11 +219,11 @@ arc4random_buf(void *_buf, size_t n) { u_char *buf = (u_char *)_buf; _ARC4_LOCK(); - arc4_check_init(); + arc4_stir_if_needed(); while (n--) { - arc4_check_stir(); + if (--arc4_count <= 0) + arc4_stir(); buf[n] = arc4_getbyte(); - arc4_count--; } _ARC4_UNLOCK(); } -- cgit v1.1 From d0004038aeb73555b710af5a77e4b38d74a757e8 Mon Sep 17 00:00:00 2001 From: davidxu Date: Thu, 17 Nov 2011 01:43:50 +0000 Subject: Pass CVWAIT flags to kernel, this should handle timeout correctly for pthread_cond_timedwait when it uses kernel-based condition variable. PR: 162403 Submitted by: jilles MFC after: 3 days --- lib/libthr/thread/thr_umtx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib') 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)); } -- cgit v1.1 From dbc322caab4934300a1ed835b0dbb1c130c890c6 Mon Sep 17 00:00:00 2001 From: kib Date: Thu, 17 Nov 2011 13:14:07 +0000 Subject: Fix typo. Submitted by: arundel MFC after: 3 days --- lib/libc/sys/stat.2 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') 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 -- cgit v1.1 From 30ab0ebac0bb7587cac9f6328e7060f33a32d69c Mon Sep 17 00:00:00 2001 From: dim Date: Thu, 17 Nov 2011 21:06:53 +0000 Subject: Revert r227538, since it doesn't compile with clang at all (it doesn't allow the built-in operations to be redefined, at least not without excessive force). Instead, just disable LLVM's support for atomic operations for now. Nothing in either clang or the tablegen tools currently depends on it. This still allows users of head built before r198344 to upgrade to top-of-head seamlessly. --- lib/clang/include/llvm/Config/config.h | 4 +--- lib/clang/include/llvm/Config/llvm-config.h | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/lib/clang/include/llvm/Config/config.h b/lib/clang/include/llvm/Config/config.h index 5ecb51c..92c960b 100644 --- a/lib/clang/include/llvm/Config/config.h +++ b/lib/clang/include/llvm/Config/config.h @@ -552,9 +552,7 @@ /* #undef LLVM_ETCDIR */ /* Has gcc/MSVC atomic intrinsics */ -#ifndef __tune_i386__ -#define LLVM_HAS_ATOMICS 1 -#endif +#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 28837f7..1b50ab8 100644 --- a/lib/clang/include/llvm/Config/llvm-config.h +++ b/lib/clang/include/llvm/Config/llvm-config.h @@ -34,9 +34,7 @@ /* #undef LLVM_ETCDIR */ /* Has gcc/MSVC atomic intrinsics */ -#ifndef __tune_i386__ -#define LLVM_HAS_ATOMICS 1 -#endif +#define LLVM_HAS_ATOMICS 0 /* Host triple we were built on */ /* #undef LLVM_HOSTTRIPLE */ -- cgit v1.1 From 1a26b28a9b13239c0dcae74ac1f94a5969fd2b3c Mon Sep 17 00:00:00 2001 From: kevlo Date: Fri, 18 Nov 2011 03:05:20 +0000 Subject: Add unicode support to msdosfs and smbfs; original pathes from imura, bug fixes by Kuan-Chung Chiu . Tested by me in production for several days at work. --- lib/libkiconv/xlat16_iconv.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'lib') 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); -- cgit v1.1 From 1d7264c97b79c6f87b505407a3979c17f93ca9f1 Mon Sep 17 00:00:00 2001 From: kib Date: Fri, 18 Nov 2011 09:56:40 +0000 Subject: Free unused allocation on error. Reported by: slonoman2011 yandex ru MFC after: 1 week --- lib/librt/timer.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib') 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); } -- cgit v1.1 From 0f6ef690b3118882121ed67561c7ce2660cfebe1 Mon Sep 17 00:00:00 2001 From: theraven Date: Sun, 20 Nov 2011 14:45:42 +0000 Subject: Implement xlocale APIs from Darwin, mainly for use by libc++. This adds a load of _l suffixed versions of various standard library functions that use the global locale, making them take an explicit locale parameter. Also adds support for per-thread locales. This work was funded by the FreeBSD Foundation. Please test any code you have that uses the C standard locale functions! Reviewed by: das (gdtoa changes) Approved by: dim (mentor) --- lib/libc/gdtoa/machdep_ldisQ.c | 9 +- lib/libc/gdtoa/machdep_ldisd.c | 10 +- lib/libc/gdtoa/machdep_ldisx.c | 10 +- lib/libc/gen/fnmatch.c | 13 +- lib/libc/gen/glob.c | 13 +- lib/libc/locale/DESIGN.xlocale | 159 ++++++++++++++++++ lib/libc/locale/Makefile.inc | 9 +- lib/libc/locale/Symbol.map | 95 +++++++++++ lib/libc/locale/ascii.c | 23 ++- lib/libc/locale/big5.c | 19 ++- lib/libc/locale/btowc.c | 15 +- lib/libc/locale/collate.c | 92 ++++++++--- lib/libc/locale/collate.h | 28 +++- lib/libc/locale/collcmp.c | 12 +- lib/libc/locale/ctype.c | 33 ++++ lib/libc/locale/duplocale.3 | 78 +++++++++ lib/libc/locale/euc.c | 19 ++- lib/libc/locale/freelocale.3 | 61 +++++++ lib/libc/locale/gb18030.c | 21 ++- lib/libc/locale/gb2312.c | 21 ++- lib/libc/locale/gbk.c | 19 ++- lib/libc/locale/lmessages.c | 65 ++++++-- lib/libc/locale/lmessages.h | 9 +- lib/libc/locale/lmonetary.c | 73 ++++++--- lib/libc/locale/lmonetary.h | 13 +- lib/libc/locale/lnumeric.c | 68 ++++++-- lib/libc/locale/lnumeric.h | 13 +- lib/libc/locale/localeconv.3 | 15 ++ lib/libc/locale/localeconv.c | 37 +++-- lib/libc/locale/mblen.c | 19 ++- lib/libc/locale/mblocal.h | 57 ++++--- lib/libc/locale/mbrlen.c | 20 ++- lib/libc/locale/mbrtowc.c | 21 ++- lib/libc/locale/mbsinit.c | 14 +- lib/libc/locale/mbsnrtowcs.c | 25 ++- lib/libc/locale/mbsrtowcs.c | 20 ++- lib/libc/locale/mbstowcs.c | 15 +- lib/libc/locale/mbtowc.c | 18 +- lib/libc/locale/mskanji.c | 19 ++- lib/libc/locale/newlocale.3 | 109 +++++++++++++ lib/libc/locale/nextwctype.c | 19 ++- lib/libc/locale/nl_langinfo.c | 72 ++++---- lib/libc/locale/none.c | 46 +++++- lib/libc/locale/querylocale.3 | 57 +++++++ lib/libc/locale/runetype.c | 27 ++- lib/libc/locale/setlocale.c | 5 +- lib/libc/locale/setrunelocale.c | 155 ++++++++---------- lib/libc/locale/table.c | 18 +- lib/libc/locale/tolower.c | 19 ++- lib/libc/locale/toupper.c | 21 ++- lib/libc/locale/uselocale.3 | 59 +++++++ lib/libc/locale/utf8.c | 23 ++- lib/libc/locale/wcrtomb.c | 21 ++- lib/libc/locale/wcsftime.c | 26 ++- lib/libc/locale/wcsnrtombs.c | 28 +++- lib/libc/locale/wcsrtombs.c | 21 ++- lib/libc/locale/wcstod.c | 37 ++++- lib/libc/locale/wcstof.c | 23 ++- lib/libc/locale/wcstoimax.c | 23 ++- lib/libc/locale/wcstol.c | 21 ++- lib/libc/locale/wcstold.c | 36 +++- lib/libc/locale/wcstoll.c | 21 ++- lib/libc/locale/wcstombs.c | 17 +- lib/libc/locale/wcstoul.c | 21 ++- lib/libc/locale/wcstoull.c | 23 ++- lib/libc/locale/wcstoumax.c | 23 ++- lib/libc/locale/wctob.c | 15 +- lib/libc/locale/wctomb.c | 18 +- lib/libc/locale/wctrans.c | 31 +++- lib/libc/locale/wctype.c | 24 ++- lib/libc/locale/wcwidth.c | 13 +- lib/libc/locale/xlocale.3 | 270 ++++++++++++++++++++++++++++++ lib/libc/locale/xlocale.c | 334 ++++++++++++++++++++++++++++++++++++++ lib/libc/locale/xlocale_private.h | 198 ++++++++++++++++++++++ lib/libc/regex/regcomp.c | 20 ++- lib/libc/stdio/Symbol.map | 40 +++++ lib/libc/stdio/asprintf.c | 18 ++ lib/libc/stdio/fgetwc.c | 21 ++- lib/libc/stdio/fgetwln.c | 16 +- lib/libc/stdio/fgetws.c | 18 +- lib/libc/stdio/fprintf.c | 20 ++- lib/libc/stdio/fputwc.c | 20 ++- lib/libc/stdio/fputws.c | 17 +- lib/libc/stdio/fscanf.c | 22 ++- lib/libc/stdio/fwprintf.c | 18 ++ lib/libc/stdio/fwscanf.c | 18 ++ lib/libc/stdio/getwc.c | 12 ++ lib/libc/stdio/getwchar.c | 12 +- lib/libc/stdio/local.h | 20 ++- lib/libc/stdio/printf.c | 17 ++ lib/libc/stdio/printfcommon.h | 24 ++- lib/libc/stdio/putwc.c | 15 +- lib/libc/stdio/putwchar.c | 15 +- lib/libc/stdio/scanf.c | 22 ++- lib/libc/stdio/snprintf.c | 33 +++- lib/libc/stdio/sprintf.c | 19 +++ lib/libc/stdio/sscanf.c | 18 ++ lib/libc/stdio/swprintf.c | 19 +++ lib/libc/stdio/swscanf.c | 19 +++ lib/libc/stdio/ungetwc.c | 21 ++- lib/libc/stdio/vasprintf.c | 16 +- lib/libc/stdio/vdprintf.c | 8 +- lib/libc/stdio/vfprintf.c | 62 ++++--- lib/libc/stdio/vfscanf.c | 51 ++++-- lib/libc/stdio/vfwprintf.c | 80 +++++---- lib/libc/stdio/vfwscanf.c | 88 +++++----- lib/libc/stdio/vprintf.c | 12 +- lib/libc/stdio/vscanf.c | 19 ++- lib/libc/stdio/vsnprintf.c | 19 ++- lib/libc/stdio/vsprintf.c | 17 +- lib/libc/stdio/vsscanf.c | 19 ++- lib/libc/stdio/vswprintf.c | 21 ++- lib/libc/stdio/vswscanf.c | 21 ++- lib/libc/stdio/vwprintf.c | 12 +- lib/libc/stdio/vwscanf.c | 12 +- lib/libc/stdio/wprintf.c | 18 ++ lib/libc/stdio/wscanf.c | 18 ++ lib/libc/stdlib/Symbol.map | 18 ++ lib/libc/stdlib/atof.c | 14 ++ lib/libc/stdlib/atoi.c | 14 ++ lib/libc/stdlib/atol.c | 14 ++ lib/libc/stdlib/atoll.c | 14 ++ lib/libc/stdlib/strfmon.c | 43 ++++- lib/libc/stdlib/strtoimax.c | 17 +- lib/libc/stdlib/strtol.c | 22 ++- lib/libc/stdlib/strtoll.c | 17 +- lib/libc/stdlib/strtoul.c | 16 +- lib/libc/stdlib/strtoull.c | 17 +- lib/libc/stdlib/strtoumax.c | 17 +- lib/libc/stdtime/strftime.c | 62 ++++--- lib/libc/stdtime/strptime.c | 170 +++++++++++-------- lib/libc/stdtime/timelocal.c | 57 +++++-- lib/libc/stdtime/timelocal.h | 8 +- lib/libc/string/Symbol.map | 8 + lib/libc/string/strcasecmp.c | 31 +++- lib/libc/string/strcasestr.c | 20 ++- lib/libc/string/strcoll.c | 31 +++- lib/libc/string/strxfrm.c | 22 ++- lib/libc/string/wcscoll.c | 20 ++- lib/libc/string/wcswidth.c | 16 +- lib/libc/string/wcsxfrm.c | 21 ++- 141 files changed, 4050 insertions(+), 800 deletions(-) create mode 100644 lib/libc/locale/DESIGN.xlocale create mode 100644 lib/libc/locale/ctype.c create mode 100644 lib/libc/locale/duplocale.3 create mode 100644 lib/libc/locale/freelocale.3 create mode 100644 lib/libc/locale/newlocale.3 create mode 100644 lib/libc/locale/querylocale.3 create mode 100644 lib/libc/locale/uselocale.3 create mode 100644 lib/libc/locale/xlocale.3 create mode 100644 lib/libc/locale/xlocale.c create mode 100644 lib/libc/locale/xlocale_private.h (limited to 'lib') 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 * 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 * 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 * 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/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/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/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 #include #include +#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 +#include #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 +#include +#include 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 #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 * 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 #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 * 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 * 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 * 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 * 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 * 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 * 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 +#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 #include #include +#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 * 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 #include #include +#include +#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 #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 #include #include +#include +#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 #include #include +#include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#include #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 +#include +#include #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 " " +.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 +#include +#include +#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 ; typecomponents[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 ; typecomponents[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) + 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 +#include +#include +#include +#include +#include +#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/regex/regcomp.c b/lib/libc/regex/regcomp.c index 2e9adeb..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: @@ -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); } 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 #include +#include 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 #include +#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 #include #include +#include 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 #include #include +#include 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 #include +#include #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 #include +#include #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 #include #include +#include /* * 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 #include +#include 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 #include #include +#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 #include #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 #include #include +#include #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 #include #include +#include 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 #include #include +#include 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 * 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 #include #include +#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 * 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 #include +#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 @@ -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 -#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 +#include 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 #include #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 #include #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 #include #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 * 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 #include #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 #include #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 #include #include +#include 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 #include #include +#include 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 #include #include +#include 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 #include #include +#include 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 +#include 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 +#include 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 +#include 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 +#include 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/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 * 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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 #include #include +#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 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 #include +#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 #include +#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 #include "collate.h" +#include + 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 +#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) -- cgit v1.1 From 4de38879e5e0ffa7986549aa0beda02dce5e3438 Mon Sep 17 00:00:00 2001 From: tuexen Date: Sun, 20 Nov 2011 15:00:45 +0000 Subject: Add support for the SCTP_REMOTE_UDP_ENCAPS_PORT socket option. Retire the the now unused sctp_udp_tunneling_for_client_enable sysctl variable. MFC after: 3 months. --- lib/libc/net/sctp_sys_calls.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') 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; -- cgit v1.1 From bf5f03ca46a93268d5d0eccc7318039bda9106d2 Mon Sep 17 00:00:00 2001 From: des Date: Sun, 20 Nov 2011 15:18:49 +0000 Subject: key_load_private() ignores the passphrase argument if the private key is unencrypted. This defeats the nullok check, because it means a non-null passphrase will successfully unlock the key. To address this, try at first to load the key without a passphrase. If this succeeds and the user provided a non-empty passphrase *or* nullok is false, reject the key. MFC after: 1 week Noticed by: Guy Helmer --- lib/libpam/modules/pam_ssh/pam_ssh.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'lib') 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 -- cgit v1.1 From f05b192013cff01ec4bb794f07f85846cb2915b3 Mon Sep 17 00:00:00 2001 From: nwhitehorn Date: Mon, 21 Nov 2011 00:49:46 +0000 Subject: Connect LLVM/clang to the build on powerpc64. After the binutils 2.17.50 import, it works without issue. --- lib/clang/clang.build.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') 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 -- cgit v1.1 From cca3084242962a9999626670f9251e776ee73876 Mon Sep 17 00:00:00 2001 From: lstewart Date: Mon, 21 Nov 2011 01:26:10 +0000 Subject: - Add the ffclock_getcounter(), ffclock_getestimate() and ffclock_setestimate() system calls to provide feed-forward clock management capabilities to userspace processes. ffclock_getcounter() returns the current value of the kernel's feed-forward clock counter. ffclock_getestimate() returns the current feed-forward clock parameter estimates and ffclock_setestimate() updates the feed-forward clock parameter estimates. - Document the syscalls in the ffclock.2 man page. - Regenerate the script-derived syscall related files. Committed on behalf of Julien Ridoux and Darryl Veitch from the University of Melbourne, Australia, as part of the FreeBSD Foundation funded "Feed-Forward Clock Synchronization Algorithms" project. For more information, see http://www.synclab.org/radclock/ Submitted by: Julien Ridoux (jridoux at unimelb edu au) --- lib/libc/sys/Makefile.inc | 4 +- lib/libc/sys/Symbol.map | 3 + lib/libc/sys/ffclock.2 | 177 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 1 deletion(-) create mode 100644 lib/libc/sys/ffclock.2 (limited to 'lib') diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 6da6a00..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 \ @@ -142,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 d0c0c94..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; 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. -- cgit v1.1 From 244cd44176273126caa7562c679c7bcf6c64be98 Mon Sep 17 00:00:00 2001 From: pluknet Date: Mon, 21 Nov 2011 14:36:19 +0000 Subject: Add history for setsockopt(2). PR: docs/162719 Submitted by: Niclas Zeising MFC after: 1 week --- lib/libc/sys/getsockopt.2 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') 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. -- cgit v1.1 From a2866d9e62ac6a68a8b8eeb0b72d0f7f5f149cde Mon Sep 17 00:00:00 2001 From: des Date: Mon, 21 Nov 2011 16:40:39 +0000 Subject: Simplify the libpam build by removing the shared modules' dependency on the shared library. The modules are loaded by the library, so we know it'll be there when we need it. MFC after: 3 weeks --- lib/libpam/Makefile.inc | 2 ++ lib/libpam/modules/Makefile.inc | 14 +------------- 2 files changed, 3 insertions(+), 13 deletions(-) (limited to 'lib') 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" -- cgit v1.1