Thu Jan 18 00:32:43 1996 Roland McGrath <roland@churchy.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / locale / locale-ctype.c
1 /* Copyright (C) 1995 Free Software Foundation, Inc.
2
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.
7
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.
12
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.  */
17
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>
28
29 #include "localedef.h"
30 #include "token.h"
31
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;
36
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; })]
49
50 /* The bit used for representing a special class.  */
51 #define BITPOS(class) ((class) - TOK_UPPER)
52 #define BIT(class) (1 << BITPOS (class))
53
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;
58
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);
62
63  
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);
68
69
70 /* Read CTYPE category.  The initial token is given as a parameter.  */
71 void
72 ctype_input (int token)
73 {
74   char *ptr;
75   int len;
76
77   /* If necessary allocate arrays.  */
78   allocate_arrays ();
79
80   while (token != TOK_END)
81     {
82       switch (token)
83         {
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:
87           {
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;
94
95             if ((class_done & bit) != 0)
96               {
97                 char tmp[len + 1];
98                 memcpy (tmp, ptr, len);
99                 tmp[len] = '\0';
100
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);
104               }
105             class_done |= bit;
106
107             do
108               {
109                 token = xlocfile_lex (&ptr, &len);
110
111                 if (token == TOK_ENDOFLINE)
112                   {
113                     SYNTAX_ERROR;
114                     break;
115                   }
116
117                 if (token == TOK_ELLIPSIS)
118                   {
119                     if (was_ell != 0 || last < 0)
120                       {
121                         error (0, 0, gettext ("%s:%Zd: illegal use of `...'"),
122                                locfile_data.filename, locfile_data.line_no);
123                         break;
124                       }
125                     was_ell = 1;
126                     continue;
127                   }
128
129                 if (token != TOK_CHAR)
130                   {
131                     if (token != TOK_ILL_CHAR)
132                       SYNTAX_ERROR;
133                     was_ell = 0;
134                     last = -1;
135                     continue;
136                   }
137
138                 if (len < 0 || !valid_char (len))
139                   {
140                     was_ell = 0;
141                     last = -1;
142                     continue;
143                   }
144
145                 /* We have found a valid character.  Include it to
146                    the class' bit set.  */
147                 if (was_ell == 0)
148                   {
149                     ELEM (ctype_b, len) |= bit;
150                     last = len;
151                   }
152                 else
153                   {
154                     int i;
155
156                     if (last > len)
157                       {
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;
164                       }
165
166                     for (i = last + 1; i <= len; ++i)
167                       ELEM (ctype_b, i) |= bit;
168
169                     last = -1;
170                   }
171                 was_ell = 0;
172               }
173             while ((token = locfile_lex (&ptr, &len)) == TOK_CHAR
174                    && len == ';');
175
176             /* Rest of the line should be empty.  */
177             ignore_to_eol (token, 0);
178           }
179           break;
180         case TOK_TOUPPER: case TOK_TOLOWER:
181           {
182             int from;
183             int to = -1;
184             int is_upper = token == TOK_TOUPPER;
185
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); 
192
193             do
194               {
195                 int ignore;
196
197                 token = xlocfile_lex (&ptr, &len);
198                 if (token != TOK_CHAR || len != '(')
199                   {
200                     SYNTAX_ERROR;
201                     break;
202                   }
203
204                 token = xlocfile_lex (&ptr, &len);
205                 if (token != TOK_CHAR && token != TOK_ILL_CHAR)
206                   {
207                     SYNTAX_ERROR;
208                     break;
209                   }
210                 from = len;
211                 ignore = token == TOK_ILL_CHAR;
212
213                 token = xlocfile_lex (&ptr, &len);
214                 if (token != TOK_CHAR || len != ',')
215                   {
216                     SYNTAX_ERROR;
217                     break;
218                   }
219
220                 token = xlocfile_lex (&ptr, &len);
221                 if (token != TOK_CHAR && token != TOK_ILL_CHAR)
222                   {
223                     SYNTAX_ERROR;
224                     break;
225                   }
226                 to = len;
227                 ignore |= token == TOK_ILL_CHAR;
228               
229                 token = xlocfile_lex (&ptr, &len);
230                 if (token != TOK_CHAR || len != ')')
231                   {
232                     SYNTAX_ERROR;
233                     break;
234                   }
235
236                 if (!ignore && valid_char (from) && valid_char (to))
237                   /* Have a valid pair.  */
238                   ELEM (is_upper ? toupper_b : tolower_b, from) = to;
239               }
240             while ((token = locfile_lex (&ptr, &len)) == TOK_CHAR
241                    && len == ';');
242
243             /* Rest of the line should be empty.  */
244             ignore_to_eol (token, 1);
245           }
246           break;
247         default:
248           SYNTAX_ERROR;
249           ignore_to_eol (0, 0);
250           break;
251         }
252
253       /* Read next token.  */
254       token = xlocfile_lex (&ptr, &len);
255     }
256
257   token = xlocfile_lex (&ptr, &len);
258
259   if (token != _NL_NUM_LC_CTYPE)
260     {
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);
265     }
266   else
267     ignore_to_eol (0, posix_conformance);
268 }
269
270
271 void
272 ctype_check(void)
273 {
274   /* Here are a lot of things to check.  See POSIX.2, table 2-6.  */
275   #define NCLASS 11
276   static const struct
277     {
278       const char *name;
279       const char allow[NCLASS];
280     }
281   valid_table[NCLASS] =
282     {
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-" }
296     };
297   int ch, cls1, cls2, eq, space_char;
298   u16 tmp;
299
300   /* Set default value for classes not specified.  */
301   set_class_defaults ();
302
303   /* Check according to table.  */
304   for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers; ++ch)
305     {
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] != '-')
313               {
314                 eq = (tmp & (1 << cls2)) != 0;
315                 switch (valid_table[cls1].allow[cls2])
316                   {
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__);
335                   }
336               }
337     }
338
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);
356 }
357
358
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)))
368
369
370 int
371 ctype_output (void)
372 {
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] =
397     {
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.  */
402
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
425     };
426   /* Parameter to writev.  */
427   struct iovec iov[11] = 
428     { 
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) }
444     };
445   int result = 0;
446   
447   /* Now we can bring the representations into the right form.  */
448   for (ch = -128; ch < -1; ++ch)
449     {
450       ctype_b[ch] = ctype_b[256 + ch];
451       toupper_b[ch] = toupper_b[256 + ch];
452       tolower_b[ch] = tolower_b[256 + ch];
453     }
454   /* Set value for EOF.  */
455   ctype_b[-1] = 0;
456   toupper_b[-1] = -1;
457   tolower_b[-1] = -1;
458
459   for (ch = -128; ch < size; ++ch)
460     ctype_b[ch] = htons (ctype_b[ch]);
461
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);
468
469   fd = creat (path, 0666);
470   if (fd == -1)
471     {
472       error (0, 0, gettext ("cannot open output file `%s': %m"), path);
473       result = 1;
474     }
475   else
476     {
477       int idx;
478
479 #if 0
480       if (writev (fd, iov, 10) == -1)
481 #else
482       if (writev (fd, iov, 6) == -1)
483 #endif
484         {
485           error (0, 0, gettext ("cannot write output file `%s': %m"), path);
486           result = 1;
487           goto close_and_return;
488         }
489
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)
493         {
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]);
499         }
500
501 #if 0
502       if (writev (fd, iov + 5, 6) == -1)
503 #else
504       if (writev (fd, iov + 3, 2) == -1)
505 #endif
506         {
507           error (0, 0, gettext ("cannot write output file `%s': %m"), path);
508           result = 1;
509         }
510
511       close_and_return:
512       close (fd);
513     }
514
515   return result;
516 }
517
518
519 /* If necessary allocate the memory for the arrays according to the
520    current character map.  */
521 static void
522 allocate_arrays (void)
523 {
524   /* Init ctype data structures.  */
525   if (ctype_b == NULL)
526     /* All data structures are not initialized yet.  */
527     {
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;
536
537       ctype_b = xmalloc ((size - (-128)) * sizeof (u16));
538       bzero (ctype_b, (size - (-128)) * sizeof (u16));
539       ctype_b += 128;
540
541
542       names_b = xmalloc (size * sizeof (i32));
543       bzero (names_b, size * sizeof (i32));
544
545       toupper_b = xmalloc ((size - (-128)) * sizeof (i32));
546       bzero (toupper_b, (size - (-128)) * sizeof (i32));
547       toupper_b += 128;
548
549       tolower_b = xmalloc ((size - (-128)) * sizeof (i32));
550       bzero (tolower_b, (size - (-128)) * sizeof (i32));
551       tolower_b += 128;
552
553       ptr = NULL;
554       /* Mark the place of the NUL character as occupied.  */
555       names_b[0] = 1;
556
557       while (iterate_table (&charmap_data.table, (void **) &ptr,
558                             (void **) &ch))
559         {
560           /* We already handled the NUL character.  */
561           if (ch == 0)
562             continue;
563
564           h = ch % charmap_data.hash_size;
565           n = 0;
566           while (names_b[h + n * charmap_data.hash_size] != 0)
567             ++n;
568
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;
572         }
573       /* Correct the value for NUL character.  */
574       names_b[0] = 0;
575     }
576 }
577
578 static void
579 set_class_defaults (void)
580 {
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!  */
585
586   void set_default (int bit, int from, int to)
587     {
588       char tmp[4];
589       int ch;
590       /* Define string.  */
591       strcpy (tmp, "<?>");
592
593       for (ch = from; ch <= to; ++ch)
594         {
595           int code;
596           tmp[1] = ch;
597
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;
603         }
604     }
605
606   /* If necessary allocate arrays.  */
607   allocate_arrays ();
608
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');
615
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');
621
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');
627
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."  */
633     {
634       int code;
635
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);
641
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);
647
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);
653
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);
659
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);
665
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);
671     }
672   
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."  */
678     {
679       if ((class_done & BIT (TOK_XDIGIT)) == 0)
680         set_default (BIT (TOK_XDIGIT), '0', '9');
681
682       if ((class_done & BIT (TOK_XDIGIT)) == 0)
683         set_default (BIT (TOK_XDIGIT), 'A', 'F');
684
685       if ((class_done & BIT (TOK_XDIGIT)) == 0)
686         set_default (BIT (TOK_XDIGIT), 'a', 'f');
687     }
688
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."  */
692    {
693       int code;
694
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);
700
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);
706     }
707
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."  */
712     {
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);
716
717       for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
718                    ++ch)
719         {
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);
724         }
725     }
726
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."  */
731     {
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);
736
737       if (space == -1)
738         error (5, 0, gettext ("character `%s' not defined while needed as "
739                               "default value"), "<space>");
740
741       for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
742                    ++ch)
743         {
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);
748         }
749       ELEM (ctype_b, space) |= BIT (TOK_PRINT);
750     }
751
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."  */
757     {
758       char tmp[4];
759       int ch;
760
761       strcpy (tmp, "<?>");
762
763       for (ch = 'a'; ch <= 'z'; ++ch)
764         {
765           int code_to, code_from;
766
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);
772
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);
779
780           ELEM (toupper_b, code_from) = code_to;
781         }
782     }
783
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'."  */
787     {
788       int ch;
789
790       for (ch = 0; ch < charmap_data.hash_size * charmap_data.hash_layers;
791                    ++ch)
792         {
793           if (ch != 0 && names_b[ch] == 0)
794             continue;
795
796           if (toupper_b[ch] != names_b[ch])
797             ELEM (tolower_b, toupper_b[ch]) = names_b[ch];
798         }
799     }
800 }
801
802
803 /* Test whether the given character is valid for the current charmap.  */
804 static int
805 valid_char (int ch)
806 {
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);
811
812   return ok;
813 }
814
815
816 /*
817  * Local Variables:
818  *  mode:c
819  *  c-basic-offset:2
820  * End:
821  */