Mon May 13 12:03:03 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[kopensolaris-gnu/glibc.git] / locale / programs / ld-ctype.c
1 /* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper, <drepper@gnu.ai.mit.edu>.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB.  If
17 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <endian.h>
25 #include <limits.h>
26 #include <string.h>
27
28 #include "locales.h"
29 #include "localeinfo.h"
30 #include "langinfo.h"
31 #include "locfile-token.h"
32 #include "stringtrans.h"
33
34 /* Uncomment the following line in the production version.  */
35 /* define NDEBUG 1 */
36 #include <assert.h>
37
38
39 void *xmalloc (size_t __n);
40 void *xcalloc (size_t __n, size_t __s);
41 void *xrealloc (void *__ptr, size_t __n);
42
43
44 /* The bit used for representing a special class.  */
45 #define BITPOS(class) ((class) - tok_upper)
46 #define BIT(class) (1 << BITPOS (class))
47
48 #define ELEM(ctype, collection, idx, value)                                   \
49   *find_idx (ctype, &ctype->collection idx, &ctype->collection##_max idx,     \
50              &ctype->collection##_act idx, value)
51
52 #define SWAPU32(w) \
53   (((w) << 24) | (((w) & 0xff00) << 8) | (((w) >> 8) & 0xff00) | ((w) >> 24))
54
55 #define SWAPU16(w) \
56   ((((w)  >> 8) & 0xff) | (((w) & 0xff) << 8))
57
58
59 /* To be compatible with former implementations we for now restrict
60    the number of bits for character classes to 16.  When compatibility
61    is not necessary anymore increase the number to 32.  */
62 #define char_class_t u_int16_t
63 #define CHAR_CLASS_TRANS SWAPU16
64 #define char_class32_t u_int32_t
65 #define CHAR_CLASS32_TRANS SWAPU32
66
67
68 /* The real definition of the struct for the LC_CTYPE locale.  */
69 struct locale_ctype_t
70 {
71   unsigned int *charnames;
72   size_t charnames_max;
73   size_t charnames_act;
74
75   /* We will allow up to 8 * sizeof(u_int32_t) - 1 character classes.  */
76 #define MAX_NR_CHARCLASS (8 * sizeof (u_int32_t) - 1)
77   int nr_charclass;
78   const char *classnames[MAX_NR_CHARCLASS];
79   unsigned long int current_class_mask;
80   unsigned int last_class_char;
81   u_int32_t *class_collection;
82   size_t class_collection_max;
83   size_t class_collection_act;
84   unsigned long int class_done;
85
86   /* If the following number ever turns out to be too small simply
87      increase it.  But I doubt it will.  --drepper@gnu */
88 #define MAX_NR_CHARMAP 16
89   const char *mapnames[MAX_NR_CHARMAP];
90   u_int32_t *map_collection[MAX_NR_CHARMAP];
91   u_int32_t map_collection_max[MAX_NR_CHARMAP];
92   u_int32_t map_collection_act[MAX_NR_CHARMAP];
93   size_t map_collection_nr;
94   size_t last_map_idx;
95   unsigned int from_map_char;
96   int toupper_done;
97   int tolower_done;
98
99   /* The arrays for the binary representation.  */
100   u_int32_t plane_size;
101   u_int32_t plane_cnt;
102   char_class_t *ctype_b;
103   char_class32_t *ctype32_b;
104   u_int32_t *names_el;
105   u_int32_t *names_eb;
106   u_int32_t **map_eb;
107   u_int32_t **map_el;
108   u_int32_t *class_name_ptr;
109   u_int32_t *map_name_ptr;
110   unsigned char *width;
111 };
112
113
114 /* Prototypes for local functions.  */
115 static void ctype_class_newP (struct linereader *lr,
116                               struct locale_ctype_t *ctype, const char *name);
117 static void ctype_map_newP (struct linereader *lr,
118                             struct locale_ctype_t *ctype,
119                             const char *name, struct charset_t *charset);
120 static u_int32_t *find_idx (struct locale_ctype_t *ctype, u_int32_t **table,
121                             size_t *max, size_t *act, unsigned int idx);
122 static void set_class_defaults (struct locale_ctype_t *ctype,
123                                 struct charset_t *charset);
124 static void allocate_arrays (struct locale_ctype_t *ctype,
125                              struct charset_t *charset);
126
127
128 void
129 ctype_startup (struct linereader *lr, struct localedef_t *locale,
130                struct charset_t *charset)
131 {
132   unsigned int cnt;
133   struct locale_ctype_t *ctype;
134
135   /* It is important that we always use UCS1 encoding for strings now.  */
136   encoding_method = ENC_UCS1;
137
138   /* Allocate the needed room.  */
139   locale->categories[LC_CTYPE].ctype = ctype =
140     (struct locale_ctype_t *) xmalloc (sizeof (struct locale_ctype_t));
141
142   /* We have no names seen yet.  */
143   ctype->charnames_max = charset->mb_cur_max == 1 ? 256 : 512;
144   ctype->charnames =
145     (unsigned int *) xmalloc (ctype->charnames_max * sizeof (unsigned int));
146   for (cnt = 0; cnt < 256; ++cnt)
147     ctype->charnames[cnt] = cnt;
148   ctype->charnames_act = 256;
149
150   /* Fill character class information.  */
151   ctype->nr_charclass = 0;
152   ctype->current_class_mask = 0;
153   ctype->last_class_char = ILLEGAL_CHAR_VALUE;
154   /* The order of the following instructions determines the bit
155      positions!  */
156   ctype_class_newP (lr, ctype, "upper");
157   ctype_class_newP (lr, ctype, "lower");
158   ctype_class_newP (lr, ctype, "alpha");
159   ctype_class_newP (lr, ctype, "digit");
160   ctype_class_newP (lr, ctype, "xdigit");
161   ctype_class_newP (lr, ctype, "space");
162   ctype_class_newP (lr, ctype, "print");
163   ctype_class_newP (lr, ctype, "graph");
164   ctype_class_newP (lr, ctype, "blank");
165   ctype_class_newP (lr, ctype, "cntrl");
166   ctype_class_newP (lr, ctype, "punct");
167   ctype_class_newP (lr, ctype, "alnum");
168
169   ctype->class_collection_max = charset->mb_cur_max == 1 ? 256 : 512;
170   ctype->class_collection
171     = (u_int32_t *) xmalloc (sizeof (unsigned long int)
172                              * ctype->class_collection_max);
173   memset (ctype->class_collection, '\0',
174           sizeof (unsigned long int) * ctype->class_collection_max);
175   ctype->class_collection_act = 256;
176
177   /* Fill character map information.  */
178   ctype->map_collection_nr = 0;
179   ctype->last_map_idx = MAX_NR_CHARMAP;
180   ctype->from_map_char = ILLEGAL_CHAR_VALUE;
181   ctype_map_newP (lr, ctype, "toupper", charset);
182   ctype_map_newP (lr, ctype, "tolower", charset);
183
184   /* Fill first 256 entries in `toupper' and `tolower' arrays.  */
185   for (cnt = 0; cnt < 256; ++cnt)
186     {
187       ctype->map_collection[0][cnt] = cnt;
188       ctype->map_collection[1][cnt] = cnt;
189     }
190 }
191
192
193 void
194 ctype_finish (struct localedef_t *locale, struct charset_t *charset)
195 {
196   /* See POSIX.2, table 2-6 for the meaning of the following table.  */
197 #define NCLASS 12
198   static const struct
199   {
200     const char *name;
201     const char allow[NCLASS];
202   }
203   valid_table[NCLASS] =
204   {
205     /* The order is important.  See token.h for more information.
206        M = Always, D = Default, - = Permitted, X = Mutually exclusive  */
207     { "upper",  "--MX-XDDXXX-" },
208     { "lower",  "--MX-XDDXXX-" },
209     { "alpha",  "---X-XDDXXX-" },
210     { "digit",  "XXX--XDDXXX-" },
211     { "xdigit", "-----XDDXXX-" },
212     { "space",  "XXXXX------X" },
213     { "print",  "---------X--" },
214     { "graph",  "---------X--" },
215     { "blank",  "XXXXXM-----X" },
216     { "cntrl",  "XXXXX-XX--XX" },
217     { "punct",  "XXXXX-DD-X-X" },
218     { "alnum",  "-----XDDXXX-" }
219   };
220   size_t cnt;
221   int cls1, cls2;
222   unsigned int space_value;
223   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
224
225   /* Set default value for classes not specified.  */
226   set_class_defaults (ctype, charset);
227
228   /* Check according to table.  */
229   for (cnt = 0; cnt < ctype->class_collection_max; ++cnt)
230     {
231       unsigned long int tmp;
232
233       tmp = ctype->class_collection[cnt];
234       if (tmp == 0)
235         continue;
236
237       for (cls1 = 0; cls1 < NCLASS; ++cls1)
238         if ((tmp & (1 << cls1)) != 0)
239           for (cls2 = 0; cls2 < NCLASS; ++cls2)
240             if (valid_table[cls1].allow[cls2] != '-')
241               {
242                 int eq = (tmp & (1 << cls2)) != 0;
243                 switch (valid_table[cls1].allow[cls2])
244                   {
245                   case 'M':
246                     if (!eq)
247                       {
248                         char buf[17];
249                         char *cp = buf;
250                         unsigned int value;
251
252                         value = ctype->charnames[cnt];
253
254                         if ((value & 0xff000000) != 0)
255                           cp += sprintf (cp, "\\%o", (value >> 24) & 0xff);
256                         if ((value & 0xffff0000) != 0)
257                           cp += sprintf (cp, "\\%o", (value >> 16) & 0xff);
258                         if ((value & 0xffffff00) != 0)
259                           cp += sprintf (cp, "\\%o", (value >> 8) & 0xff);
260                         sprintf (cp, "\\%o", value & 0xff);
261
262                         error (0, 0, _("\
263 character %s'%s' in class `%s' must be in class `%s'"), value > 256 ? "L" : "",
264                                cp, valid_table[cls1].name,
265                                valid_table[cls2].name);
266                       }
267                     break;
268
269                   case 'X':
270                     if (eq)
271                       {
272                         char buf[17];
273                         char *cp = buf;
274                         unsigned int value;
275
276                         value = ctype->charnames[cnt];
277
278                         if ((value & 0xff000000) != 0)
279                           cp += sprintf (cp, "\\%o", value >> 24);
280                         if ((value & 0xffff0000) != 0)
281                           cp += sprintf (cp, "\\%o", (value >> 16) & 0xff);
282                         if ((value & 0xffffff00) != 0)
283                           cp += sprintf (cp, "\\%o", (value >> 8) & 0xff);
284                         sprintf (cp, "\\%o", value & 0xff);
285
286                         error (0, 0, _("\
287 character %s'%s' in class `%s' must not be in class `%s'"),
288                                value > 256 ? "L" : "", cp,
289                                valid_table[cls1].name, valid_table[cls2].name);
290                       }
291                     break;
292
293                   case 'D':
294                     ctype->class_collection[cnt] |= 1 << cls2;
295                     break;
296
297                   default:
298                     error (5, 0, _("internal error in %s, line %u"),
299                            __FUNCTION__, __LINE__);
300                   }
301               }
302     }
303
304   /* ... and now test <SP> as a special case.  */
305   space_value = charset_find_value (charset, "SP", 2);
306   if (space_value == ILLEGAL_CHAR_VALUE)
307     error (0, 0, _("character <SP> not defined in character map"));
308   else if ((cnt = BITPOS (tok_space),
309             (ELEM (ctype, class_collection, , space_value)
310              & BIT (tok_space)) == 0)
311            || (cnt = BITPOS (tok_blank),
312                (ELEM (ctype, class_collection, , space_value)
313                 & BIT (tok_blank)) == 0))
314     error (0, 0, _("<SP> character not in class `%s'"),
315            valid_table[cnt].name);
316   else if ((cnt = BITPOS (tok_punct),
317             (ELEM (ctype, class_collection, , space_value)
318              & BIT (tok_punct)) != 0)
319            || (cnt = BITPOS (tok_graph),
320                (ELEM (ctype, class_collection, , space_value)
321                 & BIT (tok_graph))
322                != 0))
323     error (0, 0, _("<SP> character must not be in class `%s'"),
324            valid_table[cnt].name);
325   else
326     ELEM (ctype, class_collection, , space_value) |= BIT (tok_print);
327
328   /* Now that the tests are done make sure the name array contains all
329      characters which are handled in the WIDTH section of the
330      character set definition file.  */
331   if (charset->width_rules != NULL)
332     for (cnt = 0; cnt < charset->nwidth_rules; ++cnt)
333       {
334         size_t inner;
335         for (inner = charset->width_rules[cnt].from;
336              inner <= charset->width_rules[cnt].to; ++inner)
337           (void) find_idx (ctype, NULL, NULL, NULL, inner);
338       }
339 }
340
341
342 void
343 ctype_output (struct localedef_t *locale, struct charset_t *charset,
344               const char *output_path)
345 {
346   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
347   const size_t nelems = (_NL_ITEM_INDEX (_NL_NUM_LC_CTYPE)
348                          + 2 * (ctype->map_collection_nr - 2));
349   struct iovec iov[2 + nelems + ctype->nr_charclass
350                   + ctype->map_collection_nr];
351   struct locale_file data;
352   u_int32_t idx[nelems];
353   size_t elem, cnt, offset, total;
354
355
356   if ((locale->binary & (1 << LC_CTYPE)) != 0)
357     {
358       iov[0].iov_base = ctype;
359       iov[0].iov_len = locale->len[LC_CTYPE];
360
361       write_locale_data (output_path, "LC_CTYPE", 1, iov);
362
363       return;
364     }
365
366
367   /* Now prepare the output: Find the sizes of the table we can use.  */
368   allocate_arrays (ctype, charset);
369
370   data.magic = LIMAGIC (LC_CTYPE);
371   data.n = nelems;
372   iov[0].iov_base = (void *) &data;
373   iov[0].iov_len = sizeof (data);
374
375   iov[1].iov_base = (void *) idx;
376   iov[1].iov_len = sizeof (idx);
377
378   idx[0] = iov[0].iov_len + iov[1].iov_len;
379   offset = 0;
380
381   for (elem = 0; elem < nelems; ++elem)
382     {
383       if (elem < _NL_ITEM_INDEX (_NL_NUM_LC_CTYPE))
384         switch (elem)
385           {
386 #define CTYPE_DATA(name, base, len)                                           \
387           case _NL_ITEM_INDEX (name):                                         \
388             iov[2 + elem + offset].iov_base = base;                           \
389             iov[2 + elem + offset].iov_len = len;                             \
390             if (elem + 1 < nelems)                                            \
391               idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;     \
392             break
393
394           CTYPE_DATA (_NL_CTYPE_CLASS,
395                       ctype->ctype_b,
396                       (256 + 128) * sizeof (char_class_t));
397
398           CTYPE_DATA (_NL_CTYPE_TOUPPER_EB,
399                       ctype->map_eb[0],
400                       (ctype->plane_size * ctype->plane_cnt + 128)
401                       * sizeof (u_int32_t));
402           CTYPE_DATA (_NL_CTYPE_TOLOWER_EB,
403                       ctype->map_eb[1],
404                       (ctype->plane_size * ctype->plane_cnt + 128)
405                       * sizeof (u_int32_t));
406
407           CTYPE_DATA (_NL_CTYPE_TOUPPER_EL,
408                       ctype->map_el[0],
409                       (ctype->plane_size * ctype->plane_cnt + 128)
410                       * sizeof (u_int32_t));
411           CTYPE_DATA (_NL_CTYPE_TOLOWER_EL,
412                       ctype->map_el[1],
413                       (ctype->plane_size * ctype->plane_cnt + 128)
414                       * sizeof (u_int32_t));
415
416           CTYPE_DATA (_NL_CTYPE_CLASS32,
417                       ctype->ctype32_b,
418                       (ctype->plane_size * ctype->plane_cnt
419                        * sizeof (char_class32_t)));
420
421           CTYPE_DATA (_NL_CTYPE_NAMES_EB,
422                       ctype->names_eb, (ctype->plane_size * ctype->plane_cnt
423                                         * sizeof (u_int32_t)));
424           CTYPE_DATA (_NL_CTYPE_NAMES_EL,
425                       ctype->names_el, (ctype->plane_size * ctype->plane_cnt
426                                         * sizeof (u_int32_t)));
427
428           CTYPE_DATA (_NL_CTYPE_HASH_SIZE,
429                       &ctype->plane_size, sizeof (u_int32_t));
430           CTYPE_DATA (_NL_CTYPE_HASH_LAYERS,
431                       &ctype->plane_cnt, sizeof (u_int32_t));
432
433           case _NL_ITEM_INDEX (_NL_CTYPE_CLASS_NAMES):
434             /* The class name array.  */
435             total = 0;
436             for (cnt = 0; cnt < ctype->nr_charclass; ++cnt, ++offset)
437               {
438                 iov[2 + elem + offset].iov_base
439                   = (void *) ctype->classnames[cnt];
440                 iov[2 + elem + offset].iov_len
441                   = strlen (ctype->classnames[cnt]) + 1;
442                 total += iov[2 + elem + offset].iov_len;
443               }
444             iov[2 + elem + offset].iov_base = (void *) "";
445             iov[2 + elem + offset].iov_len = 1;
446             ++total;
447
448             if (elem + 1 < nelems)
449               idx[elem + 1] = idx[elem] + total;
450             break;
451
452           case _NL_ITEM_INDEX (_NL_CTYPE_MAP_NAMES):
453             /* The class name array.  */
454             total = 0;
455             for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt, ++offset)
456               {
457                 iov[2 + elem + offset].iov_base
458                   = (void *) ctype->mapnames[cnt];
459                 iov[2 + elem + offset].iov_len
460                   = strlen (ctype->mapnames[cnt]) + 1;
461                 total += iov[2 + elem + offset].iov_len;
462               }
463             iov[2 + elem + offset].iov_base = (void *) "";
464             iov[2 + elem + offset].iov_len = 1;
465             ++total;
466
467             if (elem + 1 < nelems)
468               idx[elem + 1] = idx[elem] + total;
469             break;
470
471           CTYPE_DATA (_NL_CTYPE_WIDTH,
472                       ctype->width, ctype->plane_size * ctype->plane_cnt);
473
474           default:
475             assert (! "unknown CTYPE element");
476           }
477       else
478         {
479           /* Handle extra maps.  */
480           size_t nr = (elem - _NL_ITEM_INDEX (_NL_NUM_LC_CTYPE)) >> 1;
481
482           if (((elem - _NL_ITEM_INDEX (_NL_NUM_LC_CTYPE)) & 1) == 0)
483             iov[2 + elem + offset].iov_base = ctype->map_eb[nr];
484           else
485             iov[2 + elem + offset].iov_base = ctype->map_el[nr];
486
487           iov[2 + elem + offset].iov_len = ((ctype->plane_size
488                                              * ctype->plane_cnt + 128)
489                                             * sizeof (u_int32_t));
490
491           if (elem + 1 < nelems)
492             idx[elem + 1] = idx[elem] + iov[2 + elem + offset].iov_len;
493         }
494     }
495
496   assert (2 + elem + offset == (nelems + ctype->nr_charclass
497                                 + ctype->map_collection_nr + 2));
498
499   write_locale_data (output_path, "LC_CTYPE", 2 + elem + offset, iov);
500 }
501
502
503 /* Character class handling.  */
504 void
505 ctype_class_new (struct linereader *lr, struct localedef_t *locale,
506                  enum token_t tok, struct token *code,
507                  struct charset_t *charset)
508 {
509   ctype_class_newP (lr, locale->categories[LC_CTYPE].ctype,
510                     code->val.str.start);
511 }
512
513
514 int
515 ctype_is_charclass (struct linereader *lr, struct localedef_t *locale,
516                     const char *name)
517 {
518   int cnt;
519
520   for (cnt = 0; cnt < locale->categories[LC_CTYPE].ctype->nr_charclass; ++cnt)
521     if (strcmp (name, locale->categories[LC_CTYPE].ctype->classnames[cnt])
522         == 0)
523       return 1;
524
525   return 0;
526 }
527
528
529 void
530 ctype_class_start (struct linereader *lr, struct localedef_t *locale,
531                    enum token_t tok, const char *str,
532                    struct charset_t *charset)
533 {
534   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
535   int cnt;
536
537   switch (tok)
538     {
539     case tok_upper:
540       str = "upper";
541       break;
542     case tok_lower:
543       str = "lower";
544       break;
545     case tok_alpha:
546       str = "alpha";
547       break;
548     case tok_digit:
549       str = "digit";
550       break;
551     case tok_xdigit:
552       str = "xdigit";
553       break;
554     case tok_space:
555       str = "space";
556       break;
557     case tok_print:
558       str = "print";
559       break;
560     case tok_graph:
561       str = "graph";
562       break;
563     case tok_blank:
564       str = "blank";
565       break;
566     case tok_cntrl:
567       str = "cntrl";
568       break;
569     case tok_punct:
570       str = "punct";
571       break;
572     case tok_alnum:
573       str = "alnum";
574       break;
575     case tok_ident:
576       break;
577     default:
578       assert (! "illegal token as class name: should not happen");
579     }
580
581   for (cnt = 0; cnt < ctype->nr_charclass; ++cnt)
582     if (strcmp (str, ctype->classnames[cnt]) == 0)
583       break;
584
585   if (cnt >= ctype->nr_charclass)
586     assert (! "unknown class in class definition: should not happen");
587
588   ctype->class_done |= BIT (tok);
589
590   ctype->current_class_mask = 1 << cnt;
591   ctype->last_class_char = ILLEGAL_CHAR_VALUE;
592 }
593
594
595 void
596 ctype_class_from (struct linereader *lr, struct localedef_t *locale,
597                   struct token *code, struct charset_t *charset)
598 {
599   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
600   unsigned int value;
601
602   value = charset_find_value (charset, code->val.str.start, code->val.str.len);
603
604   ctype->last_class_char = value;
605
606   if (value == ILLEGAL_CHAR_VALUE)
607     /* In the LC_CTYPE category it is no error when a character is
608        not found.  This has to be ignored silently.  */
609     return;
610
611   *find_idx (ctype, &ctype->class_collection, &ctype->class_collection_max,
612              &ctype->class_collection_act, value)
613     |= ctype->current_class_mask;
614 }
615
616
617 void
618 ctype_class_to (struct linereader *lr, struct localedef_t *locale,
619                 struct token *code, struct charset_t *charset)
620 {
621   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
622   unsigned int value, cnt;
623
624   value = charset_find_value (charset, code->val.str.start, code->val.str.len);
625
626   assert (value >= ctype->last_class_char);
627
628   for (cnt = ctype->last_class_char + 1; cnt <= value; ++cnt)
629     *find_idx (ctype, &ctype->class_collection, &ctype->class_collection_max,
630                &ctype->class_collection_act, cnt)
631       |= ctype->current_class_mask;
632
633   ctype->last_class_char = ILLEGAL_CHAR_VALUE;
634 }
635
636
637 void
638 ctype_class_end (struct linereader *lr, struct localedef_t *locale)
639 {
640   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
641
642   /* We have no special actions to perform here.  */
643   ctype->current_class_mask = 0;
644   ctype->last_class_char = ILLEGAL_CHAR_VALUE;
645 }
646
647
648 /* Character map handling.  */
649 void
650 ctype_map_new (struct linereader *lr, struct localedef_t *locale,
651                enum token_t tok, struct token *code,
652                struct charset_t *charset)
653 {
654   ctype_map_newP (lr, locale->categories[LC_CTYPE].ctype,
655                   code->val.str.start, charset);
656 }
657
658
659 int
660 ctype_is_charmap (struct linereader *lr, struct localedef_t *locale,
661                   const char *name)
662 {
663   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
664   size_t cnt;
665
666   for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
667     if (strcmp (name, ctype->mapnames[cnt]) == 0)
668       return 1;
669
670   return 0;
671 }
672
673
674 void
675 ctype_map_start (struct linereader *lr, struct localedef_t *locale,
676                  enum token_t tok, const char *name, struct charset_t *charset)
677 {
678   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
679   size_t cnt;
680
681   switch (tok)
682     {
683     case tok_toupper:
684       ctype->toupper_done = 1;
685       name = "toupper";
686       break;
687     case tok_tolower:
688       ctype->tolower_done = 1;
689       name = "tolower";
690       break;
691     case tok_ident:
692       break;
693     default:
694       assert (! "unknown token in category `LC_CTYPE' should not happen");
695     }
696
697   for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
698     if (strcmp (name, ctype->mapnames[cnt]) == 0)
699       break;
700
701   if (cnt == ctype->map_collection_nr)
702     assert (! "unknown token in category `LC_CTYPE' should not happen");
703
704   ctype->last_map_idx = cnt;
705   ctype->from_map_char = ILLEGAL_CHAR_VALUE;
706 }
707
708
709 void
710 ctype_map_from (struct linereader *lr, struct localedef_t *locale,
711                 struct token *code, struct charset_t *charset)
712 {
713   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
714   unsigned int value;
715
716   value = charset_find_value (charset, code->val.str.start, code->val.str.len);
717
718   if (value == ILLEGAL_CHAR_VALUE)
719     /* In the LC_CTYPE category it is no error when a character is
720        not found.  This has to be ignored silently.  */
721     return;
722
723   assert (ctype->last_map_idx < ctype->map_collection_nr);
724
725   ctype->from_map_char = value;
726 }
727
728
729 void
730 ctype_map_to (struct linereader *lr, struct localedef_t *locale,
731               struct token *code, struct charset_t *charset)
732 {
733   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
734   unsigned int value;
735
736   value = charset_find_value (charset, code->val.str.start, code->val.str.len);
737
738   if (ctype->from_map_char == ILLEGAL_CHAR_VALUE
739       || value == ILLEGAL_CHAR_VALUE)
740     {
741       /* In the LC_CTYPE category it is no error when a character is
742          not found.  This has to be ignored silently.  */
743       ctype->from_map_char = ILLEGAL_CHAR_VALUE;
744       return;
745     }
746
747   *find_idx (ctype, &ctype->map_collection[ctype->last_map_idx],
748              &ctype->map_collection_max[ctype->last_map_idx],
749              &ctype->map_collection_act[ctype->last_map_idx],
750              ctype->from_map_char) = value;
751
752   ctype->from_map_char = ILLEGAL_CHAR_VALUE;
753 }
754
755
756 void
757 ctype_map_end (struct linereader *lr, struct localedef_t *locale)
758 {
759   struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;
760
761   ctype->last_map_idx = MAX_NR_CHARMAP;
762   ctype->from_map_char = ILLEGAL_CHAR_VALUE;
763 }
764
765
766 /* Local functions.  */
767 static void
768 ctype_class_newP (struct linereader *lr, struct locale_ctype_t *ctype,
769                   const char *name)
770 {
771   int cnt;
772
773   for (cnt = 0; cnt < ctype->nr_charclass; ++cnt)
774     if (strcmp (ctype->classnames[cnt], name) == 0)
775       break;
776
777   if (cnt < ctype->nr_charclass)
778     {
779       lr_error (lr, _("character class `%s' already defined"));
780       return;
781     }
782
783   if (ctype->nr_charclass == MAX_NR_CHARCLASS)
784     /* Exit code 2 is prescribed in P1003.2b.  */
785     error (2, 0, _("\
786 implementation limit: no more than %d character classes allowed"),
787            MAX_NR_CHARCLASS);
788
789   ctype->classnames[ctype->nr_charclass++] = name;
790 }
791
792
793 static void
794 ctype_map_newP (struct linereader *lr, struct locale_ctype_t *ctype,
795                 const char *name, struct charset_t *charset)
796 {
797   size_t max_chars = 0;
798   int cnt;
799
800   for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)
801     {
802       if (strcmp (ctype->mapnames[cnt], name) == 0)
803         break;
804
805       if (max_chars < ctype->map_collection_max[cnt])
806         max_chars = ctype->map_collection_max[cnt];
807     }
808
809   if (cnt < ctype->map_collection_nr)
810     {
811       lr_error (lr, _("character map `%s' already defined"));
812       return;
813     }
814
815   if (ctype->map_collection_nr == MAX_NR_CHARMAP)
816     /* Exit code 2 is prescribed in P1003.2b.  */
817     error (2, 0, _("\
818 implementation limit: no more than %d character maps allowed"),
819            MAX_NR_CHARMAP);
820
821   ctype->mapnames[cnt] = name;
822
823   if (max_chars == 0)
824     ctype->map_collection_max[cnt] = charset->mb_cur_max == 1 ? 256 : 512;
825   else
826     ctype->map_collection_max[cnt] = max_chars;
827
828   ctype->map_collection[cnt] = (u_int32_t *)
829     xmalloc (sizeof (u_int32_t) * ctype->map_collection_max[cnt]);
830   memset (ctype->map_collection[cnt], '\0',
831           sizeof (u_int32_t) * ctype->map_collection_max[cnt]);
832   ctype->map_collection_act[cnt] = 256;
833
834   ++ctype->map_collection_nr;
835 }
836
837
838 /* We have to be prepared that TABLE, MAX, and ACT can be NULL.  This
839    is possible if we only want ot extend the name array.  */
840 static u_int32_t *
841 find_idx (struct locale_ctype_t *ctype, u_int32_t **table, size_t *max,
842           size_t *act, unsigned int idx)
843 {
844   size_t cnt;
845
846   if (idx < 256)
847     return table == NULL ? NULL : &(*table)[idx];
848
849   for (cnt = 256; cnt < ctype->charnames_act; ++cnt)
850     if (ctype->charnames[cnt] == idx)
851       break;
852
853   /* We have to distinguish two cases: the names is found or not.  */
854   if (cnt == ctype->charnames_act)
855     {
856       /* Extend the name array.  */
857       if (ctype->charnames_act == ctype->charnames_max)
858         {
859           ctype->charnames_max *= 2;
860           ctype->charnames = (unsigned int *)
861             xrealloc (ctype->charnames,
862                       sizeof (unsigned int) * ctype->charnames_max);
863         }
864       ctype->charnames[ctype->charnames_act++] = idx;
865     }
866
867   if (table == NULL)
868     /* We have done everything we are asked to do.  */
869     return NULL;
870
871   if (cnt >= *act)
872     {
873       if (cnt >= *max)
874         {
875           size_t old_max = *max;
876           do
877             *max *= 2;
878           while (*max <= cnt);
879
880           *table =
881             (u_int32_t *) xrealloc (*table, *max * sizeof (unsigned long int));
882           memset (&(*table)[old_max], '\0',
883                   (*max - old_max) * sizeof (u_int32_t));
884         }
885
886       (*table)[cnt] = 0;
887       *act = cnt;
888     }
889
890   return &(*table)[cnt];
891 }
892
893
894 static void
895 set_class_defaults (struct locale_ctype_t *ctype, struct charset_t *charset)
896 {
897   /* These function defines the default values for the classes and conversions
898      according to POSIX.2 2.5.2.1.
899      It may seem that the order of these if-blocks is arbitrary but it is NOT.
900      Don't move them unless you know what you do!  */
901
902   void set_default (int bit, int from, int to)
903     {
904       char tmp[2];
905       int ch;
906       /* Define string.  */
907       strcpy (tmp, "?");
908
909       for (ch = from; ch <= to; ++ch)
910         {
911           unsigned int value;
912           tmp[0] = ch;
913
914           value = charset_find_value (charset, tmp, 1);
915           if (value == ILLEGAL_CHAR_VALUE)
916             {
917               error (0, 0, _("\
918 character `%s' not defined while needed as default value"),
919                      tmp);
920               continue;
921             }
922           else
923             ELEM (ctype, class_collection, , value) |= bit;
924         }
925     }
926
927   /* Set default values if keyword was not present.  */
928   if ((ctype->class_done & BIT (tok_upper)) == 0)
929     /* "If this keyword [lower] is not specified, the lowercase letters
930         `A' through `Z', ..., shall automatically belong to this class,
931         with implementation defined character values."  [P1003.2, 2.5.2.1]  */
932     set_default (BIT (tok_upper), 'A', 'Z');
933
934   if ((ctype->class_done & BIT (tok_lower)) == 0)
935     /* "If this keyword [lower] is not specified, the lowercase letters
936         `a' through `z', ..., shall automatically belong to this class,
937         with implementation defined character values."  [P1003.2, 2.5.2.1]  */
938     set_default (BIT (tok_lower), 'a', 'z');
939
940   if ((ctype->class_done & BIT (tok_alpha)) == 0)
941     {
942       /* Table 2-6 in P1003.2 says that characters in class `upper' or
943          class `lower' *must* be in class `alpha'.  */
944       unsigned long int mask = BIT (tok_upper) | BIT (tok_lower);
945       size_t cnt;
946
947       for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
948         if ((ctype->class_collection[cnt] & mask) != 0)
949           ctype->class_collection[cnt] |= BIT (tok_alpha);
950     }
951
952   if ((ctype->class_done & BIT (tok_digit)) == 0)
953     /* "If this keyword [digit] is not specified, the digits `0' through
954         `9', ..., shall automatically belong to this class, with
955         implementation-defined character values."  [P1003.2, 2.5.2.1]  */
956     set_default (BIT (tok_digit), '0', '9');
957
958   /* "Only characters specified for the `alpha' and `digit' keyword
959      shall be specified.  Characters specified for the keyword `alpha'
960      and `digit' are automatically included in this class.  */
961   {
962     unsigned long int mask = BIT (tok_alpha) | BIT (tok_digit);
963     size_t cnt;
964
965     for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
966       if ((ctype->class_collection[cnt] & mask) != 0)
967         ctype->class_collection[cnt] |= BIT (tok_alnum);
968   }
969
970   if ((ctype->class_done & BIT (tok_space)) == 0)
971     /* "If this keyword [space] is not specified, the characters <space>,
972         <form-feed>, <newline>, <carriage-return>, <tab>, and
973         <vertical-tab>, ..., shall automatically belong to this class,
974         with implementation-defined character values."  [P1003.2, 2.5.2.1]  */
975     {
976       unsigned int value;
977
978       value = charset_find_value (charset, "space", 5);
979       if (value == ILLEGAL_CHAR_VALUE)
980         error (0, 0, _("\
981 character `%s' not defined while needed as default value"),
982                "<space>");
983       else
984         ELEM (ctype, class_collection, , value) |= BIT (tok_space);
985
986       value = charset_find_value (charset, "form-feed", 9);
987       if (value == ILLEGAL_CHAR_VALUE)
988         error (0, 0, _("\
989 character `%s' not defined while needed as default value"),
990                "<form-feed>");
991       else
992         ELEM (ctype, class_collection, , value) |= BIT (tok_space);
993
994       value = charset_find_value (charset, "newline", 7);
995       if (value == ILLEGAL_CHAR_VALUE)
996         error (0, 0, _("\
997 character `%s' not defined while needed as default value"),
998                "<newline>");
999       else
1000         ELEM (ctype, class_collection, , value) |= BIT (tok_space);
1001
1002       value = charset_find_value (charset, "carriage-return", 15);
1003       if (value == ILLEGAL_CHAR_VALUE)
1004         error (0, 0, _("\
1005 character `%s' not defined while needed as default value"),
1006                "<carriage-return>");
1007       else
1008         ELEM (ctype, class_collection, , value) |= BIT (tok_space);
1009
1010       value = charset_find_value (charset, "tab", 3);
1011       if (value == ILLEGAL_CHAR_VALUE)
1012         error (0, 0, _("\
1013 character `%s' not defined while needed as default value"),
1014                "<tab>");
1015       else
1016         ELEM (ctype, class_collection, , value) |= BIT (tok_space);
1017
1018       value = charset_find_value (charset, "vertical-tab", 12);
1019       if (value == ILLEGAL_CHAR_VALUE)
1020         error (0, 0, _("\
1021 character `%s' not defined while needed as default value"),
1022                "<vertical-tab>");
1023       else
1024         ELEM (ctype, class_collection, , value) |= BIT (tok_space);
1025     }
1026
1027   if ((ctype->class_done & BIT (tok_xdigit)) == 0)
1028     /* "If this keyword is not specified, the digits `0' to `9', the
1029         uppercase letters `A' through `F', and the lowercase letters `a'
1030         through `f', ..., shell automatically belong to this class, with
1031         implementation defined character values."  [P1003.2, 2.5.2.1]  */
1032     {
1033       set_default (BIT (tok_xdigit), '0', '9');
1034       set_default (BIT (tok_xdigit), 'A', 'F');
1035       set_default (BIT (tok_xdigit), 'a', 'f');
1036     }
1037
1038   if ((ctype->class_done & BIT (tok_blank)) == 0)
1039     /* "If this keyword [blank] is unspecified, the characters <space> and
1040        <tab> shall belong to this character class."  [P1003.2, 2.5.2.1]  */
1041    {
1042       unsigned int value;
1043
1044       value = charset_find_value (charset, "space", 5);
1045       if (value == ILLEGAL_CHAR_VALUE)
1046         error (0, 0, _("\
1047 character `%s' not defined while needed as default value"),
1048                "<space>");
1049       else
1050         ELEM (ctype, class_collection, , value) |= BIT (tok_blank);
1051
1052       value = charset_find_value (charset, "tab", 3);
1053       if (value == ILLEGAL_CHAR_VALUE)
1054         error (0, 0, _("\
1055 character `%s' not defined while needed as default value"),
1056                "<tab>");
1057       else
1058         ELEM (ctype, class_collection, , value) |= BIT (tok_blank);
1059     }
1060
1061   if ((ctype->class_done & BIT (tok_graph)) == 0)
1062     /* "If this keyword [graph] is not specified, characters specified for
1063         the keywords `upper', `lower', `alpha', `digit', `xdigit' and `punct',
1064         shall belong to this character class."  [P1003.2, 2.5.2.1]  */
1065     {
1066       unsigned long int mask = BIT (tok_upper) | BIT (tok_lower) |
1067         BIT (tok_alpha) | BIT (tok_digit) | BIT (tok_xdigit) | BIT (tok_punct);
1068       size_t cnt;
1069
1070       for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
1071         if ((ctype->class_collection[cnt] & mask) != 0)
1072           ctype->class_collection[cnt] |= BIT (tok_graph);
1073     }
1074
1075   if ((ctype->class_done & BIT (tok_print)) == 0)
1076     /* "If this keyword [print] is not provided, characters specified for
1077         the keywords `upper', `lower', `alpha', `digit', `xdigit', `punct',
1078         and the <space> character shall belong to this character class."
1079         [P1003.2, 2.5.2.1]  */
1080     {
1081       unsigned long int mask = BIT (tok_upper) | BIT (tok_lower) |
1082         BIT (tok_alpha) | BIT (tok_digit) | BIT (tok_xdigit) | BIT (tok_punct);
1083       size_t cnt;
1084       int space;
1085
1086       for (cnt = 0; cnt < ctype->class_collection_act; ++cnt)
1087         if ((ctype->class_collection[cnt] & mask) != 0)
1088           ctype->class_collection[cnt] |= BIT (tok_print);
1089
1090       space = charset_find_value (charset, "space", 5);
1091       if (space == ILLEGAL_CHAR_VALUE)
1092         error (0, 0, _("\
1093 character `%s' not defined while needed as default value"),
1094                "<space>");
1095       else
1096         ELEM (ctype, class_collection, , space) |= BIT (tok_print);
1097     }
1098
1099   if (ctype->toupper_done == 0)
1100     /* "If this keyword [toupper] is not spcified, the lowercase letters
1101         `a' through `z', and their corresponding uppercase letters `A' to
1102         `Z', ..., shall automatically be included, with implementation-
1103         defined character values."  [P1003.2, 2.5.2.1]  */
1104     {
1105       char tmp[4];
1106       int ch;
1107
1108       strcpy (tmp, "<?>");
1109
1110       for (ch = 'a'; ch <= 'z'; ++ch)
1111         {
1112           unsigned int value_from, value_to;
1113
1114           tmp[1] = (char) ch;
1115
1116           value_from = charset_find_value (charset, &tmp[1], 1);
1117           if (value_from == ILLEGAL_CHAR_VALUE)
1118             {
1119               error (0, 0, _("\
1120 character `%c' not defined while needed as default value"),
1121                      tmp);
1122               continue;
1123             }
1124
1125           /* This conversion is implementation defined.  */
1126           tmp[1] = (char) (ch + ('A' - 'a'));
1127           value_to = charset_find_value (charset, &tmp[1], 1);
1128           if (value_to == -1)
1129             {
1130               error (0, 0, _("\
1131 character `%s' not defined while needed as default value"),
1132                      tmp);
1133               continue;
1134             }
1135
1136           /* The index [0] is determined by the order of the
1137              `ctype_map_newP' calls in `ctype_startup'.  */
1138           ELEM (ctype, map_collection, [0], value_from) = value_to;
1139         }
1140     }
1141
1142   if (ctype->tolower_done == 0)
1143     /* "If this keyword [tolower] is not specified, the mapping shall be
1144        the reverse mapping of the one specified to `toupper'."  [P1003.2]  */
1145     {
1146       size_t cnt;
1147
1148       for (cnt = 0; cnt < ctype->map_collection_act[0]; ++cnt)
1149         if (ctype->map_collection[0][cnt] != 0)
1150           ELEM (ctype, map_collection, [1],
1151                 ctype->map_collection[0][cnt])
1152             = ctype->charnames[cnt];
1153     }
1154 }
1155
1156
1157 static void
1158 allocate_arrays (struct locale_ctype_t *ctype, struct charset_t *charset)
1159 {
1160   size_t idx;
1161
1162   /* First we have to decide how we organize the arrays.  It is easy for
1163      a one-byte character set.  But multi-byte character set cannot be
1164      stored flat because they might be sparsly used.  So we determine an
1165      optimal hashing function for the used characters.
1166
1167      We use a very trivial hashing function to store the sparse table.
1168      CH % TABSIZE is used as an index.  To solve multiple hits we have
1169      N planes.  This gurantees a fixed search time for a character [N
1170      / 2].  In the following code we determine the minmum value for
1171      TABSIZE * N, where TABSIZE >= 256.  */
1172   size_t min_total = UINT_MAX;
1173   size_t act_size = 256;
1174
1175   fputs (_("\
1176 Computing table size for character classes might take a while..."),
1177          stderr);
1178
1179   while (act_size < min_total)
1180     {
1181       size_t cnt[act_size];
1182       size_t act_planes = 1;
1183
1184       memset (cnt, '\0', sizeof cnt);
1185
1186       for (idx = 0; idx < 256; ++idx)
1187         cnt[idx] = 1;
1188
1189       for (idx = 0; idx < ctype->charnames_act; ++idx)
1190         if (ctype->charnames[idx] >= 256)
1191           {
1192             size_t nr = ctype->charnames[idx] % act_size;
1193
1194             if (++cnt[nr] > act_planes)
1195               {
1196                 act_planes = cnt[nr];
1197                 if (act_size * act_planes >= min_total)
1198                   break;
1199               }
1200           }
1201
1202       if (act_size * act_planes < min_total)
1203         {
1204           min_total = act_size * act_planes;
1205           ctype->plane_size = act_size;
1206           ctype->plane_cnt = act_planes;
1207         }
1208
1209       ++act_size;
1210     }
1211
1212   fprintf (stderr, _(" done\n"));
1213
1214
1215 #if __BYTE_ORDER == __LITTLE_ENDIAN
1216 # define NAMES_B1 ctype->names_el
1217 # define NAMES_B2 ctype->names_eb
1218 #else
1219 # define NAMES_B1 ctype->names_eb
1220 # define NAMES_B2 ctype->names_el
1221 #endif
1222
1223   ctype->names_eb = (u_int32_t *) xcalloc (ctype->plane_size
1224                                            * ctype->plane_cnt,
1225                                            sizeof (u_int32_t));
1226   ctype->names_el = (u_int32_t *) xcalloc (ctype->plane_size
1227                                            * ctype->plane_cnt,
1228                                            sizeof (u_int32_t));
1229
1230   for (idx = 1; idx < 256; ++idx)
1231     NAMES_B1[idx] = idx;
1232
1233   /* Trick: change the 0th entry's name to 1 to mark the cell occupied.  */
1234   NAMES_B1[0] = 1;
1235
1236   for (idx = 256; idx < ctype->charnames_act; ++idx)
1237     {
1238       size_t nr = (ctype->charnames[idx] % ctype->plane_size);
1239       size_t depth = 0;
1240
1241       while (NAMES_B1[nr + depth * ctype->plane_size])
1242         ++depth;
1243       assert (depth < ctype->plane_cnt);
1244
1245       NAMES_B1[nr + depth * ctype->plane_size] = ctype->charnames[idx];
1246
1247       /* Now for faster access remember the index in the NAMES_B array.  */
1248       ctype->charnames[idx] = nr + depth * ctype->plane_size;
1249     }
1250   NAMES_B1[0] = 0;
1251
1252   for (idx = 0; idx < ctype->plane_size * ctype->plane_cnt; ++idx)
1253     NAMES_B2[idx] = SWAPU32 (NAMES_B1[idx]);
1254
1255
1256   /* You wonder about this amount of memory?  This is only because some
1257      users do not manage to address the array with unsigned values or
1258      data types with range >= 256.  '\200' would result in the array
1259      index -128.  To help these poor people we duplicate the entries for
1260      128 up to 255 below the entry for \0.  */
1261   ctype->ctype_b = (char_class_t *) xcalloc (256 + 128,
1262                                              sizeof (char_class_t));
1263   ctype->ctype32_b = (char_class32_t *) xcalloc (ctype->plane_size
1264                                                  * ctype->plane_cnt,
1265                                                  sizeof (char_class32_t));
1266
1267   /* Fill in the character class information.  */
1268 #if __BYTE_ORDER == __LITTLE_ENDIAN
1269 # define TRANS(w) CHAR_CLASS_TRANS (w)
1270 # define TRANS32(w) CHAR_CLASS32_TRANS (w)
1271 #else
1272 # define TRANS(w) (w)
1273 # define TRANS32(w) (w)
1274 #endif
1275
1276   for (idx = 0; idx < ctype->class_collection_act; ++idx)
1277     if (ctype->charnames[idx] < 256)
1278       ctype->ctype_b[128 + ctype->charnames[idx]]
1279         = TRANS (ctype->class_collection[idx]);
1280
1281   /* Mirror first 127 entries.  We must take care that entry -1 is not
1282      mirrored because EOF == -1.  */
1283   for (idx = 0; idx < 127; ++idx)
1284     ctype->ctype_b[idx] = ctype->ctype_b[256 + idx];
1285
1286   /* The 32 bit array contains all characters.  */
1287   for (idx = 0; idx < ctype->class_collection_act; ++idx)
1288     ctype->ctype32_b[ctype->charnames[idx]]
1289       = TRANS32 (ctype->class_collection[idx]);
1290
1291   /* Room for table of mappings.  */
1292   ctype->map_eb = (u_int32_t **) xmalloc (ctype->map_collection_nr
1293                                           * sizeof (u_int32_t *));
1294   ctype->map_el = (u_int32_t **) xmalloc (ctype->map_collection_nr
1295                                           * sizeof (u_int32_t *));
1296
1297   /* Fill in all mappings.  */
1298   for (idx = 0; idx < ctype->map_collection_nr; ++idx)
1299     {
1300       unsigned int idx2;
1301
1302       /* Allocate table.  */
1303       ctype->map_eb[idx] = (u_int32_t *) xmalloc ((ctype->plane_size
1304                                                    * ctype->plane_cnt + 128)
1305                                                   * sizeof (u_int32_t));
1306       ctype->map_el[idx] = (u_int32_t *) xmalloc ((ctype->plane_size
1307                                                    * ctype->plane_cnt + 128)
1308                                                   * sizeof (u_int32_t));
1309
1310 #if __BYTE_ORDER == __LITTLE_ENDIAN
1311 # define MAP_B1 ctype->map_el
1312 # define MAP_B2 ctype->map_eb
1313 #else
1314 # define MAP_B1 ctype->map_eb
1315 # define MAP_B2 ctype->map_el
1316 #endif
1317
1318       /* Copy default value (identity mapping).  */
1319       memcpy (&MAP_B1[idx][128], NAMES_B1,
1320               ctype->plane_size * ctype->plane_cnt * sizeof (u_int32_t));
1321
1322       /* Copy values from collection.  */
1323       for (idx2 = 0; idx2 < ctype->map_collection_act[idx]; ++idx2)
1324         if (ctype->map_collection[idx][idx2] != 0)
1325           MAP_B1[idx][128 + ctype->charnames[idx2]] =
1326             ctype->map_collection[idx][idx2];
1327
1328       /* Mirror first 127 entries.  We must take care not to map entry
1329          -1 because EOF == -1.  */
1330       for (idx2 = 0; idx2 < 127; ++idx2)
1331         MAP_B1[idx][idx2] = MAP_B1[idx][256 + idx2];
1332
1333       /* EOF must map to EOF.  */
1334       MAP_B1[idx][127] = EOF;
1335
1336       /* And now the other byte order.  */
1337       for (idx2 = 0; idx2 < ctype->plane_size * ctype->plane_cnt + 128; ++idx2)
1338         MAP_B2[idx][idx2] = SWAPU32 (MAP_B1[idx][idx2]);
1339     }
1340
1341   /* Extra array for class and map names.  */
1342   ctype->class_name_ptr = (u_int32_t *) xmalloc (ctype->nr_charclass
1343                                                  * sizeof (u_int32_t));
1344   ctype->map_name_ptr = (u_int32_t *) xmalloc (ctype->map_collection_nr
1345                                                * sizeof (u_int32_t));
1346
1347   /* Array for width information.  Because the expected width are very
1348      small we use only one single byte.  This save space and we need
1349      not provide the information twice with both endianesses.  */
1350   ctype->width = (unsigned char *) xmalloc (ctype->plane_size
1351                                             * ctype->plane_cnt);
1352   /* Initialize with default width value.  */
1353   memset (ctype->width, charset->width_default,
1354           ctype->plane_size * ctype->plane_cnt);
1355   if (charset->width_rules != NULL)
1356     {
1357       size_t cnt;
1358
1359       for (cnt = 0; cnt < charset->nwidth_rules; ++cnt)
1360         if (charset->width_rules[cnt].width != charset->width_default)
1361           for (idx = charset->width_rules[cnt].from;
1362                idx <= charset->width_rules[cnt].to; ++idx)
1363             {
1364               size_t nr = idx % ctype->plane_size;
1365               size_t depth = 0;
1366
1367               while (NAMES_B1[nr + depth * ctype->plane_size] != nr)
1368                 ++depth;
1369               assert (depth < ctype->plane_cnt);
1370
1371               ctype->width[nr + depth * ctype->plane_size]
1372                 = charset->width_rules[cnt].width;
1373             }
1374     }
1375 }