9756dfe161
1997-12-22 18:10 Ulrich Drepper <drepper@cygnus.com> * configure.in: Stop with error if --disable-static is used when the shared lib uses this library. * gen-FAQ.pl: I've perl installed in /usr/bin. * include/bits/xopen_lim.h (STREAM_MAX): Define using FOPEN_MAX. Fix Unix98 conformance problems in the headers. * catgets/nl_types.h: Define nl_item. * grp/grp.h: Define gid_t. * include/features.h [_POSIX_C_SOURCE]: Don't define _XOPEN_SOURCE. * include/nl_types.h: New file. * include/ulimit.h: New file. * io/fcntl.h: Include sys/stat.h for Unix98. Don't define locking constants in POSIX mode. * io/utime.h: Get definition for time_t. * io/sys/stat.h: Define dev_t, gid_t, ino_t, mode_t, nlink_t, off_t, uid_t, pid_t. Define D_IFLNK and S_IFSOCK only if !__USE_UNIX98. * libio/stdio.h: Define va_list. Make snprintf also available is __USE_UNIX98. Declare getopt function and variables. * locale/langinfo.h: Include nl_types.h. Don't define nl_item. Define CODESET, CRNCYSTR, RADIXCHAR and THOUSEP as aliases. * math/math.h: Defined M_* constants as double for Unix98 mode. * posix/fnmatch.h: Pretty print. Define FNM_NOSYS. * posix/glob.h: Pretty print. Define GLOB_NOSYS. * posix/regex.h: Define REG_NOSYS. * posix/wordexp.h: Define WRDE_NOSYS. * posix/unistd.h: Define _POSIX2_VERSION. Define _XOPEN_VERSION to 500 for Unix98. * posix/sys/types.h: Alloc dev_t, mode_t, nlink_t to be defined somewhere else as well. Define clock_t for Unix98. * posix/sys/wait.h: Define pid_t. * pwd/pwd.h: Define gid_t, uid_t. * resource/Makefile (headers): Add ulimit.h. * resource/ulimit.h: New file. * sysdeps/generic/ulimit.c: Define according to X/Open using varargs instead of second argument. * sysdeps/unix/bsd/ulimit.c: Likewise. Use UL_* constants. * sysdeps/unix/sysv/linux/ulimit.c: Likewise. * resource/sys/resource.h: Don't declare ulimit here, include ulimit.h. * signal/signal.h: Define pid_t. * string/string.h: Don't declare BSD string functions in POSIX mode. * sysdeps/generic/bits/confname.h: Define _PC_VDISABLE. Add _SC_XOPEN_LEGACY, _SC_XOPEN_REALTIME and _SC_XOPEN_REALTIME_THREADS. * sysdeps/unix/sysv/linux/bits/termios.h: Clean namespace for Unix98 and POSIX. * inet/test_ifindex.c: Change test so that it does not fail for interface aliases. * locale/programs/locale.c (show_info): Use correct cast sequence for 64bit machines. * malloc/malloc.c: __malloc_initialized now signals three states: uninitialized, initializing, initialized. Used in mcheck. * malloc/mcheck.c (mabort): Add '\n' to messages. (mcheck): Allow installation when malloc is uninitialized or is just initializing. * manual/memory.texi: Explain mtrace output a bit more. * math/libm-test.c: Add more epsilons. * misc/regexp.h (compile): Remove __ prefix from parameter names. * nis/nss_nis/nis-ethers.c (internal_nis_getetherent_r): Use strncpy instead of strcpy for security. * nis/nss_nis/nis-proto.c (internal_nis_getprotoent_r): Likewise. * nis/nss_nis/nis-rpc.c (internal_nis_getrpcent_r): Likewise. * nis/nss_nis/nis-service.c (internal_nis_getservent_r): Likewise. * nss/digits_dots.c: Pretty print. * posix/getconf.c (vars): Add symbols for programming environment recognition. Recognize --version. * sysdeps/generic/sysconf.c: Handle _SC_XBS5_*, _SC_XOPEN_LEGACY, _SC_XOPEN_REALTIME, and _SC_XOPEN_REALTIME_THREADS. * sysdeps/posix/sysconf.c: Handle _SC_XBS5_* and new _XOPEN_* symbols. * sysdeps/generic/bits/stdio_lim.h: Implement handling of __need_FOPEN_MAX. * sysdeps/unix/sysv/linux/stdio_lim.h.in: Likewise. * sysdeps/posix/mk-stdiolim.c: Change to generate file handling __need_FOPEN_MAX. * sysdeps/unix/sysv/linux/Dist: Add rt_sigpending.c. * sysdeps/unix/sysv/linux/rt_sigpending.c: New file. * sysdeps/unix/sysv/linux/alpha/bits/types.h: Define __ipc_pid_t. * sysdeps/unix/sysv/linux/bits/types.h: Likewise. * sysdeps/unix/sysv/linux/sparc/sparc64/bits/types.h: Likewise. * sysdeps/unix/sysv/linux/bits/msq.h: Use __ipc_pid_t. * sysdeps/unix/sysv/linux/bits/shm.h: Likewise. * sysdeps/unix/sysv/linux/mips/bits/types.h: New file. * sysdeps/wordsize-32/inttypes.h: Add SCNd8, SCNi8, SCNo8, SCNx8, SCNu*. * sysdeps/wordsize-64/inttypes.h: Likewise. * time/africa: Update from tzdata1997j. * time/antarctica: Likewise. * time/asia: Likewise. * time/australasia: Likewise. * time/backward: Likewise. * time/etcetera: Likewise. * time/europe: Likewise. * time/factory: Likewise. * time/northamerica: Likewise. * time/pacificnew: Likewise. * time/southamerica: Likewise. * time/tzfile.h: Update from tzcode1997h. * time/zic.c: Likewise. * wcsmbs/wchar.h: Get definition of FILE. Define `struct tm' tag. Declare wcwidth and wcswidth for __USE_XOPEN. Declare the isw*() functions for Unix98. * wctype/towctrans.c: Define as __towctrans, make towctrans weak alias. * wctype/wctype.h: Declare isw*() functions also if __need_iswxxx is defined. 1997-12-21 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * locale/duplocale.c: Increase usage_count only if less than MAX_USAGE_COUNT. * locale/freelocale.c: Test usage_count against UNDELETABLE, not MAX_USAGE_COUNT. * locale/setlocale.c: Likewise. 1997-12-20 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * Makefile ($(inst_includedir)/gnu/stubs.h): Use a more direct dependency to make it easier to install it selectively. * Makerules (.SUFFIXES): Don't define any suffixes. 1997-12-20 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sysdeps/generic/fstatfs64.c: Emulate using fstatfs. * sysdeps/generic/statfs64.c: Emulate using statfs. * sysdeps/generic/getrlimit64.c: Emulate using getrlimit. * sysdeps/generic/setrlimit64.c: Emulate using setrlimit. * sysdpes/generic/ftruncate64.c: New file. * sysdpes/generic/truncate64.c: New file. * sysdeps/generic/bits/stat.h: Add LFS support. * sysdeps/generic/bits/statfs.h: Likewise. * sysdeps/unix/bsd/sun/sunos4/bits/resource.h (RLIM_INFINITY) [__USE_FILE_OFFSET64]: Make long long constant. (RLIM64_INFINITY): Likewise. * sysdeps/unix/sysv/linux/bits/resource.h (RLIM_INFINITY): Correct for LFS support. (RLIM64_INFINITY) [__USE_LARGEFILE64]: Define. * sysdeps/generic/bits/resource.h: Likewise. * misc/Makefile (routines): Add truncate64 and ftruncate64. * include/features.h: Don't prevent LFS support from defining BSD and SYSV things. * dirent/dirent.h [__USE_FILE_OFFSET64]: Don't use xxx64 names. * io/ftw.h [__USE_FILE_OFFSET64]: Likewise. * io/sys/stat.h [__USE_FILE_OFFSET64]: Likewise. * sysdeps/unix/sysv/linux/alpha/syscalls.list: Add xxx64 alias for fstatfs, statfs, getrlimit, setrlimit, ftruncate and truncate. * sysdeps/unix/sysv/linux/sparc/sparc64/syscalls.list: Likewise. * sysdeps/unix/sysv/linux/alpha/fstatfs64.c: New file. * sysdeps/unix/sysv/linux/alpha/statfs64.c: New file. * sysdeps/unix/sysv/linux/alpha/getrlimit64.c: New file. * sysdeps/unix/sysv/linux/alpha/setrlimit64.c: New file. * sysdeps/unix/sysv/linux/alpha/ftruncate64.c: New file. * sysdeps/unix/sysv/linux/alpha/truncate64.c: New file. * sysdeps/unix/sysv/linux/alpha/readdir.c: New file. * sysdeps/unix/sysv/linux/alpha/readdir64.c: New file. * sysdeps/unix/sysv/linux/alpha/readdir64_r.c: New file. * sysdeps/unix/sysv/linux/alpha/readdir_r.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/fstatfs64.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/statfs64.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/getrlimit64.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/setrlimit64.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/ftruncate64.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/truncate64.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/readdir.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/readdir64.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/readdir64_r.c: New file. * sysdeps/unix/sysv/linux/sparc/sparc64/readdir_r.c: New file. * sysdeps/unix/sysv/linux/fxstat64.c: New file. * sysdeps/unix/sysv/linux/lxstat64.c: New file. * sysdeps/unix/sysv/linux/xstat64.c: New file. * sysdeps/unix/sysv/linux/readdir64.c: New file. * sysdeps/unix/sysv/linux/readdir64_r.c: New file. * sysdeps/unix/sysv/linux/getdents64.c: New file. * sysdeps/unix/sysv/linux/Makefile (sysdep_routines) [$(subdir)=dirent]: Add getdents64. * sysdeps/unix/sysv/linux/Dist: Add getdents64.c. * sysdeps/unix/sysv/linux/xstatconv.c: LFS support. 1997-12-18 12:07 Philip Blundell <pb@nexus.co.uk> * sysdeps/generic/bits/statfs.h (struct statfs64): Added. * sysdeps/generic/getrlimit.c: Include <sys/types.h>. * sysdeps/generic/getrlimit64.c: Likewise. * sysdeps/generic/setrlimit.c: Likewise. * sysdeps/generic/setrlimit64.c: Likewise. 1997-12-17 13:57 Philip Blundell <pb@nexus.co.uk> * sysdeps/unix/sysv/linux/siglist.c: Fix compile problem if not using versioning. * sysdeps/generic/waitid.c: Include <sys/types.h> for id_t. * sysdeps/standalone/arm/bits/errno.h (EBUSY): Added. 1997-12-16 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * locale/programs/ld-ctype.c (ctype_output): Clear out the padding after the codeset name. 1997-12-16 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * libc.map: Add get_kernel_syms. 1997-12-16 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sysdeps/generic/testrtsig.h (kernel_has_rtsig): Make static. * sysdeps/unix/sysv/linux/testrtsig.h (kernel_has_rtsig): Likewise. Fix condition. 1997-12-16 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * libio/Makefile (routines) [$(versioning)=yes]: Add oldiofdopen. 1997-12-15 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sysdeps/m68k/fpu/bits/mathinline.h: Don't define exp2 inline. Define scalbln{,f,l} under __USE_ISOC9X, not __USE_MISC. 1997-12-15 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sysdeps/unix/sysv/linux/powerpc/syscall.S: Put back. * sysdeps/unix/sysv/linux/powerpc/sigreturn.S: Delete this instead. Oops. 1997-12-16 Andreas Jaeger <aj@arthur.rhein-neckar.de> * configure.in (libc_cv_gcc_alpha_ng_prefix): Correct quoting. 1997-12-16 Andreas Jaeger <aj@arthur.rhein-neckar.de> * math/libm-test.c (catanh_test): Change epsilon. Reported by H.J. Lu. 1997-12-14 19:39 H.J. Lu <hjl@gnu.org> * libc.map (__getpid): Added for linuxthreads. 1997-12-13 21:09 H.J. Lu <hjl@gnu.org> * configure.in (HAVE_DWARF2_UNWIND_INFO_STATIC): Define it if gcc uses static variable in DWARF2 unwind information for exception support. * config.h.in (HAVE_DWARF2_UNWIND_INFO_STATIC): New. * elf/soinit.c (__libc_global_ctors, _fini): Handle HAVE_DWARF2_UNWIND_INFO_STATIC. * libc.map (__register_frame*, __deregister_frame*): Make them global. 1997-12-15 Andreas Jaeger <aj@arthur.rhein-neckar.de> * math/libm-test.c: Add more tests for "normal" values. 1997-12-13 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * stdio-common/printf_fphex.c: Fix printing of long double number with a biased exponent of zero. Fix rounding. 1997-12-13 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sunrpc/rpc_main.c: Accept new flag -$. * sunrpc/Makefile (rpcgen-cmd): Pass it here. 1997-12-13 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * Makefile ($(inst_slibdir)/libc-$(version).so): Install the dynamic linker first, in case the interface has changed. 1997-12-13 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * nss/nss_files/files-alias.c (get_next_alias): Fix parameter order. 1997-12-12 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * math/tgmath.h: Check for double first, for architectures where sizeof (long double) == sizeof (double). 1997-12-07 Andreas Jaeger <aj@arthur.rhein-neckar.de> * math/libm-test.c: New tests for "normal" values added for most functions.
1421 lines
42 KiB
C
1421 lines
42 KiB
C
/* Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
|
|
|
|
The GNU C Library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version.
|
|
|
|
The GNU C Library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
|
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
Boston, MA 02111-1307, USA. */
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include <alloca.h>
|
|
#include <endian.h>
|
|
#include <limits.h>
|
|
#include <string.h>
|
|
|
|
#include "locales.h"
|
|
#include "localeinfo.h"
|
|
#include "langinfo.h"
|
|
#include "locfile-token.h"
|
|
#include "stringtrans.h"
|
|
|
|
/* Uncomment the following line in the production version. */
|
|
/* define NDEBUG 1 */
|
|
#include <assert.h>
|
|
|
|
|
|
void *xmalloc (size_t __n);
|
|
void *xcalloc (size_t __n, size_t __s);
|
|
void *xrealloc (void *__ptr, size_t __n);
|
|
|
|
|
|
/* The bit used for representing a special class. */
|
|
#define BITPOS(class) ((class) - tok_upper)
|
|
#define BIT(class) (1 << BITPOS (class))
|
|
|
|
#define ELEM(ctype, collection, idx, value) \
|
|
*find_idx (ctype, &ctype->collection idx, &ctype->collection##_max idx, \
|
|
&ctype->collection##_act idx, value)
|
|
|
|
#define SWAPU32(w) \
|
|
(((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
|
|
|
|
#define SWAPU16(w) \
|
|
((((w) >> 8) & 0xff) | (((w) & 0xff) << 8))
|
|
|
|
#define XSWAPU32(w) \
|
|
((((w) & 0xff00ff00) >> 8) | (((w) & 0xff00ff) << 8))
|
|
|
|
|
|
/* To be compatible with former implementations we for now restrict
|
|
the number of bits for character classes to 16. When compatibility
|
|
is not necessary anymore increase the number to 32. */
|
|
#define char_class_t u_int16_t
|
|
#define CHAR_CLASS_TRANS SWAPU16
|
|
#define char_class32_t u_int32_t
|
|
#define CHAR_CLASS32_TRANS XSWAPU32
|
|
|
|
|
|
/* The real definition of the struct for the LC_CTYPE locale. */
|
|
struct locale_ctype_t
|
|
{
|
|
unsigned int *charnames;
|
|
size_t charnames_max;
|
|
size_t charnames_act;
|
|
|
|
/* We will allow up to 8 * sizeof(u_int32_t) - 1 character classes. */
|
|
#define MAX_NR_CHARCLASS (8 * sizeof (u_int32_t) - 1)
|
|
size_t nr_charclass;
|
|
const char *classnames[MAX_NR_CHARCLASS];
|
|
unsigned long int current_class_mask;
|
|
unsigned int last_class_char;
|
|
u_int32_t *class_collection;
|
|
size_t class_collection_max;
|
|
size_t class_collection_act;
|
|
unsigned long int class_done;
|
|
|
|
/* If the following number ever turns out to be too small simply
|
|
increase it. But I doubt it will. --drepper@gnu */
|
|
#define MAX_NR_CHARMAP 16
|
|
const char *mapnames[MAX_NR_CHARMAP];
|
|
u_int32_t *map_collection[MAX_NR_CHARMAP];
|
|
size_t map_collection_max[MAX_NR_CHARMAP];
|
|
size_t map_collection_act[MAX_NR_CHARMAP];
|
|
size_t map_collection_nr;
|
|
size_t last_map_idx;
|
|
unsigned int from_map_char;
|
|
int toupper_done;
|
|
int tolower_done;
|
|
|
|
/* The arrays for the binary representation. */
|
|
u_int32_t plane_size;
|
|
u_int32_t plane_cnt;
|
|
char_class_t *ctype_b;
|
|
char_class32_t *ctype32_b;
|
|
u_int32_t *names_el;
|
|
u_int32_t *names_eb;
|
|
u_int32_t **map_eb;
|
|
u_int32_t **map_el;
|
|
u_int32_t *class_name_ptr;
|
|
u_int32_t *map_name_ptr;
|
|
unsigned char *width;
|
|
u_int32_t mb_cur_max;
|
|
const char *codeset_name;
|
|
};
|
|
|
|
|
|
/* Prototypes for local functions. */
|
|
static void ctype_class_newP (struct linereader *lr,
|
|
struct locale_ctype_t *ctype, const char *name);
|
|
static void ctype_map_newP (struct linereader *lr,
|
|
struct locale_ctype_t *ctype,
|
|
const char *name, struct charset_t *charset);
|
|
static u_int32_t *find_idx (struct locale_ctype_t *ctype, u_int32_t **table,
|
|
size_t *max, size_t *act, unsigned int idx);
|
|
static void set_class_defaults (struct locale_ctype_t *ctype,
|
|
struct charset_t *charset);
|
|
static void allocate_arrays (struct locale_ctype_t *ctype,
|
|
struct charset_t *charset);
|
|
|
|
|
|
void
|
|
ctype_startup (struct linereader *lr, struct localedef_t *locale,
|
|
struct charset_t *charset)
|
|
{
|
|
unsigned int cnt;
|
|
struct locale_ctype_t *ctype;
|
|
|
|
/* It is important that we always use UCS1 encoding for strings now. */
|
|
encoding_method = ENC_UCS1;
|
|
|
|
/* Allocate the needed room. */
|
|
locale->categories[LC_CTYPE].ctype = ctype =
|
|
(struct locale_ctype_t *) xmalloc (sizeof (struct locale_ctype_t));
|
|
|
|
/* We have no names seen yet. */
|
|
ctype->charnames_max = charset->mb_cur_max == 1 ? 256 : 512;
|
|
ctype->charnames =
|
|
(unsigned int *) xmalloc (ctype->charnames_max * sizeof (unsigned int));
|
|
for (cnt = 0; cnt < 256; ++cnt)
|
|
ctype->charnames[cnt] = cnt;
|
|
ctype->charnames_act = 256;
|
|
|
|
/* Fill character class information. */
|
|
ctype->nr_charclass = 0;
|
|
ctype->current_class_mask = 0;
|
|
ctype->last_class_char = ILLEGAL_CHAR_VALUE;
|
|
/* The order of the following instructions determines the bit
|
|
positions! */
|
|
ctype_class_newP (lr, ctype, "upper");
|
|
ctype_class_newP (lr, ctype, "lower");
|
|
ctype_class_newP (lr, ctype, "alpha");
|
|
ctype_class_newP (lr, ctype, "digit");
|
|
ctype_class_newP (lr, ctype, "xdigit");
|
|
ctype_class_newP (lr, ctype, "space");
|
|
ctype_class_newP (lr, ctype, "print");
|
|
ctype_class_newP (lr, ctype, "graph");
|
|
ctype_class_newP (lr, ctype, "blank");
|
|
ctype_class_newP (lr, ctype, "cntrl");
|
|
ctype_class_newP (lr, ctype, "punct");
|
|
ctype_class_newP (lr, ctype, "alnum");
|
|
|
|
ctype->class_collection_max = charset->mb_cur_max == 1 ? 256 : 512;
|
|
ctype->class_collection
|
|
= (u_int32_t *) xmalloc (sizeof (unsigned long int)
|
|
* ctype->class_collection_max);
|
|
memset (ctype->class_collection, '\0',
|
|
sizeof (unsigned long int) * ctype->class_collection_max);
|
|
ctype->class_collection_act = 256;
|
|
|
|
/* Fill character map information. */
|
|
ctype->map_collection_nr = 0;
|
|
ctype->last_map_idx = MAX_NR_CHARMAP;
|
|
ctype->from_map_char = ILLEGAL_CHAR_VALUE;
|
|
ctype_map_newP (lr, ctype, "toupper", charset);
|
|
ctype_map_newP (lr, ctype, "tolower", charset);
|
|
|
|
/* Fill first 256 entries in `toupper' and `tolower' arrays. */
|
|
for (cnt = 0; cnt < 256; ++cnt)
|
|
{
|
|
ctype->map_collection[0][cnt] = cnt;
|
|
ctype->map_collection[1][cnt] = cnt;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ctype_finish (struct localedef_t *locale, struct charset_t *charset)
|
|
{
|
|
/* See POSIX.2, table 2-6 for the meaning of the following table. */
|
|
#define NCLASS 12
|
|
static const struct
|
|
{
|
|
const char *name;
|
|
const char allow[NCLASS];
|
|
}
|
|
valid_table[NCLASS] =
|
|
{
|
|
/* The order is important. See token.h for more information.
|
|
M = Always, D = Default, - = Permitted, X = Mutually exclusive */
|
|
{ "upper", "--MX-XDDXXX-" },
|
|
{ "lower", "--MX-XDDXXX-" },
|
|
{ "alpha", "---X-XDDXXX-" },
|
|
{ "digit", "XXX--XDDXXX-" },
|
|
{ "xdigit", "-----XDDXXX-" },
|
|
{ "space", "XXXXX------X" },
|
|
{ "print", "---------X--" },
|
|
{ "graph", "---------X--" },
|
|
{ "blank", "XXXXXM-----X" },
|
|
{ "cntrl", "XXXXX-XX--XX" },
|
|
{ "punct", "XXXXX-DD-X-X" },
|
|
{ "alnum", "-----XDDXXX-" }
|
|
};
|
|
size_t cnt;
|
|
int cls1, cls2;
|
|
unsigned int space_value;
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
|
|
/* Set default value for classes not specified. */
|
|
set_class_defaults (ctype, charset);
|
|
|
|
/* Check according to table. */
|
|
for (cnt = 0; cnt < ctype->class_collection_max; ++cnt)
|
|
{
|
|
unsigned long int tmp;
|
|
|
|
tmp = ctype->class_collection[cnt];
|
|
if (tmp == 0)
|
|
continue;
|
|
|
|
for (cls1 = 0; cls1 < NCLASS; ++cls1)
|
|
if ((tmp & (1 << cls1)) != 0)
|
|
for (cls2 = 0; cls2 < NCLASS; ++cls2)
|
|
if (valid_table[cls1].allow[cls2] != '-')
|
|
{
|
|
int eq = (tmp & (1 << cls2)) != 0;
|
|
switch (valid_table[cls1].allow[cls2])
|
|
{
|
|
case 'M':
|
|
if (!eq)
|
|
{
|
|
char buf[17];
|
|
char *cp = buf;
|
|
unsigned int value;
|
|
|
|
value = ctype->charnames[cnt];
|
|
|
|
if ((value & 0xff000000) != 0)
|
|
cp += sprintf (cp, "\\%o", (value >> 24) & 0xff);
|
|
if ((value & 0xffff0000) != 0)
|
|
cp += sprintf (cp, "\\%o", (value >> 16) & 0xff);
|
|
if ((value & 0xffffff00) != 0)
|
|
cp += sprintf (cp, "\\%o", (value >> 8) & 0xff);
|
|
sprintf (cp, "\\%o", value & 0xff);
|
|
|
|
if (!be_quiet)
|
|
error (0, 0, _("\
|
|
character %s'%s' in class `%s' must be in class `%s'"), value > 256 ? "L" : "",
|
|
cp, valid_table[cls1].name,
|
|
valid_table[cls2].name);
|
|
}
|
|
break;
|
|
|
|
case 'X':
|
|
if (eq)
|
|
{
|
|
char buf[17];
|
|
char *cp = buf;
|
|
unsigned int value;
|
|
|
|
value = ctype->charnames[cnt];
|
|
|
|
if ((value & 0xff000000) != 0)
|
|
cp += sprintf (cp, "\\%o", value >> 24);
|
|
if ((value & 0xffff0000) != 0)
|
|
cp += sprintf (cp, "\\%o", (value >> 16) & 0xff);
|
|
if ((value & 0xffffff00) != 0)
|
|
cp += sprintf (cp, "\\%o", (value >> 8) & 0xff);
|
|
sprintf (cp, "\\%o", value & 0xff);
|
|
|
|
if (!be_quiet)
|
|
error (0, 0, _("\
|
|
character %s'%s' in class `%s' must not be in class `%s'"),
|
|
value > 256 ? "L" : "", cp,
|
|
valid_table[cls1].name,
|
|
valid_table[cls2].name);
|
|
}
|
|
break;
|
|
|
|
case 'D':
|
|
ctype->class_collection[cnt] |= 1 << cls2;
|
|
break;
|
|
|
|
default:
|
|
error (5, 0, _("internal error in %s, line %u"),
|
|
__FUNCTION__, __LINE__);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ... and now test <SP> as a special case. */
|
|
space_value = charset_find_value (charset, "SP", 2);
|
|
if ((wchar_t) space_value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("character <SP> not defined in character map"));
|
|
else if (((cnt = BITPOS (tok_space),
|
|
(ELEM (ctype, class_collection, , space_value)
|
|
& BIT (tok_space)) == 0)
|
|
|| (cnt = BITPOS (tok_blank),
|
|
(ELEM (ctype, class_collection, , space_value)
|
|
& BIT (tok_blank)) == 0))
|
|
&& !be_quiet)
|
|
error (0, 0, _("<SP> character not in class `%s'"),
|
|
valid_table[cnt].name);
|
|
else if (((cnt = BITPOS (tok_punct),
|
|
(ELEM (ctype, class_collection, , space_value)
|
|
& BIT (tok_punct)) != 0)
|
|
|| (cnt = BITPOS (tok_graph),
|
|
(ELEM (ctype, class_collection, , space_value)
|
|
& BIT (tok_graph))
|
|
!= 0))
|
|
&& !be_quiet)
|
|
error (0, 0, _("<SP> character must not be in class `%s'"),
|
|
valid_table[cnt].name);
|
|
else
|
|
ELEM (ctype, class_collection, , space_value) |= BIT (tok_print);
|
|
|
|
/* Now that the tests are done make sure the name array contains all
|
|
characters which are handled in the WIDTH section of the
|
|
character set definition file. */
|
|
if (charset->width_rules != NULL)
|
|
for (cnt = 0; cnt < charset->nwidth_rules; ++cnt)
|
|
{
|
|
size_t inner;
|
|
for (inner = charset->width_rules[cnt].from;
|
|
inner <= charset->width_rules[cnt].to; ++inner)
|
|
(void) find_idx (ctype, NULL, NULL, NULL, inner);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
ctype_output (struct localedef_t *locale, struct charset_t *charset,
|
|
const char *output_path)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
const size_t nelems = (_NL_ITEM_INDEX (_NL_NUM_LC_CTYPE)
|
|
+ 2 * (ctype->map_collection_nr - 2));
|
|
struct iovec iov[2 + nelems + ctype->nr_charclass
|
|
+ ctype->map_collection_nr];
|
|
struct locale_file data;
|
|
u_int32_t idx[nelems];
|
|
size_t elem, cnt, offset, total;
|
|
|
|
|
|
if ((locale->binary & (1 << LC_CTYPE)) != 0)
|
|
{
|
|
iov[0].iov_base = ctype;
|
|
iov[0].iov_len = locale->len[LC_CTYPE];
|
|
|
|
write_locale_data (output_path, "LC_CTYPE", 1, iov);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* Now prepare the output: Find the sizes of the table we can use. */
|
|
allocate_arrays (ctype, charset);
|
|
|
|
data.magic = LIMAGIC (LC_CTYPE);
|
|
data.n = nelems;
|
|
iov[0].iov_base = (void *) &data;
|
|
iov[0].iov_len = sizeof (data);
|
|
|
|
iov[1].iov_base = (void *) idx;
|
|
iov[1].iov_len = sizeof (idx);
|
|
|
|
idx[0] = iov[0].iov_len + iov[1].iov_len;
|
|
offset = 0;
|
|
|
|
for (elem = 0; elem < nelems; ++elem)
|
|
{
|
|
if (elem < _NL_ITEM_INDEX (_NL_NUM_LC_CTYPE))
|
|
switch (elem)
|
|
{
|
|
#define CTYPE_DATA(name, base, len) \
|
|
case _NL_ITEM_INDEX (name): \
|
|
iov[2 + elem + offset].iov_base = (base); \
|
|
iov[2 + elem + offset].iov_len = (len); \
|
|
if (elem + 1 < nelems) \
|
|
idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len; \
|
|
break
|
|
|
|
CTYPE_DATA (_NL_CTYPE_CLASS,
|
|
ctype->ctype_b,
|
|
(256 + 128) * sizeof (char_class_t));
|
|
|
|
CTYPE_DATA (_NL_CTYPE_TOUPPER_EB,
|
|
ctype->map_eb[0],
|
|
(ctype->plane_size * ctype->plane_cnt + 128)
|
|
* sizeof (u_int32_t));
|
|
CTYPE_DATA (_NL_CTYPE_TOLOWER_EB,
|
|
ctype->map_eb[1],
|
|
(ctype->plane_size * ctype->plane_cnt + 128)
|
|
* sizeof (u_int32_t));
|
|
|
|
CTYPE_DATA (_NL_CTYPE_TOUPPER_EL,
|
|
ctype->map_el[0],
|
|
(ctype->plane_size * ctype->plane_cnt + 128)
|
|
* sizeof (u_int32_t));
|
|
CTYPE_DATA (_NL_CTYPE_TOLOWER_EL,
|
|
ctype->map_el[1],
|
|
(ctype->plane_size * ctype->plane_cnt + 128)
|
|
* sizeof (u_int32_t));
|
|
|
|
CTYPE_DATA (_NL_CTYPE_CLASS32,
|
|
ctype->ctype32_b,
|
|
(ctype->plane_size * ctype->plane_cnt
|
|
* sizeof (char_class32_t)));
|
|
|
|
CTYPE_DATA (_NL_CTYPE_NAMES_EB,
|
|
ctype->names_eb, (ctype->plane_size * ctype->plane_cnt
|
|
* sizeof (u_int32_t)));
|
|
CTYPE_DATA (_NL_CTYPE_NAMES_EL,
|
|
ctype->names_el, (ctype->plane_size * ctype->plane_cnt
|
|
* sizeof (u_int32_t)));
|
|
|
|
CTYPE_DATA (_NL_CTYPE_HASH_SIZE,
|
|
&ctype->plane_size, sizeof (u_int32_t));
|
|
CTYPE_DATA (_NL_CTYPE_HASH_LAYERS,
|
|
&ctype->plane_cnt, sizeof (u_int32_t));
|
|
|
|
case _NL_ITEM_INDEX (_NL_CTYPE_CLASS_NAMES):
|
|
/* The class name array. */
|
|
total = 0;
|
|
for (cnt = 0; cnt < ctype->nr_charclass; ++cnt, ++offset)
|
|
{
|
|
iov[2 + elem + offset].iov_base
|
|
= (void *) ctype->classnames[cnt];
|
|
iov[2 + elem + offset].iov_len
|
|
= strlen (ctype->classnames[cnt]) + 1;
|
|
total += iov[2 + elem + offset].iov_len;
|
|
}
|
|
iov[2 + elem + offset].iov_base = (void *) "\0\0\0";
|
|
iov[2 + elem + offset].iov_len = 1 + (4 - ((total + 1) % 4));
|
|
total += 1 + (4 - ((total + 1) % 4));
|
|
|
|
if (elem + 1 < nelems)
|
|
idx[elem + 1] = idx[elem] + total;
|
|
break;
|
|
|
|
case _NL_ITEM_INDEX (_NL_CTYPE_MAP_NAMES):
|
|
/* The class name array. */
|
|
total = 0;
|
|
for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt, ++offset)
|
|
{
|
|
iov[2 + elem + offset].iov_base
|
|
= (void *) ctype->mapnames[cnt];
|
|
iov[2 + elem + offset].iov_len
|
|
= strlen (ctype->mapnames[cnt]) + 1;
|
|
total += iov[2 + elem + offset].iov_len;
|
|
}
|
|
iov[2 + elem + offset].iov_base = (void *) "\0\0\0";
|
|
iov[2 + elem + offset].iov_len = 1 + (4 - ((total + 1) % 4));
|
|
total += 1 + (4 - ((total + 1) % 4));
|
|
|
|
if (elem + 1 < nelems)
|
|
idx[elem + 1] = idx[elem] + total;
|
|
break;
|
|
|
|
CTYPE_DATA (_NL_CTYPE_WIDTH,
|
|
ctype->width, ctype->plane_size * ctype->plane_cnt);
|
|
|
|
CTYPE_DATA (_NL_CTYPE_MB_CUR_MAX,
|
|
&ctype->mb_cur_max, sizeof (u_int32_t));
|
|
|
|
case _NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME):
|
|
total = strlen (ctype->codeset_name) + 1;
|
|
if (total % 4 == 0)
|
|
iov[2 + elem + offset].iov_base = (char *) ctype->codeset_name;
|
|
else
|
|
{
|
|
iov[2 + elem + offset].iov_base = alloca ((total + 3) & ~3);
|
|
memset (mempcpy (iov[2 + elem + offset].iov_base,
|
|
ctype->codeset_name, total),
|
|
'\0', 4 - (total & 3));
|
|
total = (total + 3) & ~3;
|
|
}
|
|
iov[2 + elem + offset].iov_len = total;
|
|
if (elem + 1 < nelems)
|
|
idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
|
|
break;
|
|
|
|
default:
|
|
assert (! "unknown CTYPE element");
|
|
}
|
|
else
|
|
{
|
|
/* Handle extra maps. */
|
|
size_t nr = (elem - _NL_ITEM_INDEX (_NL_NUM_LC_CTYPE)) >> 1;
|
|
|
|
if (((elem - _NL_ITEM_INDEX (_NL_NUM_LC_CTYPE)) & 1) == 0)
|
|
iov[2 + elem + offset].iov_base = ctype->map_eb[nr];
|
|
else
|
|
iov[2 + elem + offset].iov_base = ctype->map_el[nr];
|
|
|
|
iov[2 + elem + offset].iov_len = ((ctype->plane_size
|
|
* ctype->plane_cnt + 128)
|
|
* sizeof (u_int32_t));
|
|
|
|
if (elem + 1 < nelems)
|
|
idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
|
|
}
|
|
}
|
|
|
|
assert (2 + elem + offset == (nelems + ctype->nr_charclass
|
|
+ ctype->map_collection_nr + 2));
|
|
|
|
write_locale_data (output_path, "LC_CTYPE", 2 + elem + offset, iov);
|
|
}
|
|
|
|
|
|
/* Character class handling. */
|
|
void
|
|
ctype_class_new (struct linereader *lr, struct localedef_t *locale,
|
|
enum token_t tok, struct token *code,
|
|
struct charset_t *charset)
|
|
{
|
|
ctype_class_newP (lr, locale->categories[LC_CTYPE].ctype,
|
|
code->val.str.start);
|
|
}
|
|
|
|
|
|
int
|
|
ctype_is_charclass (struct linereader *lr, struct localedef_t *locale,
|
|
const char *name)
|
|
{
|
|
size_t cnt;
|
|
|
|
for (cnt = 0; cnt < locale->categories[LC_CTYPE].ctype->nr_charclass; ++cnt)
|
|
if (strcmp (name, locale->categories[LC_CTYPE].ctype->classnames[cnt])
|
|
== 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
ctype_class_start (struct linereader *lr, struct localedef_t *locale,
|
|
enum token_t tok, const char *str,
|
|
struct charset_t *charset)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
size_t cnt;
|
|
|
|
switch (tok)
|
|
{
|
|
case tok_upper:
|
|
str = "upper";
|
|
break;
|
|
case tok_lower:
|
|
str = "lower";
|
|
break;
|
|
case tok_alpha:
|
|
str = "alpha";
|
|
break;
|
|
case tok_digit:
|
|
str = "digit";
|
|
break;
|
|
case tok_xdigit:
|
|
str = "xdigit";
|
|
break;
|
|
case tok_space:
|
|
str = "space";
|
|
break;
|
|
case tok_print:
|
|
str = "print";
|
|
break;
|
|
case tok_graph:
|
|
str = "graph";
|
|
break;
|
|
case tok_blank:
|
|
str = "blank";
|
|
break;
|
|
case tok_cntrl:
|
|
str = "cntrl";
|
|
break;
|
|
case tok_punct:
|
|
str = "punct";
|
|
break;
|
|
case tok_alnum:
|
|
str = "alnum";
|
|
break;
|
|
case tok_ident:
|
|
break;
|
|
default:
|
|
assert (! "illegal token as class name: should not happen");
|
|
}
|
|
|
|
for (cnt = 0; cnt < ctype->nr_charclass; ++cnt)
|
|
if (strcmp (str, ctype->classnames[cnt]) == 0)
|
|
break;
|
|
|
|
if (cnt >= ctype->nr_charclass)
|
|
assert (! "unknown class in class definition: should not happen");
|
|
|
|
ctype->class_done |= BIT (tok);
|
|
|
|
ctype->current_class_mask = 1 << cnt;
|
|
ctype->last_class_char = ILLEGAL_CHAR_VALUE;
|
|
}
|
|
|
|
|
|
void
|
|
ctype_class_from (struct linereader *lr, struct localedef_t *locale,
|
|
struct token *code, struct charset_t *charset)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
unsigned int value;
|
|
|
|
value = charset_find_value (charset, code->val.str.start, code->val.str.len);
|
|
|
|
ctype->last_class_char = value;
|
|
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE)
|
|
/* In the LC_CTYPE category it is no error when a character is
|
|
not found. This has to be ignored silently. */
|
|
return;
|
|
|
|
*find_idx (ctype, &ctype->class_collection, &ctype->class_collection_max,
|
|
&ctype->class_collection_act, value)
|
|
|= ctype->current_class_mask;
|
|
}
|
|
|
|
|
|
void
|
|
ctype_class_to (struct linereader *lr, struct localedef_t *locale,
|
|
struct token *code, struct charset_t *charset)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
unsigned int value, cnt;
|
|
|
|
value = charset_find_value (charset, code->val.str.start, code->val.str.len);
|
|
|
|
assert (value >= ctype->last_class_char);
|
|
|
|
for (cnt = ctype->last_class_char + 1; cnt <= value; ++cnt)
|
|
*find_idx (ctype, &ctype->class_collection, &ctype->class_collection_max,
|
|
&ctype->class_collection_act, cnt)
|
|
|= ctype->current_class_mask;
|
|
|
|
ctype->last_class_char = ILLEGAL_CHAR_VALUE;
|
|
}
|
|
|
|
|
|
void
|
|
ctype_class_end (struct linereader *lr, struct localedef_t *locale)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
|
|
/* We have no special actions to perform here. */
|
|
ctype->current_class_mask = 0;
|
|
ctype->last_class_char = ILLEGAL_CHAR_VALUE;
|
|
}
|
|
|
|
|
|
/* Character map handling. */
|
|
void
|
|
ctype_map_new (struct linereader *lr, struct localedef_t *locale,
|
|
enum token_t tok, struct token *code,
|
|
struct charset_t *charset)
|
|
{
|
|
ctype_map_newP (lr, locale->categories[LC_CTYPE].ctype,
|
|
code->val.str.start, charset);
|
|
}
|
|
|
|
|
|
int
|
|
ctype_is_charconv (struct linereader *lr, struct localedef_t *locale,
|
|
const char *name)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
size_t cnt;
|
|
|
|
for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
|
|
if (strcmp (name, ctype->mapnames[cnt]) == 0)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
void
|
|
ctype_map_start (struct linereader *lr, struct localedef_t *locale,
|
|
enum token_t tok, const char *name, struct charset_t *charset)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
size_t cnt;
|
|
|
|
switch (tok)
|
|
{
|
|
case tok_toupper:
|
|
ctype->toupper_done = 1;
|
|
name = "toupper";
|
|
break;
|
|
case tok_tolower:
|
|
ctype->tolower_done = 1;
|
|
name = "tolower";
|
|
break;
|
|
case tok_ident:
|
|
break;
|
|
default:
|
|
assert (! "unknown token in category `LC_CTYPE' should not happen");
|
|
}
|
|
|
|
for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
|
|
if (strcmp (name, ctype->mapnames[cnt]) == 0)
|
|
break;
|
|
|
|
if (cnt == ctype->map_collection_nr)
|
|
assert (! "unknown token in category `LC_CTYPE' should not happen");
|
|
|
|
ctype->last_map_idx = cnt;
|
|
ctype->from_map_char = ILLEGAL_CHAR_VALUE;
|
|
}
|
|
|
|
|
|
void
|
|
ctype_map_from (struct linereader *lr, struct localedef_t *locale,
|
|
struct token *code, struct charset_t *charset)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
unsigned int value;
|
|
|
|
value = charset_find_value (charset, code->val.str.start, code->val.str.len);
|
|
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE)
|
|
/* In the LC_CTYPE category it is no error when a character is
|
|
not found. This has to be ignored silently. */
|
|
return;
|
|
|
|
assert (ctype->last_map_idx < ctype->map_collection_nr);
|
|
|
|
ctype->from_map_char = value;
|
|
}
|
|
|
|
|
|
void
|
|
ctype_map_to (struct linereader *lr, struct localedef_t *locale,
|
|
struct token *code, struct charset_t *charset)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
unsigned int value;
|
|
|
|
value = charset_find_value (charset, code->val.str.start, code->val.str.len);
|
|
|
|
if ((wchar_t) ctype->from_map_char == ILLEGAL_CHAR_VALUE
|
|
|| (wchar_t) value == ILLEGAL_CHAR_VALUE)
|
|
{
|
|
/* In the LC_CTYPE category it is no error when a character is
|
|
not found. This has to be ignored silently. */
|
|
ctype->from_map_char = ILLEGAL_CHAR_VALUE;
|
|
return;
|
|
}
|
|
|
|
*find_idx (ctype, &ctype->map_collection[ctype->last_map_idx],
|
|
&ctype->map_collection_max[ctype->last_map_idx],
|
|
&ctype->map_collection_act[ctype->last_map_idx],
|
|
ctype->from_map_char) = value;
|
|
|
|
ctype->from_map_char = ILLEGAL_CHAR_VALUE;
|
|
}
|
|
|
|
|
|
void
|
|
ctype_map_end (struct linereader *lr, struct localedef_t *locale)
|
|
{
|
|
struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
|
|
|
|
ctype->last_map_idx = MAX_NR_CHARMAP;
|
|
ctype->from_map_char = ILLEGAL_CHAR_VALUE;
|
|
}
|
|
|
|
|
|
/* Local functions. */
|
|
static void
|
|
ctype_class_newP (struct linereader *lr, struct locale_ctype_t *ctype,
|
|
const char *name)
|
|
{
|
|
size_t cnt;
|
|
|
|
for (cnt = 0; cnt < ctype->nr_charclass; ++cnt)
|
|
if (strcmp (ctype->classnames[cnt], name) == 0)
|
|
break;
|
|
|
|
if (cnt < ctype->nr_charclass)
|
|
{
|
|
lr_error (lr, _("character class `%s' already defined"), name);
|
|
return;
|
|
}
|
|
|
|
if (ctype->nr_charclass == MAX_NR_CHARCLASS)
|
|
/* Exit code 2 is prescribed in P1003.2b. */
|
|
error (2, 0, _("\
|
|
implementation limit: no more than %d character classes allowed"),
|
|
MAX_NR_CHARCLASS);
|
|
|
|
ctype->classnames[ctype->nr_charclass++] = name;
|
|
}
|
|
|
|
|
|
static void
|
|
ctype_map_newP (struct linereader *lr, struct locale_ctype_t *ctype,
|
|
const char *name, struct charset_t *charset)
|
|
{
|
|
size_t max_chars = 0;
|
|
size_t cnt;
|
|
|
|
for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
|
|
{
|
|
if (strcmp (ctype->mapnames[cnt], name) == 0)
|
|
break;
|
|
|
|
if (max_chars < ctype->map_collection_max[cnt])
|
|
max_chars = ctype->map_collection_max[cnt];
|
|
}
|
|
|
|
if (cnt < ctype->map_collection_nr)
|
|
{
|
|
lr_error (lr, _("character map `%s' already defined"), name);
|
|
return;
|
|
}
|
|
|
|
if (ctype->map_collection_nr == MAX_NR_CHARMAP)
|
|
/* Exit code 2 is prescribed in P1003.2b. */
|
|
error (2, 0, _("\
|
|
implementation limit: no more than %d character maps allowed"),
|
|
MAX_NR_CHARMAP);
|
|
|
|
ctype->mapnames[cnt] = name;
|
|
|
|
if (max_chars == 0)
|
|
ctype->map_collection_max[cnt] = charset->mb_cur_max == 1 ? 256 : 512;
|
|
else
|
|
ctype->map_collection_max[cnt] = max_chars;
|
|
|
|
ctype->map_collection[cnt] = (u_int32_t *)
|
|
xmalloc (sizeof (u_int32_t) * ctype->map_collection_max[cnt]);
|
|
memset (ctype->map_collection[cnt], '\0',
|
|
sizeof (u_int32_t) * ctype->map_collection_max[cnt]);
|
|
ctype->map_collection_act[cnt] = 256;
|
|
|
|
++ctype->map_collection_nr;
|
|
}
|
|
|
|
|
|
/* We have to be prepared that TABLE, MAX, and ACT can be NULL. This
|
|
is possible if we only want ot extend the name array. */
|
|
static u_int32_t *
|
|
find_idx (struct locale_ctype_t *ctype, u_int32_t **table, size_t *max,
|
|
size_t *act, unsigned int idx)
|
|
{
|
|
size_t cnt;
|
|
|
|
if (idx < 256)
|
|
return table == NULL ? NULL : &(*table)[idx];
|
|
|
|
for (cnt = 256; cnt < ctype->charnames_act; ++cnt)
|
|
if (ctype->charnames[cnt] == idx)
|
|
break;
|
|
|
|
/* We have to distinguish two cases: the names is found or not. */
|
|
if (cnt == ctype->charnames_act)
|
|
{
|
|
/* Extend the name array. */
|
|
if (ctype->charnames_act == ctype->charnames_max)
|
|
{
|
|
ctype->charnames_max *= 2;
|
|
ctype->charnames = (unsigned int *)
|
|
xrealloc (ctype->charnames,
|
|
sizeof (unsigned int) * ctype->charnames_max);
|
|
}
|
|
ctype->charnames[ctype->charnames_act++] = idx;
|
|
}
|
|
|
|
if (table == NULL)
|
|
/* We have done everything we are asked to do. */
|
|
return NULL;
|
|
|
|
if (cnt >= *act)
|
|
{
|
|
if (cnt >= *max)
|
|
{
|
|
size_t old_max = *max;
|
|
do
|
|
*max *= 2;
|
|
while (*max <= cnt);
|
|
|
|
*table =
|
|
(u_int32_t *) xrealloc (*table, *max * sizeof (unsigned long int));
|
|
memset (&(*table)[old_max], '\0',
|
|
(*max - old_max) * sizeof (u_int32_t));
|
|
}
|
|
|
|
(*table)[cnt] = 0;
|
|
*act = cnt;
|
|
}
|
|
|
|
return &(*table)[cnt];
|
|
}
|
|
|
|
|
|
static void
|
|
set_class_defaults (struct locale_ctype_t *ctype, struct charset_t *charset)
|
|
{
|
|
/* These function defines the default values for the classes and conversions
|
|
according to POSIX.2 2.5.2.1.
|
|
It may seem that the order of these if-blocks is arbitrary but it is NOT.
|
|
Don't move them unless you know what you do! */
|
|
|
|
void set_default (int bit, int from, int to)
|
|
{
|
|
char tmp[2];
|
|
int ch;
|
|
/* Define string. */
|
|
strcpy (tmp, "?");
|
|
|
|
for (ch = from; ch <= to; ++ch)
|
|
{
|
|
unsigned int value;
|
|
tmp[0] = ch;
|
|
|
|
value = charset_find_value (charset, tmp, 1);
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
{
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
tmp);
|
|
continue;
|
|
}
|
|
else
|
|
ELEM (ctype, class_collection, , value) |= bit;
|
|
}
|
|
}
|
|
|
|
/* Set default values if keyword was not present. */
|
|
if ((ctype->class_done & BIT (tok_upper)) == 0)
|
|
/* "If this keyword [lower] is not specified, the lowercase letters
|
|
`A' through `Z', ..., shall automatically belong to this class,
|
|
with implementation defined character values." [P1003.2, 2.5.2.1] */
|
|
set_default (BIT (tok_upper), 'A', 'Z');
|
|
|
|
if ((ctype->class_done & BIT (tok_lower)) == 0)
|
|
/* "If this keyword [lower] is not specified, the lowercase letters
|
|
`a' through `z', ..., shall automatically belong to this class,
|
|
with implementation defined character values." [P1003.2, 2.5.2.1] */
|
|
set_default (BIT (tok_lower), 'a', 'z');
|
|
|
|
if ((ctype->class_done & BIT (tok_alpha)) == 0)
|
|
{
|
|
/* Table 2-6 in P1003.2 says that characters in class `upper' or
|
|
class `lower' *must* be in class `alpha'. */
|
|
unsigned long int mask = BIT (tok_upper) | BIT (tok_lower);
|
|
size_t cnt;
|
|
|
|
for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
|
|
if ((ctype->class_collection[cnt] & mask) != 0)
|
|
ctype->class_collection[cnt] |= BIT (tok_alpha);
|
|
}
|
|
|
|
if ((ctype->class_done & BIT (tok_digit)) == 0)
|
|
/* "If this keyword [digit] is not specified, the digits `0' through
|
|
`9', ..., shall automatically belong to this class, with
|
|
implementation-defined character values." [P1003.2, 2.5.2.1] */
|
|
set_default (BIT (tok_digit), '0', '9');
|
|
|
|
/* "Only characters specified for the `alpha' and `digit' keyword
|
|
shall be specified. Characters specified for the keyword `alpha'
|
|
and `digit' are automatically included in this class. */
|
|
{
|
|
unsigned long int mask = BIT (tok_alpha) | BIT (tok_digit);
|
|
size_t cnt;
|
|
|
|
for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
|
|
if ((ctype->class_collection[cnt] & mask) != 0)
|
|
ctype->class_collection[cnt] |= BIT (tok_alnum);
|
|
}
|
|
|
|
if ((ctype->class_done & BIT (tok_space)) == 0)
|
|
/* "If this keyword [space] is not specified, the characters <space>,
|
|
<form-feed>, <newline>, <carriage-return>, <tab>, and
|
|
<vertical-tab>, ..., shall automatically belong to this class,
|
|
with implementation-defined character values." [P1003.2, 2.5.2.1] */
|
|
{
|
|
unsigned int value;
|
|
|
|
value = charset_find_value (charset, "space", 5);
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
"<space>");
|
|
else
|
|
ELEM (ctype, class_collection, , value) |= BIT (tok_space);
|
|
|
|
value = charset_find_value (charset, "form-feed", 9);
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
"<form-feed>");
|
|
else
|
|
ELEM (ctype, class_collection, , value) |= BIT (tok_space);
|
|
|
|
value = charset_find_value (charset, "newline", 7);
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
"<newline>");
|
|
else
|
|
ELEM (ctype, class_collection, , value) |= BIT (tok_space);
|
|
|
|
value = charset_find_value (charset, "carriage-return", 15);
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
"<carriage-return>");
|
|
else
|
|
ELEM (ctype, class_collection, , value) |= BIT (tok_space);
|
|
|
|
value = charset_find_value (charset, "tab", 3);
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
"<tab>");
|
|
else
|
|
ELEM (ctype, class_collection, , value) |= BIT (tok_space);
|
|
|
|
value = charset_find_value (charset, "vertical-tab", 12);
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
"<vertical-tab>");
|
|
else
|
|
ELEM (ctype, class_collection, , value) |= BIT (tok_space);
|
|
}
|
|
|
|
if ((ctype->class_done & BIT (tok_xdigit)) == 0)
|
|
/* "If this keyword is not specified, the digits `0' to `9', the
|
|
uppercase letters `A' through `F', and the lowercase letters `a'
|
|
through `f', ..., shell automatically belong to this class, with
|
|
implementation defined character values." [P1003.2, 2.5.2.1] */
|
|
{
|
|
set_default (BIT (tok_xdigit), '0', '9');
|
|
set_default (BIT (tok_xdigit), 'A', 'F');
|
|
set_default (BIT (tok_xdigit), 'a', 'f');
|
|
}
|
|
|
|
if ((ctype->class_done & BIT (tok_blank)) == 0)
|
|
/* "If this keyword [blank] is unspecified, the characters <space> and
|
|
<tab> shall belong to this character class." [P1003.2, 2.5.2.1] */
|
|
{
|
|
unsigned int value;
|
|
|
|
value = charset_find_value (charset, "space", 5);
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
"<space>");
|
|
else
|
|
ELEM (ctype, class_collection, , value) |= BIT (tok_blank);
|
|
|
|
value = charset_find_value (charset, "tab", 3);
|
|
if ((wchar_t) value == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
"<tab>");
|
|
else
|
|
ELEM (ctype, class_collection, , value) |= BIT (tok_blank);
|
|
}
|
|
|
|
if ((ctype->class_done & BIT (tok_graph)) == 0)
|
|
/* "If this keyword [graph] is not specified, characters specified for
|
|
the keywords `upper', `lower', `alpha', `digit', `xdigit' and `punct',
|
|
shall belong to this character class." [P1003.2, 2.5.2.1] */
|
|
{
|
|
unsigned long int mask = BIT (tok_upper) | BIT (tok_lower) |
|
|
BIT (tok_alpha) | BIT (tok_digit) | BIT (tok_xdigit) | BIT (tok_punct);
|
|
size_t cnt;
|
|
|
|
for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
|
|
if ((ctype->class_collection[cnt] & mask) != 0)
|
|
ctype->class_collection[cnt] |= BIT (tok_graph);
|
|
}
|
|
|
|
if ((ctype->class_done & BIT (tok_print)) == 0)
|
|
/* "If this keyword [print] is not provided, characters specified for
|
|
the keywords `upper', `lower', `alpha', `digit', `xdigit', `punct',
|
|
and the <space> character shall belong to this character class."
|
|
[P1003.2, 2.5.2.1] */
|
|
{
|
|
unsigned long int mask = BIT (tok_upper) | BIT (tok_lower) |
|
|
BIT (tok_alpha) | BIT (tok_digit) | BIT (tok_xdigit) | BIT (tok_punct);
|
|
size_t cnt;
|
|
wchar_t space;
|
|
|
|
for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
|
|
if ((ctype->class_collection[cnt] & mask) != 0)
|
|
ctype->class_collection[cnt] |= BIT (tok_print);
|
|
|
|
space = charset_find_value (charset, "space", 5);
|
|
if (space == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
"<space>");
|
|
else
|
|
ELEM (ctype, class_collection, , space) |= BIT (tok_print);
|
|
}
|
|
|
|
if (ctype->toupper_done == 0)
|
|
/* "If this keyword [toupper] is not specified, the lowercase letters
|
|
`a' through `z', and their corresponding uppercase letters `A' to
|
|
`Z', ..., shall automatically be included, with implementation-
|
|
defined character values." [P1003.2, 2.5.2.1] */
|
|
{
|
|
char tmp[4];
|
|
int ch;
|
|
|
|
strcpy (tmp, "<?>");
|
|
|
|
for (ch = 'a'; ch <= 'z'; ++ch)
|
|
{
|
|
unsigned int value_from, value_to;
|
|
|
|
tmp[1] = (char) ch;
|
|
|
|
value_from = charset_find_value (charset, &tmp[1], 1);
|
|
if ((wchar_t) value_from == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
{
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
tmp);
|
|
continue;
|
|
}
|
|
|
|
/* This conversion is implementation defined. */
|
|
tmp[1] = (char) (ch + ('A' - 'a'));
|
|
value_to = charset_find_value (charset, &tmp[1], 1);
|
|
if ((wchar_t) value_to == ILLEGAL_CHAR_VALUE && !be_quiet)
|
|
{
|
|
error (0, 0, _("\
|
|
character `%s' not defined while needed as default value"),
|
|
tmp);
|
|
continue;
|
|
}
|
|
|
|
/* The index [0] is determined by the order of the
|
|
`ctype_map_newP' calls in `ctype_startup'. */
|
|
ELEM (ctype, map_collection, [0], value_from) = value_to;
|
|
}
|
|
}
|
|
|
|
if (ctype->tolower_done == 0)
|
|
/* "If this keyword [tolower] is not specified, the mapping shall be
|
|
the reverse mapping of the one specified to `toupper'." [P1003.2] */
|
|
{
|
|
size_t cnt;
|
|
|
|
for (cnt = 0; cnt < ctype->map_collection_act[0]; ++cnt)
|
|
if (ctype->map_collection[0][cnt] != 0)
|
|
ELEM (ctype, map_collection, [1],
|
|
ctype->map_collection[0][cnt])
|
|
= ctype->charnames[cnt];
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
allocate_arrays (struct locale_ctype_t *ctype, struct charset_t *charset)
|
|
{
|
|
size_t idx;
|
|
|
|
/* First we have to decide how we organize the arrays. It is easy
|
|
for a one-byte character set. But multi-byte character set
|
|
cannot be stored flat because the chars might be sparsely used.
|
|
So we determine an optimal hashing function for the used
|
|
characters.
|
|
|
|
We use a very trivial hashing function to store the sparse
|
|
table. CH % TABSIZE is used as an index. To solve multiple hits
|
|
we have N planes. This guarantees a fixed search time for a
|
|
character [N / 2]. In the following code we determine the minmum
|
|
value for TABSIZE * N, where TABSIZE >= 256. */
|
|
size_t min_total = UINT_MAX;
|
|
size_t act_size = 256;
|
|
|
|
if (!be_quiet)
|
|
fputs (_("\
|
|
Computing table size for character classes might take a while..."),
|
|
stderr);
|
|
|
|
while (act_size < min_total)
|
|
{
|
|
size_t cnt[act_size];
|
|
size_t act_planes = 1;
|
|
|
|
memset (cnt, '\0', sizeof cnt);
|
|
|
|
for (idx = 0; idx < 256; ++idx)
|
|
cnt[idx] = 1;
|
|
|
|
for (idx = 0; idx < ctype->charnames_act; ++idx)
|
|
if (ctype->charnames[idx] >= 256)
|
|
{
|
|
size_t nr = ctype->charnames[idx] % act_size;
|
|
|
|
if (++cnt[nr] > act_planes)
|
|
{
|
|
act_planes = cnt[nr];
|
|
if (act_size * act_planes >= min_total)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (act_size * act_planes < min_total)
|
|
{
|
|
min_total = act_size * act_planes;
|
|
ctype->plane_size = act_size;
|
|
ctype->plane_cnt = act_planes;
|
|
}
|
|
|
|
++act_size;
|
|
}
|
|
|
|
if (!be_quiet)
|
|
fputs (_(" done\n"), stderr);
|
|
|
|
|
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
# define NAMES_B1 ctype->names_el
|
|
# define NAMES_B2 ctype->names_eb
|
|
#else
|
|
# define NAMES_B1 ctype->names_eb
|
|
# define NAMES_B2 ctype->names_el
|
|
#endif
|
|
|
|
ctype->names_eb = (u_int32_t *) xcalloc (ctype->plane_size
|
|
* ctype->plane_cnt,
|
|
sizeof (u_int32_t));
|
|
ctype->names_el = (u_int32_t *) xcalloc (ctype->plane_size
|
|
* ctype->plane_cnt,
|
|
sizeof (u_int32_t));
|
|
|
|
for (idx = 1; idx < 256; ++idx)
|
|
NAMES_B1[idx] = idx;
|
|
|
|
/* Trick: change the 0th entry's name to 1 to mark the cell occupied. */
|
|
NAMES_B1[0] = 1;
|
|
|
|
for (idx = 256; idx < ctype->charnames_act; ++idx)
|
|
{
|
|
size_t nr = (ctype->charnames[idx] % ctype->plane_size);
|
|
size_t depth = 0;
|
|
|
|
while (NAMES_B1[nr + depth * ctype->plane_size])
|
|
++depth;
|
|
assert (depth < ctype->plane_cnt);
|
|
|
|
NAMES_B1[nr + depth * ctype->plane_size] = ctype->charnames[idx];
|
|
|
|
/* Now for faster access remember the index in the NAMES_B array. */
|
|
ctype->charnames[idx] = nr + depth * ctype->plane_size;
|
|
}
|
|
NAMES_B1[0] = 0;
|
|
|
|
for (idx = 0; idx < ctype->plane_size * ctype->plane_cnt; ++idx)
|
|
NAMES_B2[idx] = SWAPU32 (NAMES_B1[idx]);
|
|
|
|
|
|
/* You wonder about this amount of memory? This is only because some
|
|
users do not manage to address the array with unsigned values or
|
|
data types with range >= 256. '\200' would result in the array
|
|
index -128. To help these poor people we duplicate the entries for
|
|
128 up to 255 below the entry for \0. */
|
|
ctype->ctype_b = (char_class_t *) xcalloc (256 + 128,
|
|
sizeof (char_class_t));
|
|
ctype->ctype32_b = (char_class32_t *) xcalloc (ctype->plane_size
|
|
* ctype->plane_cnt,
|
|
sizeof (char_class32_t));
|
|
|
|
/* Fill in the character class information. */
|
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
# define TRANS(w) CHAR_CLASS_TRANS (w)
|
|
# define TRANS32(w) CHAR_CLASS32_TRANS (w)
|
|
#else
|
|
# define TRANS(w) (w)
|
|
# define TRANS32(w) (w)
|
|
#endif
|
|
|
|
for (idx = 0; idx < ctype->class_collection_act; ++idx)
|
|
if (ctype->charnames[idx] < 256)
|
|
ctype->ctype_b[128 + ctype->charnames[idx]]
|
|
= TRANS (ctype->class_collection[idx]);
|
|
|
|
/* Mirror first 127 entries. We must take care that entry -1 is not
|
|
mirrored because EOF == -1. */
|
|
for (idx = 0; idx < 127; ++idx)
|
|
ctype->ctype_b[idx] = ctype->ctype_b[256 + idx];
|
|
|
|
/* The 32 bit array contains all characters. */
|
|
for (idx = 0; idx < ctype->class_collection_act; ++idx)
|
|
ctype->ctype32_b[ctype->charnames[idx]]
|
|
= TRANS32 (ctype->class_collection[idx]);
|
|
|
|
/* Room for table of mappings. */
|
|
ctype->map_eb = (u_int32_t **) xmalloc (ctype->map_collection_nr
|
|
* sizeof (u_int32_t *));
|
|
ctype->map_el = (u_int32_t **) xmalloc (ctype->map_collection_nr
|
|
* sizeof (u_int32_t *));
|
|
|
|
/* Fill in all mappings. */
|
|
for (idx = 0; idx < ctype->map_collection_nr; ++idx)
|
|
{
|
|
unsigned int idx2;
|
|
|
|
/* Allocate table. */
|
|
ctype->map_eb[idx] = (u_int32_t *) xmalloc ((ctype->plane_size
|
|
* ctype->plane_cnt + 128)
|
|
* sizeof (u_int32_t));
|
|
ctype->map_el[idx] = (u_int32_t *) xmalloc ((ctype->plane_size
|
|
* ctype->plane_cnt + 128)
|
|
* sizeof (u_int32_t));
|
|
|
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
# define MAP_B1 ctype->map_el
|
|
# define MAP_B2 ctype->map_eb
|
|
#else
|
|
# define MAP_B1 ctype->map_eb
|
|
# define MAP_B2 ctype->map_el
|
|
#endif
|
|
|
|
/* Copy default value (identity mapping). */
|
|
memcpy (&MAP_B1[idx][128], NAMES_B1,
|
|
ctype->plane_size * ctype->plane_cnt * sizeof (u_int32_t));
|
|
|
|
/* Copy values from collection. */
|
|
for (idx2 = 0; idx2 < ctype->map_collection_act[idx]; ++idx2)
|
|
if (ctype->map_collection[idx][idx2] != 0)
|
|
MAP_B1[idx][128 + ctype->charnames[idx2]] =
|
|
ctype->map_collection[idx][idx2];
|
|
|
|
/* Mirror first 127 entries. We must take care not to map entry
|
|
-1 because EOF == -1. */
|
|
for (idx2 = 0; idx2 < 127; ++idx2)
|
|
MAP_B1[idx][idx2] = MAP_B1[idx][256 + idx2];
|
|
|
|
/* EOF must map to EOF. */
|
|
MAP_B1[idx][127] = EOF;
|
|
|
|
/* And now the other byte order. */
|
|
for (idx2 = 0; idx2 < ctype->plane_size * ctype->plane_cnt + 128; ++idx2)
|
|
MAP_B2[idx][idx2] = SWAPU32 (MAP_B1[idx][idx2]);
|
|
}
|
|
|
|
/* Extra array for class and map names. */
|
|
ctype->class_name_ptr = (u_int32_t *) xmalloc (ctype->nr_charclass
|
|
* sizeof (u_int32_t));
|
|
ctype->map_name_ptr = (u_int32_t *) xmalloc (ctype->map_collection_nr
|
|
* sizeof (u_int32_t));
|
|
|
|
/* Array for width information. Because the expected width are very
|
|
small we use only one single byte. This save space and we need
|
|
not provide the information twice with both endianesses. */
|
|
ctype->width = (unsigned char *) xmalloc (ctype->plane_size
|
|
* ctype->plane_cnt);
|
|
/* Initialize with default width value. */
|
|
memset (ctype->width, charset->width_default,
|
|
ctype->plane_size * ctype->plane_cnt);
|
|
if (charset->width_rules != NULL)
|
|
{
|
|
size_t cnt;
|
|
|
|
for (cnt = 0; cnt < charset->nwidth_rules; ++cnt)
|
|
if (charset->width_rules[cnt].width != charset->width_default)
|
|
for (idx = charset->width_rules[cnt].from;
|
|
idx <= charset->width_rules[cnt].to; ++idx)
|
|
{
|
|
size_t nr = idx % ctype->plane_size;
|
|
size_t depth = 0;
|
|
|
|
while (NAMES_B1[nr + depth * ctype->plane_size] != nr)
|
|
++depth;
|
|
assert (depth < ctype->plane_cnt);
|
|
|
|
ctype->width[nr + depth * ctype->plane_size]
|
|
= charset->width_rules[cnt].width;
|
|
}
|
|
}
|
|
|
|
/* Compute MB_CUR_MAX. Please note the value mb_cur_max in the
|
|
character set definition gives the number of bytes in the wide
|
|
character representation. We compute the number of bytes used
|
|
for the UTF-8 encoded form. */
|
|
ctype->mb_cur_max = ((int []) { 2, 3, 5, 6 }) [charset->mb_cur_max - 1];
|
|
|
|
/* We need the name of the currently used 8-bit character set to
|
|
make correct conversion between this 8-bit representation and the
|
|
ISO 10646 character set used internally for wide characters. */
|
|
ctype->codeset_name = charset->code_set_name;
|
|
}
|