1 /* Copyright (C) 1995 Free Software Foundation, Inc.
3 The GNU C Library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Library General Public License as
5 published by the Free Software Foundation; either version 2 of the
6 License, or (at your option) any later version.
8 The GNU C Library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
13 You should have received a copy of the GNU Library General Public
14 License along with the GNU C Library; see the file COPYING.LIB. If
15 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
16 Cambridge, MA 02139, USA. */
22 #include <localeinfo.h>
26 #include <netinet/in.h>
29 #include "localedef.h"
32 /* Arrays representing ctype tables. They must be initialized for the
33 right size to hold the full charmap. */
35 static i32
*names_b
, *toupper_b
, *tolower_b
;
37 /* For accessing the element of the (possibly sparse) array we use this
39 #define ELEM(arr, idx) \
40 (arr)[({ int h = idx % charmap_data.hash_size; \
42 while (n < charmap_data.hash_layers \
43 && names_b[n * charmap_data.hash_size + h] != idx) \
45 if (n >= charmap_data.hash_layers) \
46 error (6, 0, gettext ("internal error in %s, line %u"), \
47 __FUNCTION__, __LINE__); \
48 n * charmap_data.hash_size + h; })]
50 /* The bit used for representing a special class. */
51 #define BITPOS(class) ((class) - TOK_UPPER)
52 #define BIT(class) (1 << BITPOS (class))
54 /* Remember which class or conversion is already done. */
55 static unsigned short class_done
= 0;
56 static unsigned short toupper_done
= 0;
57 static unsigned short tolower_done
= 0;
59 #define SYNTAX_ERROR \
60 error (0, 0, gettext ("%s:%Zd: syntax error in locale definition file"), \
61 locfile_data.filename, locfile_data.line_no);
64 /* Prototypes for local functions. */
65 static void allocate_arrays (void);
66 static void set_class_defaults (void);
67 static int valid_char (int ch
);
70 /* Read CTYPE category. The initial token is given as a parameter. */
72 ctype_input (int token
)
77 /* If necessary allocate arrays. */
80 while (token
!= TOK_END
)
84 case TOK_UPPER
: case TOK_LOWER
: case TOK_ALPHA
: case TOK_DIGIT
:
85 case TOK_XDIGIT
: case TOK_SPACE
: case TOK_PRINT
: case TOK_GRAPH
:
86 case TOK_BLANK
: case TOK_CNTRL
: case TOK_PUNCT
:
88 /* TAKE CARE: the order of the tokens in "token.h" determines
89 the bit used to indicate the membership in the class. This
90 also has to correspond to the values used in <ctype.h>. */
91 int bit
= BIT (token
);
95 if ((class_done
& bit
) != 0)
98 memcpy (tmp
, ptr
, len
);
101 error (0, 0, gettext ("%s:%Zd: duplicate definiton of item "
102 "`%s' in category `LC_CTYPE'"),
103 locfile_data
.filename
, locfile_data
.line_no
, tmp
);
109 token
= xlocfile_lex (&ptr
, &len
);
111 if (token
== TOK_ENDOFLINE
)
117 if (token
== TOK_ELLIPSIS
)
119 if (was_ell
!= 0 || last
< 0)
121 error (0, 0, gettext ("%s:%Zd: illegal use of `...'"),
122 locfile_data
.filename
, locfile_data
.line_no
);
129 if (token
!= TOK_CHAR
)
131 if (token
!= TOK_ILL_CHAR
)
138 if (len
< 0 || !valid_char (len
))
145 /* We have found a valid character. Include it to
146 the class' bit set. */
149 ELEM (ctype_b
, len
) |= bit
;
158 error (0, 0, gettext ("%s:%Zd: lower bound of "
159 "ellipsis not smaller"),
160 locfile_data
.filename
, locfile_data
.line_no
);
166 for (i
= last
+ 1; i
<= len
; ++i
)
167 ELEM (ctype_b
, i
) |= bit
;
173 while ((token
= locfile_lex (&ptr
, &len
)) == TOK_CHAR
176 /* Rest of the line should be empty. */
177 ignore_to_eol (token
, 0);
180 case TOK_TOUPPER
: case TOK_TOLOWER
:
184 int is_upper
= token
== TOK_TOUPPER
;
186 if (((is_upper
? toupper_done
: tolower_done
) & BIT (token
)) != 0)
187 error (0, 0, gettext ("%s:%Zd: duplicate definition of item "
188 "`%s' in category `LC_CTYPE'"),
189 locfile_data
.filename
, locfile_data
.line_no
,
190 is_upper
? "toupper" : "tolower");
191 (is_upper
? toupper_done
: tolower_done
) |= BIT (token
);
197 token
= xlocfile_lex (&ptr
, &len
);
198 if (token
!= TOK_CHAR
|| len
!= '(')
204 token
= xlocfile_lex (&ptr
, &len
);
205 if (token
!= TOK_CHAR
&& token
!= TOK_ILL_CHAR
)
211 ignore
= token
== TOK_ILL_CHAR
;
213 token
= xlocfile_lex (&ptr
, &len
);
214 if (token
!= TOK_CHAR
|| len
!= ',')
220 token
= xlocfile_lex (&ptr
, &len
);
221 if (token
!= TOK_CHAR
&& token
!= TOK_ILL_CHAR
)
227 ignore
|= token
== TOK_ILL_CHAR
;
229 token
= xlocfile_lex (&ptr
, &len
);
230 if (token
!= TOK_CHAR
|| len
!= ')')
236 if (!ignore
&& valid_char (from
) && valid_char (to
))
237 /* Have a valid pair. */
238 ELEM (is_upper
? toupper_b
: tolower_b
, from
) = to
;
240 while ((token
= locfile_lex (&ptr
, &len
)) == TOK_CHAR
243 /* Rest of the line should be empty. */
244 ignore_to_eol (token
, 1);
249 ignore_to_eol (0, 0);
253 /* Read next token. */
254 token
= xlocfile_lex (&ptr
, &len
);
257 token
= xlocfile_lex (&ptr
, &len
);
259 if (token
!= _NL_NUM_LC_CTYPE
)
261 error (0, 0, gettext ("%s:%Zd: category `%s' does not end with "
262 "`END %s'"), locfile_data
.filename
,
263 locfile_data
.line_no
, "LC_CTYPE", "LC_CTYPE");
264 ignore_to_eol (0, 0);
267 ignore_to_eol (0, posix_conformance
);
274 /* Here are a lot of things to check. See POSIX.2, table 2-6. */
279 const char allow
[NCLASS
];
281 valid_table
[NCLASS
] =
283 /* The order is important. See token.h for more information.
284 M = Always, D = Default, - = Permitted, X = Mutually exclusive */
285 [BITPOS (TOK_UPPER
)] = { "upper", "--MX-XDDXXX" },
286 [BITPOS (TOK_LOWER
)] = { "lower", "--MX-XDDXXX" },
287 [BITPOS (TOK_ALPHA
)] = { "alpha", "---X-XDDXXX" },
288 [BITPOS (TOK_DIGIT
)] = { "digit", "XXX--XDDXXX" },
289 [BITPOS (TOK_XDIGIT
)] = { "xdigit", "-----XDDXXX" },
290 [BITPOS (TOK_SPACE
)] = { "space", "XXXXX------" },
291 [BITPOS (TOK_PRINT
)] = { "print", "---------X-" },
292 [BITPOS (TOK_GRAPH
)] = { "graph", "---------X-" },
293 [BITPOS (TOK_BLANK
)] = { "blank", "XXXXXM-----" },
294 [BITPOS (TOK_CNTRL
)] = { "cntrl", "XXXXX-XX--X" },
295 [BITPOS (TOK_PUNCT
)] = { "punct", "XXXXX-DD-X-" }
297 int ch
, cls1
, cls2
, eq
, space_char
;
300 /* Set default value for classes not specified. */
301 set_class_defaults ();
303 /* Check according to table. */
304 for (ch
= 0; ch
< charmap_data
.hash_size
* charmap_data
.hash_layers
; ++ch
)
306 if (ch
!= 0 && names_b
[ch
] == 0)
308 tmp
= ELEM (ctype_b
, names_b
[ch
]);
309 for (cls1
= 0; cls1
< NCLASS
; ++cls1
)
310 if ((tmp
& (1 << cls1
)) != 0)
311 for (cls2
= 0; cls2
< NCLASS
; ++cls2
)
312 if (cls2
!= cls1
&& valid_table
[cls1
].allow
[cls2
] != '-')
314 eq
= (tmp
& (1 << cls2
)) != 0;
315 switch (valid_table
[cls1
].allow
[cls2
])
319 error (0, 0, gettext ("character '\\%o' in class `%s' "
320 "must be in class `%s'"), ch
,
321 valid_table
[cls1
].name
, valid_table
[cls2
].name
);
325 error (0, 0, gettext ("character '\\%o' inc class `%s' "
326 "must not be in class `%s'"), ch
,
327 valid_table
[cls1
].name
, valid_table
[cls2
].name
);
330 ELEM (ctype_b
, names_b
[ch
]) |= 1 << cls2
;
333 error (5, 0, gettext ("internal error in %s, line %u"),
334 __FUNCTION__
, __LINE__
);
339 /* ... and now test <SP> as a special case. */
340 if (find_entry (&charmap_data
.table
, "SP", 2, (void **) &space_char
) == 0)
341 error (0, 0, gettext ("character <SP> not defined in character map"));
342 else if ((tmp
= BITPOS (TOK_SPACE
),
343 (ELEM (ctype_b
, space_char
) & BIT (TOK_SPACE
)) == 0)
344 || (tmp
= BITPOS (TOK_BLANK
),
345 (ELEM (ctype_b
, space_char
) & BIT (TOK_BLANK
)) == 0))
346 error (0, 0, gettext ("<SP> character not in class `%s'"),
347 valid_table
[tmp
].name
);
348 else if ((tmp
= BITPOS (TOK_PUNCT
),
349 (ELEM (ctype_b
, space_char
) & BIT (TOK_PUNCT
)) != 0)
350 || (tmp
= BITPOS (TOK_GRAPH
),
351 (ELEM (ctype_b
, space_char
) & BIT (TOK_GRAPH
)) != 0))
352 error (0, 0, gettext ("<SP> character must not be in class `%s'"),
353 valid_table
[tmp
].name
);
355 ELEM (ctype_b
, space_char
) |= BIT (TOK_PRINT
);
359 /* These macros can change little to big endian and vice versa. */
361 ((u16) (((((unsigned short) (v)) & 0x00ff) << 8) \
362 | ((((unsigned short) (v)) & 0xff00) >> 8)))
364 ((u32) (((((u32) (v)) & 0x000000ff) << 24) \
365 | ((((u32) (v)) & 0x0000ff00) << 8) \
366 | ((((u32) (v)) & 0x00ff0000) >> 8) \
367 | ((((u32) (v)) & 0xff000000) >> 24)))
375 /* File descriptor for output file. */
378 i32 magic
= LIMAGIC (LC_CTYPE
);
379 /* Number of table. */
381 /* Number ints in leading information table. */
383 i32 n
= 2 + 2 * tables
;
387 /* Values describing the character set. */
388 char mb_cur_min
= (char) charmap_data
.mb_cur_min
;
389 char mb_cur_max
= (char) charmap_data
.mb_cur_max
;
390 /* Optimal size of hashing table. */
391 i32 hash_size
= charmap_data
.hash_size
;
392 i32 hash_layers
= charmap_data
.hash_layers
;
393 /* Number of elements in the tables. */
394 int size
= hash_size
* charmap_data
.hash_layers
;
395 /* Positions of the tables. */
398 /* No, no. We don't play towers of Hanoi. This is a more or less
399 readable table of the offsets of the different strings in the
400 produced file. It is seperated in three columns which represent
401 the number of values with 1, 2, and 4 bytes. */
409 2 + 2 * (128 + size
) + 4 * (4 + n
),
410 2 + 2 * (128 + size
) + 4 * ((4 + n
) + (size
+ 128)),
411 2 + 2 * (128 + size
) + 4 * ((4 + n
) + 2 * (size
+ 128)),
412 2 + 2 * (128 + size
) + 4 * ((4 + n
) + 2 * (size
+ 128) + 1 * size
),
413 2 + 2 * (128 + size
) + 4 * ((5 + n
) + 2 * (size
+ 128) + 1 * size
),
414 2 + 2 * (128 + size
) + 4 * ((6 + n
) + 2 * (size
+ 128) + 1 * size
),
415 2 + 2 * (2 * (128 + size
)) + 4 * ((6 + n
) + 2 * (size
+ 128) + 1 * size
),
416 2 + 2 * (2 * (128 + size
)) + 4 * ((6 + n
) + 3 * (size
+ 128) + 1 * size
),
417 2 + 2 * (2 * (128 + size
)) + 4 * ((6 + n
) + 4 * (size
+ 128) + 1 * size
),
420 2 * (128 + size
) + 4 * (2 + n
),
421 2 * (128 + size
) + 4 * ((2 + n
) + (size
+ 128)),
422 2 * (128 + size
) + 4 * ((2 + n
) + 2 * (size
+ 128)),
423 2 * (128 + size
) + 4 * ((2 + n
) + 3 * (size
+ 128)),
426 /* Parameter to writev. */
427 struct iovec iov
[11] =
429 { &magic
, sizeof (i32
) },
430 { &n
, sizeof (i32
) },
432 { pos
, sizeof (pos
) },
435 { &hash_size
, sizeof (i32
) },
436 { &hash_layers
, sizeof (i32
) },
440 { ctype_b
- 128, (size
+ 128) * sizeof (u16
) },
441 { toupper_b
- 128, (size
+ 128) * sizeof (i32
) },
442 { tolower_b
- 128, (size
+ 128) * sizeof (i32
) },
443 { names_b
, size
* sizeof (i32
) }
447 /* Now we can bring the representations into the right form. */
448 for (ch
= -128; ch
< -1; ++ch
)
450 ctype_b
[ch
] = ctype_b
[256 + ch
];
451 toupper_b
[ch
] = toupper_b
[256 + ch
];
452 tolower_b
[ch
] = tolower_b
[256 + ch
];
454 /* Set value for EOF. */
459 for (ch
= -128; ch
< size
; ++ch
)
460 ctype_b
[ch
] = htons (ctype_b
[ch
]);
462 /* Construct the output filename from the argument given to
463 localedef on the command line. */
464 path
= (char *) alloca (strlen (output_path
) +
465 strlen (category
[LC_CTYPE
].name
) + 1);
466 t
= stpcpy (path
, output_path
);
467 strcpy (t
, category
[LC_CTYPE
].name
);
469 fd
= creat (path
, 0666);
472 error (0, 0, gettext ("cannot open output file `%s': %m"), path
);
480 if (writev (fd
, iov
, 10) == -1)
482 if (writev (fd
, iov
, 6) == -1)
485 error (0, 0, gettext ("cannot write output file `%s': %m"), path
);
487 goto close_and_return
;
490 /* Now we have to write the three tables with different endianess. */
491 hash_size
= SWAP32 (hash_size
);
492 for (idx
= -128; idx
< size
; ++idx
)
494 ctype_b
[idx
] = SWAP16 (ctype_b
[idx
]);
495 toupper_b
[idx
] = SWAP32 (toupper_b
[idx
]);
496 tolower_b
[idx
] = SWAP32 (tolower_b
[idx
]);
498 names_b
[idx
] = SWAP32 (names_b
[idx
]);
502 if (writev (fd
, iov
+ 5, 6) == -1)
504 if (writev (fd
, iov
+ 3, 2) == -1)
507 error (0, 0, gettext ("cannot write output file `%s': %m"), path
);
519 /* If necessary allocate the memory for the arrays according to the
520 current character map. */
522 allocate_arrays (void)
524 /* Init ctype data structures. */
526 /* All data structures are not initialized yet. */
528 /* You wonder about this amount of memory? This is only because
529 some users do not manage to address the array with unsigned
530 values or data types with range >= 256. '\200' would result
531 in the array index -128. To help these poor people we
532 duplicate the entries for 128 upto 255 below the entry for \0. */
535 int size
= charmap_data
.hash_size
* charmap_data
.hash_layers
;
537 ctype_b
= (u16
*) xcalloc (size
- (-128), sizeof (u16
));
541 names_b
= (i32
*) xcalloc (size
, sizeof (i32
));
543 toupper_b
= (i32
*) xcalloc ((size
- (-128)), sizeof (i32
));
546 tolower_b
= (i32
*) xcalloc ((size
- (-128)), sizeof (i32
));
550 /* Mark the place of the NUL character as occupied. */
553 while (iterate_table (&charmap_data
.table
, (void **) &ptr
,
556 /* We already handled the NUL character. */
560 h
= ch
% charmap_data
.hash_size
;
562 while (names_b
[h
+ n
* charmap_data
.hash_size
] != 0)
565 names_b
[h
+ n
* charmap_data
.hash_size
] = ch
;
566 toupper_b
[h
+ n
* charmap_data
.hash_size
] = ch
;
567 tolower_b
[h
+ n
* charmap_data
.hash_size
] = ch
;
569 /* Correct the value for NUL character. */
575 set_class_defaults (void)
577 /* These function defines the default values for the classes and conversions
578 according to POSIX.2 2.5.2.1.
579 It may seem that the order of these if-blocks is arbitrary but it is NOT.
580 Don't move them unless you know what you do! */
582 void set_default (int bit
, int from
, int to
)
589 for (ch
= from
; ch
<= to
; ++ch
)
594 code
= find_char (tmp
+ 1, 1);
596 error (5, 0, gettext ("character `%s' not defined while needed "
597 "as default value"), tmp
);
598 ELEM (ctype_b
, code
) |= bit
;
602 /* If necessary allocate arrays. */
605 /* Set default values if keyword was not present. */
606 if ((class_done
& BIT (TOK_UPPER
)) == 0)
607 /* "If this keyword [lower] is not specified, the lowercase letters
608 `A' through `Z', ..., shall automatically belong to this class,
609 with implementation defined character values." */
610 set_default (BIT (TOK_UPPER
), 'A', 'Z');
612 if ((class_done
& BIT (TOK_LOWER
)) == 0)
613 /* "If this keyword [lower] is not specified, the lowercase letters
614 `a' through `z', ..., shall automatically belong to this class,
615 with implementation defined character values." */
616 set_default (BIT (TOK_LOWER
), 'a', 'z');
618 if ((class_done
& BIT (TOK_DIGIT
)) == 0)
619 /* "If this keyword [digit] is not specified, the digits `0' through
620 `9', ..., shall automatically belong to this class, with
621 implementation-defined character values." */
622 set_default (BIT (TOK_DIGIT
), '0', '9');
624 if ((class_done
& BIT (TOK_SPACE
)) == 0)
625 /* "If this keyword [space] is not specified, the characters <space>,
626 <form-feed>, <newline>, <carriage-return>, <tab>, and
627 <vertical-tab>, ..., shall automatically belong to this class,
628 with implementtation-defined character values." */
632 code
= find_char ("space", 5);
634 error (5, 0, gettext ("character `%s' not defined while needed as "
635 "default value"), "<space>");
636 ELEM (ctype_b
, code
) |= BIT (TOK_SPACE
);
638 code
= find_char ("form-feed", 9);
640 error (5, 0, gettext ("character `%s' not defined while needed as "
641 "default value"), "<form-feed>");
642 ELEM (ctype_b
, code
) |= BIT (TOK_SPACE
);
644 code
= find_char ("newline", 7);
646 error (5, 0, gettext ("character `%s' not defined while needed as "
647 "default value"), "<newline>");
648 ELEM (ctype_b
, code
) |= BIT (TOK_SPACE
);
650 code
= find_char ("carriage-return", 15);
652 error (5, 0, gettext ("character `%s' not defined while needed as "
653 "default value"), "<carriage-return>");
654 ELEM (ctype_b
, code
) |= BIT (TOK_SPACE
);
656 code
= find_char ("tab", 3);
658 error (5, 0, gettext ("character `%s' not defined while needed as "
659 "default value"), "<tab>");
660 ELEM (ctype_b
, code
) |= BIT (TOK_SPACE
);
662 code
= find_char ("vertical-tab", 11);
664 error (5, 0, gettext ("character `%s' not defined while needed as "
665 "default value"), "<vertical-tab>");
666 ELEM (ctype_b
, code
) |= BIT (TOK_SPACE
);
669 if ((class_done
& BIT (TOK_XDIGIT
)) == 0)
670 /* "If this keyword is not specified, the digits `0' to `9', the
671 uppercase letters `A' through `F', and the lowercase letters `a'
672 through `f', ..., shell automatically belong to this class, with
673 implementation defined character values." */
675 if ((class_done
& BIT (TOK_XDIGIT
)) == 0)
676 set_default (BIT (TOK_XDIGIT
), '0', '9');
678 if ((class_done
& BIT (TOK_XDIGIT
)) == 0)
679 set_default (BIT (TOK_XDIGIT
), 'A', 'F');
681 if ((class_done
& BIT (TOK_XDIGIT
)) == 0)
682 set_default (BIT (TOK_XDIGIT
), 'a', 'f');
685 if ((class_done
& BIT (TOK_BLANK
)) == 0)
686 /* "If this keyword [blank] is unspecified, the characters <space> and
687 <tab> shall belong to this character class." */
691 code
= find_char ("space", 5);
693 error (5, 0, gettext ("character `%s' not defined while needed as "
694 "default value"), "<space>");
695 ELEM (ctype_b
, code
) |= BIT (TOK_BLANK
);
697 code
= find_char ("tab", 3);
699 error (5, 0, gettext ("character `%s' not defined while needed as "
700 "default value"), "<tab>");
701 ELEM (ctype_b
, code
) |= BIT (TOK_BLANK
);
704 if ((class_done
& BIT (TOK_GRAPH
)) == 0)
705 /* "If this keyword [graph] is not specified, characters specified for
706 the keywords `upper', `lower', `alpha', `digit', `xdigit' and `punct',
707 shall belong to this character class." */
710 unsigned short int mask
= BIT (TOK_UPPER
) | BIT (TOK_LOWER
) |
711 BIT (TOK_ALPHA
) | BIT (TOK_DIGIT
) | BIT (TOK_XDIGIT
) | BIT (TOK_PUNCT
);
713 for (ch
= 0; ch
< charmap_data
.hash_size
* charmap_data
.hash_layers
;
716 if (ch
!= 0 && names_b
[ch
] == 0)
718 if ((ELEM (ctype_b
, names_b
[ch
]) & mask
) != 0)
719 ELEM (ctype_b
, names_b
[ch
]) |= BIT (TOK_GRAPH
);
723 if ((class_done
& BIT (TOK_PRINT
)) == 0)
724 /* "If this keyword [print] is not provided, characters specified for
725 the keywords `upper', `lower', `alpha', `digit', `xdigit', `punct',
726 and the <space> character shall belong to this character class." */
729 int space
= find_char ("space", 5);
730 unsigned short int mask
= BIT (TOK_UPPER
) | BIT (TOK_LOWER
) |
731 BIT (TOK_ALPHA
) | BIT (TOK_DIGIT
) | BIT (TOK_XDIGIT
) | BIT (TOK_PUNCT
);
734 error (5, 0, gettext ("character `%s' not defined while needed as "
735 "default value"), "<space>");
737 for (ch
= 0; ch
< charmap_data
.hash_size
* charmap_data
.hash_layers
;
740 if (ch
!= 0 && names_b
[ch
] == 0)
742 if ((ELEM (ctype_b
, names_b
[ch
]) & mask
) != 0)
743 ELEM (ctype_b
, names_b
[ch
]) |= BIT (TOK_PRINT
);
745 ELEM (ctype_b
, space
) |= BIT (TOK_PRINT
);
748 if (toupper_done
== 0)
749 /* "If this keyword [toupper] is not spcified, the lowercase letters
750 `a' through `z', and their corresponding uppercase letters `A' to
751 `Z', ..., shall automatically be included, with implementation-
752 defined character values." */
759 for (ch
= 'a'; ch
<= 'z'; ++ch
)
761 int code_to
, code_from
;
764 code_from
= find_char (tmp
+ 1, 1);
766 error (5, 0, gettext ("character `%s' not defined while needed "
767 "as default value"), tmp
);
769 /* This conversion is implementation defined. */
770 tmp
[1] = ch
+ ('A' - 'a');
771 code_to
= find_char (tmp
+ 1, 1);
773 error (5, 0, gettext ("character `%s' not defined while needed "
774 "as default value"), tmp
);
776 ELEM (toupper_b
, code_from
) = code_to
;
780 if (tolower_done
== 0)
781 /* "If this keyword [tolower] is not specified, the mapping shall be
782 the reverse mapping of the one specified to `toupper'." */
786 for (ch
= 0; ch
< charmap_data
.hash_size
* charmap_data
.hash_layers
;
789 if (ch
!= 0 && names_b
[ch
] == 0)
792 if (toupper_b
[ch
] != names_b
[ch
])
793 ELEM (tolower_b
, toupper_b
[ch
]) = names_b
[ch
];
799 /* Test whether the given character is valid for the current charmap. */
803 /* FIXME: this assumes 32-bit integers. */
805 && (charmap_data
.mb_cur_max
< 4
806 ? ch
< 1 << (8 * charmap_data
.mb_cur_max
) : 1);