Sun Dec 17 15:56:35 1995 Miles Bader <miles@gnu.ai.mit.edu>
[glibc.git] / locale / locale-ctype.c
blobe7a1e97960cea4c30cf9b16625526748c1b8e245
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. */
18 #include <alloca.h>
19 #include <fcntl.h>
20 #include <libintl.h>
21 #include <locale.h>
22 #include <localeinfo.h>
23 #include <langinfo.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <netinet/in.h>
27 #include <sys/uio.h>
29 #include "localedef.h"
30 #include "token.h"
32 /* Arrays representing ctype tables. They must be initialized for the
33 right size to hold the full charmap. */
34 static u16 *ctype_b;
35 static i32 *names_b, *toupper_b, *tolower_b;
37 /* For accessing the element of the (possibly sparse) array we use this
38 macro. */
39 #define ELEM(arr, idx) \
40 (arr)[({ int h = idx % charmap_data.hash_size; \
41 int n = 0; \
42 while (n < charmap_data.hash_layers \
43 && names_b[n * charmap_data.hash_size + h] != idx) \
44 ++n; \
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. */
71 void
72 ctype_input (int token)
74 char *ptr;
75 int len;
77 /* If necessary allocate arrays. */
78 allocate_arrays ();
80 while (token != TOK_END)
82 switch (token)
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);
92 int was_ell = 0;
93 int last = -1;
95 if ((class_done & bit) != 0)
97 char tmp[len + 1];
98 memcpy (tmp, ptr, len);
99 tmp[len] = '\0';
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);
105 class_done |= bit;
109 token = xlocfile_lex (&ptr, &len);
111 if (token == TOK_ENDOFLINE)
113 SYNTAX_ERROR;
114 break;
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);
123 break;
125 was_ell = 1;
126 continue;
129 if (token != TOK_CHAR)
131 if (token != TOK_ILL_CHAR)
132 SYNTAX_ERROR;
133 was_ell = 0;
134 last = -1;
135 continue;
138 if (len < 0 || !valid_char (len))
140 was_ell = 0;
141 last = -1;
142 continue;
145 /* We have found a valid character. Include it to
146 the class' bit set. */
147 if (was_ell == 0)
149 ELEM (ctype_b, len) |= bit;
150 last = len;
152 else
154 int i;
156 if (last > len)
158 error (0, 0, gettext ("%s:%Zd: lower bound of "
159 "ellipsis not smaller"),
160 locfile_data.filename, locfile_data.line_no);
161 was_ell = 0;
162 last = -1;
163 continue;
166 for (i = last + 1; i <= len; ++i)
167 ELEM (ctype_b, i) |= bit;
169 last = -1;
171 was_ell = 0;
173 while ((token = locfile_lex (&ptr, &len)) == TOK_CHAR
174 && len == ';');
176 /* Rest of the line should be empty. */
177 ignore_to_eol (token, 0);
179 break;
180 case TOK_TOUPPER: case TOK_TOLOWER:
182 int from;
183 int to = -1;
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);
195 int ignore;
197 token = xlocfile_lex (&ptr, &len);
198 if (token != TOK_CHAR || len != '(')
200 SYNTAX_ERROR;
201 break;
204 token = xlocfile_lex (&ptr, &len);
205 if (token != TOK_CHAR && token != TOK_ILL_CHAR)
207 SYNTAX_ERROR;
208 break;
210 from = len;
211 ignore = token == TOK_ILL_CHAR;
213 token = xlocfile_lex (&ptr, &len);
214 if (token != TOK_CHAR || len != ',')
216 SYNTAX_ERROR;
217 break;
220 token = xlocfile_lex (&ptr, &len);
221 if (token != TOK_CHAR && token != TOK_ILL_CHAR)
223 SYNTAX_ERROR;
224 break;
226 to = len;
227 ignore |= token == TOK_ILL_CHAR;
229 token = xlocfile_lex (&ptr, &len);
230 if (token != TOK_CHAR || len != ')')
232 SYNTAX_ERROR;
233 break;
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
241 && len == ';');
243 /* Rest of the line should be empty. */
244 ignore_to_eol (token, 1);
246 break;
247 default:
248 SYNTAX_ERROR;
249 ignore_to_eol (0, 0);
250 break;
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);
266 else
267 ignore_to_eol (0, posix_conformance);
271 void
272 ctype_check(void)
274 /* Here are a lot of things to check. See POSIX.2, table 2-6. */
275 #define NCLASS 11
276 static const struct
278 const char *name;
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;
298 u16 tmp;
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)
307 continue;
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])
317 case 'M':
318 if (!eq)
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);
322 break;
323 case 'X':
324 if (eq)
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);
328 break;
329 case 'D':
330 ELEM (ctype_b, names_b[ch]) |= 1 << cls2;
331 break;
332 default:
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);
354 else
355 ELEM (ctype_b, space_char) |= BIT (TOK_PRINT);
359 /* These macros can change little to big endian and vice versa. */
360 #define SWAP16(v) \
361 ((u16) (((((unsigned short) (v)) & 0x00ff) << 8) \
362 | ((((unsigned short) (v)) & 0xff00) >> 8)))
363 #define SWAP32(v) \
364 ((u32) (((((u32) (v)) & 0x000000ff) << 24) \
365 | ((((u32) (v)) & 0x0000ff00) << 8) \
366 | ((((u32) (v)) & 0x00ff0000) >> 8) \
367 | ((((u32) (v)) & 0xff000000) >> 24)))
371 ctype_output (void)
373 char *path, *t;
374 int ch;
375 /* File descriptor for output file. */
376 int fd;
377 /* Magic number. */
378 i32 magic = LIMAGIC (LC_CTYPE);
379 /* Number of table. */
380 int tables = 6;
381 /* Number ints in leading information table. */
382 #if 0
383 i32 n = 2 + 2 * tables;
384 #else
385 i32 n = 5;
386 #endif
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. */
396 i32 pos[14] =
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. */
403 #if 0
404 4 * (2 + n),
405 1 + 4 * (2 + n),
406 2 + 4 * (2 + n),
407 2 + 4 * (3 + n),
408 2 + 4 * (4 + n),
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),
418 #else
419 4 * (2 + n),
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)),
424 #endif
426 /* Parameter to writev. */
427 struct iovec iov[11] =
429 { &magic, sizeof (i32) },
430 { &n, sizeof (i32) },
431 #if 0
432 { pos, sizeof (pos) },
433 { &mb_cur_min, 1 },
434 { &mb_cur_max, 1 },
435 { &hash_size, sizeof (i32) },
436 { &hash_layers, sizeof (i32) },
437 #else
438 { pos, 5 * 4 },
439 #endif
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) }
445 int result = 0;
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. */
455 ctype_b[-1] = 0;
456 toupper_b[-1] = -1;
457 tolower_b[-1] = -1;
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);
470 if (fd == -1)
472 error (0, 0, gettext ("cannot open output file `%s': %m"), path);
473 result = 1;
475 else
477 int idx;
479 #if 0
480 if (writev (fd, iov, 10) == -1)
481 #else
482 if (writev (fd, iov, 6) == -1)
483 #endif
485 error (0, 0, gettext ("cannot write output file `%s': %m"), path);
486 result = 1;
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]);
497 if (idx >= 0)
498 names_b[idx] = SWAP32 (names_b[idx]);
501 #if 0
502 if (writev (fd, iov + 5, 6) == -1)
503 #else
504 if (writev (fd, iov + 3, 2) == -1)
505 #endif
507 error (0, 0, gettext ("cannot write output file `%s': %m"), path);
508 result = 1;
511 close_and_return:
512 close (fd);
515 return result;
519 /* If necessary allocate the memory for the arrays according to the
520 current character map. */
521 static void
522 allocate_arrays (void)
524 /* Init ctype data structures. */
525 if (ctype_b == NULL)
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. */
533 int ch, h, n;
534 char *ptr;
535 int size = charmap_data.hash_size * charmap_data.hash_layers;
537 ctype_b = xmalloc ((size - (-128)) * sizeof (u16));
538 bzero (ctype_b, (size - (-128)) * sizeof (u16));
539 ctype_b += 128;
542 names_b = xmalloc (size * sizeof (i32));
543 bzero (names_b, size * sizeof (i32));
545 toupper_b = xmalloc ((size - (-128)) * sizeof (i32));
546 bzero (toupper_b, (size - (-128)) * sizeof (i32));
547 toupper_b += 128;
549 tolower_b = xmalloc ((size - (-128)) * sizeof (i32));
550 bzero (tolower_b, (size - (-128)) * sizeof (i32));
551 tolower_b += 128;
553 ptr = NULL;
554 /* Mark the place of the NUL character as occupied. */
555 names_b[0] = 1;
557 while (iterate_table (&charmap_data.table, (void **) &ptr,
558 (void **) &ch))
560 /* We already handled the NUL character. */
561 if (ch == 0)
562 continue;
564 h = ch % charmap_data.hash_size;
565 n = 0;
566 while (names_b[h + n * charmap_data.hash_size] != 0)
567 ++n;
569 names_b[h + n * charmap_data.hash_size] = ch;
570 toupper_b[h + n * charmap_data.hash_size] = ch;
571 tolower_b[h + n * charmap_data.hash_size] = ch;
573 /* Correct the value for NUL character. */
574 names_b[0] = 0;
578 static void
579 set_class_defaults (void)
581 /* These function defines the default values for the classes and conversions
582 according to POSIX.2 2.5.2.1.
583 It may seem that the order of these if-blocks is arbitrary but it is NOT.
584 Don't move them unless you know what you do! */
586 void set_default (int bit, int from, int to)
588 char tmp[4];
589 int ch;
590 /* Define string. */
591 strcpy (tmp, "<?>");
593 for (ch = from; ch <= to; ++ch)
595 int code;
596 tmp[1] = ch;
598 code = find_char (tmp + 1, 1);
599 if (code == -1)
600 error (5, 0, gettext ("character `%s' not defined while needed "
601 "as default value"), tmp);
602 ELEM (ctype_b, code) |= bit;
606 /* If necessary allocate arrays. */
607 allocate_arrays ();
609 /* Set default values if keyword was not present. */
610 if ((class_done & BIT (TOK_UPPER)) == 0)
611 /* "If this keyword [lower] is not specified, the lowercase letters
612 `A' through `Z', ..., shall automatically belong to this class,
613 with implementation defined character values." */
614 set_default (BIT (TOK_UPPER), 'A', 'Z');
616 if ((class_done & BIT (TOK_LOWER)) == 0)
617 /* "If this keyword [lower] is not specified, the lowercase letters
618 `a' through `z', ..., shall automatically belong to this class,
619 with implementation defined character values." */
620 set_default (BIT (TOK_LOWER), 'a', 'z');
622 if ((class_done & BIT (TOK_DIGIT)) == 0)
623 /* "If this keyword [digit] is not specified, the digits `0' through
624 `9', ..., shall automatically belong to this class, with
625 implementation-defined character values." */
626 set_default (BIT (TOK_DIGIT), '0', '9');
628 if ((class_done & BIT (TOK_SPACE)) == 0)
629 /* "If this keyword [space] is not specified, the characters <space>,
630 <form-feed>, <newline>, <carriage-return>, <tab>, and
631 <vertical-tab>, ..., shall automatically belong to this class,
632 with implementtation-defined character values." */
634 int code;
636 code = find_char ("space", 5);
637 if (code == -1)
638 error (5, 0, gettext ("character `%s' not defined while needed as "
639 "default value"), "<space>");
640 ELEM (ctype_b, code) |= BIT (TOK_SPACE);
642 code = find_char ("form-feed", 9);
643 if (code == -1)
644 error (5, 0, gettext ("character `%s' not defined while needed as "
645 "default value"), "<form-feed>");
646 ELEM (ctype_b, code) |= BIT (TOK_SPACE);
648 code = find_char ("newline", 7);
649 if (code == -1)
650 error (5, 0, gettext ("character `%s' not defined while needed as "
651 "default value"), "<newline>");
652 ELEM (ctype_b, code) |= BIT (TOK_SPACE);
654 code = find_char ("carriage-return", 15);
655 if (code == -1)
656 error (5, 0, gettext ("character `%s' not defined while needed as "
657 "default value"), "<carriage-return>");
658 ELEM (ctype_b, code) |= BIT (TOK_SPACE);
660 code = find_char ("tab", 3);
661 if (code == -1)
662 error (5, 0, gettext ("character `%s' not defined while needed as "
663 "default value"), "<tab>");
664 ELEM (ctype_b, code) |= BIT (TOK_SPACE);
666 code = find_char ("vertical-tab", 11);
667 if (code == -1)
668 error (5, 0, gettext ("character `%s' not defined while needed as "
669 "default value"), "<vertical-tab>");
670 ELEM (ctype_b, code) |= BIT (TOK_SPACE);
673 if ((class_done & BIT (TOK_XDIGIT)) == 0)
674 /* "If this keyword is not specified, the digits `0' to `9', the
675 uppercase letters `A' through `F', and the lowercase letters `a'
676 through `f', ..., shell automatically belong to this class, with
677 implementation defined character values." */
679 if ((class_done & BIT (TOK_XDIGIT)) == 0)
680 set_default (BIT (TOK_XDIGIT), '0', '9');
682 if ((class_done & BIT (TOK_XDIGIT)) == 0)
683 set_default (BIT (TOK_XDIGIT), 'A', 'F');
685 if ((class_done & BIT (TOK_XDIGIT)) == 0)
686 set_default (BIT (TOK_XDIGIT), 'a', 'f');
689 if ((class_done & BIT (TOK_BLANK)) == 0)
690 /* "If this keyword [blank] is unspecified, the characters <space> and
691 <tab> shall belong to this character class." */
693 int code;
695 code = find_char ("space", 5);
696 if (code == -1)
697 error (5, 0, gettext ("character `%s' not defined while needed as "
698 "default value"), "<space>");
699 ELEM (ctype_b, code) |= BIT (TOK_BLANK);
701 code = find_char ("tab", 3);
702 if (code == -1)
703 error (5, 0, gettext ("character `%s' not defined while needed as "
704 "default value"), "<tab>");
705 ELEM (ctype_b, code) |= BIT (TOK_BLANK);
708 if ((class_done & BIT (TOK_GRAPH)) == 0)
709 /* "If this keyword [graph] is not specified, characters specified for
710 the keywords `upper', `lower', `alpha', `digit', `xdigit' and `punct',
711 shall belong to this character class." */
713 int ch;
714 unsigned short int mask = BIT (TOK_UPPER) | BIT (TOK_LOWER) |
715 BIT (TOK_ALPHA) | BIT (TOK_DIGIT) | BIT (TOK_XDIGIT) | BIT (TOK_PUNCT);
717 for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
718 ++ch)
720 if (ch != 0 && names_b[ch] == 0)
721 continue;
722 if ((ELEM (ctype_b, names_b[ch]) & mask) != 0)
723 ELEM (ctype_b, names_b[ch]) |= BIT (TOK_GRAPH);
727 if ((class_done & BIT (TOK_PRINT)) == 0)
728 /* "If this keyword [print] is not provided, characters specified for
729 the keywords `upper', `lower', `alpha', `digit', `xdigit', `punct',
730 and the <space> character shall belong to this character class." */
732 int ch;
733 int space = find_char ("space", 5);
734 unsigned short int mask = BIT (TOK_UPPER) | BIT (TOK_LOWER) |
735 BIT (TOK_ALPHA) | BIT (TOK_DIGIT) | BIT (TOK_XDIGIT) | BIT (TOK_PUNCT);
737 if (space == -1)
738 error (5, 0, gettext ("character `%s' not defined while needed as "
739 "default value"), "<space>");
741 for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
742 ++ch)
744 if (ch != 0 && names_b[ch] == 0)
745 continue;
746 if ((ELEM (ctype_b, names_b[ch]) & mask) != 0)
747 ELEM (ctype_b, names_b[ch]) |= BIT (TOK_PRINT);
749 ELEM (ctype_b, space) |= BIT (TOK_PRINT);
752 if (toupper_done == 0)
753 /* "If this keyword [toupper] is not spcified, the lowercase letters
754 `a' through `z', and their corresponding uppercase letters `A' to
755 `Z', ..., shall automatically be included, with implementation-
756 defined character values." */
758 char tmp[4];
759 int ch;
761 strcpy (tmp, "<?>");
763 for (ch = 'a'; ch <= 'z'; ++ch)
765 int code_to, code_from;
767 tmp[1] = ch;
768 code_from = find_char (tmp + 1, 1);
769 if (code_from == -1)
770 error (5, 0, gettext ("character `%s' not defined while needed "
771 "as default value"), tmp);
773 /* This conversion is implementation defined. */
774 tmp[1] = ch + ('A' - 'a');
775 code_to = find_char (tmp + 1, 1);
776 if (code_to == -1)
777 error (5, 0, gettext ("character `%s' not defined while needed "
778 "as default value"), tmp);
780 ELEM (toupper_b, code_from) = code_to;
784 if (tolower_done == 0)
785 /* "If this keyword [tolower] is not specified, the mapping shall be
786 the reverse mapping of the one specified to `toupper'." */
788 int ch;
790 for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
791 ++ch)
793 if (ch != 0 && names_b[ch] == 0)
794 continue;
796 if (toupper_b[ch] != names_b[ch])
797 ELEM (tolower_b, toupper_b[ch]) = names_b[ch];
803 /* Test whether the given character is valid for the current charmap. */
804 static int
805 valid_char (int ch)
807 /* FIXME: this assumes 32-bit integers. */
808 int ok = ch >= 0
809 && (charmap_data.mb_cur_max < 4
810 ? ch < 1 << (8 * charmap_data.mb_cur_max) : 1);
812 return ok;
817 * Local Variables:
818 * mode:c
819 * c-basic-offset:2
820 * End: