Fix 2009-02-07 commit of format strings.
[gnulib.git] / lib / gen-uni-tables.c
1 /* Generate Unicode conforming character classification tables and
2    line break properties tables and word break property tables and
3    case mapping tables from a UnicodeData file.
4    Copyright (C) 2000-2002, 2004, 2007-2009 Free Software Foundation, Inc.
5    Written by Bruno Haible <bruno@clisp.org>, 2000-2002.
6
7    This program is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20 /* Usage example:
21      $ gen-uni-tables /usr/local/share/Unidata/UnicodeData.txt \
22                       /usr/local/share/Unidata/PropList.txt \
23                       /usr/local/share/Unidata/DerivedCoreProperties.txt \
24                       /usr/local/share/Unidata/Scripts.txt \
25                       /usr/local/share/Unidata/Blocks.txt \
26                       /usr/local/share/Unidata/PropList-3.0.1.txt \
27                       /usr/local/share/Unidata/EastAsianWidth.txt \
28                       /usr/local/share/Unidata/LineBreak.txt \
29                       /usr/local/share/Unidata/WordBreakProperty.txt \
30                       5.1.0
31  */
32
33 #include <stdbool.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <time.h>
39
40 /* ========================================================================= */
41
42 /* Reading UnicodeData.txt.  */
43 /* See UCD.html.  */
44
45 /* This structure represents one line in the UnicodeData.txt file.  */
46 struct unicode_attribute
47 {
48   const char *name;           /* Character name */
49   const char *category;       /* General category */
50   const char *combining;      /* Canonical combining class */
51   const char *bidi;           /* Bidirectional category */
52   const char *decomposition;  /* Character decomposition mapping */
53   const char *decdigit;       /* Decimal digit value */
54   const char *digit;          /* Digit value */
55   const char *numeric;        /* Numeric value */
56   bool mirrored;              /* mirrored */
57   const char *oldname;        /* Old Unicode 1.0 name */
58   const char *comment;        /* Comment */
59   unsigned int upper;         /* Uppercase mapping */
60   unsigned int lower;         /* Lowercase mapping */
61   unsigned int title;         /* Titlecase mapping */
62 };
63
64 /* Missing fields are represented with "" for strings, and NONE for
65    characters.  */
66 #define NONE (~(unsigned int)0)
67
68 /* The entire contents of the UnicodeData.txt file.  */
69 struct unicode_attribute unicode_attributes [0x110000];
70
71 /* Stores in unicode_attributes[i] the values from the given fields.  */
72 static void
73 fill_attribute (unsigned int i,
74                 const char *field1, const char *field2,
75                 const char *field3, const char *field4,
76                 const char *field5, const char *field6,
77                 const char *field7, const char *field8,
78                 const char *field9, const char *field10,
79                 const char *field11, const char *field12,
80                 const char *field13, const char *field14)
81 {
82   struct unicode_attribute * uni;
83
84   if (i >= 0x110000)
85     {
86       fprintf (stderr, "index too large\n");
87       exit (1);
88     }
89   if (strcmp (field2, "Cs") == 0)
90     /* Surrogates are UTF-16 artefacts, not real characters. Ignore them.  */
91     return;
92   uni = &unicode_attributes[i];
93   /* Copy the strings.  */
94   uni->name          = strdup (field1);
95   uni->category      = (field2[0] == '\0' ? "" : strdup (field2));
96   uni->combining     = (field3[0] == '\0' ? "" : strdup (field3));
97   uni->bidi          = (field4[0] == '\0' ? "" : strdup (field4));
98   uni->decomposition = (field5[0] == '\0' ? "" : strdup (field5));
99   uni->decdigit      = (field6[0] == '\0' ? "" : strdup (field6));
100   uni->digit         = (field7[0] == '\0' ? "" : strdup (field7));
101   uni->numeric       = (field8[0] == '\0' ? "" : strdup (field8));
102   uni->mirrored      = (field9[0] == 'Y');
103   uni->oldname       = (field10[0] == '\0' ? "" : strdup (field10));
104   uni->comment       = (field11[0] == '\0' ? "" : strdup (field11));
105   uni->upper = (field12[0] =='\0' ? NONE : strtoul (field12, NULL, 16));
106   uni->lower = (field13[0] =='\0' ? NONE : strtoul (field13, NULL, 16));
107   uni->title = (field14[0] =='\0' ? NONE : strtoul (field14, NULL, 16));
108 }
109
110 /* Maximum length of a field in the UnicodeData.txt file.  */
111 #define FIELDLEN 120
112
113 /* Reads the next field from STREAM.  The buffer BUFFER has size FIELDLEN.
114    Reads up to (but excluding) DELIM.
115    Returns 1 when a field was successfully read, otherwise 0.  */
116 static int
117 getfield (FILE *stream, char *buffer, int delim)
118 {
119   int count = 0;
120   int c;
121
122   for (; (c = getc (stream)), (c != EOF && c != delim); )
123     {
124       /* The original unicode.org UnicodeData.txt file happens to have
125          CR/LF line terminators.  Silently convert to LF.  */
126       if (c == '\r')
127         continue;
128
129       /* Put c into the buffer.  */
130       if (++count >= FIELDLEN - 1)
131         {
132           fprintf (stderr, "field longer than expected, increase FIELDLEN\n");
133           exit (1);
134         }
135       *buffer++ = c;
136     }
137
138   if (c == EOF)
139     return 0;
140
141   *buffer = '\0';
142   return 1;
143 }
144
145 /* Stores in unicode_attributes[] the entire contents of the UnicodeData.txt
146    file.  */
147 static void
148 fill_attributes (const char *unicodedata_filename)
149 {
150   unsigned int i, j;
151   FILE *stream;
152   char field0[FIELDLEN];
153   char field1[FIELDLEN];
154   char field2[FIELDLEN];
155   char field3[FIELDLEN];
156   char field4[FIELDLEN];
157   char field5[FIELDLEN];
158   char field6[FIELDLEN];
159   char field7[FIELDLEN];
160   char field8[FIELDLEN];
161   char field9[FIELDLEN];
162   char field10[FIELDLEN];
163   char field11[FIELDLEN];
164   char field12[FIELDLEN];
165   char field13[FIELDLEN];
166   char field14[FIELDLEN];
167   int lineno = 0;
168
169   for (i = 0; i < 0x110000; i++)
170     unicode_attributes[i].name = NULL;
171
172   stream = fopen (unicodedata_filename, "r");
173   if (stream == NULL)
174     {
175       fprintf (stderr, "error during fopen of '%s'\n", unicodedata_filename);
176       exit (1);
177     }
178
179   for (;;)
180     {
181       int n;
182
183       lineno++;
184       n = getfield (stream, field0, ';');
185       n += getfield (stream, field1, ';');
186       n += getfield (stream, field2, ';');
187       n += getfield (stream, field3, ';');
188       n += getfield (stream, field4, ';');
189       n += getfield (stream, field5, ';');
190       n += getfield (stream, field6, ';');
191       n += getfield (stream, field7, ';');
192       n += getfield (stream, field8, ';');
193       n += getfield (stream, field9, ';');
194       n += getfield (stream, field10, ';');
195       n += getfield (stream, field11, ';');
196       n += getfield (stream, field12, ';');
197       n += getfield (stream, field13, ';');
198       n += getfield (stream, field14, '\n');
199       if (n == 0)
200         break;
201       if (n != 15)
202         {
203           fprintf (stderr, "short line in '%s':%d\n",
204                    unicodedata_filename, lineno);
205           exit (1);
206         }
207       i = strtoul (field0, NULL, 16);
208       if (field1[0] == '<'
209           && strlen (field1) >= 9
210           && strcmp (field1 + strlen(field1) - 8, ", First>") == 0)
211         {
212           /* Deal with a range. */
213           lineno++;
214           n = getfield (stream, field0, ';');
215           n += getfield (stream, field1, ';');
216           n += getfield (stream, field2, ';');
217           n += getfield (stream, field3, ';');
218           n += getfield (stream, field4, ';');
219           n += getfield (stream, field5, ';');
220           n += getfield (stream, field6, ';');
221           n += getfield (stream, field7, ';');
222           n += getfield (stream, field8, ';');
223           n += getfield (stream, field9, ';');
224           n += getfield (stream, field10, ';');
225           n += getfield (stream, field11, ';');
226           n += getfield (stream, field12, ';');
227           n += getfield (stream, field13, ';');
228           n += getfield (stream, field14, '\n');
229           if (n != 15)
230             {
231               fprintf (stderr, "missing end range in '%s':%d\n",
232                        unicodedata_filename, lineno);
233               exit (1);
234             }
235           if (!(field1[0] == '<'
236                 && strlen (field1) >= 8
237                 && strcmp (field1 + strlen (field1) - 7, ", Last>") == 0))
238             {
239               fprintf (stderr, "missing end range in '%s':%d\n",
240                        unicodedata_filename, lineno);
241               exit (1);
242             }
243           field1[strlen (field1) - 7] = '\0';
244           j = strtoul (field0, NULL, 16);
245           for (; i <= j; i++)
246             fill_attribute (i, field1+1, field2, field3, field4, field5,
247                                field6, field7, field8, field9, field10,
248                                field11, field12, field13, field14);
249         }
250       else
251         {
252           /* Single character line */
253           fill_attribute (i, field1, field2, field3, field4, field5,
254                              field6, field7, field8, field9, field10,
255                              field11, field12, field13, field14);
256         }
257     }
258   if (ferror (stream) || fclose (stream))
259     {
260       fprintf (stderr, "error reading from '%s'\n", unicodedata_filename);
261       exit (1);
262     }
263 }
264
265 /* ========================================================================= */
266
267 /* General category.  */
268 /* See Unicode 3.0 book, section 4.5,
269        UCD.html.  */
270
271 static bool
272 is_category_L (unsigned int ch)
273 {
274   return (unicode_attributes[ch].name != NULL
275           && unicode_attributes[ch].category[0] == 'L');
276 }
277
278 static bool
279 is_category_Lu (unsigned int ch)
280 {
281   return (unicode_attributes[ch].name != NULL
282           && unicode_attributes[ch].category[0] == 'L'
283           && unicode_attributes[ch].category[1] == 'u');
284 }
285
286 static bool
287 is_category_Ll (unsigned int ch)
288 {
289   return (unicode_attributes[ch].name != NULL
290           && unicode_attributes[ch].category[0] == 'L'
291           && unicode_attributes[ch].category[1] == 'l');
292 }
293
294 static bool
295 is_category_Lt (unsigned int ch)
296 {
297   return (unicode_attributes[ch].name != NULL
298           && unicode_attributes[ch].category[0] == 'L'
299           && unicode_attributes[ch].category[1] == 't');
300 }
301
302 static bool
303 is_category_Lm (unsigned int ch)
304 {
305   return (unicode_attributes[ch].name != NULL
306           && unicode_attributes[ch].category[0] == 'L'
307           && unicode_attributes[ch].category[1] == 'm');
308 }
309
310 static bool
311 is_category_Lo (unsigned int ch)
312 {
313   return (unicode_attributes[ch].name != NULL
314           && unicode_attributes[ch].category[0] == 'L'
315           && unicode_attributes[ch].category[1] == 'o');
316 }
317
318 static bool
319 is_category_M (unsigned int ch)
320 {
321   return (unicode_attributes[ch].name != NULL
322           && unicode_attributes[ch].category[0] == 'M');
323 }
324
325 static bool
326 is_category_Mn (unsigned int ch)
327 {
328   return (unicode_attributes[ch].name != NULL
329           && unicode_attributes[ch].category[0] == 'M'
330           && unicode_attributes[ch].category[1] == 'n');
331 }
332
333 static bool
334 is_category_Mc (unsigned int ch)
335 {
336   return (unicode_attributes[ch].name != NULL
337           && unicode_attributes[ch].category[0] == 'M'
338           && unicode_attributes[ch].category[1] == 'c');
339 }
340
341 static bool
342 is_category_Me (unsigned int ch)
343 {
344   return (unicode_attributes[ch].name != NULL
345           && unicode_attributes[ch].category[0] == 'M'
346           && unicode_attributes[ch].category[1] == 'e');
347 }
348
349 static bool
350 is_category_N (unsigned int ch)
351 {
352   return (unicode_attributes[ch].name != NULL
353           && unicode_attributes[ch].category[0] == 'N');
354 }
355
356 static bool
357 is_category_Nd (unsigned int ch)
358 {
359   return (unicode_attributes[ch].name != NULL
360           && unicode_attributes[ch].category[0] == 'N'
361           && unicode_attributes[ch].category[1] == 'd');
362 }
363
364 static bool
365 is_category_Nl (unsigned int ch)
366 {
367   return (unicode_attributes[ch].name != NULL
368           && unicode_attributes[ch].category[0] == 'N'
369           && unicode_attributes[ch].category[1] == 'l');
370 }
371
372 static bool
373 is_category_No (unsigned int ch)
374 {
375   return (unicode_attributes[ch].name != NULL
376           && unicode_attributes[ch].category[0] == 'N'
377           && unicode_attributes[ch].category[1] == 'o');
378 }
379
380 static bool
381 is_category_P (unsigned int ch)
382 {
383   return (unicode_attributes[ch].name != NULL
384           && unicode_attributes[ch].category[0] == 'P');
385 }
386
387 static bool
388 is_category_Pc (unsigned int ch)
389 {
390   return (unicode_attributes[ch].name != NULL
391           && unicode_attributes[ch].category[0] == 'P'
392           && unicode_attributes[ch].category[1] == 'c');
393 }
394
395 static bool
396 is_category_Pd (unsigned int ch)
397 {
398   return (unicode_attributes[ch].name != NULL
399           && unicode_attributes[ch].category[0] == 'P'
400           && unicode_attributes[ch].category[1] == 'd');
401 }
402
403 static bool
404 is_category_Ps (unsigned int ch)
405 {
406   return (unicode_attributes[ch].name != NULL
407           && unicode_attributes[ch].category[0] == 'P'
408           && unicode_attributes[ch].category[1] == 's');
409 }
410
411 static bool
412 is_category_Pe (unsigned int ch)
413 {
414   return (unicode_attributes[ch].name != NULL
415           && unicode_attributes[ch].category[0] == 'P'
416           && unicode_attributes[ch].category[1] == 'e');
417 }
418
419 static bool
420 is_category_Pi (unsigned int ch)
421 {
422   return (unicode_attributes[ch].name != NULL
423           && unicode_attributes[ch].category[0] == 'P'
424           && unicode_attributes[ch].category[1] == 'i');
425 }
426
427 static bool
428 is_category_Pf (unsigned int ch)
429 {
430   return (unicode_attributes[ch].name != NULL
431           && unicode_attributes[ch].category[0] == 'P'
432           && unicode_attributes[ch].category[1] == 'f');
433 }
434
435 static bool
436 is_category_Po (unsigned int ch)
437 {
438   return (unicode_attributes[ch].name != NULL
439           && unicode_attributes[ch].category[0] == 'P'
440           && unicode_attributes[ch].category[1] == 'o');
441 }
442
443 static bool
444 is_category_S (unsigned int ch)
445 {
446   return (unicode_attributes[ch].name != NULL
447           && unicode_attributes[ch].category[0] == 'S');
448 }
449
450 static bool
451 is_category_Sm (unsigned int ch)
452 {
453   return (unicode_attributes[ch].name != NULL
454           && unicode_attributes[ch].category[0] == 'S'
455           && unicode_attributes[ch].category[1] == 'm');
456 }
457
458 static bool
459 is_category_Sc (unsigned int ch)
460 {
461   return (unicode_attributes[ch].name != NULL
462           && unicode_attributes[ch].category[0] == 'S'
463           && unicode_attributes[ch].category[1] == 'c');
464 }
465
466 static bool
467 is_category_Sk (unsigned int ch)
468 {
469   return (unicode_attributes[ch].name != NULL
470           && unicode_attributes[ch].category[0] == 'S'
471           && unicode_attributes[ch].category[1] == 'k');
472 }
473
474 static bool
475 is_category_So (unsigned int ch)
476 {
477   return (unicode_attributes[ch].name != NULL
478           && unicode_attributes[ch].category[0] == 'S'
479           && unicode_attributes[ch].category[1] == 'o');
480 }
481
482 static bool
483 is_category_Z (unsigned int ch)
484 {
485   return (unicode_attributes[ch].name != NULL
486           && unicode_attributes[ch].category[0] == 'Z');
487 }
488
489 static bool
490 is_category_Zs (unsigned int ch)
491 {
492   return (unicode_attributes[ch].name != NULL
493           && unicode_attributes[ch].category[0] == 'Z'
494           && unicode_attributes[ch].category[1] == 's');
495 }
496
497 static bool
498 is_category_Zl (unsigned int ch)
499 {
500   return (unicode_attributes[ch].name != NULL
501           && unicode_attributes[ch].category[0] == 'Z'
502           && unicode_attributes[ch].category[1] == 'l');
503 }
504
505 static bool
506 is_category_Zp (unsigned int ch)
507 {
508   return (unicode_attributes[ch].name != NULL
509           && unicode_attributes[ch].category[0] == 'Z'
510           && unicode_attributes[ch].category[1] == 'p');
511 }
512
513 static bool
514 is_category_C (unsigned int ch)
515 {
516   return (unicode_attributes[ch].name == NULL
517           || unicode_attributes[ch].category[0] == 'C');
518 }
519
520 static bool
521 is_category_Cc (unsigned int ch)
522 {
523   return (unicode_attributes[ch].name != NULL
524           && unicode_attributes[ch].category[0] == 'C'
525           && unicode_attributes[ch].category[1] == 'c');
526 }
527
528 static bool
529 is_category_Cf (unsigned int ch)
530 {
531   return (unicode_attributes[ch].name != NULL
532           && unicode_attributes[ch].category[0] == 'C'
533           && unicode_attributes[ch].category[1] == 'f');
534 }
535
536 static bool
537 is_category_Cs (unsigned int ch)
538 {
539   return (ch >= 0xd800 && ch < 0xe000);
540 }
541
542 static bool
543 is_category_Co (unsigned int ch)
544 {
545   return (unicode_attributes[ch].name != NULL
546           && unicode_attributes[ch].category[0] == 'C'
547           && unicode_attributes[ch].category[1] == 'o');
548 }
549
550 static bool
551 is_category_Cn (unsigned int ch)
552 {
553   return (unicode_attributes[ch].name == NULL
554           && !(ch >= 0xd800 && ch < 0xe000));
555 }
556
557 /* Output a boolean property in a human readable format.  */
558 static void
559 debug_output_predicate (const char *filename, bool (*predicate) (unsigned int))
560 {
561   FILE *stream;
562   unsigned int ch;
563
564   stream = fopen (filename, "w");
565   if (stream == NULL)
566     {
567       fprintf (stderr, "cannot open '%s' for writing\n", filename);
568       exit (1);
569     }
570
571 #if 0 /* This yields huge text output.  */
572   for (ch = 0; ch < 0x110000; ch++)
573     if (predicate (ch))
574       {
575         fprintf (stream, "0x%04X\n", ch);
576       }
577 #else
578   for (ch = 0; ch < 0x110000; ch++)
579     if (predicate (ch))
580       {
581         unsigned int first = ch;
582         unsigned int last;
583
584         while (ch + 1 < 0x110000 && predicate (ch + 1))
585           ch++;
586         last = ch;
587         if (first < last)
588           fprintf (stream, "0x%04X..0x%04X\n", first, last);
589         else
590           fprintf (stream, "0x%04X\n", ch);
591       }
592 #endif
593
594   if (ferror (stream) || fclose (stream))
595     {
596       fprintf (stderr, "error writing to '%s'\n", filename);
597       exit (1);
598     }
599 }
600
601 /* Output the unit test for a boolean property.  */
602 static void
603 output_predicate_test (const char *filename, bool (*predicate) (unsigned int), const char *expression)
604 {
605   FILE *stream;
606   bool need_comma;
607   unsigned int ch;
608
609   stream = fopen (filename, "w");
610   if (stream == NULL)
611     {
612       fprintf (stderr, "cannot open '%s' for writing\n", filename);
613       exit (1);
614     }
615
616   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
617   fprintf (stream, "/* Test the Unicode character type functions.\n");
618   fprintf (stream, "   Copyright (C) 2007 Free Software Foundation, Inc.\n");
619   fprintf (stream, "\n");
620   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
621   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
622   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
623   fprintf (stream, "   (at your option) any later version.\n");
624   fprintf (stream, "\n");
625   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
626   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
627   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
628   fprintf (stream, "   GNU General Public License for more details.\n");
629   fprintf (stream, "\n");
630   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
631   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
632   fprintf (stream, "\n");
633   fprintf (stream, "#include \"test-predicate-part1.h\"\n");
634   fprintf (stream, "\n");
635
636   need_comma = false;
637   for (ch = 0; ch < 0x110000; ch++)
638     if (predicate (ch))
639       {
640         unsigned int first = ch;
641         unsigned int last;
642
643         while (ch + 1 < 0x110000 && predicate (ch + 1))
644           ch++;
645         last = ch;
646         if (need_comma)
647           fprintf (stream, ",\n");
648         fprintf (stream, "    { 0x%04X, 0x%04X }", first, last);
649         need_comma = true;
650       }
651   if (need_comma)
652     fprintf (stream, "\n");
653
654   fprintf (stream, "\n");
655   fprintf (stream, "#define PREDICATE(c) %s\n", expression);
656   fprintf (stream, "#include \"test-predicate-part2.h\"\n");
657
658   if (ferror (stream) || fclose (stream))
659     {
660       fprintf (stderr, "error writing to '%s'\n", filename);
661       exit (1);
662     }
663 }
664
665 /* Construction of sparse 3-level tables.  */
666 #define TABLE predicate_table
667 #define xmalloc malloc
668 #define xrealloc realloc
669 #include "3levelbit.h"
670
671 /* Output a boolean property in a three-level bitmap.  */
672 static void
673 output_predicate (const char *filename, bool (*predicate) (unsigned int), const char *name, const char *comment, const char *version)
674 {
675   FILE *stream;
676   unsigned int ch, i;
677   struct predicate_table t;
678   unsigned int level1_offset, level2_offset, level3_offset;
679
680   stream = fopen (filename, "w");
681   if (stream == NULL)
682     {
683       fprintf (stderr, "cannot open '%s' for writing\n", filename);
684       exit (1);
685     }
686
687   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
688   fprintf (stream, "/* %s of Unicode characters.  */\n", comment);
689   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
690            version);
691
692   t.p = 4; /* or: 5 */
693   t.q = 7; /* or: 6 */
694   predicate_table_init (&t);
695
696   for (ch = 0; ch < 0x110000; ch++)
697     if (predicate (ch))
698       predicate_table_add (&t, ch);
699
700   predicate_table_finalize (&t);
701
702   /* Offsets in t.result, in memory of this process.  */
703   level1_offset =
704     5 * sizeof (uint32_t);
705   level2_offset =
706     5 * sizeof (uint32_t)
707     + t.level1_size * sizeof (uint32_t);
708   level3_offset =
709     5 * sizeof (uint32_t)
710     + t.level1_size * sizeof (uint32_t)
711     + (t.level2_size << t.q) * sizeof (uint32_t);
712
713   for (i = 0; i < 5; i++)
714     if (i != 1)
715       fprintf (stream, "#define header_%d %d\n", i,
716                ((uint32_t *) t.result)[i]);
717
718   fprintf (stream, "static const\n");
719   fprintf (stream, "struct\n");
720   fprintf (stream, "  {\n");
721   fprintf (stream, "    int header[1];\n");
722   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
723   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
724   fprintf (stream, "    /*unsigned*/ int level3[%zu << %d];\n", t.level3_size, t.p);
725   fprintf (stream, "  }\n");
726   fprintf (stream, "%s =\n", name);
727   fprintf (stream, "{\n");
728   fprintf (stream, "  { %d },\n", ((uint32_t *) t.result)[1]);
729   fprintf (stream, "  {");
730   if (t.level1_size > 1)
731     fprintf (stream, "\n   ");
732   for (i = 0; i < t.level1_size; i++)
733     {
734       uint32_t offset;
735       if (i > 0 && (i % 1) == 0)
736         fprintf (stream, "\n   ");
737       offset = ((uint32_t *) (t.result + level1_offset))[i];
738       if (offset == 0)
739         fprintf (stream, " %5d", -1);
740       else
741         fprintf (stream, " %5zu * sizeof (int) / sizeof (short) + %5zu",
742                  1 + t.level1_size, (offset - level2_offset) / sizeof (uint32_t));
743       if (i+1 < t.level1_size)
744         fprintf (stream, ",");
745     }
746   if (t.level1_size > 1)
747     fprintf (stream, "\n ");
748   fprintf (stream, " },\n");
749   fprintf (stream, "  {");
750   if (t.level2_size << t.q > 1)
751     fprintf (stream, "\n   ");
752   for (i = 0; i < t.level2_size << t.q; i++)
753     {
754       uint32_t offset;
755       if (i > 0 && (i % 1) == 0)
756         fprintf (stream, "\n   ");
757       offset = ((uint32_t *) (t.result + level2_offset))[i];
758       if (offset == 0)
759         fprintf (stream, " %5d", -1);
760       else
761         fprintf (stream, " %5zu + %5zu * sizeof (short) / sizeof (int) + %5zu",
762                  1 + t.level1_size, t.level2_size << t.q, (offset - level3_offset) / sizeof (uint32_t));
763       if (i+1 < t.level2_size << t.q)
764         fprintf (stream, ",");
765     }
766   if (t.level2_size << t.q > 1)
767     fprintf (stream, "\n ");
768   fprintf (stream, " },\n");
769   fprintf (stream, "  {");
770   if (t.level3_size << t.p > 4)
771     fprintf (stream, "\n   ");
772   for (i = 0; i < t.level3_size << t.p; i++)
773     {
774       if (i > 0 && (i % 4) == 0)
775         fprintf (stream, "\n   ");
776       fprintf (stream, " 0x%08X",
777                ((uint32_t *) (t.result + level3_offset))[i]);
778       if (i+1 < t.level3_size << t.p)
779         fprintf (stream, ",");
780     }
781   if (t.level3_size << t.p > 4)
782     fprintf (stream, "\n ");
783   fprintf (stream, " }\n");
784   fprintf (stream, "};\n");
785
786   if (ferror (stream) || fclose (stream))
787     {
788       fprintf (stderr, "error writing to '%s'\n", filename);
789       exit (1);
790     }
791 }
792
793 /* Output all categories.  */
794 static void
795 output_categories (const char *version)
796 {
797 #define CATEGORY(C) \
798   debug_output_predicate ("unictype/categ_" #C ".txt", is_category_ ## C); \
799   output_predicate_test ("../tests/unictype/test-categ_" #C ".c", is_category_ ## C, "uc_is_general_category (c, UC_CATEGORY_" #C ")"); \
800   output_predicate ("unictype/categ_" #C ".h", is_category_ ## C, "u_categ_" #C, "Categories", version);
801   CATEGORY (L)
802   CATEGORY (Lu)
803   CATEGORY (Ll)
804   CATEGORY (Lt)
805   CATEGORY (Lm)
806   CATEGORY (Lo)
807   CATEGORY (M)
808   CATEGORY (Mn)
809   CATEGORY (Mc)
810   CATEGORY (Me)
811   CATEGORY (N)
812   CATEGORY (Nd)
813   CATEGORY (Nl)
814   CATEGORY (No)
815   CATEGORY (P)
816   CATEGORY (Pc)
817   CATEGORY (Pd)
818   CATEGORY (Ps)
819   CATEGORY (Pe)
820   CATEGORY (Pi)
821   CATEGORY (Pf)
822   CATEGORY (Po)
823   CATEGORY (S)
824   CATEGORY (Sm)
825   CATEGORY (Sc)
826   CATEGORY (Sk)
827   CATEGORY (So)
828   CATEGORY (Z)
829   CATEGORY (Zs)
830   CATEGORY (Zl)
831   CATEGORY (Zp)
832   CATEGORY (C)
833   CATEGORY (Cc)
834   CATEGORY (Cf)
835   CATEGORY (Cs)
836   CATEGORY (Co)
837   CATEGORY (Cn)
838 #undef CATEGORY
839 }
840
841 enum
842 {
843   UC_CATEGORY_MASK_L  = 0x0000001f,
844   UC_CATEGORY_MASK_Lu = 0x00000001,
845   UC_CATEGORY_MASK_Ll = 0x00000002,
846   UC_CATEGORY_MASK_Lt = 0x00000004,
847   UC_CATEGORY_MASK_Lm = 0x00000008,
848   UC_CATEGORY_MASK_Lo = 0x00000010,
849   UC_CATEGORY_MASK_M  = 0x000000e0,
850   UC_CATEGORY_MASK_Mn = 0x00000020,
851   UC_CATEGORY_MASK_Mc = 0x00000040,
852   UC_CATEGORY_MASK_Me = 0x00000080,
853   UC_CATEGORY_MASK_N  = 0x00000700,
854   UC_CATEGORY_MASK_Nd = 0x00000100,
855   UC_CATEGORY_MASK_Nl = 0x00000200,
856   UC_CATEGORY_MASK_No = 0x00000400,
857   UC_CATEGORY_MASK_P  = 0x0003f800,
858   UC_CATEGORY_MASK_Pc = 0x00000800,
859   UC_CATEGORY_MASK_Pd = 0x00001000,
860   UC_CATEGORY_MASK_Ps = 0x00002000,
861   UC_CATEGORY_MASK_Pe = 0x00004000,
862   UC_CATEGORY_MASK_Pi = 0x00008000,
863   UC_CATEGORY_MASK_Pf = 0x00010000,
864   UC_CATEGORY_MASK_Po = 0x00020000,
865   UC_CATEGORY_MASK_S  = 0x003c0000,
866   UC_CATEGORY_MASK_Sm = 0x00040000,
867   UC_CATEGORY_MASK_Sc = 0x00080000,
868   UC_CATEGORY_MASK_Sk = 0x00100000,
869   UC_CATEGORY_MASK_So = 0x00200000,
870   UC_CATEGORY_MASK_Z  = 0x01c00000,
871   UC_CATEGORY_MASK_Zs = 0x00400000,
872   UC_CATEGORY_MASK_Zl = 0x00800000,
873   UC_CATEGORY_MASK_Zp = 0x01000000,
874   UC_CATEGORY_MASK_C  = 0x3e000000,
875   UC_CATEGORY_MASK_Cc = 0x02000000,
876   UC_CATEGORY_MASK_Cf = 0x04000000,
877   UC_CATEGORY_MASK_Cs = 0x08000000,
878   UC_CATEGORY_MASK_Co = 0x10000000,
879   UC_CATEGORY_MASK_Cn = 0x20000000
880 };
881
882 static int
883 general_category_byname (const char *category_name)
884 {
885   if (category_name[0] != '\0'
886       && (category_name[1] == '\0' || category_name[2] == '\0'))
887     switch (category_name[0])
888       {
889       case 'L':
890         switch (category_name[1])
891           {
892           case '\0': return UC_CATEGORY_MASK_L;
893           case 'u': return UC_CATEGORY_MASK_Lu;
894           case 'l': return UC_CATEGORY_MASK_Ll;
895           case 't': return UC_CATEGORY_MASK_Lt;
896           case 'm': return UC_CATEGORY_MASK_Lm;
897           case 'o': return UC_CATEGORY_MASK_Lo;
898           }
899         break;
900       case 'M':
901         switch (category_name[1])
902           {
903           case '\0': return UC_CATEGORY_MASK_M;
904           case 'n': return UC_CATEGORY_MASK_Mn;
905           case 'c': return UC_CATEGORY_MASK_Mc;
906           case 'e': return UC_CATEGORY_MASK_Me;
907           }
908         break;
909       case 'N':
910         switch (category_name[1])
911           {
912           case '\0': return UC_CATEGORY_MASK_N;
913           case 'd': return UC_CATEGORY_MASK_Nd;
914           case 'l': return UC_CATEGORY_MASK_Nl;
915           case 'o': return UC_CATEGORY_MASK_No;
916           }
917         break;
918       case 'P':
919         switch (category_name[1])
920           {
921           case '\0': return UC_CATEGORY_MASK_P;
922           case 'c': return UC_CATEGORY_MASK_Pc;
923           case 'd': return UC_CATEGORY_MASK_Pd;
924           case 's': return UC_CATEGORY_MASK_Ps;
925           case 'e': return UC_CATEGORY_MASK_Pe;
926           case 'i': return UC_CATEGORY_MASK_Pi;
927           case 'f': return UC_CATEGORY_MASK_Pf;
928           case 'o': return UC_CATEGORY_MASK_Po;
929           }
930         break;
931       case 'S':
932         switch (category_name[1])
933           {
934           case '\0': return UC_CATEGORY_MASK_S;
935           case 'm': return UC_CATEGORY_MASK_Sm;
936           case 'c': return UC_CATEGORY_MASK_Sc;
937           case 'k': return UC_CATEGORY_MASK_Sk;
938           case 'o': return UC_CATEGORY_MASK_So;
939           }
940         break;
941       case 'Z':
942         switch (category_name[1])
943           {
944           case '\0': return UC_CATEGORY_MASK_Z;
945           case 's': return UC_CATEGORY_MASK_Zs;
946           case 'l': return UC_CATEGORY_MASK_Zl;
947           case 'p': return UC_CATEGORY_MASK_Zp;
948           }
949         break;
950       case 'C':
951         switch (category_name[1])
952           {
953           case '\0': return UC_CATEGORY_MASK_C;
954           case 'c': return UC_CATEGORY_MASK_Cc;
955           case 'f': return UC_CATEGORY_MASK_Cf;
956           case 's': return UC_CATEGORY_MASK_Cs;
957           case 'o': return UC_CATEGORY_MASK_Co;
958           case 'n': return UC_CATEGORY_MASK_Cn;
959           }
960         break;
961       }
962   /* Invalid category name.  */
963   abort ();
964 }
965
966 /* Construction of sparse 3-level tables.  */
967 #define TABLE category_table
968 #define ELEMENT uint8_t
969 #define DEFAULT 29 /* = log2(UC_CATEGORY_MASK_Cn) */
970 #define xmalloc malloc
971 #define xrealloc realloc
972 #include "3level.h"
973
974 /* Output the per-character category table.  */
975 static void
976 output_category (const char *filename, const char *version)
977 {
978   FILE *stream;
979   unsigned int ch, i;
980   struct category_table t;
981   unsigned int level1_offset, level2_offset, level3_offset;
982   uint16_t *level3_packed;
983
984   stream = fopen (filename, "w");
985   if (stream == NULL)
986     {
987       fprintf (stderr, "cannot open '%s' for writing\n", filename);
988       exit (1);
989     }
990
991   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
992   fprintf (stream, "/* Categories of Unicode characters.  */\n");
993   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
994            version);
995
996   t.p = 7;
997   t.q = 9;
998   category_table_init (&t);
999
1000   for (ch = 0; ch < 0x110000; ch++)
1001     {
1002       int value;
1003       unsigned int log2_value;
1004
1005       if (is_category_Cs (ch))
1006         value = UC_CATEGORY_MASK_Cs;
1007       else if (unicode_attributes[ch].name != NULL)
1008         value = general_category_byname (unicode_attributes[ch].category);
1009       else
1010         continue;
1011
1012       /* Now value should contain exactly one bit.  */
1013       if (value == 0 || ((value & (value - 1)) != 0))
1014         abort ();
1015
1016       for (log2_value = 0; value > 1; value >>= 1, log2_value++);
1017
1018       category_table_add (&t, ch, log2_value);
1019     }
1020
1021   category_table_finalize (&t);
1022
1023   /* Offsets in t.result, in memory of this process.  */
1024   level1_offset =
1025     5 * sizeof (uint32_t);
1026   level2_offset =
1027     5 * sizeof (uint32_t)
1028     + t.level1_size * sizeof (uint32_t);
1029   level3_offset =
1030     5 * sizeof (uint32_t)
1031     + t.level1_size * sizeof (uint32_t)
1032     + (t.level2_size << t.q) * sizeof (uint32_t);
1033
1034   for (i = 0; i < 5; i++)
1035     fprintf (stream, "#define category_header_%d %d\n", i,
1036              ((uint32_t *) t.result)[i]);
1037   fprintf (stream, "static const\n");
1038   fprintf (stream, "struct\n");
1039   fprintf (stream, "  {\n");
1040   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1041   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1042   fprintf (stream, "    unsigned short level3[%zu * %d + 1];\n", t.level3_size,
1043            (1 << t.p) * 5 / 16);
1044   fprintf (stream, "  }\n");
1045   fprintf (stream, "u_category =\n");
1046   fprintf (stream, "{\n");
1047   fprintf (stream, "  {");
1048   if (t.level1_size > 8)
1049     fprintf (stream, "\n   ");
1050   for (i = 0; i < t.level1_size; i++)
1051     {
1052       uint32_t offset;
1053       if (i > 0 && (i % 8) == 0)
1054         fprintf (stream, "\n   ");
1055       offset = ((uint32_t *) (t.result + level1_offset))[i];
1056       if (offset == 0)
1057         fprintf (stream, " %5d", -1);
1058       else
1059         fprintf (stream, " %5zu",
1060                  (offset - level2_offset) / sizeof (uint32_t));
1061       if (i+1 < t.level1_size)
1062         fprintf (stream, ",");
1063     }
1064   if (t.level1_size > 8)
1065     fprintf (stream, "\n ");
1066   fprintf (stream, " },\n");
1067   fprintf (stream, "  {");
1068   if (t.level2_size << t.q > 8)
1069     fprintf (stream, "\n   ");
1070   for (i = 0; i < t.level2_size << t.q; i++)
1071     {
1072       uint32_t offset;
1073       if (i > 0 && (i % 8) == 0)
1074         fprintf (stream, "\n   ");
1075       offset = ((uint32_t *) (t.result + level2_offset))[i];
1076       if (offset == 0)
1077         fprintf (stream, " %5d", -1);
1078       else
1079         fprintf (stream, " %5zu",
1080                  (offset - level3_offset) / sizeof (uint8_t));
1081       if (i+1 < t.level2_size << t.q)
1082         fprintf (stream, ",");
1083     }
1084   if (t.level2_size << t.q > 8)
1085     fprintf (stream, "\n ");
1086   fprintf (stream, " },\n");
1087   /* Pack the level3 array.  Each entry needs 5 bits only.  Use 16-bit units,
1088      not 32-bit units, in order to make the lookup function easier.  */
1089   level3_packed =
1090     (uint16_t *)
1091     calloc ((t.level3_size << t.p) * 5 / 16 + 1, sizeof (uint16_t));
1092   for (i = 0; i < t.level3_size << t.p; i++)
1093     {
1094       unsigned int j = (i * 5) / 16;
1095       unsigned int k = (i * 5) % 16;
1096       uint32_t value = ((unsigned char *) (t.result + level3_offset))[i];
1097       value = level3_packed[j] | (level3_packed[j+1] << 16) | (value << k);
1098       level3_packed[j] = value & 0xffff;
1099       level3_packed[j+1] = value >> 16;
1100     }
1101   fprintf (stream, "  {");
1102   if ((t.level3_size << t.p) * 5 / 16 + 1 > 8)
1103     fprintf (stream, "\n   ");
1104   for (i = 0; i < (t.level3_size << t.p) * 5 / 16 + 1; i++)
1105     {
1106       if (i > 0 && (i % 8) == 0)
1107         fprintf (stream, "\n   ");
1108       fprintf (stream, " 0x%04x", level3_packed[i]);
1109       if (i+1 < (t.level3_size << t.p) * 5 / 16 + 1)
1110         fprintf (stream, ",");
1111     }
1112   if ((t.level3_size << t.p) * 5 / 16 + 1 > 8)
1113     fprintf (stream, "\n ");
1114   fprintf (stream, " }\n");
1115   free (level3_packed);
1116   fprintf (stream, "};\n");
1117
1118   if (ferror (stream) || fclose (stream))
1119     {
1120       fprintf (stderr, "error writing to '%s'\n", filename);
1121       exit (1);
1122     }
1123 }
1124
1125 /* ========================================================================= */
1126
1127 /* Canonical combining class.  */
1128 /* See Unicode 3.0 book, section 4.2,
1129        UCD.html.  */
1130
1131 /* Construction of sparse 3-level tables.  */
1132 #define TABLE combclass_table
1133 #define ELEMENT uint8_t
1134 #define DEFAULT 0
1135 #define xmalloc malloc
1136 #define xrealloc realloc
1137 #include "3level.h"
1138
1139 /* Output the per-character combining class table.  */
1140 static void
1141 output_combclass (const char *filename, const char *version)
1142 {
1143   FILE *stream;
1144   unsigned int ch, i;
1145   struct combclass_table t;
1146   unsigned int level1_offset, level2_offset, level3_offset;
1147
1148   stream = fopen (filename, "w");
1149   if (stream == NULL)
1150     {
1151       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1152       exit (1);
1153     }
1154
1155   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1156   fprintf (stream, "/* Combining class of Unicode characters.  */\n");
1157   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
1158            version);
1159
1160   t.p = 7;
1161   t.q = 9;
1162   combclass_table_init (&t);
1163
1164   for (ch = 0; ch < 0x110000; ch++)
1165     if (unicode_attributes[ch].name != NULL)
1166       {
1167         int value = atoi (unicode_attributes[ch].combining);
1168         if (!(value >= 0 && value <= 255))
1169           abort ();
1170         combclass_table_add (&t, ch, value);
1171       }
1172
1173   combclass_table_finalize (&t);
1174
1175   /* Offsets in t.result, in memory of this process.  */
1176   level1_offset =
1177     5 * sizeof (uint32_t);
1178   level2_offset =
1179     5 * sizeof (uint32_t)
1180     + t.level1_size * sizeof (uint32_t);
1181   level3_offset =
1182     5 * sizeof (uint32_t)
1183     + t.level1_size * sizeof (uint32_t)
1184     + (t.level2_size << t.q) * sizeof (uint32_t);
1185
1186   for (i = 0; i < 5; i++)
1187     fprintf (stream, "#define combclass_header_%d %d\n", i,
1188              ((uint32_t *) t.result)[i]);
1189   fprintf (stream, "static const\n");
1190   fprintf (stream, "struct\n");
1191   fprintf (stream, "  {\n");
1192   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1193   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1194   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
1195   fprintf (stream, "  }\n");
1196   fprintf (stream, "u_combclass =\n");
1197   fprintf (stream, "{\n");
1198   fprintf (stream, "  {");
1199   if (t.level1_size > 8)
1200     fprintf (stream, "\n   ");
1201   for (i = 0; i < t.level1_size; i++)
1202     {
1203       uint32_t offset;
1204       if (i > 0 && (i % 8) == 0)
1205         fprintf (stream, "\n   ");
1206       offset = ((uint32_t *) (t.result + level1_offset))[i];
1207       if (offset == 0)
1208         fprintf (stream, " %5d", -1);
1209       else
1210         fprintf (stream, " %5zu",
1211                  (offset - level2_offset) / sizeof (uint32_t));
1212       if (i+1 < t.level1_size)
1213         fprintf (stream, ",");
1214     }
1215   if (t.level1_size > 8)
1216     fprintf (stream, "\n ");
1217   fprintf (stream, " },\n");
1218   fprintf (stream, "  {");
1219   if (t.level2_size << t.q > 8)
1220     fprintf (stream, "\n   ");
1221   for (i = 0; i < t.level2_size << t.q; i++)
1222     {
1223       uint32_t offset;
1224       if (i > 0 && (i % 8) == 0)
1225         fprintf (stream, "\n   ");
1226       offset = ((uint32_t *) (t.result + level2_offset))[i];
1227       if (offset == 0)
1228         fprintf (stream, " %5d", -1);
1229       else
1230         fprintf (stream, " %5zu",
1231                  (offset - level3_offset) / sizeof (uint8_t));
1232       if (i+1 < t.level2_size << t.q)
1233         fprintf (stream, ",");
1234     }
1235   if (t.level2_size << t.q > 8)
1236     fprintf (stream, "\n ");
1237   fprintf (stream, " },\n");
1238   fprintf (stream, "  {");
1239   if (t.level3_size << t.p > 8)
1240     fprintf (stream, "\n   ");
1241   for (i = 0; i < t.level3_size << t.p; i++)
1242     {
1243       if (i > 0 && (i % 8) == 0)
1244         fprintf (stream, "\n   ");
1245       fprintf (stream, " %3d", ((uint8_t *) (t.result + level3_offset))[i]);
1246       if (i+1 < t.level3_size << t.p)
1247         fprintf (stream, ",");
1248     }
1249   if (t.level3_size << t.p > 8)
1250     fprintf (stream, "\n ");
1251   fprintf (stream, " }\n");
1252   fprintf (stream, "};\n");
1253
1254   if (ferror (stream) || fclose (stream))
1255     {
1256       fprintf (stderr, "error writing to '%s'\n", filename);
1257       exit (1);
1258     }
1259 }
1260
1261 /* ========================================================================= */
1262
1263 /* Bidirectional category.  */
1264 /* See Unicode 3.0 book, section 4.3,
1265        UCD.html.  */
1266
1267 enum
1268 {
1269   UC_BIDI_L,   /* Left-to-Right */
1270   UC_BIDI_LRE, /* Left-to-Right Embedding */
1271   UC_BIDI_LRO, /* Left-to-Right Override */
1272   UC_BIDI_R,   /* Right-to-Left */
1273   UC_BIDI_AL,  /* Right-to-Left Arabic */
1274   UC_BIDI_RLE, /* Right-to-Left Embedding */
1275   UC_BIDI_RLO, /* Right-to-Left Override */
1276   UC_BIDI_PDF, /* Pop Directional Format */
1277   UC_BIDI_EN,  /* European Number */
1278   UC_BIDI_ES,  /* European Number Separator */
1279   UC_BIDI_ET,  /* European Number Terminator */
1280   UC_BIDI_AN,  /* Arabic Number */
1281   UC_BIDI_CS,  /* Common Number Separator */
1282   UC_BIDI_NSM, /* Non-Spacing Mark */
1283   UC_BIDI_BN,  /* Boundary Neutral */
1284   UC_BIDI_B,   /* Paragraph Separator */
1285   UC_BIDI_S,   /* Segment Separator */
1286   UC_BIDI_WS,  /* Whitespace */
1287   UC_BIDI_ON   /* Other Neutral */
1288 };
1289
1290 static int
1291 bidi_category_byname (const char *category_name)
1292 {
1293   switch (category_name[0])
1294     {
1295     case 'A':
1296       switch (category_name[1])
1297         {
1298         case 'L':
1299           if (category_name[2] == '\0')
1300             return UC_BIDI_AL;
1301           break;
1302         case 'N':
1303           if (category_name[2] == '\0')
1304             return UC_BIDI_AN;
1305           break;
1306         }
1307       break;
1308     case 'B':
1309       switch (category_name[1])
1310         {
1311         case '\0':
1312           return UC_BIDI_B;
1313         case 'N':
1314           if (category_name[2] == '\0')
1315             return UC_BIDI_BN;
1316           break;
1317         }
1318       break;
1319     case 'C':
1320       switch (category_name[1])
1321         {
1322         case 'S':
1323           if (category_name[2] == '\0')
1324             return UC_BIDI_CS;
1325           break;
1326         }
1327       break;
1328     case 'E':
1329       switch (category_name[1])
1330         {
1331         case 'N':
1332           if (category_name[2] == '\0')
1333             return UC_BIDI_EN;
1334           break;
1335         case 'S':
1336           if (category_name[2] == '\0')
1337             return UC_BIDI_ES;
1338           break;
1339         case 'T':
1340           if (category_name[2] == '\0')
1341             return UC_BIDI_ET;
1342           break;
1343         }
1344       break;
1345     case 'L':
1346       switch (category_name[1])
1347         {
1348         case '\0':
1349           return UC_BIDI_L;
1350         case 'R':
1351           switch (category_name[2])
1352             {
1353             case 'E':
1354               if (category_name[3] == '\0')
1355                 return UC_BIDI_LRE;
1356               break;
1357             case 'O':
1358               if (category_name[3] == '\0')
1359                 return UC_BIDI_LRO;
1360               break;
1361             }
1362           break;
1363         }
1364       break;
1365     case 'N':
1366       switch (category_name[1])
1367         {
1368         case 'S':
1369           switch (category_name[2])
1370             {
1371             case 'M':
1372               if (category_name[3] == '\0')
1373                 return UC_BIDI_NSM;
1374               break;
1375             }
1376           break;
1377         }
1378       break;
1379     case 'O':
1380       switch (category_name[1])
1381         {
1382         case 'N':
1383           if (category_name[2] == '\0')
1384             return UC_BIDI_ON;
1385           break;
1386         }
1387       break;
1388     case 'P':
1389       switch (category_name[1])
1390         {
1391         case 'D':
1392           switch (category_name[2])
1393             {
1394             case 'F':
1395               if (category_name[3] == '\0')
1396                 return UC_BIDI_PDF;
1397               break;
1398             }
1399           break;
1400         }
1401       break;
1402     case 'R':
1403       switch (category_name[1])
1404         {
1405         case '\0':
1406           return UC_BIDI_R;
1407         case 'L':
1408           switch (category_name[2])
1409             {
1410             case 'E':
1411               if (category_name[3] == '\0')
1412                 return UC_BIDI_RLE;
1413               break;
1414             case 'O':
1415               if (category_name[3] == '\0')
1416                 return UC_BIDI_RLO;
1417               break;
1418             }
1419           break;
1420         }
1421       break;
1422     case 'S':
1423       if (category_name[1] == '\0')
1424         return UC_BIDI_S;
1425       break;
1426     case 'W':
1427       switch (category_name[1])
1428         {
1429         case 'S':
1430           if (category_name[2] == '\0')
1431             return UC_BIDI_WS;
1432           break;
1433         }
1434       break;
1435     }
1436   /* Invalid bidi category name.  */
1437   abort ();
1438 }
1439
1440 static int
1441 get_bidi_category (unsigned int ch)
1442 {
1443   if (unicode_attributes[ch].name != NULL)
1444     return bidi_category_byname (unicode_attributes[ch].bidi);
1445   else
1446     {
1447       /* The bidi category of unassigned characters depends on the range.
1448          See UTR #9 and DerivedBidiClass.txt.  */
1449       if ((ch >= 0x0590 && ch <= 0x05FF)
1450           || (ch >= 0x07FB && ch <= 0x08FF)
1451           || (ch >= 0xFB37 && ch <= 0xFB45)
1452           || (ch >= 0x10800 && ch <= 0x10FFF))
1453         return UC_BIDI_R;
1454       else if ((ch >= 0x0600 && ch <= 0x07BF)
1455                || (ch >= 0x2064 && ch <= 0x2069)
1456                || (ch >= 0xFBB2 && ch <= 0xFDCF)
1457                || (ch >= 0xFDFE && ch <= 0xFEFE))
1458         return UC_BIDI_AL;
1459       else if ((ch >= 0xFDD0 && ch <= 0xFDEF)
1460                || (ch >= 0xFFF0 && ch <= 0xFFFF)
1461                || (ch & 0xFFFF) == 0xFFFE
1462                || (ch & 0xFFFF) == 0xFFFF
1463                || (ch >= 0xE0000 && ch <= 0xE0FFF))
1464         return UC_BIDI_BN;
1465       else
1466         return UC_BIDI_L;
1467     }
1468 }
1469
1470 /* Construction of sparse 3-level tables.  */
1471 #define TABLE bidi_category_table
1472 #define ELEMENT uint8_t
1473 #define DEFAULT UC_BIDI_L
1474 #define xmalloc malloc
1475 #define xrealloc realloc
1476 #include "3level.h"
1477
1478 /* Output the per-character bidi category table.  */
1479 static void
1480 output_bidi_category (const char *filename, const char *version)
1481 {
1482   FILE *stream;
1483   unsigned int ch, i;
1484   struct bidi_category_table t;
1485   unsigned int level1_offset, level2_offset, level3_offset;
1486   uint16_t *level3_packed;
1487
1488   stream = fopen (filename, "w");
1489   if (stream == NULL)
1490     {
1491       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1492       exit (1);
1493     }
1494
1495   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1496   fprintf (stream, "/* Bidi categories of Unicode characters.  */\n");
1497   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
1498            version);
1499
1500   t.p = 7;
1501   t.q = 9;
1502   bidi_category_table_init (&t);
1503
1504   for (ch = 0; ch < 0x110000; ch++)
1505     {
1506       int value = get_bidi_category (ch);
1507
1508       bidi_category_table_add (&t, ch, value);
1509     }
1510
1511   bidi_category_table_finalize (&t);
1512
1513   /* Offsets in t.result, in memory of this process.  */
1514   level1_offset =
1515     5 * sizeof (uint32_t);
1516   level2_offset =
1517     5 * sizeof (uint32_t)
1518     + t.level1_size * sizeof (uint32_t);
1519   level3_offset =
1520     5 * sizeof (uint32_t)
1521     + t.level1_size * sizeof (uint32_t)
1522     + (t.level2_size << t.q) * sizeof (uint32_t);
1523
1524   for (i = 0; i < 5; i++)
1525     fprintf (stream, "#define bidi_category_header_%d %d\n", i,
1526              ((uint32_t *) t.result)[i]);
1527   fprintf (stream, "static const\n");
1528   fprintf (stream, "struct\n");
1529   fprintf (stream, "  {\n");
1530   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1531   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1532   fprintf (stream, "    unsigned short level3[%zu * %d + 1];\n", t.level3_size,
1533            (1 << t.p) * 5 / 16);
1534   fprintf (stream, "  }\n");
1535   fprintf (stream, "u_bidi_category =\n");
1536   fprintf (stream, "{\n");
1537   fprintf (stream, "  {");
1538   if (t.level1_size > 8)
1539     fprintf (stream, "\n   ");
1540   for (i = 0; i < t.level1_size; i++)
1541     {
1542       uint32_t offset;
1543       if (i > 0 && (i % 8) == 0)
1544         fprintf (stream, "\n   ");
1545       offset = ((uint32_t *) (t.result + level1_offset))[i];
1546       if (offset == 0)
1547         fprintf (stream, " %5d", -1);
1548       else
1549         fprintf (stream, " %5zu",
1550                  (offset - level2_offset) / sizeof (uint32_t));
1551       if (i+1 < t.level1_size)
1552         fprintf (stream, ",");
1553     }
1554   if (t.level1_size > 8)
1555     fprintf (stream, "\n ");
1556   fprintf (stream, " },\n");
1557   fprintf (stream, "  {");
1558   if (t.level2_size << t.q > 8)
1559     fprintf (stream, "\n   ");
1560   for (i = 0; i < t.level2_size << t.q; i++)
1561     {
1562       uint32_t offset;
1563       if (i > 0 && (i % 8) == 0)
1564         fprintf (stream, "\n   ");
1565       offset = ((uint32_t *) (t.result + level2_offset))[i];
1566       if (offset == 0)
1567         fprintf (stream, " %5d", -1);
1568       else
1569         fprintf (stream, " %5zu",
1570                  (offset - level3_offset) / sizeof (uint8_t));
1571       if (i+1 < t.level2_size << t.q)
1572         fprintf (stream, ",");
1573     }
1574   if (t.level2_size << t.q > 8)
1575     fprintf (stream, "\n ");
1576   fprintf (stream, " },\n");
1577   /* Pack the level3 array.  Each entry needs 5 bits only.  Use 16-bit units,
1578      not 32-bit units, in order to make the lookup function easier.  */
1579   level3_packed =
1580     (uint16_t *)
1581     calloc ((t.level3_size << t.p) * 5 / 16 + 1, sizeof (uint16_t));
1582   for (i = 0; i < t.level3_size << t.p; i++)
1583     {
1584       unsigned int j = (i * 5) / 16;
1585       unsigned int k = (i * 5) % 16;
1586       uint32_t value = ((unsigned char *) (t.result + level3_offset))[i];
1587       value = level3_packed[j] | (level3_packed[j+1] << 16) | (value << k);
1588       level3_packed[j] = value & 0xffff;
1589       level3_packed[j+1] = value >> 16;
1590     }
1591   fprintf (stream, "  {");
1592   if ((t.level3_size << t.p) * 5 / 16 + 1 > 8)
1593     fprintf (stream, "\n   ");
1594   for (i = 0; i < (t.level3_size << t.p) * 5 / 16 + 1; i++)
1595     {
1596       if (i > 0 && (i % 8) == 0)
1597         fprintf (stream, "\n   ");
1598       fprintf (stream, " 0x%04x", level3_packed[i]);
1599       if (i+1 < (t.level3_size << t.p) * 5 / 16 + 1)
1600         fprintf (stream, ",");
1601     }
1602   if ((t.level3_size << t.p) * 5 / 16 + 1 > 8)
1603     fprintf (stream, "\n ");
1604   fprintf (stream, " }\n");
1605   free (level3_packed);
1606   fprintf (stream, "};\n");
1607
1608   if (ferror (stream) || fclose (stream))
1609     {
1610       fprintf (stderr, "error writing to '%s'\n", filename);
1611       exit (1);
1612     }
1613 }
1614
1615 /* ========================================================================= */
1616
1617 /* Decimal digit value.  */
1618 /* See Unicode 3.0 book, section 4.6.  */
1619
1620 static int
1621 get_decdigit_value (unsigned int ch)
1622 {
1623   if (unicode_attributes[ch].name != NULL
1624       && unicode_attributes[ch].decdigit[0] != '\0')
1625     return atoi (unicode_attributes[ch].decdigit);
1626   return -1;
1627 }
1628
1629 /* Construction of sparse 3-level tables.  */
1630 #define TABLE decdigit_table
1631 #define ELEMENT uint8_t
1632 #define DEFAULT 0
1633 #define xmalloc malloc
1634 #define xrealloc realloc
1635 #include "3level.h"
1636
1637 /* Output the unit test for the per-character decimal digit value table.  */
1638 static void
1639 output_decimal_digit_test (const char *filename, const char *version)
1640 {
1641   FILE *stream;
1642   bool need_comma;
1643   unsigned int ch;
1644
1645   stream = fopen (filename, "w");
1646   if (stream == NULL)
1647     {
1648       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1649       exit (1);
1650     }
1651
1652   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1653   fprintf (stream, "/* Decimal digit values of Unicode characters.  */\n");
1654   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
1655            version);
1656
1657   need_comma = false;
1658   for (ch = 0; ch < 0x110000; ch++)
1659     {
1660       int value = get_decdigit_value (ch);
1661
1662       if (!(value >= -1 && value < 10))
1663         abort ();
1664
1665       if (value >= 0)
1666         {
1667           if (need_comma)
1668             fprintf (stream, ",\n");
1669           fprintf (stream, "    { 0x%04X, %d }", ch, value);
1670           need_comma = true;
1671         }
1672     }
1673   if (need_comma)
1674     fprintf (stream, "\n");
1675
1676   if (ferror (stream) || fclose (stream))
1677     {
1678       fprintf (stderr, "error writing to '%s'\n", filename);
1679       exit (1);
1680     }
1681 }
1682
1683 /* Output the per-character decimal digit value table.  */
1684 static void
1685 output_decimal_digit (const char *filename, const char *version)
1686 {
1687   FILE *stream;
1688   unsigned int ch, i;
1689   struct decdigit_table t;
1690   unsigned int level1_offset, level2_offset, level3_offset;
1691
1692   stream = fopen (filename, "w");
1693   if (stream == NULL)
1694     {
1695       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1696       exit (1);
1697     }
1698
1699   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1700   fprintf (stream, "/* Decimal digit values of Unicode characters.  */\n");
1701   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
1702            version);
1703
1704   t.p = 7;
1705   t.q = 9;
1706   decdigit_table_init (&t);
1707
1708   for (ch = 0; ch < 0x110000; ch++)
1709     {
1710       int value = 1 + get_decdigit_value (ch);
1711
1712       if (!(value >= 0 && value <= 10))
1713         abort ();
1714
1715       decdigit_table_add (&t, ch, value);
1716     }
1717
1718   decdigit_table_finalize (&t);
1719
1720   /* Offsets in t.result, in memory of this process.  */
1721   level1_offset =
1722     5 * sizeof (uint32_t);
1723   level2_offset =
1724     5 * sizeof (uint32_t)
1725     + t.level1_size * sizeof (uint32_t);
1726   level3_offset =
1727     5 * sizeof (uint32_t)
1728     + t.level1_size * sizeof (uint32_t)
1729     + (t.level2_size << t.q) * sizeof (uint32_t);
1730
1731   for (i = 0; i < 5; i++)
1732     fprintf (stream, "#define decdigit_header_%d %d\n", i,
1733              ((uint32_t *) t.result)[i]);
1734   fprintf (stream, "static const\n");
1735   fprintf (stream, "struct\n");
1736   fprintf (stream, "  {\n");
1737   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1738   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1739   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size,
1740            t.p - 1);
1741   fprintf (stream, "  }\n");
1742   fprintf (stream, "u_decdigit =\n");
1743   fprintf (stream, "{\n");
1744   fprintf (stream, "  {");
1745   if (t.level1_size > 8)
1746     fprintf (stream, "\n   ");
1747   for (i = 0; i < t.level1_size; i++)
1748     {
1749       uint32_t offset;
1750       if (i > 0 && (i % 8) == 0)
1751         fprintf (stream, "\n   ");
1752       offset = ((uint32_t *) (t.result + level1_offset))[i];
1753       if (offset == 0)
1754         fprintf (stream, " %5d", -1);
1755       else
1756         fprintf (stream, " %5zu",
1757                  (offset - level2_offset) / sizeof (uint32_t));
1758       if (i+1 < t.level1_size)
1759         fprintf (stream, ",");
1760     }
1761   if (t.level1_size > 8)
1762     fprintf (stream, "\n ");
1763   fprintf (stream, " },\n");
1764   fprintf (stream, "  {");
1765   if (t.level2_size << t.q > 8)
1766     fprintf (stream, "\n   ");
1767   for (i = 0; i < t.level2_size << t.q; i++)
1768     {
1769       uint32_t offset;
1770       if (i > 0 && (i % 8) == 0)
1771         fprintf (stream, "\n   ");
1772       offset = ((uint32_t *) (t.result + level2_offset))[i];
1773       if (offset == 0)
1774         fprintf (stream, " %5d", -1);
1775       else
1776         fprintf (stream, " %5zu",
1777                  (offset - level3_offset) / sizeof (uint8_t));
1778       if (i+1 < t.level2_size << t.q)
1779         fprintf (stream, ",");
1780     }
1781   if (t.level2_size << t.q > 8)
1782     fprintf (stream, "\n ");
1783   fprintf (stream, " },\n");
1784   /* Pack the level3 array.  Each entry needs 4 bits only.  */
1785   fprintf (stream, "  {");
1786   if (t.level3_size << (t.p - 1) > 8)
1787     fprintf (stream, "\n   ");
1788   for (i = 0; i < t.level3_size << (t.p - 1); i++)
1789     {
1790       if (i > 0 && (i % 8) == 0)
1791         fprintf (stream, "\n   ");
1792       fprintf (stream, " 0x%02x",
1793                ((uint8_t *) (t.result + level3_offset))[2*i]
1794                + (((uint8_t *) (t.result + level3_offset))[2*i+1] << 4));
1795       if (i+1 < t.level3_size << (t.p - 1))
1796         fprintf (stream, ",");
1797     }
1798   if (t.level3_size << (t.p - 1) > 8)
1799     fprintf (stream, "\n ");
1800   fprintf (stream, " }\n");
1801   fprintf (stream, "};\n");
1802
1803   if (ferror (stream) || fclose (stream))
1804     {
1805       fprintf (stderr, "error writing to '%s'\n", filename);
1806       exit (1);
1807     }
1808 }
1809
1810 /* ========================================================================= */
1811
1812 /* Digit value.  */
1813 /* See Unicode 3.0 book, section 4.6.  */
1814
1815 static int
1816 get_digit_value (unsigned int ch)
1817 {
1818   if (unicode_attributes[ch].name != NULL
1819       && unicode_attributes[ch].digit[0] != '\0')
1820     return atoi (unicode_attributes[ch].digit);
1821   return -1;
1822 }
1823
1824 /* Output the unit test for the per-character digit value table.  */
1825 static void
1826 output_digit_test (const char *filename, const char *version)
1827 {
1828   FILE *stream;
1829   bool need_comma;
1830   unsigned int ch;
1831
1832   stream = fopen (filename, "w");
1833   if (stream == NULL)
1834     {
1835       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1836       exit (1);
1837     }
1838
1839   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1840   fprintf (stream, "/* Digit values of Unicode characters.  */\n");
1841   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
1842            version);
1843
1844   need_comma = false;
1845   for (ch = 0; ch < 0x110000; ch++)
1846     {
1847       int value = get_digit_value (ch);
1848
1849       if (!(value >= -1 && value < 10))
1850         abort ();
1851
1852       if (value >= 0)
1853         {
1854           if (need_comma)
1855             fprintf (stream, ",\n");
1856           fprintf (stream, "    { 0x%04X, %d }", ch, value);
1857           need_comma = true;
1858         }
1859     }
1860   if (need_comma)
1861     fprintf (stream, "\n");
1862
1863   if (ferror (stream) || fclose (stream))
1864     {
1865       fprintf (stderr, "error writing to '%s'\n", filename);
1866       exit (1);
1867     }
1868 }
1869
1870 /* Output the per-character digit value table.  */
1871 static void
1872 output_digit (const char *filename, const char *version)
1873 {
1874   FILE *stream;
1875   unsigned int ch, i;
1876   struct decdigit_table t;
1877   unsigned int level1_offset, level2_offset, level3_offset;
1878
1879   stream = fopen (filename, "w");
1880   if (stream == NULL)
1881     {
1882       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1883       exit (1);
1884     }
1885
1886   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1887   fprintf (stream, "/* Digit values of Unicode characters.  */\n");
1888   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
1889            version);
1890
1891   t.p = 7;
1892   t.q = 9;
1893   decdigit_table_init (&t);
1894
1895   for (ch = 0; ch < 0x110000; ch++)
1896     {
1897       int value = 1 + get_digit_value (ch);
1898
1899       if (!(value >= 0 && value <= 10))
1900         abort ();
1901
1902       decdigit_table_add (&t, ch, value);
1903     }
1904
1905   decdigit_table_finalize (&t);
1906
1907   /* Offsets in t.result, in memory of this process.  */
1908   level1_offset =
1909     5 * sizeof (uint32_t);
1910   level2_offset =
1911     5 * sizeof (uint32_t)
1912     + t.level1_size * sizeof (uint32_t);
1913   level3_offset =
1914     5 * sizeof (uint32_t)
1915     + t.level1_size * sizeof (uint32_t)
1916     + (t.level2_size << t.q) * sizeof (uint32_t);
1917
1918   for (i = 0; i < 5; i++)
1919     fprintf (stream, "#define digit_header_%d %d\n", i,
1920              ((uint32_t *) t.result)[i]);
1921   fprintf (stream, "static const\n");
1922   fprintf (stream, "struct\n");
1923   fprintf (stream, "  {\n");
1924   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1925   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1926   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size,
1927            t.p - 1);
1928   fprintf (stream, "  }\n");
1929   fprintf (stream, "u_digit =\n");
1930   fprintf (stream, "{\n");
1931   fprintf (stream, "  {");
1932   if (t.level1_size > 8)
1933     fprintf (stream, "\n   ");
1934   for (i = 0; i < t.level1_size; i++)
1935     {
1936       uint32_t offset;
1937       if (i > 0 && (i % 8) == 0)
1938         fprintf (stream, "\n   ");
1939       offset = ((uint32_t *) (t.result + level1_offset))[i];
1940       if (offset == 0)
1941         fprintf (stream, " %5d", -1);
1942       else
1943         fprintf (stream, " %5zu",
1944                  (offset - level2_offset) / sizeof (uint32_t));
1945       if (i+1 < t.level1_size)
1946         fprintf (stream, ",");
1947     }
1948   if (t.level1_size > 8)
1949     fprintf (stream, "\n ");
1950   fprintf (stream, " },\n");
1951   fprintf (stream, "  {");
1952   if (t.level2_size << t.q > 8)
1953     fprintf (stream, "\n   ");
1954   for (i = 0; i < t.level2_size << t.q; i++)
1955     {
1956       uint32_t offset;
1957       if (i > 0 && (i % 8) == 0)
1958         fprintf (stream, "\n   ");
1959       offset = ((uint32_t *) (t.result + level2_offset))[i];
1960       if (offset == 0)
1961         fprintf (stream, " %5d", -1);
1962       else
1963         fprintf (stream, " %5zu",
1964                  (offset - level3_offset) / sizeof (uint8_t));
1965       if (i+1 < t.level2_size << t.q)
1966         fprintf (stream, ",");
1967     }
1968   if (t.level2_size << t.q > 8)
1969     fprintf (stream, "\n ");
1970   fprintf (stream, " },\n");
1971   /* Pack the level3 array.  Each entry needs 4 bits only.  */
1972   fprintf (stream, "  {");
1973   if (t.level3_size << (t.p - 1) > 8)
1974     fprintf (stream, "\n   ");
1975   for (i = 0; i < t.level3_size << (t.p - 1); i++)
1976     {
1977       if (i > 0 && (i % 8) == 0)
1978         fprintf (stream, "\n   ");
1979       fprintf (stream, " 0x%02x",
1980                ((uint8_t *) (t.result + level3_offset))[2*i]
1981                + (((uint8_t *) (t.result + level3_offset))[2*i+1] << 4));
1982       if (i+1 < t.level3_size << (t.p - 1))
1983         fprintf (stream, ",");
1984     }
1985   if (t.level3_size << (t.p - 1) > 8)
1986     fprintf (stream, "\n ");
1987   fprintf (stream, " }\n");
1988   fprintf (stream, "};\n");
1989
1990   if (ferror (stream) || fclose (stream))
1991     {
1992       fprintf (stderr, "error writing to '%s'\n", filename);
1993       exit (1);
1994     }
1995 }
1996
1997 /* ========================================================================= */
1998
1999 /* Numeric value.  */
2000 /* See Unicode 3.0 book, section 4.6.  */
2001
2002 typedef struct { int numerator; int denominator; } uc_fraction_t;
2003
2004 static uc_fraction_t
2005 get_numeric_value (unsigned int ch)
2006 {
2007   uc_fraction_t value;
2008
2009   if (unicode_attributes[ch].name != NULL
2010       && unicode_attributes[ch].numeric[0] != '\0')
2011     {
2012       const char *str = unicode_attributes[ch].numeric;
2013       /* str is of the form "integer" or "integer/posinteger".  */
2014       value.numerator = atoi (str);
2015       if (strchr (str, '/') != NULL)
2016         value.denominator = atoi (strchr (str, '/') + 1);
2017       else
2018         value.denominator = 1;
2019     }
2020   else
2021     {
2022       value.numerator = 0;
2023       value.denominator = 0;
2024     }
2025   return value;
2026 }
2027
2028 /* Output the unit test for the per-character numeric value table.  */
2029 static void
2030 output_numeric_test (const char *filename, const char *version)
2031 {
2032   FILE *stream;
2033   bool need_comma;
2034   unsigned int ch;
2035
2036   stream = fopen (filename, "w");
2037   if (stream == NULL)
2038     {
2039       fprintf (stderr, "cannot open '%s' for writing\n", filename);
2040       exit (1);
2041     }
2042
2043   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
2044   fprintf (stream, "/* Numeric values of Unicode characters.  */\n");
2045   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
2046            version);
2047
2048   need_comma = false;
2049   for (ch = 0; ch < 0x110000; ch++)
2050     {
2051       uc_fraction_t value = get_numeric_value (ch);
2052
2053       if (value.numerator != 0 || value.denominator != 0)
2054         {
2055           if (need_comma)
2056             fprintf (stream, ",\n");
2057           fprintf (stream, "    { 0x%04X, %d, %d }",
2058                    ch, value.numerator, value.denominator);
2059           need_comma = true;
2060         }
2061     }
2062   if (need_comma)
2063     fprintf (stream, "\n");
2064
2065   if (ferror (stream) || fclose (stream))
2066     {
2067       fprintf (stderr, "error writing to '%s'\n", filename);
2068       exit (1);
2069     }
2070 }
2071
2072 /* Construction of sparse 3-level tables.  */
2073 #define TABLE numeric_table
2074 #define ELEMENT uint8_t
2075 #define DEFAULT 0
2076 #define xmalloc malloc
2077 #define xrealloc realloc
2078 #include "3level.h"
2079
2080 /* Output the per-character numeric value table.  */
2081 static void
2082 output_numeric (const char *filename, const char *version)
2083 {
2084   FILE *stream;
2085   uc_fraction_t fractions[128];
2086   unsigned int nfractions;
2087   unsigned int ch, i, j;
2088   struct numeric_table t;
2089   unsigned int level1_offset, level2_offset, level3_offset;
2090   uint16_t *level3_packed;
2091
2092   stream = fopen (filename, "w");
2093   if (stream == NULL)
2094     {
2095       fprintf (stderr, "cannot open '%s' for writing\n", filename);
2096       exit (1);
2097     }
2098
2099   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
2100   fprintf (stream, "/* Numeric values of Unicode characters.  */\n");
2101   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
2102            version);
2103
2104   /* Create table of occurring fractions.  */
2105   nfractions = 0;
2106   for (ch = 0; ch < 0x110000; ch++)
2107     {
2108       uc_fraction_t value = get_numeric_value (ch);
2109
2110       for (i = 0; i < nfractions; i++)
2111         if (value.numerator == fractions[i].numerator
2112             && value.denominator == fractions[i].denominator)
2113           break;
2114       if (i == nfractions)
2115         {
2116           if (nfractions == 128)
2117             abort ();
2118           for (i = 0; i < nfractions; i++)
2119             if (value.denominator < fractions[i].denominator
2120                 || (value.denominator == fractions[i].denominator
2121                     && value.numerator < fractions[i].numerator))
2122               break;
2123           for (j = nfractions; j > i; j--)
2124             fractions[j] = fractions[j - 1];
2125           fractions[i] = value;
2126           nfractions++;
2127         }
2128     }
2129
2130   fprintf (stream, "static const uc_fraction_t u_numeric_values[%d] =\n",
2131            nfractions);
2132   fprintf (stream, "{\n");
2133   for (i = 0; i < nfractions; i++)
2134     {
2135       fprintf (stream, "  { %d, %d }", fractions[i].numerator,
2136                fractions[i].denominator);
2137       if (i+1 < nfractions)
2138         fprintf (stream, ",");
2139       fprintf (stream, "\n");
2140     }
2141   fprintf (stream, "};\n");
2142
2143   t.p = 7;
2144   t.q = 9;
2145   numeric_table_init (&t);
2146
2147   for (ch = 0; ch < 0x110000; ch++)
2148     {
2149       uc_fraction_t value = get_numeric_value (ch);
2150
2151       for (i = 0; i < nfractions; i++)
2152         if (value.numerator == fractions[i].numerator
2153             && value.denominator == fractions[i].denominator)
2154           break;
2155       if (i == nfractions)
2156         abort ();
2157
2158       numeric_table_add (&t, ch, i);
2159     }
2160
2161   numeric_table_finalize (&t);
2162
2163   /* Offsets in t.result, in memory of this process.  */
2164   level1_offset =
2165     5 * sizeof (uint32_t);
2166   level2_offset =
2167     5 * sizeof (uint32_t)
2168     + t.level1_size * sizeof (uint32_t);
2169   level3_offset =
2170     5 * sizeof (uint32_t)
2171     + t.level1_size * sizeof (uint32_t)
2172     + (t.level2_size << t.q) * sizeof (uint32_t);
2173
2174   for (i = 0; i < 5; i++)
2175     fprintf (stream, "#define numeric_header_%d %d\n", i,
2176              ((uint32_t *) t.result)[i]);
2177   fprintf (stream, "static const\n");
2178   fprintf (stream, "struct\n");
2179   fprintf (stream, "  {\n");
2180   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
2181   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
2182   fprintf (stream, "    unsigned short level3[%zu * %d + 1];\n", t.level3_size,
2183            (1 << t.p) * 7 / 16);
2184   fprintf (stream, "  }\n");
2185   fprintf (stream, "u_numeric =\n");
2186   fprintf (stream, "{\n");
2187   fprintf (stream, "  {");
2188   if (t.level1_size > 8)
2189     fprintf (stream, "\n   ");
2190   for (i = 0; i < t.level1_size; i++)
2191     {
2192       uint32_t offset;
2193       if (i > 0 && (i % 8) == 0)
2194         fprintf (stream, "\n   ");
2195       offset = ((uint32_t *) (t.result + level1_offset))[i];
2196       if (offset == 0)
2197         fprintf (stream, " %5d", -1);
2198       else
2199         fprintf (stream, " %5zu",
2200                  (offset - level2_offset) / sizeof (uint32_t));
2201       if (i+1 < t.level1_size)
2202         fprintf (stream, ",");
2203     }
2204   if (t.level1_size > 8)
2205     fprintf (stream, "\n ");
2206   fprintf (stream, " },\n");
2207   fprintf (stream, "  {");
2208   if (t.level2_size << t.q > 8)
2209     fprintf (stream, "\n   ");
2210   for (i = 0; i < t.level2_size << t.q; i++)
2211     {
2212       uint32_t offset;
2213       if (i > 0 && (i % 8) == 0)
2214         fprintf (stream, "\n   ");
2215       offset = ((uint32_t *) (t.result + level2_offset))[i];
2216       if (offset == 0)
2217         fprintf (stream, " %5d", -1);
2218       else
2219         fprintf (stream, " %5zu",
2220                  (offset - level3_offset) / sizeof (uint8_t));
2221       if (i+1 < t.level2_size << t.q)
2222         fprintf (stream, ",");
2223     }
2224   if (t.level2_size << t.q > 8)
2225     fprintf (stream, "\n ");
2226   fprintf (stream, " },\n");
2227   /* Pack the level3 array.  Each entry needs 7 bits only.  Use 16-bit units,
2228      not 32-bit units, in order to make the lookup function easier.  */
2229   level3_packed =
2230     (uint16_t *)
2231     calloc ((t.level3_size << t.p) * 7 / 16 + 1, sizeof (uint16_t));
2232   for (i = 0; i < t.level3_size << t.p; i++)
2233     {
2234       unsigned int j = (i * 7) / 16;
2235       unsigned int k = (i * 7) % 16;
2236       uint32_t value = ((unsigned char *) (t.result + level3_offset))[i];
2237       value = level3_packed[j] | (level3_packed[j+1] << 16) | (value << k);
2238       level3_packed[j] = value & 0xffff;
2239       level3_packed[j+1] = value >> 16;
2240     }
2241   fprintf (stream, "  {");
2242   if ((t.level3_size << t.p) * 7 / 16 + 1 > 8)
2243     fprintf (stream, "\n   ");
2244   for (i = 0; i < (t.level3_size << t.p) * 7 / 16 + 1; i++)
2245     {
2246       if (i > 0 && (i % 8) == 0)
2247         fprintf (stream, "\n   ");
2248       fprintf (stream, " 0x%04x", level3_packed[i]);
2249       if (i+1 < (t.level3_size << t.p) * 7 / 16 + 1)
2250         fprintf (stream, ",");
2251     }
2252   if ((t.level3_size << t.p) * 7 / 16 + 1 > 8)
2253     fprintf (stream, "\n ");
2254   fprintf (stream, " }\n");
2255   free (level3_packed);
2256   fprintf (stream, "};\n");
2257
2258   if (ferror (stream) || fclose (stream))
2259     {
2260       fprintf (stderr, "error writing to '%s'\n", filename);
2261       exit (1);
2262     }
2263 }
2264
2265 /* ========================================================================= */
2266
2267 /* Mirrored.  */
2268 /* See Unicode 3.0 book, section 4.7,
2269        UAX #9.  */
2270
2271 /* List of mirrored character pairs.  This is a subset of the characters
2272    having the BidiMirrored property.  */
2273 static unsigned int mirror_pairs[][2] =
2274 {
2275   { 0x0028, 0x0029 },
2276   { 0x003C, 0x003E },
2277   { 0x005B, 0x005D },
2278   { 0x007B, 0x007D },
2279   { 0x00AB, 0x00BB },
2280   { 0x2039, 0x203A },
2281   { 0x2045, 0x2046 },
2282   { 0x207D, 0x207E },
2283   { 0x208D, 0x208E },
2284   { 0x2208, 0x220B },
2285   { 0x220A, 0x220D },
2286   { 0x223C, 0x223D },
2287   { 0x2243, 0x22CD },
2288   { 0x2252, 0x2253 },
2289   { 0x2254, 0x2255 },
2290   { 0x2264, 0x2265 },
2291   { 0x2266, 0x2267 },
2292   { 0x226A, 0x226B },
2293   { 0x2276, 0x2277 },
2294   { 0x2278, 0x2279 },
2295   { 0x227A, 0x227B },
2296   { 0x227C, 0x227D },
2297   { 0x2282, 0x2283 },
2298   { 0x2286, 0x2287 },
2299   { 0x228F, 0x2290 },
2300   { 0x2291, 0x2292 },
2301   { 0x22A2, 0x22A3 },
2302   { 0x22B0, 0x22B1 },
2303   { 0x22B2, 0x22B3 },
2304   { 0x22B4, 0x22B5 },
2305   { 0x22B6, 0x22B7 },
2306   { 0x22C9, 0x22CA },
2307   { 0x22CB, 0x22CC },
2308   { 0x22D0, 0x22D1 },
2309   { 0x22D6, 0x22D7 },
2310   { 0x22D8, 0x22D9 },
2311   { 0x22DA, 0x22DB },
2312   { 0x22DC, 0x22DD },
2313   { 0x22DE, 0x22DF },
2314   { 0x22F0, 0x22F1 },
2315   { 0x2308, 0x2309 },
2316   { 0x230A, 0x230B },
2317   { 0x2329, 0x232A },
2318   { 0x3008, 0x3009 },
2319   { 0x300A, 0x300B },
2320   { 0x300C, 0x300D },
2321   { 0x300E, 0x300F },
2322   { 0x3010, 0x3011 },
2323   { 0x3014, 0x3015 },
2324   { 0x3016, 0x3017 },
2325   { 0x3018, 0x3019 },
2326   { 0x301A, 0x301B }
2327 };
2328
2329 static int
2330 get_mirror_value (unsigned int ch)
2331 {
2332   bool mirrored;
2333   unsigned int mirror_char;
2334   unsigned int i;
2335
2336   mirrored = (unicode_attributes[ch].name != NULL
2337               && unicode_attributes[ch].mirrored);
2338   mirror_char = 0xfffd;
2339   for (i = 0; i < sizeof (mirror_pairs) / sizeof (mirror_pairs[0]); i++)
2340     if (ch == mirror_pairs[i][0])
2341       {
2342         mirror_char = mirror_pairs[i][1];
2343         break;
2344       }
2345     else if (ch == mirror_pairs[i][1])
2346       {
2347         mirror_char = mirror_pairs[i][0];
2348         break;
2349       }
2350   if (mirrored)
2351     return (int) mirror_char - (int) ch;
2352   else
2353     {
2354       if (mirror_char != 0xfffd)
2355         abort ();
2356       return 0;
2357     }
2358 }
2359
2360 /* Construction of sparse 3-level tables.  */
2361 #define TABLE mirror_table
2362 #define ELEMENT int32_t
2363 #define DEFAULT 0
2364 #define xmalloc malloc
2365 #define xrealloc realloc
2366 #include "3level.h"
2367
2368 /* Output the per-character mirror table.  */
2369 static void
2370 output_mirror (const char *filename, const char *version)
2371 {
2372   FILE *stream;
2373   unsigned int ch, i;
2374   struct mirror_table t;
2375   unsigned int level1_offset, level2_offset, level3_offset;
2376
2377   stream = fopen (filename, "w");
2378   if (stream == NULL)
2379     {
2380       fprintf (stderr, "cannot open '%s' for writing\n", filename);
2381       exit (1);
2382     }
2383
2384   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
2385   fprintf (stream, "/* Mirrored Unicode characters.  */\n");
2386   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
2387            version);
2388
2389   t.p = 7;
2390   t.q = 9;
2391   mirror_table_init (&t);
2392
2393   for (ch = 0; ch < 0x110000; ch++)
2394     {
2395       int value = get_mirror_value (ch);
2396
2397       mirror_table_add (&t, ch, value);
2398     }
2399
2400   mirror_table_finalize (&t);
2401
2402   /* Offsets in t.result, in memory of this process.  */
2403   level1_offset =
2404     5 * sizeof (uint32_t);
2405   level2_offset =
2406     5 * sizeof (uint32_t)
2407     + t.level1_size * sizeof (uint32_t);
2408   level3_offset =
2409     5 * sizeof (uint32_t)
2410     + t.level1_size * sizeof (uint32_t)
2411     + (t.level2_size << t.q) * sizeof (uint32_t);
2412
2413   for (i = 0; i < 5; i++)
2414     fprintf (stream, "#define mirror_header_%d %d\n", i,
2415              ((uint32_t *) t.result)[i]);
2416   fprintf (stream, "static const\n");
2417   fprintf (stream, "struct\n");
2418   fprintf (stream, "  {\n");
2419   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
2420   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
2421   fprintf (stream, "    int level3[%zu << %d];\n", t.level3_size, t.p);
2422   fprintf (stream, "  }\n");
2423   fprintf (stream, "u_mirror =\n");
2424   fprintf (stream, "{\n");
2425   fprintf (stream, "  {");
2426   if (t.level1_size > 8)
2427     fprintf (stream, "\n   ");
2428   for (i = 0; i < t.level1_size; i++)
2429     {
2430       uint32_t offset;
2431       if (i > 0 && (i % 8) == 0)
2432         fprintf (stream, "\n   ");
2433       offset = ((uint32_t *) (t.result + level1_offset))[i];
2434       if (offset == 0)
2435         fprintf (stream, " %5d", -1);
2436       else
2437         fprintf (stream, " %5zu",
2438                  (offset - level2_offset) / sizeof (uint32_t));
2439       if (i+1 < t.level1_size)
2440         fprintf (stream, ",");
2441     }
2442   if (t.level1_size > 8)
2443     fprintf (stream, "\n ");
2444   fprintf (stream, " },\n");
2445   fprintf (stream, "  {");
2446   if (t.level2_size << t.q > 8)
2447     fprintf (stream, "\n   ");
2448   for (i = 0; i < t.level2_size << t.q; i++)
2449     {
2450       uint32_t offset;
2451       if (i > 0 && (i % 8) == 0)
2452         fprintf (stream, "\n   ");
2453       offset = ((uint32_t *) (t.result + level2_offset))[i];
2454       if (offset == 0)
2455         fprintf (stream, " %5d", -1);
2456       else
2457         fprintf (stream, " %5zu",
2458                  (offset - level3_offset) / sizeof (int32_t));
2459       if (i+1 < t.level2_size << t.q)
2460         fprintf (stream, ",");
2461     }
2462   if (t.level2_size << t.q > 8)
2463     fprintf (stream, "\n ");
2464   fprintf (stream, " },\n");
2465   fprintf (stream, "  {");
2466   if (t.level3_size << t.p > 8)
2467     fprintf (stream, "\n   ");
2468   for (i = 0; i < t.level3_size << t.p; i++)
2469     {
2470       if (i > 0 && (i % 8) == 0)
2471         fprintf (stream, "\n   ");
2472       fprintf (stream, " %5d", ((int32_t *) (t.result + level3_offset))[i]);
2473       if (i+1 < t.level3_size << t.p)
2474         fprintf (stream, ",");
2475     }
2476   if (t.level3_size << t.p > 8)
2477     fprintf (stream, "\n ");
2478   fprintf (stream, " }\n");
2479   fprintf (stream, "};\n");
2480
2481   if (ferror (stream) || fclose (stream))
2482     {
2483       fprintf (stderr, "error writing to '%s'\n", filename);
2484       exit (1);
2485     }
2486 }
2487
2488 /* ========================================================================= */
2489
2490 /* Properties.  */
2491
2492 /* Reading PropList.txt and DerivedCoreProperties.txt.  */
2493 enum
2494 {
2495   /* PropList.txt */
2496   PROP_WHITE_SPACE,
2497   PROP_BIDI_CONTROL,
2498   PROP_JOIN_CONTROL,
2499   PROP_DASH,
2500   PROP_HYPHEN,
2501   PROP_QUOTATION_MARK,
2502   PROP_TERMINAL_PUNCTUATION,
2503   PROP_OTHER_MATH,
2504   PROP_HEX_DIGIT,
2505   PROP_ASCII_HEX_DIGIT,
2506   PROP_OTHER_ALPHABETIC,
2507   PROP_IDEOGRAPHIC,
2508   PROP_DIACRITIC,
2509   PROP_EXTENDER,
2510   PROP_OTHER_LOWERCASE,
2511   PROP_OTHER_UPPERCASE,
2512   PROP_NONCHARACTER_CODE_POINT,
2513   PROP_OTHER_GRAPHEME_EXTEND,
2514   PROP_IDS_BINARY_OPERATOR,
2515   PROP_IDS_TRINARY_OPERATOR,
2516   PROP_RADICAL,
2517   PROP_UNIFIED_IDEOGRAPH,
2518   PROP_OTHER_DEFAULT_IGNORABLE_CODE_POINT,
2519   PROP_DEPRECATED,
2520   PROP_SOFT_DOTTED,
2521   PROP_LOGICAL_ORDER_EXCEPTION,
2522   PROP_OTHER_ID_START,
2523   PROP_OTHER_ID_CONTINUE,
2524   PROP_STERM,
2525   PROP_VARIATION_SELECTOR,
2526   PROP_PATTERN_WHITE_SPACE,
2527   PROP_PATTERN_SYNTAX,
2528   /* DerivedCoreProperties.txt */
2529   PROP_MATH,
2530   PROP_ALPHABETIC,
2531   PROP_LOWERCASE,
2532   PROP_UPPERCASE,
2533   PROP_ID_START,
2534   PROP_ID_CONTINUE,
2535   PROP_XID_START,
2536   PROP_XID_CONTINUE,
2537   PROP_DEFAULT_IGNORABLE_CODE_POINT,
2538   PROP_GRAPHEME_EXTEND,
2539   PROP_GRAPHEME_BASE,
2540   PROP_GRAPHEME_LINK
2541 };
2542 unsigned long long unicode_properties[0x110000];
2543
2544 static void
2545 clear_properties (void)
2546 {
2547   unsigned int i;
2548
2549   for (i = 0; i < 0x110000; i++)
2550     unicode_properties[i] = 0;
2551 }
2552
2553 /* Stores in unicode_properties[] the properties from the
2554    PropList.txt or DerivedCoreProperties.txt file.  */
2555 static void
2556 fill_properties (const char *proplist_filename)
2557 {
2558   unsigned int i;
2559   FILE *stream;
2560
2561   stream = fopen (proplist_filename, "r");
2562   if (stream == NULL)
2563     {
2564       fprintf (stderr, "error during fopen of '%s'\n", proplist_filename);
2565       exit (1);
2566     }
2567
2568   for (;;)
2569     {
2570       char buf[200+1];
2571       unsigned int i1, i2;
2572       char padding[200+1];
2573       char propname[200+1];
2574       unsigned int propvalue;
2575
2576       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
2577         break;
2578
2579       if (buf[0] == '\0' || buf[0] == '#')
2580         continue;
2581
2582       if (sscanf (buf, "%X..%X%[ ;]%[^ ]", &i1, &i2, padding, propname) != 4)
2583         {
2584           if (sscanf (buf, "%X%[ ;]%[^ ]", &i1, padding, propname) != 3)
2585             {
2586               fprintf (stderr, "parse error in '%s'\n", proplist_filename);
2587               exit (1);
2588             }
2589           i2 = i1;
2590         }
2591 #define PROP(name,value) \
2592       if (strcmp (propname, name) == 0) propvalue = value; else
2593       /* PropList.txt */
2594       PROP ("White_Space", PROP_WHITE_SPACE)
2595       PROP ("Bidi_Control", PROP_BIDI_CONTROL)
2596       PROP ("Join_Control", PROP_JOIN_CONTROL)
2597       PROP ("Dash", PROP_DASH)
2598       PROP ("Hyphen", PROP_HYPHEN)
2599       PROP ("Quotation_Mark", PROP_QUOTATION_MARK)
2600       PROP ("Terminal_Punctuation", PROP_TERMINAL_PUNCTUATION)
2601       PROP ("Other_Math", PROP_OTHER_MATH)
2602       PROP ("Hex_Digit", PROP_HEX_DIGIT)
2603       PROP ("ASCII_Hex_Digit", PROP_ASCII_HEX_DIGIT)
2604       PROP ("Other_Alphabetic", PROP_OTHER_ALPHABETIC)
2605       PROP ("Ideographic", PROP_IDEOGRAPHIC)
2606       PROP ("Diacritic", PROP_DIACRITIC)
2607       PROP ("Extender", PROP_EXTENDER)
2608       PROP ("Other_Lowercase", PROP_OTHER_LOWERCASE)
2609       PROP ("Other_Uppercase", PROP_OTHER_UPPERCASE)
2610       PROP ("Noncharacter_Code_Point", PROP_NONCHARACTER_CODE_POINT)
2611       PROP ("Other_Grapheme_Extend", PROP_OTHER_GRAPHEME_EXTEND)
2612       PROP ("IDS_Binary_Operator", PROP_IDS_BINARY_OPERATOR)
2613       PROP ("IDS_Trinary_Operator", PROP_IDS_TRINARY_OPERATOR)
2614       PROP ("Radical", PROP_RADICAL)
2615       PROP ("Unified_Ideograph", PROP_UNIFIED_IDEOGRAPH)
2616       PROP ("Other_Default_Ignorable_Code_Point", PROP_OTHER_DEFAULT_IGNORABLE_CODE_POINT)
2617       PROP ("Deprecated", PROP_DEPRECATED)
2618       PROP ("Soft_Dotted", PROP_SOFT_DOTTED)
2619       PROP ("Logical_Order_Exception", PROP_LOGICAL_ORDER_EXCEPTION)
2620       PROP ("Other_ID_Start", PROP_OTHER_ID_START)
2621       PROP ("Other_ID_Continue", PROP_OTHER_ID_CONTINUE)
2622       PROP ("STerm", PROP_STERM)
2623       PROP ("Variation_Selector", PROP_VARIATION_SELECTOR)
2624       PROP ("Pattern_White_Space", PROP_PATTERN_WHITE_SPACE)
2625       PROP ("Pattern_Syntax", PROP_PATTERN_SYNTAX)
2626       /* DerivedCoreProperties.txt */
2627       PROP ("Math", PROP_MATH)
2628       PROP ("Alphabetic", PROP_ALPHABETIC)
2629       PROP ("Lowercase", PROP_LOWERCASE)
2630       PROP ("Uppercase", PROP_UPPERCASE)
2631       PROP ("ID_Start", PROP_ID_START)
2632       PROP ("ID_Continue", PROP_ID_CONTINUE)
2633       PROP ("XID_Start", PROP_XID_START)
2634       PROP ("XID_Continue", PROP_XID_CONTINUE)
2635       PROP ("Default_Ignorable_Code_Point", PROP_DEFAULT_IGNORABLE_CODE_POINT)
2636       PROP ("Grapheme_Extend", PROP_GRAPHEME_EXTEND)
2637       PROP ("Grapheme_Base", PROP_GRAPHEME_BASE)
2638       PROP ("Grapheme_Link", PROP_GRAPHEME_LINK)
2639 #undef PROP
2640         {
2641           fprintf (stderr, "unknown property named '%s' in '%s'\n", propname,
2642                    proplist_filename);
2643           exit (1);
2644         }
2645       if (!(i1 <= i2 && i2 < 0x110000))
2646         abort ();
2647
2648       for (i = i1; i <= i2; i++)
2649         unicode_properties[i] |= 1ULL << propvalue;
2650     }
2651
2652   if (ferror (stream) || fclose (stream))
2653     {
2654       fprintf (stderr, "error reading from '%s'\n", proplist_filename);
2655       exit (1);
2656     }
2657 }
2658
2659 /* Stores in array the given property from the Unicode 3.0 PropList.txt
2660    file.  */
2661 static void
2662 fill_property30 (char array[0x110000], const char *proplist_filename, const char *property_name)
2663 {
2664   unsigned int i;
2665   FILE *stream;
2666   char buf[100+1];
2667
2668   for (i = 0; i < 0x110000; i++)
2669     array[i] = 0;
2670
2671   stream = fopen (proplist_filename, "r");
2672   if (stream == NULL)
2673     {
2674       fprintf (stderr, "error during fopen of '%s'\n", proplist_filename);
2675       exit (1);
2676     }
2677
2678   /* Search for the "Property dump for: ..." line.  */
2679   do
2680     {
2681       if (fscanf (stream, "%100[^\n]\n", buf) < 1)
2682         {
2683           fprintf (stderr, "no property found in '%s'\n", proplist_filename);
2684           exit (1);
2685         }
2686     }
2687   while (strstr (buf, property_name) == NULL);
2688
2689   for (;;)
2690     {
2691       unsigned int i1, i2;
2692
2693       if (fscanf (stream, "%100[^\n]\n", buf) < 1)
2694         break;
2695       if (buf[0] == '*')
2696         break;
2697       if (strlen (buf) >= 10 && buf[4] == '.' && buf[5] == '.')
2698         {
2699           if (sscanf (buf, "%4X..%4X", &i1, &i2) < 2)
2700             {
2701               fprintf (stderr, "parse error in property in '%s'\n",
2702                        proplist_filename);
2703               exit (1);
2704             }
2705         }
2706       else if (strlen (buf) >= 4)
2707         {
2708           if (sscanf (buf, "%4X", &i1) < 1)
2709             {
2710               fprintf (stderr, "parse error in property in '%s'\n",
2711                        proplist_filename);
2712               exit (1);
2713             }
2714           i2 = i1;
2715         }
2716       else
2717         {
2718           fprintf (stderr, "parse error in property in '%s'\n",
2719                    proplist_filename);
2720           exit (1);
2721         }
2722       if (!(i1 <= i2 && i2 < 0x110000))
2723         abort ();
2724       for (i = i1; i <= i2; i++)
2725         array[i] = 1;
2726     }
2727   if (ferror (stream) || fclose (stream))
2728     {
2729       fprintf (stderr, "error reading from '%s'\n", proplist_filename);
2730       exit (1);
2731     }
2732 }
2733
2734 /* Properties from Unicode 3.0 PropList.txt file.  */
2735
2736 /* The paired punctuation property from the PropList.txt file.  */
2737 char unicode_pairedpunctuation[0x110000];
2738
2739 /* The left of pair property from the PropList.txt file.  */
2740 char unicode_leftofpair[0x110000];
2741
2742 static void
2743 fill_properties30 (const char *proplist30_filename)
2744 {
2745   fill_property30 (unicode_pairedpunctuation, proplist30_filename, "(Paired Punctuation)");
2746   fill_property30 (unicode_leftofpair, proplist30_filename, "(Left of Pair)");
2747 }
2748
2749 /* ------------------------------------------------------------------------- */
2750
2751 /* See PropList.txt, UCD.html.  */
2752 static bool
2753 is_property_white_space (unsigned int ch)
2754 {
2755   return ((unicode_properties[ch] & (1ULL << PROP_WHITE_SPACE)) != 0);
2756 }
2757
2758 /* See Unicode 3.0 book, section 4.10,
2759        PropList.txt, UCD.html,
2760        DerivedCoreProperties.txt, UCD.html.  */
2761 static bool
2762 is_property_alphabetic (unsigned int ch)
2763 {
2764   bool result1 =
2765     is_category_L (ch)
2766     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_ALPHABETIC)) != 0)
2767     /* For some reason, the following are listed as having property
2768        Alphabetic but not as having property Other_Alphabetic.  */
2769     || (ch >= 0x16EE && ch <= 0x16F0) /* RUNIC SYMBOLS */
2770     || (ch >= 0x2160 && ch <= 0x2182) /* ROMAN NUMERALS */
2771     || (ch >= 0x2185 && ch <= 0x2188) /* ROMAN NUMERALS */
2772     || (ch >= 0x24D0 && ch <= 0x24E9) /* CIRCLED LATIN SMALL LETTER */
2773     || (ch == 0x3007) /* IDEOGRAPHIC NUMBER ZERO */
2774     || (ch >= 0x3021 && ch <= 0x3029) /* HANGZHOU NUMERAL */
2775     || (ch >= 0x3038 && ch <= 0x303A) /* HANGZHOU NUMERAL */
2776     || (ch >= 0x10140 && ch <= 0x10174) /* GREEK ACROPHONICS */
2777     || (ch == 0x10341) /* GOTHIC LETTER NINETY */
2778     || (ch == 0x1034A) /* GOTHIC LETTER NINE HUNDRED */
2779     || (ch >= 0x103D1 && ch <= 0x103D5) /* OLD PERSIAN NUMBERS */
2780     || (ch >= 0x12400 && ch <= 0x12462); /* CUNEIFORM NUMERIC SIGNS */
2781   bool result2 =
2782     ((unicode_properties[ch] & (1ULL << PROP_ALPHABETIC)) != 0);
2783
2784   if (result1 != result2)
2785     abort ();
2786   return result1;
2787 }
2788
2789 /* See PropList.txt, UCD.html.  */
2790 static bool
2791 is_property_other_alphabetic (unsigned int ch)
2792 {
2793   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_ALPHABETIC)) != 0);
2794 }
2795
2796 /* See PropList.txt, UCD.html.  */
2797 static bool
2798 is_property_not_a_character (unsigned int ch)
2799 {
2800   return ((unicode_properties[ch] & (1ULL << PROP_NONCHARACTER_CODE_POINT)) != 0);
2801 }
2802
2803 /* See PropList.txt, UCD.html,
2804        DerivedCoreProperties.txt, UCD.html.  */
2805 static bool
2806 is_property_default_ignorable_code_point (unsigned int ch)
2807 {
2808   bool result1 =
2809     (is_category_Cf (ch)
2810      && !(ch >= 0xFFF9 && ch <= 0xFFFB) /* Annotations */
2811      && !((ch >= 0x0600 && ch <= 0x0603) || ch == 0x06DD || ch == 0x070F))
2812     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_DEFAULT_IGNORABLE_CODE_POINT)) != 0)
2813     || ((unicode_properties[ch] & (1ULL << PROP_VARIATION_SELECTOR)) != 0);
2814   bool result2 =
2815     ((unicode_properties[ch] & (1ULL << PROP_DEFAULT_IGNORABLE_CODE_POINT)) != 0);
2816
2817   if (result1 != result2)
2818     abort ();
2819   return result1;
2820 }
2821
2822 /* See PropList.txt, UCD.html.  */
2823 static bool
2824 is_property_other_default_ignorable_code_point (unsigned int ch)
2825 {
2826   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_DEFAULT_IGNORABLE_CODE_POINT)) != 0);
2827 }
2828
2829 /* See PropList.txt, UCD.html.  */
2830 static bool
2831 is_property_deprecated (unsigned int ch)
2832 {
2833   return ((unicode_properties[ch] & (1ULL << PROP_DEPRECATED)) != 0);
2834 }
2835
2836 /* See PropList.txt, UCD.html.  */
2837 static bool
2838 is_property_logical_order_exception (unsigned int ch)
2839 {
2840   return ((unicode_properties[ch] & (1ULL << PROP_LOGICAL_ORDER_EXCEPTION)) != 0);
2841 }
2842
2843 /* See PropList.txt, UCD.html.  */
2844 static bool
2845 is_property_variation_selector (unsigned int ch)
2846 {
2847   return ((unicode_properties[ch] & (1ULL << PROP_VARIATION_SELECTOR)) != 0);
2848 }
2849
2850 /* See PropList-3.0.1.txt.  */
2851 static bool
2852 is_property_private_use (unsigned int ch)
2853 {
2854   /* Determined through "grep 'Private Use,' UnicodeData-3.1.0.txt".  */
2855   return (ch >= 0xE000 && ch <= 0xF8FF)
2856          || (ch >= 0xF0000 && ch <= 0xFFFFD)
2857          || (ch >= 0x100000 && ch <= 0x10FFFD);
2858 }
2859
2860 /* See PropList-3.0.1.txt.  */
2861 static bool
2862 is_property_unassigned_code_value (unsigned int ch)
2863 {
2864   return (is_category_Cn (ch) && !is_property_not_a_character (ch));
2865 }
2866
2867 /* See PropList.txt, UCD.html,
2868        DerivedCoreProperties.txt, UCD.html.  */
2869 static bool
2870 is_property_uppercase (unsigned int ch)
2871 {
2872   bool result1 =
2873     is_category_Lu (ch)
2874     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_UPPERCASE)) != 0);
2875   bool result2 =
2876     ((unicode_properties[ch] & (1ULL << PROP_UPPERCASE)) != 0);
2877
2878   if (result1 != result2)
2879     abort ();
2880   return result1;
2881 }
2882
2883 /* See PropList.txt, UCD.html.  */
2884 static bool
2885 is_property_other_uppercase (unsigned int ch)
2886 {
2887   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_UPPERCASE)) != 0);
2888 }
2889
2890 /* See PropList.txt, UCD.html,
2891        DerivedCoreProperties.txt, UCD.html.  */
2892 static bool
2893 is_property_lowercase (unsigned int ch)
2894 {
2895   bool result1 =
2896     is_category_Ll (ch)
2897     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_LOWERCASE)) != 0);
2898   bool result2 =
2899     ((unicode_properties[ch] & (1ULL << PROP_LOWERCASE)) != 0);
2900
2901   if (result1 != result2)
2902     abort ();
2903   return result1;
2904 }
2905
2906 /* See PropList.txt, UCD.html.  */
2907 static bool
2908 is_property_other_lowercase (unsigned int ch)
2909 {
2910   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_LOWERCASE)) != 0);
2911 }
2912
2913 /* See PropList-3.0.1.txt.  */
2914 static bool
2915 is_property_titlecase (unsigned int ch)
2916 {
2917   return is_category_Lt (ch);
2918 }
2919
2920 /* See PropList.txt, UCD.html.  */
2921 static bool
2922 is_property_soft_dotted (unsigned int ch)
2923 {
2924   return ((unicode_properties[ch] & (1ULL << PROP_SOFT_DOTTED)) != 0);
2925 }
2926
2927 /* See DerivedCoreProperties.txt, UCD.html.  */
2928 static bool
2929 is_property_id_start (unsigned int ch)
2930 {
2931   return ((unicode_properties[ch] & (1ULL << PROP_ID_START)) != 0);
2932 }
2933
2934 /* See PropList.txt, UCD.html.  */
2935 static bool
2936 is_property_other_id_start (unsigned int ch)
2937 {
2938   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_ID_START)) != 0);
2939 }
2940
2941 /* See DerivedCoreProperties.txt, UCD.html.  */
2942 static bool
2943 is_property_id_continue (unsigned int ch)
2944 {
2945   return ((unicode_properties[ch] & (1ULL << PROP_ID_CONTINUE)) != 0);
2946 }
2947
2948 /* See PropList.txt, UCD.html.  */
2949 static bool
2950 is_property_other_id_continue (unsigned int ch)
2951 {
2952   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_ID_CONTINUE)) != 0);
2953 }
2954
2955 /* See DerivedCoreProperties.txt, UCD.html.  */
2956 static bool
2957 is_property_xid_start (unsigned int ch)
2958 {
2959   return ((unicode_properties[ch] & (1ULL << PROP_XID_START)) != 0);
2960 }
2961
2962 /* See DerivedCoreProperties.txt, UCD.html.  */
2963 static bool
2964 is_property_xid_continue (unsigned int ch)
2965 {
2966   return ((unicode_properties[ch] & (1ULL << PROP_XID_CONTINUE)) != 0);
2967 }
2968
2969 /* See PropList.txt, UCD.html.  */
2970 static bool
2971 is_property_pattern_white_space (unsigned int ch)
2972 {
2973   return ((unicode_properties[ch] & (1ULL << PROP_PATTERN_WHITE_SPACE)) != 0);
2974 }
2975
2976 /* See PropList.txt, UCD.html.  */
2977 static bool
2978 is_property_pattern_syntax (unsigned int ch)
2979 {
2980   return ((unicode_properties[ch] & (1ULL << PROP_PATTERN_SYNTAX)) != 0);
2981 }
2982
2983 /* See PropList.txt, UCD.html.  */
2984 static bool
2985 is_property_join_control (unsigned int ch)
2986 {
2987   return ((unicode_properties[ch] & (1ULL << PROP_JOIN_CONTROL)) != 0);
2988 }
2989
2990 /* See DerivedCoreProperties.txt, UCD.html.  */
2991 static bool
2992 is_property_grapheme_base (unsigned int ch)
2993 {
2994   return ((unicode_properties[ch] & (1ULL << PROP_GRAPHEME_BASE)) != 0);
2995 }
2996
2997 /* See DerivedCoreProperties.txt, UCD.html.  */
2998 static bool
2999 is_property_grapheme_extend (unsigned int ch)
3000 {
3001   return ((unicode_properties[ch] & (1ULL << PROP_GRAPHEME_EXTEND)) != 0);
3002 }
3003
3004 /* See PropList.txt, UCD.html.  */
3005 static bool
3006 is_property_other_grapheme_extend (unsigned int ch)
3007 {
3008   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_GRAPHEME_EXTEND)) != 0);
3009 }
3010
3011 /* See DerivedCoreProperties.txt, UCD.html.  */
3012 static bool
3013 is_property_grapheme_link (unsigned int ch)
3014 {
3015   return ((unicode_properties[ch] & (1ULL << PROP_GRAPHEME_LINK)) != 0);
3016 }
3017
3018 /* See PropList.txt, UCD.html.  */
3019 static bool
3020 is_property_bidi_control (unsigned int ch)
3021 {
3022   return ((unicode_properties[ch] & (1ULL << PROP_BIDI_CONTROL)) != 0);
3023 }
3024
3025 /* See PropList-3.0.1.txt.  */
3026 static bool
3027 is_property_bidi_left_to_right (unsigned int ch)
3028 {
3029   return (get_bidi_category (ch) == UC_BIDI_L);
3030 }
3031
3032 /* See PropList-3.0.1.txt.  */
3033 static bool
3034 is_property_bidi_hebrew_right_to_left (unsigned int ch)
3035 {
3036   return (get_bidi_category (ch) == UC_BIDI_R);
3037 }
3038
3039 /* See PropList-3.0.1.txt.  */
3040 static bool
3041 is_property_bidi_arabic_right_to_left (unsigned int ch)
3042 {
3043   return (get_bidi_category (ch) == UC_BIDI_AL);
3044 }
3045
3046 /* See PropList-3.0.1.txt.  */
3047 static bool
3048 is_property_bidi_european_digit (unsigned int ch)
3049 {
3050   return (get_bidi_category (ch) == UC_BIDI_EN);
3051 }
3052
3053 /* See PropList-3.0.1.txt.  */
3054 static bool
3055 is_property_bidi_eur_num_separator (unsigned int ch)
3056 {
3057   return (get_bidi_category (ch) == UC_BIDI_ES);
3058 }
3059
3060 /* See PropList-3.0.1.txt.  */
3061 static bool
3062 is_property_bidi_eur_num_terminator (unsigned int ch)
3063 {
3064   return (get_bidi_category (ch) == UC_BIDI_ET);
3065 }
3066
3067 /* See PropList-3.0.1.txt.  */
3068 static bool
3069 is_property_bidi_arabic_digit (unsigned int ch)
3070 {
3071   return (get_bidi_category (ch) == UC_BIDI_AN);
3072 }
3073
3074 /* See PropList-3.0.1.txt.  */
3075 static bool
3076 is_property_bidi_common_separator (unsigned int ch)
3077 {
3078   return (get_bidi_category (ch) == UC_BIDI_CS);
3079 }
3080
3081 /* See PropList-3.0.1.txt.  */
3082 static bool
3083 is_property_bidi_block_separator (unsigned int ch)
3084 {
3085   return (get_bidi_category (ch) == UC_BIDI_B);
3086 }
3087
3088 /* See PropList-3.0.1.txt.  */
3089 static bool
3090 is_property_bidi_segment_separator (unsigned int ch)
3091 {
3092   return (get_bidi_category (ch) == UC_BIDI_S);
3093 }
3094
3095 /* See PropList-3.0.1.txt.  */
3096 static bool
3097 is_property_bidi_whitespace (unsigned int ch)
3098 {
3099   return (get_bidi_category (ch) == UC_BIDI_WS);
3100 }
3101
3102 /* See PropList-3.0.1.txt.  */
3103 static bool
3104 is_property_bidi_non_spacing_mark (unsigned int ch)
3105 {
3106   return (get_bidi_category (ch) == UC_BIDI_NSM);
3107 }
3108
3109 /* See PropList-3.0.1.txt.  */
3110 static bool
3111 is_property_bidi_boundary_neutral (unsigned int ch)
3112 {
3113   return (get_bidi_category (ch) == UC_BIDI_BN);
3114 }
3115
3116 /* See PropList-3.0.1.txt.  */
3117 static bool
3118 is_property_bidi_pdf (unsigned int ch)
3119 {
3120   return (get_bidi_category (ch) == UC_BIDI_PDF);
3121 }
3122
3123 /* See PropList-3.0.1.txt.  */
3124 static bool
3125 is_property_bidi_embedding_or_override (unsigned int ch)
3126 {
3127   int category = get_bidi_category (ch);
3128   return (category == UC_BIDI_LRE || category == UC_BIDI_LRO
3129           || category == UC_BIDI_RLE || category == UC_BIDI_RLO);
3130 }
3131
3132 /* See PropList-3.0.1.txt.  */
3133 static bool
3134 is_property_bidi_other_neutral (unsigned int ch)
3135 {
3136   return (get_bidi_category (ch) == UC_BIDI_ON);
3137 }
3138
3139 /* See PropList.txt, UCD.html.  */
3140 static bool
3141 is_property_hex_digit (unsigned int ch)
3142 {
3143   return ((unicode_properties[ch] & (1ULL << PROP_HEX_DIGIT)) != 0);
3144 }
3145
3146 /* See PropList.txt, UCD.html.  */
3147 static bool
3148 is_property_ascii_hex_digit (unsigned int ch)
3149 {
3150   return ((unicode_properties[ch] & (1ULL << PROP_ASCII_HEX_DIGIT)) != 0);
3151 }
3152
3153 /* See Unicode 3.0 book, section 4.10,
3154        PropList.txt, UCD.html.  */
3155 static bool
3156 is_property_ideographic (unsigned int ch)
3157 {
3158   return ((unicode_properties[ch] & (1ULL << PROP_IDEOGRAPHIC)) != 0);
3159 }
3160
3161 /* See PropList.txt, UCD.html.  */
3162 static bool
3163 is_property_unified_ideograph (unsigned int ch)
3164 {
3165   return ((unicode_properties[ch] & (1ULL << PROP_UNIFIED_IDEOGRAPH)) != 0);
3166 }
3167
3168 /* See PropList.txt, UCD.html.  */
3169 static bool
3170 is_property_radical (unsigned int ch)
3171 {
3172   return ((unicode_properties[ch] & (1ULL << PROP_RADICAL)) != 0);
3173 }
3174
3175 /* See PropList.txt, UCD.html.  */
3176 static bool
3177 is_property_ids_binary_operator (unsigned int ch)
3178 {
3179   return ((unicode_properties[ch] & (1ULL << PROP_IDS_BINARY_OPERATOR)) != 0);
3180 }
3181
3182 /* See PropList.txt, UCD.html.  */
3183 static bool
3184 is_property_ids_trinary_operator (unsigned int ch)
3185 {
3186   return ((unicode_properties[ch] & (1ULL << PROP_IDS_TRINARY_OPERATOR)) != 0);
3187 }
3188
3189 /* See PropList-3.0.1.txt.  */
3190 static bool
3191 is_property_zero_width (unsigned int ch)
3192 {
3193   return is_category_Cf (ch)
3194          || (unicode_attributes[ch].name != NULL
3195              && strstr (unicode_attributes[ch].name, "ZERO WIDTH") != NULL);
3196 }
3197
3198 /* See PropList-3.0.1.txt.  */
3199 static bool
3200 is_property_space (unsigned int ch)
3201 {
3202   return is_category_Zs (ch);
3203 }
3204
3205 /* See PropList-3.0.1.txt.  */
3206 static bool
3207 is_property_non_break (unsigned int ch)
3208 {
3209   /* This is exactly the set of characters having line breaking
3210      property GL.  */
3211   return (ch == 0x00A0 /* NO-BREAK SPACE */
3212           || ch == 0x034F /* COMBINING GRAPHEME JOINER */
3213           || ch == 0x035C /* COMBINING DOUBLE BREVE BELOW */
3214           || ch == 0x035D /* COMBINING DOUBLE BREVE */
3215           || ch == 0x035E /* COMBINING DOUBLE MACRON */
3216           || ch == 0x035F /* COMBINING DOUBLE MACRON BELOW */
3217           || ch == 0x0360 /* COMBINING DOUBLE TILDE */
3218           || ch == 0x0361 /* COMBINING DOUBLE INVERTED BREVE */
3219           || ch == 0x0362 /* COMBINING DOUBLE RIGHTWARDS ARROW BELOW */
3220           || ch == 0x0F08 /* TIBETAN MARK SBRUL SHAD */
3221           || ch == 0x0F0C /* TIBETAN MARK DELIMITER TSHEG BSTAR */
3222           || ch == 0x0F12 /* TIBETAN MARK RGYA GRAM SHAD */
3223           || ch == 0x180E /* MONGOLIAN VOWEL SEPARATOR */
3224           || ch == 0x2007 /* FIGURE SPACE */
3225           || ch == 0x2011 /* NON-BREAKING HYPHEN */
3226           || ch == 0x202F /* NARROW NO-BREAK SPACE */);
3227 }
3228
3229 /* See PropList-3.0.1.txt.  */
3230 static bool
3231 is_property_iso_control (unsigned int ch)
3232 {
3233   bool result1 =
3234     (unicode_attributes[ch].name != NULL
3235      && strcmp (unicode_attributes[ch].name, "<control>") == 0);
3236   bool result2 =
3237     is_category_Cc (ch);
3238
3239   if (result1 != result2)
3240     abort ();
3241   return result1;
3242 }
3243
3244 /* See PropList-3.0.1.txt.  */
3245 static bool
3246 is_property_format_control (unsigned int ch)
3247 {
3248   return (is_category_Cf (ch)
3249           && get_bidi_category (ch) == UC_BIDI_BN
3250           && !is_property_join_control (ch)
3251           && ch != 0xFEFF);
3252 }
3253
3254 /* See PropList.txt, UCD.html.  */
3255 static bool
3256 is_property_dash (unsigned int ch)
3257 {
3258   return ((unicode_properties[ch] & (1ULL << PROP_DASH)) != 0);
3259 }
3260
3261 /* See PropList.txt, UCD.html.  */
3262 static bool
3263 is_property_hyphen (unsigned int ch)
3264 {
3265   return ((unicode_properties[ch] & (1ULL << PROP_HYPHEN)) != 0);
3266 }
3267
3268 /* See PropList-3.0.1.txt.  */
3269 static bool
3270 is_property_punctuation (unsigned int ch)
3271 {
3272   return is_category_P (ch);
3273 }
3274
3275 /* See PropList-3.0.1.txt.  */
3276 static bool
3277 is_property_line_separator (unsigned int ch)
3278 {
3279   return is_category_Zl (ch);
3280 }
3281
3282 /* See PropList-3.0.1.txt.  */
3283 static bool
3284 is_property_paragraph_separator (unsigned int ch)
3285 {
3286   return is_category_Zp (ch);
3287 }
3288
3289 /* See PropList.txt, UCD.html.  */
3290 static bool
3291 is_property_quotation_mark (unsigned int ch)
3292 {
3293   return ((unicode_properties[ch] & (1ULL << PROP_QUOTATION_MARK)) != 0);
3294 }
3295
3296 /* See PropList.txt, UCD.html.  */
3297 static bool
3298 is_property_sentence_terminal (unsigned int ch)
3299 {
3300   return ((unicode_properties[ch] & (1ULL << PROP_STERM)) != 0);
3301 }
3302
3303 /* See PropList.txt, UCD.html.  */
3304 static bool
3305 is_property_terminal_punctuation (unsigned int ch)
3306 {
3307   return ((unicode_properties[ch] & (1ULL << PROP_TERMINAL_PUNCTUATION)) != 0);
3308 }
3309
3310 /* See PropList-3.0.1.txt.  */
3311 static bool
3312 is_property_currency_symbol (unsigned int ch)
3313 {
3314   return is_category_Sc (ch);
3315 }
3316
3317 /* See Unicode 3.0 book, section 4.9,
3318        PropList.txt, UCD.html,
3319        DerivedCoreProperties.txt, UCD.html.  */
3320 static bool
3321 is_property_math (unsigned int ch)
3322 {
3323   bool result1 =
3324     is_category_Sm (ch)
3325     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_MATH)) != 0);
3326   bool result2 =
3327     ((unicode_properties[ch] & (1ULL << PROP_MATH)) != 0);
3328
3329   if (result1 != result2)
3330     abort ();
3331   return result1;
3332 }
3333
3334 /* See PropList.txt, UCD.html.  */
3335 static bool
3336 is_property_other_math (unsigned int ch)
3337 {
3338   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_MATH)) != 0);
3339 }
3340
3341 /* See PropList-3.0.1.txt.  */
3342 static bool
3343 is_property_paired_punctuation (unsigned int ch)
3344 {
3345   return unicode_pairedpunctuation[ch];
3346 }
3347
3348 /* See PropList-3.0.1.txt.  */
3349 static bool
3350 is_property_left_of_pair (unsigned int ch)
3351 {
3352   return unicode_leftofpair[ch];
3353 }
3354
3355 /* See PropList-3.0.1.txt.  */
3356 static bool
3357 is_property_combining (unsigned int ch)
3358 {
3359   return (unicode_attributes[ch].name != NULL
3360           && (strcmp (unicode_attributes[ch].combining, "0") != 0
3361               || is_category_Mc (ch)
3362               || is_category_Me (ch)
3363               || is_category_Mn (ch)));
3364 }
3365
3366 #if 0 /* same as is_property_bidi_non_spacing_mark */
3367 /* See PropList-3.0.1.txt.  */
3368 static bool
3369 is_property_non_spacing (unsigned int ch)
3370 {
3371   return (unicode_attributes[ch].name != NULL
3372           && get_bidi_category (ch) == UC_BIDI_NSM);
3373 }
3374 #endif
3375
3376 /* See PropList-3.0.1.txt.  */
3377 static bool
3378 is_property_composite (unsigned int ch)
3379 {
3380   /* This definition differs from the one in PropList-3.0.1.txt, but is more
3381      logical in some sense.  */
3382   if (ch >= 0xAC00 && ch <= 0xD7A4) /* Hangul Syllables */
3383     return true;
3384   if (unicode_attributes[ch].name != NULL
3385       && unicode_attributes[ch].decomposition != NULL)
3386     {
3387       /* Test whether the decomposition contains more than one character,
3388          and the first is not a space.  */
3389       const char *decomp = unicode_attributes[ch].decomposition;
3390       if (decomp[0] == '<')
3391         {
3392           decomp = strchr (decomp, '>') + 1;
3393           if (decomp[0] == ' ')
3394             decomp++;
3395         }
3396       return strchr (decomp, ' ') != NULL && strncmp (decomp, "0020 ", 5) != 0;
3397     }
3398   return false;
3399 }
3400
3401 /* See PropList-3.0.1.txt.  */
3402 static bool
3403 is_property_decimal_digit (unsigned int ch)
3404 {
3405   return is_category_Nd (ch);
3406 }
3407
3408 /* See PropList-3.0.1.txt.  */
3409 static bool
3410 is_property_numeric (unsigned int ch)
3411 {
3412   return ((get_numeric_value (ch)).denominator > 0)
3413          || (ch == 0x09F8) /* BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR */
3414          || (ch == 0x2183); /* ROMAN NUMERAL REVERSED ONE HUNDRED */
3415 }
3416
3417 /* See PropList.txt, UCD.html.  */
3418 static bool
3419 is_property_diacritic (unsigned int ch)
3420 {
3421   return ((unicode_properties[ch] & (1ULL << PROP_DIACRITIC)) != 0);
3422 }
3423
3424 /* See PropList.txt, UCD.html.  */
3425 static bool
3426 is_property_extender (unsigned int ch)
3427 {
3428   return ((unicode_properties[ch] & (1ULL << PROP_EXTENDER)) != 0);
3429 }
3430
3431 /* See PropList-3.0.1.txt.  */
3432 static bool
3433 is_property_ignorable_control (unsigned int ch)
3434 {
3435   return ((is_category_Cc (ch) && get_bidi_category (ch) == UC_BIDI_BN)
3436           || is_category_Cf (ch))
3437          && ch != 0x0000;
3438 }
3439
3440 /* ------------------------------------------------------------------------- */
3441
3442 /* Output all properties.  */
3443 static void
3444 output_properties (const char *version)
3445 {
3446 #define PROPERTY(P) \
3447   debug_output_predicate ("unictype/pr_" #P ".txt", is_property_ ## P); \
3448   output_predicate_test ("../tests/unictype/test-pr_" #P ".c", is_property_ ## P, "uc_is_property_" #P " (c)"); \
3449   output_predicate ("unictype/pr_" #P ".h", is_property_ ## P, "u_property_" #P, "Properties", version);
3450   PROPERTY(white_space)
3451   PROPERTY(alphabetic)
3452   PROPERTY(other_alphabetic)
3453   PROPERTY(not_a_character)
3454   PROPERTY(default_ignorable_code_point)
3455   PROPERTY(other_default_ignorable_code_point)
3456   PROPERTY(deprecated)
3457   PROPERTY(logical_order_exception)
3458   PROPERTY(variation_selector)
3459   PROPERTY(private_use)
3460   PROPERTY(unassigned_code_value)
3461   PROPERTY(uppercase)
3462   PROPERTY(other_uppercase)
3463   PROPERTY(lowercase)
3464   PROPERTY(other_lowercase)
3465   PROPERTY(titlecase)
3466   PROPERTY(soft_dotted)
3467   PROPERTY(id_start)
3468   PROPERTY(other_id_start)
3469   PROPERTY(id_continue)
3470   PROPERTY(other_id_continue)
3471   PROPERTY(xid_start)
3472   PROPERTY(xid_continue)
3473   PROPERTY(pattern_white_space)
3474   PROPERTY(pattern_syntax)
3475   PROPERTY(join_control)
3476   PROPERTY(grapheme_base)
3477   PROPERTY(grapheme_extend)
3478   PROPERTY(other_grapheme_extend)
3479   PROPERTY(grapheme_link)
3480   PROPERTY(bidi_control)
3481   PROPERTY(bidi_left_to_right)
3482   PROPERTY(bidi_hebrew_right_to_left)
3483   PROPERTY(bidi_arabic_right_to_left)
3484   PROPERTY(bidi_european_digit)
3485   PROPERTY(bidi_eur_num_separator)
3486   PROPERTY(bidi_eur_num_terminator)
3487   PROPERTY(bidi_arabic_digit)
3488   PROPERTY(bidi_common_separator)
3489   PROPERTY(bidi_block_separator)
3490   PROPERTY(bidi_segment_separator)
3491   PROPERTY(bidi_whitespace)
3492   PROPERTY(bidi_non_spacing_mark)
3493   PROPERTY(bidi_boundary_neutral)
3494   PROPERTY(bidi_pdf)
3495   PROPERTY(bidi_embedding_or_override)
3496   PROPERTY(bidi_other_neutral)
3497   PROPERTY(hex_digit)
3498   PROPERTY(ascii_hex_digit)
3499   PROPERTY(ideographic)
3500   PROPERTY(unified_ideograph)
3501   PROPERTY(radical)
3502   PROPERTY(ids_binary_operator)
3503   PROPERTY(ids_trinary_operator)
3504   PROPERTY(zero_width)
3505   PROPERTY(space)
3506   PROPERTY(non_break)
3507   PROPERTY(iso_control)
3508   PROPERTY(format_control)
3509   PROPERTY(dash)
3510   PROPERTY(hyphen)
3511   PROPERTY(punctuation)
3512   PROPERTY(line_separator)
3513   PROPERTY(paragraph_separator)
3514   PROPERTY(quotation_mark)
3515   PROPERTY(sentence_terminal)
3516   PROPERTY(terminal_punctuation)
3517   PROPERTY(currency_symbol)
3518   PROPERTY(math)
3519   PROPERTY(other_math)
3520   PROPERTY(paired_punctuation)
3521   PROPERTY(left_of_pair)
3522   PROPERTY(combining)
3523   PROPERTY(composite)
3524   PROPERTY(decimal_digit)
3525   PROPERTY(numeric)
3526   PROPERTY(diacritic)
3527   PROPERTY(extender)
3528   PROPERTY(ignorable_control)
3529 #undef PROPERTY
3530 }
3531
3532 /* ========================================================================= */
3533
3534 /* Scripts.  */
3535
3536 static const char *scripts[256];
3537 static unsigned int numscripts;
3538
3539 static uint8_t unicode_scripts[0x110000];
3540
3541 static void
3542 fill_scripts (const char *scripts_filename)
3543 {
3544   FILE *stream;
3545   unsigned int i;
3546
3547   stream = fopen (scripts_filename, "r");
3548   if (stream == NULL)
3549     {
3550       fprintf (stderr, "error during fopen of '%s'\n", scripts_filename);
3551       exit (1);
3552     }
3553
3554   numscripts = 0;
3555
3556   for (i = 0; i < 0x110000; i++)
3557     unicode_scripts[i] = (uint8_t)~(uint8_t)0;
3558
3559   for (;;)
3560     {
3561       char buf[200+1];
3562       unsigned int i1, i2;
3563       char padding[200+1];
3564       char scriptname[200+1];
3565       int script;
3566
3567       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
3568         break;
3569
3570       if (buf[0] == '\0' || buf[0] == '#')
3571         continue;
3572
3573       if (sscanf (buf, "%X..%X%[ ;]%[^ ]", &i1, &i2, padding, scriptname) != 4)
3574         {
3575           if (sscanf (buf, "%X%[ ;]%[^ ]", &i1, padding, scriptname) != 3)
3576             {
3577               fprintf (stderr, "parse error in '%s'\n", scripts_filename);
3578               exit (1);
3579             }
3580           i2 = i1;
3581         }
3582       if (i2 < i1)
3583         abort ();
3584       if (i2 >= 0x110000)
3585         abort ();
3586
3587       for (script = numscripts - 1; script >= 0; script--)
3588         if (strcmp (scripts[script], scriptname) == 0)
3589           break;
3590       if (script < 0)
3591         {
3592           scripts[numscripts] = strdup (scriptname);
3593           script = numscripts;
3594           numscripts++;
3595           if (numscripts == 256)
3596             abort ();
3597         }
3598
3599       for (i = i1; i <= i2; i++)
3600         {
3601           if (unicode_scripts[i] != (uint8_t)~(uint8_t)0)
3602             fprintf (stderr, "0x%04X belongs to multiple scripts\n", i);
3603           unicode_scripts[i] = script;
3604         }
3605     }
3606
3607   if (ferror (stream) || fclose (stream))
3608     {
3609       fprintf (stderr, "error reading from '%s'\n", scripts_filename);
3610       exit (1);
3611     }
3612 }
3613
3614 /* Construction of sparse 3-level tables.  */
3615 #define TABLE script_table
3616 #define ELEMENT uint8_t
3617 #define DEFAULT (uint8_t)~(uint8_t)0
3618 #define xmalloc malloc
3619 #define xrealloc realloc
3620 #include "3level.h"
3621
3622 static void
3623 output_scripts (const char *version)
3624 {
3625   const char *filename = "unictype/scripts.h";
3626   FILE *stream;
3627   unsigned int ch, s, i;
3628   struct script_table t;
3629   unsigned int level1_offset, level2_offset, level3_offset;
3630
3631   typedef struct
3632   {
3633     const char *lowercase_name;
3634   }
3635   scriptinfo_t;
3636   scriptinfo_t scriptinfo[256];
3637
3638   stream = fopen (filename, "w");
3639   if (stream == NULL)
3640     {
3641       fprintf (stderr, "cannot open '%s' for writing\n", filename);
3642       exit (1);
3643     }
3644
3645   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
3646   fprintf (stream, "/* Unicode scripts.  */\n");
3647   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
3648            version);
3649
3650   for (s = 0; s < numscripts; s++)
3651     {
3652       char *lcp = strdup (scripts[s]);
3653       char *cp;
3654
3655       for (cp = lcp; *cp != '\0'; cp++)
3656         if (*cp >= 'A' && *cp <= 'Z')
3657           *cp += 'a' - 'A';
3658
3659       scriptinfo[s].lowercase_name = lcp;
3660     }
3661
3662   for (s = 0; s < numscripts; s++)
3663     {
3664       fprintf (stream, "static const uc_interval_t script_%s_intervals[] =\n",
3665                scriptinfo[s].lowercase_name);
3666       fprintf (stream, "{\n");
3667       i = 0;
3668       for (ch = 0; ch < 0x110000; ch++)
3669         if (unicode_scripts[ch] == s)
3670           {
3671             unsigned int start;
3672             unsigned int end;
3673
3674             start = ch;
3675             while (ch + 1 < 0x110000 && unicode_scripts[ch + 1] == s)
3676               ch++;
3677             end = ch;
3678
3679             if (i > 0)
3680               fprintf (stream, ",\n");
3681             if (start == end)
3682               fprintf (stream, "  { 0x%04X, 1, 1 }", start);
3683             else
3684               fprintf (stream, "  { 0x%04X, 1, 0 }, { 0x%04X, 0, 1 }",
3685                        start, end);
3686             i++;
3687           }
3688       fprintf (stream, "\n");
3689       fprintf (stream, "};\n");
3690     }
3691
3692   fprintf (stream, "static const uc_script_t scripts[%d] =\n", numscripts);
3693   fprintf (stream, "{\n");
3694   for (s = 0; s < numscripts; s++)
3695     {
3696       fprintf (stream, "  {\n");
3697       fprintf (stream, "    sizeof (script_%s_intervals) / sizeof (uc_interval_t),\n",
3698                scriptinfo[s].lowercase_name);
3699       fprintf (stream, "    script_%s_intervals,\n",
3700                scriptinfo[s].lowercase_name);
3701       fprintf (stream, "    \"%s\"\n", scripts[s]);
3702       fprintf (stream, "  }");
3703       if (s+1 < numscripts)
3704         fprintf (stream, ",");
3705       fprintf (stream, "\n");
3706     }
3707   fprintf (stream, "};\n");
3708
3709   t.p = 7;
3710   t.q = 9;
3711   script_table_init (&t);
3712
3713   for (ch = 0; ch < 0x110000; ch++)
3714     {
3715       unsigned int s = unicode_scripts[ch];
3716       if (s != (uint8_t)~(uint8_t)0)
3717         script_table_add (&t, ch, s);
3718     }
3719
3720   script_table_finalize (&t);
3721
3722   /* Offsets in t.result, in memory of this process.  */
3723   level1_offset =
3724     5 * sizeof (uint32_t);
3725   level2_offset =
3726     5 * sizeof (uint32_t)
3727     + t.level1_size * sizeof (uint32_t);
3728   level3_offset =
3729     5 * sizeof (uint32_t)
3730     + t.level1_size * sizeof (uint32_t)
3731     + (t.level2_size << t.q) * sizeof (uint32_t);
3732
3733   for (i = 0; i < 5; i++)
3734     fprintf (stream, "#define script_header_%d %d\n", i,
3735              ((uint32_t *) t.result)[i]);
3736   fprintf (stream, "static const\n");
3737   fprintf (stream, "struct\n");
3738   fprintf (stream, "  {\n");
3739   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
3740   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
3741   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
3742   fprintf (stream, "  }\n");
3743   fprintf (stream, "u_script =\n");
3744   fprintf (stream, "{\n");
3745   fprintf (stream, "  {");
3746   if (t.level1_size > 8)
3747     fprintf (stream, "\n   ");
3748   for (i = 0; i < t.level1_size; i++)
3749     {
3750       uint32_t offset;
3751       if (i > 0 && (i % 8) == 0)
3752         fprintf (stream, "\n   ");
3753       offset = ((uint32_t *) (t.result + level1_offset))[i];
3754       if (offset == 0)
3755         fprintf (stream, " %5d", -1);
3756       else
3757         fprintf (stream, " %5zu",
3758                  (offset - level2_offset) / sizeof (uint32_t));
3759       if (i+1 < t.level1_size)
3760         fprintf (stream, ",");
3761     }
3762   if (t.level1_size > 8)
3763     fprintf (stream, "\n ");
3764   fprintf (stream, " },\n");
3765   fprintf (stream, "  {");
3766   if (t.level2_size << t.q > 8)
3767     fprintf (stream, "\n   ");
3768   for (i = 0; i < t.level2_size << t.q; i++)
3769     {
3770       uint32_t offset;
3771       if (i > 0 && (i % 8) == 0)
3772         fprintf (stream, "\n   ");
3773       offset = ((uint32_t *) (t.result + level2_offset))[i];
3774       if (offset == 0)
3775         fprintf (stream, " %5d", -1);
3776       else
3777         fprintf (stream, " %5zu",
3778                  (offset - level3_offset) / sizeof (uint8_t));
3779       if (i+1 < t.level2_size << t.q)
3780         fprintf (stream, ",");
3781     }
3782   if (t.level2_size << t.q > 8)
3783     fprintf (stream, "\n ");
3784   fprintf (stream, " },\n");
3785   fprintf (stream, "  {");
3786   if (t.level3_size << t.p > 8)
3787     fprintf (stream, "\n   ");
3788   for (i = 0; i < t.level3_size << t.p; i++)
3789     {
3790       if (i > 0 && (i % 8) == 0)
3791         fprintf (stream, "\n   ");
3792       fprintf (stream, " %3d", ((uint8_t *) (t.result + level3_offset))[i]);
3793       if (i+1 < t.level3_size << t.p)
3794         fprintf (stream, ",");
3795     }
3796   if (t.level3_size << t.p > 8)
3797     fprintf (stream, "\n ");
3798   fprintf (stream, " }\n");
3799   fprintf (stream, "};\n");
3800
3801   if (ferror (stream) || fclose (stream))
3802     {
3803       fprintf (stderr, "error writing to '%s'\n", filename);
3804       exit (1);
3805     }
3806 }
3807
3808 static void
3809 output_scripts_byname (const char *version)
3810 {
3811   const char *filename = "unictype/scripts_byname.gperf";
3812   FILE *stream;
3813   unsigned int s;
3814
3815   stream = fopen (filename, "w");
3816   if (stream == NULL)
3817     {
3818       fprintf (stderr, "cannot open '%s' for writing\n", filename);
3819       exit (1);
3820     }
3821
3822   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
3823   fprintf (stream, "/* Unicode scripts.  */\n");
3824   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
3825            version);
3826   fprintf (stream, "struct named_script { const char *name; unsigned int index; };\n");
3827   fprintf (stream, "%%struct-type\n");
3828   fprintf (stream, "%%language=ANSI-C\n");
3829   fprintf (stream, "%%define hash-function-name scripts_hash\n");
3830   fprintf (stream, "%%define lookup-function-name uc_script_lookup\n");
3831   fprintf (stream, "%%readonly-tables\n");
3832   fprintf (stream, "%%global-table\n");
3833   fprintf (stream, "%%define word-array-name script_names\n");
3834   fprintf (stream, "%%%%\n");
3835   for (s = 0; s < numscripts; s++)
3836     fprintf (stream, "%s, %u\n", scripts[s], s);
3837
3838   if (ferror (stream) || fclose (stream))
3839     {
3840       fprintf (stderr, "error writing to '%s'\n", filename);
3841       exit (1);
3842     }
3843 }
3844
3845 /* ========================================================================= */
3846
3847 /* Blocks.  */
3848
3849 typedef struct { unsigned int start; unsigned int end; const char *name; }
3850   block_t;
3851 static block_t blocks[256];
3852 static unsigned int numblocks;
3853
3854 static void
3855 fill_blocks (const char *blocks_filename)
3856 {
3857   FILE *stream;
3858
3859   stream = fopen (blocks_filename, "r");
3860   if (stream == NULL)
3861     {
3862       fprintf (stderr, "error during fopen of '%s'\n", blocks_filename);
3863       exit (1);
3864     }
3865
3866   for (;;)
3867     {
3868       char buf[200+1];
3869       unsigned int i1, i2;
3870       char padding[200+1];
3871       char blockname[200+1];
3872
3873       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
3874         break;
3875
3876       if (buf[0] == '\0' || buf[0] == '#')
3877         continue;
3878
3879       if (sscanf (buf, "%X..%X%[ ;]%[^\r]", &i1, &i2, padding, blockname) != 4)
3880         {
3881           fprintf (stderr, "parse error in '%s'\n", blocks_filename);
3882           exit (1);
3883         }
3884       blocks[numblocks].start = i1;
3885       blocks[numblocks].end = i2;
3886       blocks[numblocks].name = strdup (blockname);
3887       /* It must be sorted.  */
3888       if (numblocks > 0 && !(blocks[numblocks-1].end < blocks[numblocks].start))
3889         abort ();
3890       numblocks++;
3891       if (numblocks == 256)
3892         abort ();
3893     }
3894
3895   if (ferror (stream) || fclose (stream))
3896     {
3897       fprintf (stderr, "error reading from '%s'\n", blocks_filename);
3898       exit (1);
3899     }
3900 }
3901
3902 /* Return the smallest block index among the blocks for characters >= ch.  */
3903 static unsigned int
3904 block_first_index (unsigned int ch)
3905 {
3906   /* Binary search.  */
3907   unsigned int lo = 0;
3908   unsigned int hi = numblocks;
3909   /* Invariants:
3910      All blocks[i], i < lo, have blocks[i].end < ch,
3911      all blocks[i], i >= hi, have blocks[i].end >= ch.  */
3912   while (lo < hi)
3913     {
3914       unsigned int mid = (lo + hi) / 2; /* >= lo, < hi */
3915       if (blocks[mid].end < ch)
3916         lo = mid + 1;
3917       else
3918         hi = mid;
3919     }
3920   return hi;
3921 }
3922
3923 /* Return the largest block index among the blocks for characters <= ch,
3924    plus 1.  */
3925 static unsigned int
3926 block_last_index (unsigned int ch)
3927 {
3928   /* Binary search.  */
3929   unsigned int lo = 0;
3930   unsigned int hi = numblocks;
3931   /* Invariants:
3932      All blocks[i], i < lo, have blocks[i].start <= ch,
3933      all blocks[i], i >= hi, have blocks[i].start > ch.  */
3934   while (lo < hi)
3935     {
3936       unsigned int mid = (lo + hi) / 2; /* >= lo, < hi */
3937       if (blocks[mid].start <= ch)
3938         lo = mid + 1;
3939       else
3940         hi = mid;
3941     }
3942   return hi;
3943 }
3944
3945 static void
3946 output_blocks (const char *version)
3947 {
3948   const char *filename = "unictype/blocks.h";
3949   const unsigned int shift = 8; /* bits to shift away for array access */
3950   const unsigned int threshold = 0x30000; /* cut-off table here to save space */
3951   FILE *stream;
3952   unsigned int i;
3953   unsigned int i1;
3954
3955   stream = fopen (filename, "w");
3956   if (stream == NULL)
3957     {
3958       fprintf (stderr, "cannot open '%s' for writing\n", filename);
3959       exit (1);
3960     }
3961
3962   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
3963   fprintf (stream, "/* Unicode blocks.  */\n");
3964   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
3965            version);
3966
3967   fprintf (stream, "static const uc_block_t blocks[] =\n");
3968   fprintf (stream, "{\n");
3969   for (i = 0; i < numblocks; i++)
3970     {
3971       fprintf (stream, "  { 0x%04X, 0x%04X, \"%s\" }", blocks[i].start,
3972                blocks[i].end, blocks[i].name);
3973       if (i+1 < numblocks)
3974         fprintf (stream, ",");
3975       fprintf (stream, "\n");
3976     }
3977   fprintf (stream, "};\n");
3978   fprintf (stream, "#define blocks_level1_shift %d\n", shift);
3979   fprintf (stream, "#define blocks_level1_threshold 0x%04X\n", threshold);
3980   fprintf (stream, "static const uint8_t blocks_level1[%d * 2] =\n",
3981            threshold >> shift);
3982   fprintf (stream, "{\n");
3983   for (i1 = 0; i1 < (threshold >> shift); i1++)
3984     {
3985       unsigned int first_index = block_first_index (i1 << shift);
3986       unsigned int last_index = block_last_index (((i1 + 1) << shift) - 1);
3987       fprintf (stream, "  %3d, %3d", first_index, last_index);
3988       if (i1+1 < (threshold >> shift))
3989         fprintf (stream, ",");
3990       fprintf (stream, "\n");
3991     }
3992   fprintf (stream, "};\n");
3993   fprintf (stream, "#define blocks_upper_first_index %d\n",
3994            block_first_index (threshold));
3995   fprintf (stream, "#define blocks_upper_last_index %d\n",
3996            block_last_index (0x10FFFF));
3997
3998   if (ferror (stream) || fclose (stream))
3999     {
4000       fprintf (stderr, "error writing to '%s'\n", filename);
4001       exit (1);
4002     }
4003 }
4004
4005 /* ========================================================================= */
4006
4007 /* C and Java syntax.  */
4008
4009 enum
4010 {
4011   UC_IDENTIFIER_START,    /* valid as first or subsequent character */
4012   UC_IDENTIFIER_VALID,    /* valid as subsequent character only */
4013   UC_IDENTIFIER_INVALID,  /* not valid */
4014   UC_IDENTIFIER_IGNORABLE /* ignorable (Java only) */
4015 };
4016
4017 /* ISO C 99 section 6.4.(3).  */
4018 static bool
4019 is_c_whitespace (unsigned int ch)
4020 {
4021   return (ch == ' ' /* space */
4022           || ch == '\t' /* horizontal tab */
4023           || ch == '\n' || ch == '\r' /* new-line */
4024           || ch == '\v' /* vertical tab */
4025           || ch == '\f'); /* form-feed */
4026 }
4027
4028 /* ISO C 99 section 6.4.2.1 and appendix D.  */
4029 static int
4030 c_ident_category (unsigned int ch)
4031 {
4032   /* Section 6.4.2.1.  */
4033   if (ch >= '0' && ch <= '9')
4034     return UC_IDENTIFIER_VALID;
4035   if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_')
4036     return UC_IDENTIFIER_START;
4037   /* Appendix D.  */
4038   if (0
4039       /* Latin */
4040       || (ch == 0x00AA)
4041       || (ch == 0x00BA)
4042       || (ch >= 0x00C0 && ch <= 0x00D6)
4043       || (ch >= 0x00D8 && ch <= 0x00F6)
4044       || (ch >= 0x00F8 && ch <= 0x01F5)
4045       || (ch >= 0x01FA && ch <= 0x0217)
4046       || (ch >= 0x0250 && ch <= 0x02A8)
4047       || (ch >= 0x1E00 && ch <= 0x1E9B)
4048       || (ch >= 0x1EA0 && ch <= 0x1EF9)
4049       || (ch == 0x207F)
4050       /* Greek */
4051       || (ch == 0x0386)
4052       || (ch >= 0x0388 && ch <= 0x038A)
4053       || (ch == 0x038C)
4054       || (ch >= 0x038E && ch <= 0x03A1)
4055       || (ch >= 0x03A3 && ch <= 0x03CE)
4056       || (ch >= 0x03D0 && ch <= 0x03D6)
4057       || (ch == 0x03DA)
4058       || (ch == 0x03DC)
4059       || (ch == 0x03DE)
4060       || (ch == 0x03E0)
4061       || (ch >= 0x03E2 && ch <= 0x03F3)
4062       || (ch >= 0x1F00 && ch <= 0x1F15)
4063       || (ch >= 0x1F18 && ch <= 0x1F1D)
4064       || (ch >= 0x1F20 && ch <= 0x1F45)
4065       || (ch >= 0x1F48 && ch <= 0x1F4D)
4066       || (ch >= 0x1F50 && ch <= 0x1F57)
4067       || (ch == 0x1F59)
4068       || (ch == 0x1F5B)
4069       || (ch == 0x1F5D)
4070       || (ch >= 0x1F5F && ch <= 0x1F7D)
4071       || (ch >= 0x1F80 && ch <= 0x1FB4)
4072       || (ch >= 0x1FB6 && ch <= 0x1FBC)
4073       || (ch >= 0x1FC2 && ch <= 0x1FC4)
4074       || (ch >= 0x1FC6 && ch <= 0x1FCC)
4075       || (ch >= 0x1FD0 && ch <= 0x1FD3)
4076       || (ch >= 0x1FD6 && ch <= 0x1FDB)
4077       || (ch >= 0x1FE0 && ch <= 0x1FEC)
4078       || (ch >= 0x1FF2 && ch <= 0x1FF4)
4079       || (ch >= 0x1FF6 && ch <= 0x1FFC)
4080       /* Cyrillic */
4081       || (ch >= 0x0401 && ch <= 0x040C)
4082       || (ch >= 0x040E && ch <= 0x044F)
4083       || (ch >= 0x0451 && ch <= 0x045C)
4084       || (ch >= 0x045E && ch <= 0x0481)
4085       || (ch >= 0x0490 && ch <= 0x04C4)
4086       || (ch >= 0x04C7 && ch <= 0x04C8)
4087       || (ch >= 0x04CB && ch <= 0x04CC)
4088       || (ch >= 0x04D0 && ch <= 0x04EB)
4089       || (ch >= 0x04EE && ch <= 0x04F5)
4090       || (ch >= 0x04F8 && ch <= 0x04F9)
4091       /* Armenian */
4092       || (ch >= 0x0531 && ch <= 0x0556)
4093       || (ch >= 0x0561 && ch <= 0x0587)
4094       /* Hebrew */
4095       || (ch >= 0x05B0 && ch <= 0x05B9)
4096       || (ch >= 0x05BB && ch <= 0x05BD)
4097       || (ch == 0x05BF)
4098       || (ch >= 0x05C1 && ch <= 0x05C2)
4099       || (ch >= 0x05D0 && ch <= 0x05EA)
4100       || (ch >= 0x05F0 && ch <= 0x05F2)
4101       /* Arabic */
4102       || (ch >= 0x0621 && ch <= 0x063A)
4103       || (ch >= 0x0640 && ch <= 0x0652)
4104       || (ch >= 0x0670 && ch <= 0x06B7)
4105       || (ch >= 0x06BA && ch <= 0x06BE)
4106       || (ch >= 0x06C0 && ch <= 0x06CE)
4107       || (ch >= 0x06D0 && ch <= 0x06DC)
4108       || (ch >= 0x06E5 && ch <= 0x06E8)
4109       || (ch >= 0x06EA && ch <= 0x06ED)
4110       /* Devanagari */
4111       || (ch >= 0x0901 && ch <= 0x0903)
4112       || (ch >= 0x0905 && ch <= 0x0939)
4113       || (ch >= 0x093E && ch <= 0x094D)
4114       || (ch >= 0x0950 && ch <= 0x0952)
4115       || (ch >= 0x0958 && ch <= 0x0963)
4116       /* Bengali */
4117       || (ch >= 0x0981 && ch <= 0x0983)
4118       || (ch >= 0x0985 && ch <= 0x098C)
4119       || (ch >= 0x098F && ch <= 0x0990)
4120       || (ch >= 0x0993 && ch <= 0x09A8)
4121       || (ch >= 0x09AA && ch <= 0x09B0)
4122       || (ch == 0x09B2)
4123       || (ch >= 0x09B6 && ch <= 0x09B9)
4124       || (ch >= 0x09BE && ch <= 0x09C4)
4125       || (ch >= 0x09C7 && ch <= 0x09C8)
4126       || (ch >= 0x09CB && ch <= 0x09CD)
4127       || (ch >= 0x09DC && ch <= 0x09DD)
4128       || (ch >= 0x09DF && ch <= 0x09E3)
4129       || (ch >= 0x09F0 && ch <= 0x09F1)
4130       /* Gurmukhi */
4131       || (ch == 0x0A02)
4132       || (ch >= 0x0A05 && ch <= 0x0A0A)
4133       || (ch >= 0x0A0F && ch <= 0x0A10)
4134       || (ch >= 0x0A13 && ch <= 0x0A28)
4135       || (ch >= 0x0A2A && ch <= 0x0A30)
4136       || (ch >= 0x0A32 && ch <= 0x0A33)
4137       || (ch >= 0x0A35 && ch <= 0x0A36)
4138       || (ch >= 0x0A38 && ch <= 0x0A39)
4139       || (ch >= 0x0A3E && ch <= 0x0A42)
4140       || (ch >= 0x0A47 && ch <= 0x0A48)
4141       || (ch >= 0x0A4B && ch <= 0x0A4D)
4142       || (ch >= 0x0A59 && ch <= 0x0A5C)
4143       || (ch == 0x0A5E)
4144       || (ch == 0x0A74)
4145       /* Gujarati */
4146       || (ch >= 0x0A81 && ch <= 0x0A83)
4147       || (ch >= 0x0A85 && ch <= 0x0A8B)
4148       || (ch == 0x0A8D)
4149       || (ch >= 0x0A8F && ch <= 0x0A91)
4150       || (ch >= 0x0A93 && ch <= 0x0AA8)
4151       || (ch >= 0x0AAA && ch <= 0x0AB0)
4152       || (ch >= 0x0AB2 && ch <= 0x0AB3)
4153       || (ch >= 0x0AB5 && ch <= 0x0AB9)
4154       || (ch >= 0x0ABD && ch <= 0x0AC5)
4155       || (ch >= 0x0AC7 && ch <= 0x0AC9)
4156       || (ch >= 0x0ACB && ch <= 0x0ACD)
4157       || (ch == 0x0AD0)
4158       || (ch == 0x0AE0)
4159       /* Oriya */
4160       || (ch >= 0x0B01 && ch <= 0x0B03)
4161       || (ch >= 0x0B05 && ch <= 0x0B0C)
4162       || (ch >= 0x0B0F && ch <= 0x0B10)
4163       || (ch >= 0x0B13 && ch <= 0x0B28)
4164       || (ch >= 0x0B2A && ch <= 0x0B30)
4165       || (ch >= 0x0B32 && ch <= 0x0B33)
4166       || (ch >= 0x0B36 && ch <= 0x0B39)
4167       || (ch >= 0x0B3E && ch <= 0x0B43)
4168       || (ch >= 0x0B47 && ch <= 0x0B48)
4169       || (ch >= 0x0B4B && ch <= 0x0B4D)
4170       || (ch >= 0x0B5C && ch <= 0x0B5D)
4171       || (ch >= 0x0B5F && ch <= 0x0B61)
4172       /* Tamil */
4173       || (ch >= 0x0B82 && ch <= 0x0B83)
4174       || (ch >= 0x0B85 && ch <= 0x0B8A)
4175       || (ch >= 0x0B8E && ch <= 0x0B90)
4176       || (ch >= 0x0B92 && ch <= 0x0B95)
4177       || (ch >= 0x0B99 && ch <= 0x0B9A)
4178       || (ch == 0x0B9C)
4179       || (ch >= 0x0B9E && ch <= 0x0B9F)
4180       || (ch >= 0x0BA3 && ch <= 0x0BA4)
4181       || (ch >= 0x0BA8 && ch <= 0x0BAA)
4182       || (ch >= 0x0BAE && ch <= 0x0BB5)
4183       || (ch >= 0x0BB7 && ch <= 0x0BB9)
4184       || (ch >= 0x0BBE && ch <= 0x0BC2)
4185       || (ch >= 0x0BC6 && ch <= 0x0BC8)
4186       || (ch >= 0x0BCA && ch <= 0x0BCD)
4187       /* Telugu */
4188       || (ch >= 0x0C01 && ch <= 0x0C03)
4189       || (ch >= 0x0C05 && ch <= 0x0C0C)
4190       || (ch >= 0x0C0E && ch <= 0x0C10)
4191       || (ch >= 0x0C12 && ch <= 0x0C28)
4192       || (ch >= 0x0C2A && ch <= 0x0C33)
4193       || (ch >= 0x0C35 && ch <= 0x0C39)
4194       || (ch >= 0x0C3E && ch <= 0x0C44)
4195       || (ch >= 0x0C46 && ch <= 0x0C48)
4196       || (ch >= 0x0C4A && ch <= 0x0C4D)
4197       || (ch >= 0x0C60 && ch <= 0x0C61)
4198       /* Kannada */
4199       || (ch >= 0x0C82 && ch <= 0x0C83)
4200       || (ch >= 0x0C85 && ch <= 0x0C8C)
4201       || (ch >= 0x0C8E && ch <= 0x0C90)
4202       || (ch >= 0x0C92 && ch <= 0x0CA8)
4203       || (ch >= 0x0CAA && ch <= 0x0CB3)
4204       || (ch >= 0x0CB5 && ch <= 0x0CB9)
4205       || (ch >= 0x0CBE && ch <= 0x0CC4)
4206       || (ch >= 0x0CC6 && ch <= 0x0CC8)
4207       || (ch >= 0x0CCA && ch <= 0x0CCD)
4208       || (ch == 0x0CDE)
4209       || (ch >= 0x0CE0 && ch <= 0x0CE1)
4210       /* Malayalam */
4211       || (ch >= 0x0D02 && ch <= 0x0D03)
4212       || (ch >= 0x0D05 && ch <= 0x0D0C)
4213       || (ch >= 0x0D0E && ch <= 0x0D10)
4214       || (ch >= 0x0D12 && ch <= 0x0D28)
4215       || (ch >= 0x0D2A && ch <= 0x0D39)
4216       || (ch >= 0x0D3E && ch <= 0x0D43)
4217       || (ch >= 0x0D46 && ch <= 0x0D48)
4218       || (ch >= 0x0D4A && ch <= 0x0D4D)
4219       || (ch >= 0x0D60 && ch <= 0x0D61)
4220       /* Thai */
4221       || (ch >= 0x0E01 && ch <= 0x0E3A)
4222       || (ch >= 0x0E40 && ch <= 0x0E5B)
4223       /* Lao */
4224       || (ch >= 0x0E81 && ch <= 0x0E82)
4225       || (ch == 0x0E84)
4226       || (ch >= 0x0E87 && ch <= 0x0E88)
4227       || (ch == 0x0E8A)
4228       || (ch == 0x0E8D)
4229       || (ch >= 0x0E94 && ch <= 0x0E97)
4230       || (ch >= 0x0E99 && ch <= 0x0E9F)
4231       || (ch >= 0x0EA1 && ch <= 0x0EA3)
4232       || (ch == 0x0EA5)
4233       || (ch == 0x0EA7)
4234       || (ch >= 0x0EAA && ch <= 0x0EAB)
4235       || (ch >= 0x0EAD && ch <= 0x0EAE)
4236       || (ch >= 0x0EB0 && ch <= 0x0EB9)
4237       || (ch >= 0x0EBB && ch <= 0x0EBD)
4238       || (ch >= 0x0EC0 && ch <= 0x0EC4)
4239       || (ch == 0x0EC6)
4240       || (ch >= 0x0EC8 && ch <= 0x0ECD)
4241       || (ch >= 0x0EDC && ch <= 0x0EDD)
4242       /* Tibetan */
4243       || (ch == 0x0F00)
4244       || (ch >= 0x0F18 && ch <= 0x0F19)
4245       || (ch == 0x0F35)
4246       || (ch == 0x0F37)
4247       || (ch == 0x0F39)
4248       || (ch >= 0x0F3E && ch <= 0x0F47)
4249       || (ch >= 0x0F49 && ch <= 0x0F69)
4250       || (ch >= 0x0F71 && ch <= 0x0F84)
4251       || (ch >= 0x0F86 && ch <= 0x0F8B)
4252       || (ch >= 0x0F90 && ch <= 0x0F95)
4253       || (ch == 0x0F97)
4254       || (ch >= 0x0F99 && ch <= 0x0FAD)
4255       || (ch >= 0x0FB1 && ch <= 0x0FB7)
4256       || (ch == 0x0FB9)
4257       /* Georgian */
4258       || (ch >= 0x10A0 && ch <= 0x10C5)
4259       || (ch >= 0x10D0 && ch <= 0x10F6)
4260       /* Hiragana */
4261       || (ch >= 0x3041 && ch <= 0x3093)
4262       || (ch >= 0x309B && ch <= 0x309C)
4263       /* Katakana */
4264       || (ch >= 0x30A1 && ch <= 0x30F6)
4265       || (ch >= 0x30FB && ch <= 0x30FC)
4266       /* Bopomofo */
4267       || (ch >= 0x3105 && ch <= 0x312C)
4268       /* CJK Unified Ideographs */
4269       || (ch >= 0x4E00 && ch <= 0x9FA5)
4270       /* Hangul */
4271       || (ch >= 0xAC00 && ch <= 0xD7A3)
4272       /* Digits */
4273       || (ch >= 0x0660 && ch <= 0x0669)
4274       || (ch >= 0x06F0 && ch <= 0x06F9)
4275       || (ch >= 0x0966 && ch <= 0x096F)
4276       || (ch >= 0x09E6 && ch <= 0x09EF)
4277       || (ch >= 0x0A66 && ch <= 0x0A6F)
4278       || (ch >= 0x0AE6 && ch <= 0x0AEF)
4279       || (ch >= 0x0B66 && ch <= 0x0B6F)
4280       || (ch >= 0x0BE7 && ch <= 0x0BEF)
4281       || (ch >= 0x0C66 && ch <= 0x0C6F)
4282       || (ch >= 0x0CE6 && ch <= 0x0CEF)
4283       || (ch >= 0x0D66 && ch <= 0x0D6F)
4284       || (ch >= 0x0E50 && ch <= 0x0E59)
4285       || (ch >= 0x0ED0 && ch <= 0x0ED9)
4286       || (ch >= 0x0F20 && ch <= 0x0F33)
4287       /* Special characters */
4288       || (ch == 0x00B5)
4289       || (ch == 0x00B7)
4290       || (ch >= 0x02B0 && ch <= 0x02B8)
4291       || (ch == 0x02BB)
4292       || (ch >= 0x02BD && ch <= 0x02C1)
4293       || (ch >= 0x02D0 && ch <= 0x02D1)
4294       || (ch >= 0x02E0 && ch <= 0x02E4)
4295       || (ch == 0x037A)
4296       || (ch == 0x0559)
4297       || (ch == 0x093D)
4298       || (ch == 0x0B3D)
4299       || (ch == 0x1FBE)
4300       || (ch >= 0x203F && ch <= 0x2040)
4301       || (ch == 0x2102)
4302       || (ch == 0x2107)
4303       || (ch >= 0x210A && ch <= 0x2113)
4304       || (ch == 0x2115)
4305       || (ch >= 0x2118 && ch <= 0x211D)
4306       || (ch == 0x2124)
4307       || (ch == 0x2126)
4308       || (ch == 0x2128)
4309       || (ch >= 0x212A && ch <= 0x2131)
4310       || (ch >= 0x2133 && ch <= 0x2138)
4311       || (ch >= 0x2160 && ch <= 0x2182)
4312       || (ch >= 0x3005 && ch <= 0x3007)
4313       || (ch >= 0x3021 && ch <= 0x3029)
4314      )
4315     return UC_IDENTIFIER_START;
4316   return UC_IDENTIFIER_INVALID;
4317 }
4318
4319 /* The Java Language Specification, 3rd edition, Â§3.6.
4320    http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#95710  */
4321 static bool
4322 is_java_whitespace (unsigned int ch)
4323 {
4324   return (ch == ' ' || ch == '\t' || ch == '\f'
4325           || ch == '\n' || ch == '\r');
4326 }
4327
4328 /* The Java Language Specification, 3rd edition, Â§3.8.
4329    http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#40625
4330    and Character.isJavaIdentifierStart and Character.isJavaIdentifierPart  */
4331 static int
4332 java_ident_category (unsigned int ch)
4333 {
4334   /* FIXME: Check this against Sun's JDK implementation.  */
4335   if (is_category_L (ch) /* = Character.isLetter(ch) */
4336       || is_category_Nl (ch) /* = Character.getType(ch)==LETTER_NUMBER */
4337       || is_category_Sc (ch) /* currency symbol */
4338       || is_category_Pc (ch) /* connector punctuation */
4339      )
4340     return UC_IDENTIFIER_START;
4341   if (is_category_Nd (ch) /* digit */
4342       || is_category_Mc (ch) /* combining mark */
4343       || is_category_Mn (ch) /* non-spacing mark */
4344      )
4345     return UC_IDENTIFIER_VALID;
4346   if ((ch >= 0x0000 && ch <= 0x0008)
4347       || (ch >= 0x000E && ch <= 0x001B)
4348       || (ch >= 0x007F && ch <= 0x009F)
4349       || is_category_Cf (ch) /* = Character.getType(ch)==FORMAT */
4350      )
4351     return UC_IDENTIFIER_IGNORABLE;
4352   return UC_IDENTIFIER_INVALID;
4353 }
4354
4355 /* Construction of sparse 3-level tables.  */
4356 #define TABLE identsyntax_table
4357 #define ELEMENT uint8_t
4358 #define DEFAULT UC_IDENTIFIER_INVALID
4359 #define xmalloc malloc
4360 #define xrealloc realloc
4361 #include "3level.h"
4362
4363 /* Output an identifier syntax categorization in a three-level bitmap.  */
4364 static void
4365 output_ident_category (const char *filename, int (*predicate) (unsigned int), const char *name, const char *version)
4366 {
4367   FILE *stream;
4368   unsigned int ch, i;
4369   struct identsyntax_table t;
4370   unsigned int level1_offset, level2_offset, level3_offset;
4371
4372   stream = fopen (filename, "w");
4373   if (stream == NULL)
4374     {
4375       fprintf (stderr, "cannot open '%s' for writing\n", filename);
4376       exit (1);
4377     }
4378
4379   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
4380   fprintf (stream, "/* Language syntax properties of Unicode characters.  */\n");
4381   fprintf (stream, "/* Generated automatically by gen-ctype.c for Unicode %s.  */\n",
4382            version);
4383
4384   t.p = 7; /* or 8 */
4385   t.q = 5; /* or 4 */
4386   identsyntax_table_init (&t);
4387
4388   for (ch = 0; ch < 0x110000; ch++)
4389     {
4390       int syntaxcode = predicate (ch);
4391       if (syntaxcode != UC_IDENTIFIER_INVALID)
4392         identsyntax_table_add (&t, ch, syntaxcode);
4393     }
4394
4395   identsyntax_table_finalize (&t);
4396
4397   /* Offsets in t.result, in memory of this process.  */
4398   level1_offset =
4399     5 * sizeof (uint32_t);
4400   level2_offset =
4401     5 * sizeof (uint32_t)
4402     + t.level1_size * sizeof (uint32_t);
4403   level3_offset =
4404     5 * sizeof (uint32_t)
4405     + t.level1_size * sizeof (uint32_t)
4406     + (t.level2_size << t.q) * sizeof (uint32_t);
4407
4408   for (i = 0; i < 5; i++)
4409     fprintf (stream, "#define identsyntax_header_%d %d\n", i,
4410              ((uint32_t *) t.result)[i]);
4411   fprintf (stream, "static const\n");
4412   fprintf (stream, "struct\n");
4413   fprintf (stream, "  {\n");
4414   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
4415   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
4416   fprintf (stream, "    unsigned short level3[%zu * %d];\n", t.level3_size,
4417            (1 << t.p) * 2 / 16);
4418   fprintf (stream, "  }\n");
4419   fprintf (stream, "%s =\n", name);
4420   fprintf (stream, "{\n");
4421   fprintf (stream, "  {");
4422   if (t.level1_size > 8)
4423     fprintf (stream, "\n   ");
4424   for (i = 0; i < t.level1_size; i++)
4425     {
4426       uint32_t offset;
4427       if (i > 0 && (i % 8) == 0)
4428         fprintf (stream, "\n   ");
4429       offset = ((uint32_t *) (t.result + level1_offset))[i];
4430       if (offset == 0)
4431         fprintf (stream, " %5d", -1);
4432       else
4433         fprintf (stream, " %5zu",
4434                  (offset - level2_offset) / sizeof (uint32_t));
4435       if (i+1 < t.level1_size)
4436         fprintf (stream, ",");
4437     }
4438   if (t.level1_size > 8)
4439     fprintf (stream, "\n ");
4440   fprintf (stream, " },\n");
4441   fprintf (stream, "  {");
4442   if (t.level2_size << t.q > 8)
4443     fprintf (stream, "\n   ");
4444   for (i = 0; i < t.level2_size << t.q; i++)
4445     {
4446       uint32_t offset;
4447       if (i > 0 && (i % 8) == 0)
4448         fprintf (stream, "\n   ");
4449       offset = ((uint32_t *) (t.result + level2_offset))[i];
4450       if (offset == 0)
4451         fprintf (stream, " %5d", -1);
4452       else
4453         fprintf (stream, " %5zu",
4454                  (offset - level3_offset) / sizeof (uint8_t));
4455       if (i+1 < t.level2_size << t.q)
4456         fprintf (stream, ",");
4457     }
4458   if (t.level2_size << t.q > 8)
4459     fprintf (stream, "\n ");
4460   fprintf (stream, " },\n");
4461   /* Pack the level3 array.  Each entry needs 2 bits only.  */
4462   fprintf (stream, "  {");
4463   if ((t.level3_size << t.p) * 2 / 16 > 8)
4464     fprintf (stream, "\n   ");
4465   for (i = 0; i < (t.level3_size << t.p) * 2 / 16; i++)
4466     {
4467       if (i > 0 && (i % 8) == 0)
4468         fprintf (stream, "\n   ");
4469       fprintf (stream, " 0x%04x",
4470                (((uint8_t *) (t.result + level3_offset))[8 * i] << 0)
4471                | (((uint8_t *) (t.result + level3_offset))[8 * i + 1] << 2)
4472                | (((uint8_t *) (t.result + level3_offset))[8 * i + 2] << 4)
4473                | (((uint8_t *) (t.result + level3_offset))[8 * i + 3] << 6)
4474                | (((uint8_t *) (t.result + level3_offset))[8 * i + 4] << 8)
4475                | (((uint8_t *) (t.result + level3_offset))[8 * i + 5] << 10)
4476                | (((uint8_t *) (t.result + level3_offset))[8 * i + 6] << 12)
4477                | (((uint8_t *) (t.result + level3_offset))[8 * i + 7] << 14));
4478       if (i+1 < (t.level3_size << t.p) * 2 / 16)
4479         fprintf (stream, ",");
4480     }
4481   if ((t.level3_size << t.p) * 2 / 16 > 8)
4482     fprintf (stream, "\n ");
4483   fprintf (stream, " }\n");
4484   fprintf (stream, "};\n");
4485
4486   if (ferror (stream) || fclose (stream))
4487     {
4488       fprintf (stderr, "error writing to '%s'\n", filename);
4489       exit (1);
4490     }
4491 }
4492
4493 static void
4494 output_ident_properties (const char *version)
4495 {
4496 #define PROPERTY(P) \
4497   debug_output_predicate ("unictype/sy_" #P ".txt", is_ ## P); \
4498   output_predicate_test ("../tests/unictype/test-sy_" #P ".c", is_ ## P, "uc_is_" #P " (c)"); \
4499   output_predicate ("unictype/sy_" #P ".h", is_ ## P, "u_" #P, "Language syntax properties", version);
4500   PROPERTY(c_whitespace)
4501   PROPERTY(java_whitespace)
4502 #undef PROPERTY
4503
4504   output_ident_category ("unictype/sy_c_ident.h", c_ident_category, "u_c_ident", version);
4505   output_ident_category ("unictype/sy_java_ident.h", java_ident_category, "u_java_ident", version);
4506 }
4507
4508 /* ========================================================================= */
4509
4510 /* Like ISO C <ctype.h> and <wctype.h>.  Compatible to glibc's
4511    glibc/localedata/locales/i18n file, generated by
4512    glibc/localedata/gen-unicode-ctype.c.  */
4513
4514 /* Character mappings.  */
4515
4516 static unsigned int
4517 to_upper (unsigned int ch)
4518 {
4519   if (unicode_attributes[ch].name != NULL
4520       && unicode_attributes[ch].upper != NONE)
4521     return unicode_attributes[ch].upper;
4522   else
4523     return ch;
4524 }
4525
4526 static unsigned int
4527 to_lower (unsigned int ch)
4528 {
4529   if (unicode_attributes[ch].name != NULL
4530       && unicode_attributes[ch].lower != NONE)
4531     return unicode_attributes[ch].lower;
4532   else
4533     return ch;
4534 }
4535
4536 static unsigned int
4537 to_title (unsigned int ch)
4538 {
4539   if (unicode_attributes[ch].name != NULL
4540       && unicode_attributes[ch].title != NONE)
4541     return unicode_attributes[ch].title;
4542   else
4543     return ch;
4544 }
4545
4546 /* Character class properties.  */
4547
4548 static bool
4549 is_upper (unsigned int ch)
4550 {
4551   return (to_lower (ch) != ch);
4552 }
4553
4554 static bool
4555 is_lower (unsigned int ch)
4556 {
4557   return (to_upper (ch) != ch)
4558          /* <U00DF> is lowercase, but without simple to_upper mapping.  */
4559          || (ch == 0x00DF);
4560 }
4561
4562 static bool
4563 is_alpha (unsigned int ch)
4564 {
4565   return (unicode_attributes[ch].name != NULL
4566           && ((unicode_attributes[ch].category[0] == 'L'
4567                /* Theppitak Karoonboonyanan <thep@links.nectec.or.th> says
4568                   <U0E2F>, <U0E46> should belong to is_punct.  */
4569                && (ch != 0x0E2F) && (ch != 0x0E46))
4570               /* Theppitak Karoonboonyanan <thep@links.nectec.or.th> says
4571                  <U0E31>, <U0E34>..<U0E3A>, <U0E47>..<U0E4E> are is_alpha.  */
4572               || (ch == 0x0E31)
4573               || (ch >= 0x0E34 && ch <= 0x0E3A)
4574               || (ch >= 0x0E47 && ch <= 0x0E4E)
4575               /* Avoid warning for <U0345>.  */
4576               || (ch == 0x0345)
4577               /* Avoid warnings for <U2160>..<U217F>.  */
4578               || (unicode_attributes[ch].category[0] == 'N'
4579                   && unicode_attributes[ch].category[1] == 'l')
4580               /* Avoid warnings for <U24B6>..<U24E9>.  */
4581               || (unicode_attributes[ch].category[0] == 'S'
4582                   && unicode_attributes[ch].category[1] == 'o'
4583                   && strstr (unicode_attributes[ch].name, " LETTER ")
4584                      != NULL)
4585               /* Consider all the non-ASCII digits as alphabetic.
4586                  ISO C 99 forbids us to have them in category "digit",
4587                  but we want iswalnum to return true on them.  */
4588               || (unicode_attributes[ch].category[0] == 'N'
4589                   && unicode_attributes[ch].category[1] == 'd'
4590                   && !(ch >= 0x0030 && ch <= 0x0039))));
4591 }
4592
4593 static bool
4594 is_digit (unsigned int ch)
4595 {
4596 #if 0
4597   return (unicode_attributes[ch].name != NULL
4598           && unicode_attributes[ch].category[0] == 'N'
4599           && unicode_attributes[ch].category[1] == 'd');
4600   /* Note: U+0BE7..U+0BEF and U+1369..U+1371 are digit systems without
4601      a zero.  Must add <0> in front of them by hand.  */
4602 #else
4603   /* SUSV2 gives us some freedom for the "digit" category, but ISO C 99
4604      takes it away:
4605      7.25.2.1.5:
4606         The iswdigit function tests for any wide character that corresponds
4607         to a decimal-digit character (as defined in 5.2.1).
4608      5.2.1:
4609         the 10 decimal digits 0 1 2 3 4 5 6 7 8 9
4610    */
4611   return (ch >= 0x0030 && ch <= 0x0039);
4612 #endif
4613 }
4614
4615 static bool
4616 is_outdigit (unsigned int ch)
4617 {
4618   return (ch >= 0x0030 && ch <= 0x0039);
4619 }
4620
4621 static bool
4622 is_alnum (unsigned int ch)
4623 {
4624   return is_alpha (ch) || is_digit (ch);
4625 }
4626
4627 static bool
4628 is_blank (unsigned int ch)
4629 {
4630   return (ch == 0x0009 /* '\t' */
4631           /* Category Zs without mention of "<noBreak>" */
4632           || (unicode_attributes[ch].name != NULL
4633               && unicode_attributes[ch].category[0] == 'Z'
4634               && unicode_attributes[ch].category[1] == 's'
4635               && !strstr (unicode_attributes[ch].decomposition, "<noBreak>")));
4636 }
4637
4638 static bool
4639 is_space (unsigned int ch)
4640 {
4641   /* Don't make U+00A0 a space. Non-breaking space means that all programs
4642      should treat it like a punctuation character, not like a space. */
4643   return (ch == 0x0020 /* ' ' */
4644           || ch == 0x000C /* '\f' */
4645           || ch == 0x000A /* '\n' */
4646           || ch == 0x000D /* '\r' */
4647           || ch == 0x0009 /* '\t' */
4648           || ch == 0x000B /* '\v' */
4649           /* Categories Zl, Zp, and Zs without mention of "<noBreak>" */
4650           || (unicode_attributes[ch].name != NULL
4651               && unicode_attributes[ch].category[0] == 'Z'
4652               && (unicode_attributes[ch].category[1] == 'l'
4653                   || unicode_attributes[ch].category[1] == 'p'
4654                   || (unicode_attributes[ch].category[1] == 's'
4655                       && !strstr (unicode_attributes[ch].decomposition,
4656                                   "<noBreak>")))));
4657 }
4658
4659 static bool
4660 is_cntrl (unsigned int ch)
4661 {
4662   return (unicode_attributes[ch].name != NULL
4663           && (strcmp (unicode_attributes[ch].name, "<control>") == 0
4664               /* Categories Zl and Zp */
4665               || (unicode_attributes[ch].category[0] == 'Z'
4666                   && (unicode_attributes[ch].category[1] == 'l'
4667                       || unicode_attributes[ch].category[1] == 'p'))));
4668 }
4669
4670 static bool
4671 is_xdigit (unsigned int ch)
4672 {
4673 #if 0
4674   return is_digit (ch)
4675          || (ch >= 0x0041 && ch <= 0x0046)
4676          || (ch >= 0x0061 && ch <= 0x0066);
4677 #else
4678   /* SUSV2 gives us some freedom for the "xdigit" category, but ISO C 99
4679      takes it away:
4680      7.25.2.1.12:
4681         The iswxdigit function tests for any wide character that corresponds
4682         to a hexadecimal-digit character (as defined in 6.4.4.1).
4683      6.4.4.1:
4684         hexadecimal-digit: one of 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F
4685    */
4686   return (ch >= 0x0030 && ch <= 0x0039)
4687          || (ch >= 0x0041 && ch <= 0x0046)
4688          || (ch >= 0x0061 && ch <= 0x0066);
4689 #endif
4690 }
4691
4692 static bool
4693 is_graph (unsigned int ch)
4694 {
4695   return (unicode_attributes[ch].name != NULL
4696           && strcmp (unicode_attributes[ch].name, "<control>")
4697           && !is_space (ch));
4698 }
4699
4700 static bool
4701 is_print (unsigned int ch)
4702 {
4703   return (unicode_attributes[ch].name != NULL
4704           && strcmp (unicode_attributes[ch].name, "<control>")
4705           /* Categories Zl and Zp */
4706           && !(unicode_attributes[ch].name != NULL
4707                && unicode_attributes[ch].category[0] == 'Z'
4708                && (unicode_attributes[ch].category[1] == 'l'
4709                    || unicode_attributes[ch].category[1] == 'p')));
4710 }
4711
4712 static bool
4713 is_punct (unsigned int ch)
4714 {
4715 #if 0
4716   return (unicode_attributes[ch].name != NULL
4717           && unicode_attributes[ch].category[0] == 'P');
4718 #else
4719   /* The traditional POSIX definition of punctuation is every graphic,
4720      non-alphanumeric character.  */
4721   return (is_graph (ch) && !is_alpha (ch) && !is_digit (ch));
4722 #endif
4723 }
4724
4725 /* Output all properties.  */
4726 static void
4727 output_old_ctype (const char *version)
4728 {
4729 #define PROPERTY(P) \
4730   debug_output_predicate ("unictype/ctype_" #P ".txt", is_ ## P); \
4731   output_predicate_test ("../tests/unictype/test-ctype_" #P ".c", is_ ## P, "uc_is_" #P " (c)"); \
4732   output_predicate ("unictype/ctype_" #P ".h", is_ ## P, "u_is_" #P, "ISO C <ctype.h> like properties", version);
4733   PROPERTY(alnum)
4734   PROPERTY(alpha)
4735   PROPERTY(cntrl)
4736   PROPERTY(digit)
4737   PROPERTY(graph)
4738   PROPERTY(lower)
4739   PROPERTY(print)
4740   PROPERTY(punct)
4741   PROPERTY(space)
4742   PROPERTY(upper)
4743   PROPERTY(xdigit)
4744   PROPERTY(blank)
4745 #undef PROPERTY
4746 }
4747
4748 #if 0
4749
4750 static bool
4751 is_combining (unsigned int ch)
4752 {
4753   /* Up to Unicode 3.0.1 we took the Combining property from the PropList.txt
4754      file. In 3.0.1 it was identical to the union of the general categories
4755      "Mn", "Mc", "Me". In Unicode 3.1 this property has been dropped from the
4756      PropList.txt file, so we take the latter definition.  */
4757   return (unicode_attributes[ch].name != NULL
4758           && unicode_attributes[ch].category[0] == 'M'
4759           && (unicode_attributes[ch].category[1] == 'n'
4760               || unicode_attributes[ch].category[1] == 'c'
4761               || unicode_attributes[ch].category[1] == 'e'));
4762 }
4763
4764 static bool
4765 is_combining_level3 (unsigned int ch)
4766 {
4767   return is_combining (ch)
4768          && !(unicode_attributes[ch].combining[0] != '\0'
4769               && unicode_attributes[ch].combining[0] != '0'
4770               && strtoul (unicode_attributes[ch].combining, NULL, 10) >= 200);
4771 }
4772
4773 /* Return the UCS symbol string for a Unicode character.  */
4774 static const char *
4775 ucs_symbol (unsigned int i)
4776 {
4777   static char buf[11+1];
4778
4779   sprintf (buf, (i < 0x10000 ? "<U%04X>" : "<U%08X>"), i);
4780   return buf;
4781 }
4782
4783 /* Return the UCS symbol range string for a Unicode characters interval.  */
4784 static const char *
4785 ucs_symbol_range (unsigned int low, unsigned int high)
4786 {
4787   static char buf[24+1];
4788
4789   strcpy (buf, ucs_symbol (low));
4790   strcat (buf, "..");
4791   strcat (buf, ucs_symbol (high));
4792   return buf;
4793 }
4794
4795 /* Output a character class (= property) table.  */
4796
4797 static void
4798 output_charclass (FILE *stream, const char *classname,
4799                   bool (*func) (unsigned int))
4800 {
4801   char table[0x110000];
4802   unsigned int i;
4803   bool need_semicolon;
4804   const int max_column = 75;
4805   int column;
4806
4807   for (i = 0; i < 0x110000; i++)
4808     table[i] = (int) func (i);
4809
4810   fprintf (stream, "%s ", classname);
4811   need_semicolon = false;
4812   column = 1000;
4813   for (i = 0; i < 0x110000; )
4814     {
4815       if (!table[i])
4816         i++;
4817       else
4818         {
4819           unsigned int low, high;
4820           char buf[25];
4821
4822           low = i;
4823           do
4824             i++;
4825           while (i < 0x110000 && table[i]);
4826           high = i - 1;
4827
4828           if (low == high)
4829             strcpy (buf, ucs_symbol (low));
4830           else
4831             strcpy (buf, ucs_symbol_range (low, high));
4832
4833           if (need_semicolon)
4834             {
4835               fprintf (stream, ";");
4836               column++;
4837             }
4838
4839           if (column + strlen (buf) > max_column)
4840             {
4841               fprintf (stream, "/\n   ");
4842               column = 3;
4843             }
4844
4845           fprintf (stream, "%s", buf);
4846           column += strlen (buf);
4847           need_semicolon = true;
4848         }
4849     }
4850   fprintf (stream, "\n");
4851 }
4852
4853 /* Output a character mapping table.  */
4854
4855 static void
4856 output_charmap (FILE *stream, const char *mapname,
4857                 unsigned int (*func) (unsigned int))
4858 {
4859   char table[0x110000];
4860   unsigned int i;
4861   bool need_semicolon;
4862   const int max_column = 75;
4863   int column;
4864
4865   for (i = 0; i < 0x110000; i++)
4866     table[i] = (func (i) != i);
4867
4868   fprintf (stream, "%s ", mapname);
4869   need_semicolon = false;
4870   column = 1000;
4871   for (i = 0; i < 0x110000; i++)
4872     if (table[i])
4873       {
4874         char buf[25+1];
4875
4876         strcpy (buf, "(");
4877         strcat (buf, ucs_symbol (i));
4878         strcat (buf, ",");
4879         strcat (buf, ucs_symbol (func (i)));
4880         strcat (buf, ")");
4881
4882         if (need_semicolon)
4883           {
4884             fprintf (stream, ";");
4885             column++;
4886           }
4887
4888         if (column + strlen (buf) > max_column)
4889           {
4890             fprintf (stream, "/\n   ");
4891             column = 3;
4892           }
4893
4894         fprintf (stream, "%s", buf);
4895         column += strlen (buf);
4896         need_semicolon = true;
4897       }
4898   fprintf (stream, "\n");
4899 }
4900
4901 /* Output the width table.  */
4902
4903 static void
4904 output_widthmap (FILE *stream)
4905 {
4906 }
4907
4908 /* Output the tables to the given file.  */
4909
4910 static void
4911 output_tables (const char *filename, const char *version)
4912 {
4913   FILE *stream;
4914   unsigned int ch;
4915
4916   stream = fopen (filename, "w");
4917   if (stream == NULL)
4918     {
4919       fprintf (stderr, "cannot open '%s' for writing\n", filename);
4920       exit (1);
4921     }
4922
4923   fprintf (stream, "escape_char /\n");
4924   fprintf (stream, "comment_char %%\n");
4925   fprintf (stream, "\n");
4926   fprintf (stream, "%% Generated automatically by gen-unicode-ctype for Unicode %s.\n",
4927            version);
4928   fprintf (stream, "\n");
4929
4930   fprintf (stream, "LC_IDENTIFICATION\n");
4931   fprintf (stream, "title     \"Unicode %s FDCC-set\"\n", version);
4932   fprintf (stream, "source    \"UnicodeData.txt, PropList.txt\"\n");
4933   fprintf (stream, "address   \"\"\n");
4934   fprintf (stream, "contact   \"\"\n");
4935   fprintf (stream, "email     \"bug-glibc@gnu.org\"\n");
4936   fprintf (stream, "tel       \"\"\n");
4937   fprintf (stream, "fax       \"\"\n");
4938   fprintf (stream, "language  \"\"\n");
4939   fprintf (stream, "territory \"Earth\"\n");
4940   fprintf (stream, "revision  \"%s\"\n", version);
4941   {
4942     time_t now;
4943     char date[11];
4944     now = time (NULL);
4945     strftime (date, sizeof (date), "%Y-%m-%d", gmtime (&now));
4946     fprintf (stream, "date      \"%s\"\n", date);
4947   }
4948   fprintf (stream, "category  \"unicode:2001\";LC_CTYPE\n");
4949   fprintf (stream, "END LC_IDENTIFICATION\n");
4950   fprintf (stream, "\n");
4951
4952   /* Verifications. */
4953   for (ch = 0; ch < 0x110000; ch++)
4954     {
4955       /* toupper restriction: "Only characters specified for the keywords
4956          lower and upper shall be specified.  */
4957       if (to_upper (ch) != ch && !(is_lower (ch) || is_upper (ch)))
4958         fprintf (stderr,
4959                  "%s is not upper|lower but toupper(0x%04X) = 0x%04X\n",
4960                  ucs_symbol (ch), ch, to_upper (ch));
4961
4962       /* tolower restriction: "Only characters specified for the keywords
4963          lower and upper shall be specified.  */
4964       if (to_lower (ch) != ch && !(is_lower (ch) || is_upper (ch)))
4965         fprintf (stderr,
4966                  "%s is not upper|lower but tolower(0x%04X) = 0x%04X\n",
4967                  ucs_symbol (ch), ch, to_lower (ch));
4968
4969       /* alpha restriction: "Characters classified as either upper or lower
4970          shall automatically belong to this class.  */
4971       if ((is_lower (ch) || is_upper (ch)) && !is_alpha (ch))
4972         fprintf (stderr, "%s is upper|lower but not alpha\n", ucs_symbol (ch));
4973
4974       /* alpha restriction: "No character specified for the keywords cntrl,
4975          digit, punct or space shall be specified."  */
4976       if (is_alpha (ch) && is_cntrl (ch))
4977         fprintf (stderr, "%s is alpha and cntrl\n", ucs_symbol (ch));
4978       if (is_alpha (ch) && is_digit (ch))
4979         fprintf (stderr, "%s is alpha and digit\n", ucs_symbol (ch));
4980       if (is_alpha (ch) && is_punct (ch))
4981         fprintf (stderr, "%s is alpha and punct\n", ucs_symbol (ch));
4982       if (is_alpha (ch) && is_space (ch))
4983         fprintf (stderr, "%s is alpha and space\n", ucs_symbol (ch));
4984
4985       /* space restriction: "No character specified for the keywords upper,
4986          lower, alpha, digit, graph or xdigit shall be specified."
4987          upper, lower, alpha already checked above.  */
4988       if (is_space (ch) && is_digit (ch))
4989         fprintf (stderr, "%s is space and digit\n", ucs_symbol (ch));
4990       if (is_space (ch) && is_graph (ch))
4991         fprintf (stderr, "%s is space and graph\n", ucs_symbol (ch));
4992       if (is_space (ch) && is_xdigit (ch))
4993         fprintf (stderr, "%s is space and xdigit\n", ucs_symbol (ch));
4994
4995       /* cntrl restriction: "No character specified for the keywords upper,
4996          lower, alpha, digit, punct, graph, print or xdigit shall be
4997          specified."  upper, lower, alpha already checked above.  */
4998       if (is_cntrl (ch) && is_digit (ch))
4999         fprintf (stderr, "%s is cntrl and digit\n", ucs_symbol (ch));
5000       if (is_cntrl (ch) && is_punct (ch))
5001         fprintf (stderr, "%s is cntrl and punct\n", ucs_symbol (ch));
5002       if (is_cntrl (ch) && is_graph (ch))
5003         fprintf (stderr, "%s is cntrl and graph\n", ucs_symbol (ch));
5004       if (is_cntrl (ch) && is_print (ch))
5005         fprintf (stderr, "%s is cntrl and print\n", ucs_symbol (ch));
5006       if (is_cntrl (ch) && is_xdigit (ch))
5007         fprintf (stderr, "%s is cntrl and xdigit\n", ucs_symbol (ch));
5008
5009       /* punct restriction: "No character specified for the keywords upper,
5010          lower, alpha, digit, cntrl, xdigit or as the <space> character shall
5011          be specified."  upper, lower, alpha, cntrl already checked above.  */
5012       if (is_punct (ch) && is_digit (ch))
5013         fprintf (stderr, "%s is punct and digit\n", ucs_symbol (ch));
5014       if (is_punct (ch) && is_xdigit (ch))
5015         fprintf (stderr, "%s is punct and xdigit\n", ucs_symbol (ch));
5016       if (is_punct (ch) && (ch == 0x0020))
5017         fprintf (stderr, "%s is punct\n", ucs_symbol (ch));
5018
5019       /* graph restriction: "No character specified for the keyword cntrl
5020          shall be specified."  Already checked above.  */
5021
5022       /* print restriction: "No character specified for the keyword cntrl
5023          shall be specified."  Already checked above.  */
5024
5025       /* graph - print relation: differ only in the <space> character.
5026          How is this possible if there are more than one space character?!
5027          I think susv2/xbd/locale.html should speak of "space characters",
5028          not "space character".  */
5029       if (is_print (ch) && !(is_graph (ch) || /* ch == 0x0020 */ is_space (ch)))
5030         fprintf (stderr,
5031                  "%s is print but not graph|<space>\n", ucs_symbol (ch));
5032       if (!is_print (ch) && (is_graph (ch) || ch == 0x0020))
5033         fprintf (stderr,
5034                  "%s is graph|<space> but not print\n", ucs_symbol (ch));
5035     }
5036
5037   fprintf (stream, "LC_CTYPE\n");
5038   output_charclass (stream, "upper", is_upper);
5039   output_charclass (stream, "lower", is_lower);
5040   output_charclass (stream, "alpha", is_alpha);
5041   output_charclass (stream, "digit", is_digit);
5042   output_charclass (stream, "outdigit", is_outdigit);
5043   output_charclass (stream, "blank", is_blank);
5044   output_charclass (stream, "space", is_space);
5045   output_charclass (stream, "cntrl", is_cntrl);
5046   output_charclass (stream, "punct", is_punct);
5047   output_charclass (stream, "xdigit", is_xdigit);
5048   output_charclass (stream, "graph", is_graph);
5049   output_charclass (stream, "print", is_print);
5050   output_charclass (stream, "class \"combining\";", is_combining);
5051   output_charclass (stream, "class \"combining_level3\";", is_combining_level3);
5052   output_charmap (stream, "toupper", to_upper);
5053   output_charmap (stream, "tolower", to_lower);
5054   output_charmap (stream, "map \"totitle\";", to_title);
5055   output_widthmap (stream);
5056   fprintf (stream, "END LC_CTYPE\n");
5057
5058   if (ferror (stream) || fclose (stream))
5059     {
5060       fprintf (stderr, "error writing to '%s'\n", filename);
5061       exit (1);
5062     }
5063 }
5064
5065 #endif
5066
5067 /* ========================================================================= */
5068
5069 /* The width property from the EastAsianWidth.txt file.
5070    Each is NULL (unassigned) or "N", "A", "H", "W", "F", "Na".  */
5071 const char * unicode_width[0x110000];
5072
5073 /* Stores in unicode_width[] the width property from the EastAsianWidth.txt
5074    file.  */
5075 static void
5076 fill_width (const char *width_filename)
5077 {
5078   unsigned int i, j;
5079   FILE *stream;
5080   char field0[FIELDLEN];
5081   char field1[FIELDLEN];
5082   char field2[FIELDLEN];
5083   int lineno = 0;
5084
5085   for (i = 0; i < 0x110000; i++)
5086     unicode_width[i] = (unicode_attributes[i].name != NULL ? "N" : NULL);
5087
5088   stream = fopen (width_filename, "r");
5089   if (stream == NULL)
5090     {
5091       fprintf (stderr, "error during fopen of '%s'\n", width_filename);
5092       exit (1);
5093     }
5094
5095   for (;;)
5096     {
5097       int n;
5098       int c;
5099
5100       lineno++;
5101       c = getc (stream);
5102       if (c == EOF)
5103         break;
5104       if (c == '#')
5105         {
5106           do c = getc (stream); while (c != EOF && c != '\n');
5107           continue;
5108         }
5109       ungetc (c, stream);
5110       n = getfield (stream, field0, ';');
5111       n += getfield (stream, field1, ' ');
5112       n += getfield (stream, field2, '\n');
5113       if (n == 0)
5114         break;
5115       if (n != 3)
5116         {
5117           fprintf (stderr, "short line in '%s':%d\n", width_filename, lineno);
5118           exit (1);
5119         }
5120       i = strtoul (field0, NULL, 16);
5121       if (strstr (field0, "..") != NULL)
5122         {
5123           /* Deal with a range.  */
5124           j = strtoul (strstr (field0, "..") + 2, NULL, 16);
5125           for (; i <= j; i++)
5126             unicode_width[i] = strdup (field1);
5127         }
5128       else
5129         {
5130           /* Single character line.  */
5131           unicode_width[i] = strdup (field1);
5132         }
5133     }
5134   if (ferror (stream) || fclose (stream))
5135     {
5136       fprintf (stderr, "error reading from '%s'\n", width_filename);
5137       exit (1);
5138     }
5139 }
5140
5141 /* Line breaking classification.  */
5142
5143 enum
5144 {
5145   /* Values >= 24 are resolved at run time. */
5146   LBP_BK = 24, /* mandatory break */
5147 /*LBP_CR,         carriage return - not used here because it's a DOSism */
5148 /*LBP_LF,         line feed - not used here because it's a DOSism */
5149   LBP_CM = 25, /* attached characters and combining marks */
5150 /*LBP_NL,         next line - not used here because it's equivalent to LBP_BK */
5151 /*LBP_SG,         surrogates - not used here because they are not characters */
5152   LBP_WJ =  0, /* word joiner */
5153   LBP_ZW = 26, /* zero width space */
5154   LBP_GL =  1, /* non-breaking (glue) */
5155   LBP_SP = 27, /* space */
5156   LBP_B2 =  2, /* break opportunity before and after */
5157   LBP_BA =  3, /* break opportunity after */
5158   LBP_BB =  4, /* break opportunity before */
5159   LBP_HY =  5, /* hyphen */
5160   LBP_CB = 28, /* contingent break opportunity */
5161   LBP_CL =  6, /* closing punctuation */
5162   LBP_EX =  7, /* exclamation/interrogation */
5163   LBP_IN =  8, /* inseparable */
5164   LBP_NS =  9, /* non starter */
5165   LBP_OP = 10, /* opening punctuation */
5166   LBP_QU = 11, /* ambiguous quotation */
5167   LBP_IS = 12, /* infix separator (numeric) */
5168   LBP_NU = 13, /* numeric */
5169   LBP_PO = 14, /* postfix (numeric) */
5170   LBP_PR = 15, /* prefix (numeric) */
5171   LBP_SY = 16, /* symbols allowing breaks */
5172   LBP_AI = 29, /* ambiguous (alphabetic or ideograph) */
5173   LBP_AL = 17, /* ordinary alphabetic and symbol characters */
5174   LBP_H2 = 18, /* Hangul LV syllable */
5175   LBP_H3 = 19, /* Hangul LVT syllable */
5176   LBP_ID = 20, /* ideographic */
5177   LBP_JL = 21, /* Hangul L Jamo */
5178   LBP_JV = 22, /* Hangul V Jamo */
5179   LBP_JT = 23, /* Hangul T Jamo */
5180   LBP_SA = 30, /* complex context (South East Asian) */
5181   LBP_XX = 31  /* unknown */
5182 };
5183
5184 /* Returns the line breaking classification for ch, as a bit mask.  */
5185 static int
5186 get_lbp (unsigned int ch)
5187 {
5188   int attr = 0;
5189
5190   if (unicode_attributes[ch].name != NULL)
5191     {
5192       /* mandatory break */
5193       if (ch == 0x000A || ch == 0x000D || ch == 0x0085 /* newline */
5194           || ch == 0x000C /* form feed */
5195           || ch == 0x000B /* line tabulation */
5196           || ch == 0x2028 /* LINE SEPARATOR */
5197           || ch == 0x2029 /* PARAGRAPH SEPARATOR */)
5198         attr |= 1 << LBP_BK;
5199
5200       if (ch == 0x2060 /* WORD JOINER */
5201           || ch == 0xFEFF /* ZERO WIDTH NO-BREAK SPACE */)
5202         attr |= 1 << LBP_WJ;
5203
5204       /* zero width space */
5205       if (ch == 0x200B /* ZERO WIDTH SPACE */)
5206         attr |= 1 << LBP_ZW;
5207
5208       /* non-breaking (glue) */
5209       if (ch == 0x00A0 /* NO-BREAK SPACE */
5210           || ch == 0x202F /* NARROW NO-BREAK SPACE */
5211           || ch == 0x180E /* MONGOLIAN VOWEL SEPARATOR */
5212           || ch == 0x034F /* COMBINING GRAPHEME JOINER */
5213           || ch == 0x2007 /* FIGURE SPACE */
5214           || ch == 0x2011 /* NON-BREAKING HYPHEN */
5215           || ch == 0x0F08 /* TIBETAN MARK SBRUL SHAD */
5216           || ch == 0x0F0C /* TIBETAN MARK DELIMITER TSHEG BSTAR */
5217           || ch == 0x0F12 /* TIBETAN MARK RGYA GRAM SHAD */
5218           || (ch >= 0x035C && ch <= 0x0362) /* COMBINING DOUBLE ... */)
5219         attr |= 1 << LBP_GL;
5220
5221       /* space */
5222       if (ch == 0x0020 /* SPACE */)
5223         attr |= 1 << LBP_SP;
5224
5225       /* break opportunity before and after */
5226       if (ch == 0x2014 /* EM DASH */)
5227         attr |= 1 << LBP_B2;
5228
5229       /* break opportunity after */
5230       if (ch == 0x1680 /* OGHAM SPACE MARK */
5231           || ch == 0x2000 /* EN QUAD */
5232           || ch == 0x2001 /* EM QUAD */
5233           || ch == 0x2002 /* EN SPACE */
5234           || ch == 0x2003 /* EM SPACE */
5235           || ch == 0x2004 /* THREE-PER-EM SPACE */
5236           || ch == 0x2005 /* FOUR-PER-EM SPACE */
5237           || ch == 0x2006 /* SIX-PER-EM SPACE */
5238           || ch == 0x2008 /* PUNCTUATION SPACE */
5239           || ch == 0x2009 /* THIN SPACE */
5240           || ch == 0x200A /* HAIR SPACE */
5241           || ch == 0x205F /* MEDIUM MATHEMATICAL SPACE */
5242           || ch == 0x0009 /* tab */
5243           || ch == 0x00AD /* SOFT HYPHEN */
5244           || ch == 0x058A /* ARMENIAN HYPHEN */
5245           || ch == 0x2010 /* HYPHEN */
5246           || ch == 0x2012 /* FIGURE DASH */
5247           || ch == 0x2013 /* EN DASH */
5248           || ch == 0x05BE /* HEBREW PUNCTUATION MAQAF */
5249           || ch == 0x0F0B /* TIBETAN MARK INTERSYLLABIC TSHEG */
5250           || ch == 0x1361 /* ETHIOPIC WORDSPACE */
5251           || ch == 0x17D8 /* KHMER SIGN BEYYAL */
5252           || ch == 0x17DA /* KHMER SIGN KOOMUUT */
5253           || ch == 0x2027 /* HYPHENATION POINT */
5254           || ch == 0x007C /* VERTICAL LINE */
5255           || ch == 0x16EB /* RUNIC SINGLE PUNCTUATION */
5256           || ch == 0x16EC /* RUNIC MULTIPLE PUNCTUATION */
5257           || ch == 0x16ED /* RUNIC CROSS PUNCTUATION */
5258           || ch == 0x2056 /* THREE DOT PUNCTUATION */
5259           || ch == 0x2058 /* FOUR DOT PUNCTUATION */
5260           || ch == 0x2059 /* FIVE DOT PUNCTUATION */
5261           || ch == 0x205A /* TWO DOT PUNCTUATION */
5262           || ch == 0x205B /* FOUR DOT MARK */
5263           || ch == 0x205D /* TRICOLON */
5264           || ch == 0x205E /* VERTICAL FOUR DOTS */
5265           || ch == 0x2E19 /* PALM BRANCH */
5266           || ch == 0x2E2A /* TWO DOTS OVER ONE DOT PUNCTUATION */
5267           || ch == 0x2E2B /* ONE DOT OVER TWO DOTS PUNCTUATION */
5268           || ch == 0x2E2C /* SQUARED FOUR DOT PUNCTUATION */
5269           || ch == 0x2E2D /* FIVE DOT PUNCTUATION */
5270           || ch == 0x2E30 /* RING POINT */
5271           || ch == 0x10100 /* AEGEAN WORD SEPARATOR LINE */
5272           || ch == 0x10101 /* AEGEAN WORD SEPARATOR DOT */
5273           || ch == 0x10102 /* AEGEAN CHECK MARK */
5274           || ch == 0x1039F /* UGARITIC WORD DIVIDER */
5275           || ch == 0x103D0 /* OLD PERSIAN WORD DIVIDER */
5276           || ch == 0x1091F /* PHOENICIAN WORD SEPARATOR */
5277           || ch == 0x12470 /* CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER */
5278           || ch == 0x0964 /* DEVANAGARI DANDA */
5279           || ch == 0x0965 /* DEVANAGARI DOUBLE DANDA */
5280           || ch == 0x0E5A /* THAI CHARACTER ANGKHANKHU */
5281           || ch == 0x0E5B /* THAI CHARACTER KHOMUT */
5282           || ch == 0x104A /* MYANMAR SIGN LITTLE SECTION */
5283           || ch == 0x104B /* MYANMAR SIGN SECTION */
5284           || ch == 0x1735 /* PHILIPPINE SINGLE PUNCTUATION */
5285           || ch == 0x1736 /* PHILIPPINE DOUBLE PUNCTUATION */
5286           || ch == 0x17D4 /* KHMER SIGN KHAN */
5287           || ch == 0x17D5 /* KHMER SIGN BARIYOOSAN */
5288           || ch == 0x1B5E /* BALINESE CARIK SIKI */
5289           || ch == 0x1B5F /* BALINESE CARIK PAREREN */
5290           || ch == 0xA8CE /* SAURASHTRA DANDA */
5291           || ch == 0xA8CF /* SAURASHTRA DOUBLE DANDA */
5292           || ch == 0xAA5D /* CHAM PUNCTUATION DANDA */
5293           || ch == 0xAA5E /* CHAM PUNCTUATION DOUBLE DANDA */
5294           || ch == 0xAA5F /* CHAM PUNCTUATION TRIPLE DANDA */
5295           || ch == 0x10A56 /* KHAROSHTHI PUNCTUATION DANDA */
5296           || ch == 0x10A57 /* KHAROSHTHI PUNCTUATION DOUBLE DANDA */
5297           || ch == 0x0F34 /* TIBETAN MARK BSDUS RTAGS */
5298           || ch == 0x0F7F /* TIBETAN SIGN RNAM BCAD */
5299           || ch == 0x0F85 /* TIBETAN MARK PALUTA */
5300           || ch == 0x0FBE /* TIBETAN KU RU KHA */
5301           || ch == 0x0FBF /* TIBETAN KU RU KHA BZHI MIG CAN */
5302           || ch == 0x0FD2 /* TIBETAN MARK NYIS TSHEG */
5303           || ch == 0x1804 /* MONGOLIAN COLON */
5304           || ch == 0x1805 /* MONGOLIAN FOUR DOTS */
5305           || ch == 0x1B5A /* BALINESE PANTI */
5306           || ch == 0x1B5B /* BALINESE PAMADA */
5307           || ch == 0x1B5C /* BALINESE WINDU */
5308           || ch == 0x1B5D /* BALINESE CARIK PAMUNGKAH */
5309           || ch == 0x1B60 /* BALINESE PAMENENG */
5310           || ch == 0x1C3B /* LEPCHA PUNCTUATION TA-ROL */
5311           || ch == 0x1C3C /* LEPCHA PUNCTUATION NYET THYOOM TA-ROL */
5312           || ch == 0x1C3D /* LEPCHA PUNCTUATION CER-WA */
5313           || ch == 0x1C3E /* LEPCHA PUNCTUATION TSHOOK CER-WA */
5314           || ch == 0x1C3F /* LEPCHA PUNCTUATION TSHOOK */
5315           || ch == 0x1C7E /* OL CHIKI PUNCTUATION MUCAAD */
5316           || ch == 0x1C7F /* OL CHIKI PUNCTUATION DOUBLE MUCAAD */
5317           || ch == 0x2CFA /* COPTIC OLD NUBIAN DIRECT QUESTION MARK */
5318           || ch == 0x2CFB /* COPTIC OLD NUBIAN INDIRECT QUESTION MARK */
5319           || ch == 0x2CFC /* COPTIC OLD NUBIAN VERSE DIVIDER */
5320           || ch == 0x2CFF /* COPTIC MORPHOLOGICAL DIVIDER */
5321           || (ch >= 0x2E0E && ch <= 0x2E15) /* EDITORIAL CORONIS .. UPWARDS ANCORA */
5322           || ch == 0x2E17 /* DOUBLE OBLIQUE HYPHEN */
5323           || ch == 0xA60D /* VAI COMMA */
5324           || ch == 0xA60F /* VAI QUESTION MARK */
5325           || ch == 0xA92E /* KAYAH LI SIGN CWI */
5326           || ch == 0xA92F /* KAYAH LI SIGN SHYA */
5327           || ch == 0x10A50 /* KHAROSHTHI PUNCTUATION DOT */
5328           || ch == 0x10A51 /* KHAROSHTHI PUNCTUATION SMALL CIRCLE */
5329           || ch == 0x10A52 /* KHAROSHTHI PUNCTUATION CIRCLE */
5330           || ch == 0x10A53 /* KHAROSHTHI PUNCTUATION CRESCENT BAR */
5331           || ch == 0x10A54 /* KHAROSHTHI PUNCTUATION MANGALAM */
5332           || ch == 0x10A55 /* KHAROSHTHI PUNCTUATION LOTUS */
5333           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5334           || ch == 0x12471 /* CUNEIFORM PUNCTUATION SIGN VERTICAL COLON */
5335           || ch == 0x12472 /* CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON */
5336           || ch == 0x12473 /* CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON */)
5337         attr |= 1 << LBP_BA;
5338
5339       /* break opportunity before */
5340       if (ch == 0x00B4 /* ACUTE ACCENT */
5341           || ch == 0x1FFD /* GREEK OXIA */
5342           || ch == 0x02DF /* MODIFIER LETTER CROSS ACCENT */
5343           || ch == 0x02C8 /* MODIFIER LETTER VERTICAL LINE */
5344           || ch == 0x02CC /* MODIFIER LETTER LOW VERTICAL LINE */
5345           || ch == 0x0F01 /* TIBETAN MARK GTER YIG MGO TRUNCATED A */
5346           || ch == 0x0F02 /* TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA */
5347           || ch == 0x0F03 /* TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA */
5348           || ch == 0x0F04 /* TIBETAN MARK INITIAL YIG MGO MDUN MA */
5349           || ch == 0x0F06 /* TIBETAN MARK CARET YIG MGO PHUR SHAD MA */
5350           || ch == 0x0F07 /* TIBETAN MARK YIG MGO TSHEG SHAD MA */
5351           || ch == 0x0F09 /* TIBETAN MARK BSKUR YIG MGO */
5352           || ch == 0x0F0A /* TIBETAN MARK BKA- SHOG YIG MGO */
5353           || ch == 0x0FD0 /* TIBETAN MARK BSKA- SHOG GI MGO RGYAN */
5354           || ch == 0x0FD1 /* TIBETAN MARK MNYAM YIG GI MGO RGYAN */
5355           || ch == 0x0FD3 /* TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA */
5356           || ch == 0xA874 /* PHAGS-PA SINGLE HEAD MARK */
5357           || ch == 0xA875 /* PHAGS-PA DOUBLE HEAD MARK */
5358           || ch == 0x1806 /* MONGOLIAN TODO SOFT HYPHEN */)
5359         attr |= 1 << LBP_BB;
5360
5361       /* hyphen */
5362       if (ch == 0x002D /* HYPHEN-MINUS */)
5363         attr |= 1 << LBP_HY;
5364
5365       /* contingent break opportunity */
5366       if (ch == 0xFFFC /* OBJECT REPLACEMENT CHARACTER */)
5367         attr |= 1 << LBP_CB;
5368
5369       /* closing punctuation */
5370       if ((unicode_attributes[ch].category[0] == 'P'
5371            && unicode_attributes[ch].category[1] == 'e')
5372           || ch == 0x3001 /* IDEOGRAPHIC COMMA */
5373           || ch == 0x3002 /* IDEOGRAPHIC FULL STOP */
5374           || ch == 0xFE11 /* PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA */
5375           || ch == 0xFE12 /* PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP */
5376           || ch == 0xFE50 /* SMALL COMMA */
5377           || ch == 0xFE52 /* SMALL FULL STOP */
5378           || ch == 0xFF0C /* FULLWIDTH COMMA */
5379           || ch == 0xFF0E /* FULLWIDTH FULL STOP */
5380           || ch == 0xFF61 /* HALFWIDTH IDEOGRAPHIC FULL STOP */
5381           || ch == 0xFF64 /* HALFWIDTH IDEOGRAPHIC COMMA */)
5382         attr |= 1 << LBP_CL;
5383
5384       /* exclamation/interrogation */
5385       if (ch == 0x0021 /* EXCLAMATION MARK */
5386           || ch == 0x003F /* QUESTION MARK */
5387           || ch == 0x05C6 /* HEBREW PUNCTUATION NUN HAFUKHA */
5388           || ch == 0x061B /* ARABIC SEMICOLON */
5389           || ch == 0x061E /* ARABIC TRIPLE DOT PUNCTUATION MARK */
5390           || ch == 0x061F /* ARABIC QUESTION MARK */
5391           || ch == 0x06D4 /* ARABIC FULL STOP */
5392           || ch == 0x07F9 /* NKO EXCLAMATION MARK */
5393           || ch == 0x0F0D /* TIBETAN MARK SHAD */
5394           || ch == 0x0F0E /* TIBETAN MARK NYIS SHAD */
5395           || ch == 0x0F0F /* TIBETAN MARK TSHEG SHAD */
5396           || ch == 0x0F10 /* TIBETAN MARK NYIS TSHEG SHAD */
5397           || ch == 0x0F11 /* TIBETAN MARK RIN CHEN SPUNGS SHAD */
5398           || ch == 0x0F14 /* TIBETAN MARK GTER TSHEG */
5399           || ch == 0x1802 /* MONGOLIAN COMMA */
5400           || ch == 0x1803 /* MONGOLIAN FULL STOP */
5401           || ch == 0x1808 /* MONGOLIAN MANCHU COMMA */
5402           || ch == 0x1809 /* MONGOLIAN MANCHU FULL STOP */
5403           || ch == 0x1944 /* LIMBU EXCLAMATION MARK */
5404           || ch == 0x1945 /* LIMBU QUESTION MARK */
5405           || ch == 0x2762 /* HEAVY EXCLAMATION MARK ORNAMENT */
5406           || ch == 0x2763 /* HEAVY HEART EXCLAMATION MARK ORNAMENT */
5407           || ch == 0x2CF9 /* COPTIC OLD NUBIAN FULL STOP */
5408           || ch == 0x2CFE /* COPTIC FULL STOP */
5409           || ch == 0x2E2E /* REVERSED QUESTION MARK */
5410 #if REVISION_22
5411           || ch == 0xA60C /* VAI SYLLABLE LENGTHENER */
5412 #endif
5413           || ch == 0xA60E /* VAI FULL STOP */
5414           || ch == 0xA876 /* PHAGS-PA MARK SHAD */
5415           || ch == 0xA877 /* PHAGS-PA MARK DOUBLE SHAD */
5416           || ch == 0xFE15 /* PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK */
5417           || ch == 0xFE16 /* PRESENTATION FORM FOR VERTICAL QUESTION MARK */
5418           || ch == 0xFE56 /* SMALL QUESTION MARK */
5419           || ch == 0xFE57 /* SMALL EXCLAMATION MARK */
5420           || ch == 0xFF01 /* FULLWIDTH EXCLAMATION MARK */
5421           || ch == 0xFF1F /* FULLWIDTH QUESTION MARK */)
5422         attr |= 1 << LBP_EX;
5423
5424       /* inseparable */
5425       if (ch == 0x2024 /* ONE DOT LEADER */
5426           || ch == 0x2025 /* TWO DOT LEADER */
5427           || ch == 0x2026 /* HORIZONTAL ELLIPSIS */
5428           || ch == 0xFE19 /* PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS */)
5429         attr |= 1 << LBP_IN;
5430
5431       /* non starter */
5432       if (ch == 0x17D6 /* KHMER SIGN CAMNUC PII KUUH */
5433           || ch == 0x203C /* DOUBLE EXCLAMATION MARK */
5434           || ch == 0x203D /* INTERROBANG */
5435           || ch == 0x2047 /* DOUBLE QUESTION MARK */
5436           || ch == 0x2048 /* QUESTION EXCLAMATION MARK */
5437           || ch == 0x2049 /* EXCLAMATION QUESTION MARK */
5438           || ch == 0x3005 /* IDEOGRAPHIC ITERATION MARK */
5439           || ch == 0x301C /* WAVE DASH */
5440           || ch == 0x303C /* MASU MARK */
5441           || ch == 0x303B /* VERTICAL IDEOGRAPHIC ITERATION MARK */
5442           || ch == 0x309B /* KATAKANA-HIRAGANA VOICED SOUND MARK */
5443           || ch == 0x309C /* KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
5444           || ch == 0x309D /* HIRAGANA ITERATION MARK */
5445           || ch == 0x309E /* HIRAGANA VOICED ITERATION MARK */
5446           || ch == 0x30A0 /* KATAKANA-HIRAGANA DOUBLE HYPHEN */
5447           || ch == 0x30FB /* KATAKANA MIDDLE DOT */
5448           || ch == 0x30FC /* KATAKANA-HIRAGANA PROLONGED SOUND MARK */
5449           || ch == 0x30FD /* KATAKANA ITERATION MARK */
5450           || ch == 0x30FE /* KATAKANA VOICED ITERATION MARK */
5451           || ch == 0xA015 /* YI SYLLABLE WU */
5452           || ch == 0xFE54 /* SMALL SEMICOLON */
5453           || ch == 0xFE55 /* SMALL COLON */
5454           || ch == 0xFF1A /* FULLWIDTH COLON */
5455           || ch == 0xFF1B /* FULLWIDTH SEMICOLON */
5456           || ch == 0xFF65 /* HALFWIDTH KATAKANA MIDDLE DOT */
5457           || ch == 0xFF70 /* HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */
5458           || ch == 0xFF9E /* HALFWIDTH KATAKANA VOICED SOUND MARK */
5459           || ch == 0xFF9F /* HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */
5460           || strstr (unicode_attributes[ch].name, "HIRAGANA LETTER SMALL ") != NULL
5461           || strstr (unicode_attributes[ch].name, "KATAKANA LETTER SMALL ") != NULL)
5462         attr |= 1 << LBP_NS;
5463
5464       /* opening punctuation */
5465       if ((unicode_attributes[ch].category[0] == 'P'
5466            && unicode_attributes[ch].category[1] == 's')
5467           || ch == 0x00A1 /* INVERTED EXCLAMATION MARK */
5468           || ch == 0x00BF /* INVERTED QUESTION MARK */
5469           || ch == 0x2E18 /* INVERTED INTERROBANG */)
5470         attr |= 1 << LBP_OP;
5471
5472       /* ambiguous quotation */
5473       if ((unicode_attributes[ch].category[0] == 'P'
5474            && (unicode_attributes[ch].category[1] == 'f'
5475                || unicode_attributes[ch].category[1] == 'i'))
5476           || ch == 0x0022 /* QUOTATION MARK */
5477           || ch == 0x0027 /* APOSTROPHE */
5478           || ch == 0x275B /* HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT */
5479           || ch == 0x275C /* HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT */
5480           || ch == 0x275D /* HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT */
5481           || ch == 0x275E /* HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT */
5482           || ch == 0x2E00 /* RIGHT ANGLE SUBSTITUTION MARKER */
5483           || ch == 0x2E01 /* RIGHT ANGLE DOTTED SUBSTITUTION MARKER */
5484           || ch == 0x2E06 /* RAISED INTERPOLATION MARKER */
5485           || ch == 0x2E07 /* RAISED DOTTED INTERPOLATION MARKER */
5486           || ch == 0x2E08 /* DOTTED TRANSPOSITION MARKER */
5487           || ch == 0x2E0B /* RAISED SQUARE */)
5488         attr |= 1 << LBP_QU;
5489
5490       /* infix separator (numeric) */
5491       if (ch == 0x002C /* COMMA */
5492           || ch == 0x002E /* FULL STOP */
5493           || ch == 0x003A /* COLON */
5494           || ch == 0x003B /* SEMICOLON */
5495           || ch == 0x037E /* GREEK QUESTION MARK */
5496           || ch == 0x0589 /* ARMENIAN FULL STOP */
5497           || ch == 0x060C /* ARABIC COMMA */
5498           || ch == 0x060D /* ARABIC DATE SEPARATOR */
5499           || ch == 0x07F8 /* NKO COMMA */
5500           || ch == 0x2044 /* FRACTION SLASH */
5501           || ch == 0xFE10 /* PRESENTATION FORM FOR VERTICAL COMMA */
5502           || ch == 0xFE13 /* PRESENTATION FORM FOR VERTICAL COLON */
5503           || ch == 0xFE14 /* PRESENTATION FORM FOR VERTICAL SEMICOLON */)
5504         attr |= 1 << LBP_IS;
5505
5506       /* numeric */
5507       if ((unicode_attributes[ch].category[0] == 'N'
5508            && unicode_attributes[ch].category[1] == 'd'
5509            && strstr (unicode_attributes[ch].name, "FULLWIDTH") == NULL)
5510           || ch == 0x066B /* ARABIC DECIMAL SEPARATOR */
5511           || ch == 0x066C /* ARABIC THOUSANDS SEPARATOR */)
5512         attr |= 1 << LBP_NU;
5513
5514       /* postfix (numeric) */
5515       if (ch == 0x0025 /* PERCENT SIGN */
5516           || ch == 0x00A2 /* CENT SIGN */
5517           || ch == 0x00B0 /* DEGREE SIGN */
5518           || ch == 0x060B /* AFGHANI SIGN */
5519           || ch == 0x066A /* ARABIC PERCENT SIGN */
5520           || ch == 0x2030 /* PER MILLE SIGN */
5521           || ch == 0x2031 /* PER TEN THOUSAND SIGN */
5522           || ch == 0x2032 /* PRIME */
5523           || ch == 0x2033 /* DOUBLE PRIME */
5524           || ch == 0x2034 /* TRIPLE PRIME */
5525           || ch == 0x2035 /* REVERSED PRIME */
5526           || ch == 0x2036 /* REVERSED DOUBLE PRIME */
5527           || ch == 0x2037 /* REVERSED TRIPLE PRIME */
5528           || ch == 0x20A7 /* PESETA SIGN */
5529           || ch == 0x2103 /* DEGREE CELSIUS */
5530           || ch == 0x2109 /* DEGREE FAHRENHEIT */
5531           || ch == 0xFDFC /* RIAL SIGN */
5532           || ch == 0xFE6A /* SMALL PERCENT SIGN */
5533           || ch == 0xFF05 /* FULLWIDTH PERCENT SIGN */
5534           || ch == 0xFFE0 /* FULLWIDTH DIGIT ZERO */
5535           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5536           || ch == 0x0609 /* ARABIC-INDIC PER MILLE SIGN */
5537           || ch == 0x060A /* ARABIC-INDIC PER TEN THOUSAND SIGN */
5538           || ch == 0x0D79 /* MALAYALAM DATE MARK */)
5539         attr |= 1 << LBP_PO;
5540
5541       /* prefix (numeric) */
5542       if ((unicode_attributes[ch].category[0] == 'S'
5543            && unicode_attributes[ch].category[1] == 'c')
5544           || ch == 0x002B /* PLUS SIGN */
5545           || ch == 0x005C /* REVERSE SOLIDUS */
5546           || ch == 0x00B1 /* PLUS-MINUS SIGN */
5547           || ch == 0x2116 /* NUMERO SIGN */
5548           || ch == 0x2212 /* MINUS SIGN */
5549           || ch == 0x2213 /* MINUS-OR-PLUS SIGN */)
5550         if (!(attr & (1 << LBP_PO)))
5551           attr |= 1 << LBP_PR;
5552
5553       /* symbols allowing breaks */
5554       if (ch == 0x002F /* SOLIDUS */)
5555         attr |= 1 << LBP_SY;
5556
5557       if (ch >= 0xAC00 && ch <= 0xD7A3 && ((ch - 0xAC00) % 28) == 0)
5558         attr |= 1 << LBP_H2;
5559
5560       if (ch >= 0xAC00 && ch <= 0xD7A3 && ((ch - 0xAC00) % 28) != 0)
5561         attr |= 1 << LBP_H3;
5562
5563       if ((ch >= 0x1100 && ch <= 0x1159) || ch == 0x115F)
5564         attr |= 1 << LBP_JL;
5565
5566       if (ch >= 0x1160 && ch <= 0x11A2)
5567         attr |= 1 << LBP_JV;
5568
5569       if (ch >= 0x11A8 && ch <= 0x11F9)
5570         attr |= 1 << LBP_JT;
5571
5572       /* complex context (South East Asian) */
5573       if (((unicode_attributes[ch].category[0] == 'C'
5574             && unicode_attributes[ch].category[1] == 'f')
5575            || (unicode_attributes[ch].category[0] == 'L'
5576                && (unicode_attributes[ch].category[1] == 'm'
5577                    || unicode_attributes[ch].category[1] == 'o'))
5578            || (unicode_attributes[ch].category[0] == 'M'
5579                && (unicode_attributes[ch].category[1] == 'c'
5580                    || unicode_attributes[ch].category[1] == 'n'))
5581            /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5582            || ch == 0x109E /* MYANMAR SYMBOL SHAN ONE */
5583            || ch == 0x109F /* MYANMAR SYMBOL SHAN EXCLAMATION */
5584            || ch == 0x19DE /* NEW TAI LUE SIGN LAE */
5585            || ch == 0x19DF /* NEW TAI LUE SIGN LAEV */)
5586           && ((ch >= 0x0E00 && ch <= 0x0EFF)
5587               || (ch >= 0x1000 && ch <= 0x109F)
5588               || (ch >= 0x1780 && ch <= 0x17FF)
5589               || (ch >= 0x1950 && ch <= 0x19DF)))
5590         attr |= 1 << LBP_SA;
5591
5592       /* attached characters and combining marks */
5593       if ((unicode_attributes[ch].category[0] == 'M'
5594            && (unicode_attributes[ch].category[1] == 'c'
5595                || unicode_attributes[ch].category[1] == 'e'
5596                || unicode_attributes[ch].category[1] == 'n'))
5597           || (unicode_attributes[ch].category[0] == 'C'
5598               && (unicode_attributes[ch].category[1] == 'c'
5599                   || unicode_attributes[ch].category[1] == 'f')))
5600         if (!(attr & ((1 << LBP_BK) | (1 << LBP_BA) | (1 << LBP_GL) | (1 << LBP_SA) | (1 << LBP_WJ) | (1 << LBP_ZW))))
5601           attr |= 1 << LBP_CM;
5602
5603       /* ideographic */
5604       if ((ch >= 0x2E80 && ch <= 0x2FFF) /* CJK RADICAL, KANGXI RADICAL, IDEOGRAPHIC DESCRIPTION */
5605           || ch == 0x3000 /* IDEOGRAPHIC SPACE */
5606           || (ch >= 0x3040 && ch <= 0x309F) /* HIRAGANA */
5607           || (ch >= 0x30A0 && ch <= 0x30FF) /* KATAKANA */
5608           || (ch >= 0x3400 && ch <= 0x4DB5) /* CJK Ideograph Extension A */
5609           || (ch >= 0x4E00 && ch <= 0x9FC3) /* CJK Ideograph */
5610           || (ch >= 0xF900 && ch <= 0xFAD9) /* CJK COMPATIBILITY IDEOGRAPH */
5611           || (ch >= 0xA000 && ch <= 0xA48F) /* YI SYLLABLE */
5612           || (ch >= 0xA490 && ch <= 0xA4CF) /* YI RADICAL */
5613           || ch == 0xFE62 /* SMALL PLUS SIGN */
5614           || ch == 0xFE63 /* SMALL HYPHEN-MINUS */
5615           || ch == 0xFE64 /* SMALL LESS-THAN SIGN */
5616           || ch == 0xFE65 /* SMALL GREATER-THAN SIGN */
5617           || ch == 0xFE66 /* SMALL EQUALS SIGN */
5618           || (ch >= 0xFF10 && ch <= 0xFF19) /* FULLWIDTH DIGIT */
5619           || (ch >= 0x20000 && ch <= 0x2A6D6) /* CJK Ideograph Extension B */
5620           || (ch >= 0x2F800 && ch <= 0x2FA1D) /* CJK COMPATIBILITY IDEOGRAPH */
5621           || strstr (unicode_attributes[ch].name, "FULLWIDTH LATIN ") != NULL
5622           || (ch >= 0x3000 && ch <= 0x33FF
5623               && !(attr & ((1 << LBP_CM) | (1 << LBP_NS) | (1 << LBP_OP) | (1 << LBP_CL))))
5624           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5625           || ch == 0xFE30 /* PRESENTATION FORM FOR VERTICAL TWO DOT LEADER */
5626           || ch == 0xFE31 /* PRESENTATION FORM FOR VERTICAL EM DASH */
5627           || ch == 0xFE32 /* PRESENTATION FORM FOR VERTICAL EN DASH */
5628           || ch == 0xFE33 /* PRESENTATION FORM FOR VERTICAL LOW LINE */
5629           || ch == 0xFE34 /* PRESENTATION FORM FOR VERTICAL WAVY LOW LINE */
5630           || ch == 0xFE45 /* SESAME DOT */
5631           || ch == 0xFE46 /* WHITE SESAME DOT */
5632           || ch == 0xFE49 /* DASHED OVERLINE */
5633           || ch == 0xFE4A /* CENTRELINE OVERLINE */
5634           || ch == 0xFE4B /* WAVY OVERLINE */
5635           || ch == 0xFE4C /* DOUBLE WAVY OVERLINE */
5636           || ch == 0xFE4D /* DASHED LOW LINE */
5637           || ch == 0xFE4E /* CENTRELINE LOW LINE */
5638           || ch == 0xFE4F /* WAVY LOW LINE */
5639           || ch == 0xFE51 /* SMALL IDEOGRAPHIC COMMA */
5640           || ch == 0xFE58 /* SMALL EM DASH */
5641           || ch == 0xFE5F /* SMALL NUMBER SIGN */
5642           || ch == 0xFE60 /* SMALL AMPERSAND */
5643           || ch == 0xFE61 /* SMALL ASTERISK */
5644           || ch == 0xFE68 /* SMALL REVERSE SOLIDUS */
5645           || ch == 0xFE6B /* SMALL COMMERCIAL AT */
5646           || ch == 0xFF02 /* FULLWIDTH QUOTATION MARK */
5647           || ch == 0xFF03 /* FULLWIDTH NUMBER SIGN */
5648           || ch == 0xFF06 /* FULLWIDTH AMPERSAND */
5649           || ch == 0xFF07 /* FULLWIDTH APOSTROPHE */
5650           || ch == 0xFF0A /* FULLWIDTH ASTERISK */
5651           || ch == 0xFF0B /* FULLWIDTH PLUS SIGN */
5652           || ch == 0xFF0D /* FULLWIDTH HYPHEN-MINUS */
5653           || ch == 0xFF0F /* FULLWIDTH SOLIDUS */
5654           || ch == 0xFF1C /* FULLWIDTH LESS-THAN SIGN */
5655           || ch == 0xFF1D /* FULLWIDTH EQUALS SIGN */
5656           || ch == 0xFF1E /* FULLWIDTH GREATER-THAN SIGN */
5657           || ch == 0xFF20 /* FULLWIDTH COMMERCIAL AT */
5658           || ch == 0xFF3C /* FULLWIDTH REVERSE SOLIDUS */
5659           || ch == 0xFF3E /* FULLWIDTH CIRCUMFLEX ACCENT */
5660           || ch == 0xFF3F /* FULLWIDTH LOW LINE */
5661           || ch == 0xFF40 /* FULLWIDTH GRAVE ACCENT */
5662           || ch == 0xFF5C /* FULLWIDTH VERTICAL LINE */
5663           || ch == 0xFF5E /* FULLWIDTH TILDE */
5664           || ch == 0xFFE2 /* FULLWIDTH NOT SIGN */
5665           || ch == 0xFFE3 /* FULLWIDTH MACRON */
5666           || ch == 0xFFE4 /* FULLWIDTH BROKEN BAR */)
5667         if (!(attr & ((1 << LBP_NS) | (1 << LBP_CM))))
5668           {
5669             /* ambiguous (ideograph) ? */
5670             if ((unicode_width[ch] != NULL
5671                  && unicode_width[ch][0] == 'A'
5672                  && ch >= 0x2000)
5673                 || ch == 0x24EA /* CIRCLED DIGIT ZERO */
5674                 || (ch >= 0x2780 && ch <= 0x2793) /* DINGBAT ... CIRCLED DIGIT ... */)
5675               attr |= 1 << LBP_AI;
5676             else
5677               attr |= 1 << LBP_ID;
5678           }
5679
5680       /* ordinary alphabetic and symbol characters */
5681       if ((unicode_attributes[ch].category[0] == 'L'
5682            && (unicode_attributes[ch].category[1] == 'u'
5683                || unicode_attributes[ch].category[1] == 'l'
5684                || unicode_attributes[ch].category[1] == 't'
5685                || unicode_attributes[ch].category[1] == 'm'
5686                || unicode_attributes[ch].category[1] == 'o'))
5687           || (unicode_attributes[ch].category[0] == 'S'
5688               && (unicode_attributes[ch].category[1] == 'm'
5689                   || unicode_attributes[ch].category[1] == 'k'
5690                   || unicode_attributes[ch].category[1] == 'o'))
5691           || (unicode_attributes[ch].category[0] == 'N'
5692               && (unicode_attributes[ch].category[1] == 'l'
5693                   || unicode_attributes[ch].category[1] == 'o'))
5694           || (unicode_attributes[ch].category[0] == 'P'
5695               && (unicode_attributes[ch].category[1] == 'c'
5696                   || unicode_attributes[ch].category[1] == 'd'
5697                   || unicode_attributes[ch].category[1] == 'o'))
5698           || ch == 0x0600 /* ARABIC NUMBER SIGN */
5699           || ch == 0x0601 /* ARABIC SIGN SANAH */
5700           || ch == 0x0602 /* ARABIC FOOTNOTE MARKER */
5701           || ch == 0x0603 /* ARABIC SIGN SAFHA */
5702           || ch == 0x06DD /* ARABIC END OF AYAH */
5703           || ch == 0x070F /* SYRIAC ABBREVIATION MARK */
5704           || ch == 0x2061 /* FUNCTION APPLICATION */
5705           || ch == 0x2062 /* INVISIBLE TIMES */
5706           || ch == 0x2063 /* INVISIBLE SEPARATOR */
5707           || ch == 0x2064 /* INVISIBLE PLUS */)
5708         if (!(attr & ((1 << LBP_GL) | (1 << LBP_B2) | (1 << LBP_BA) | (1 << LBP_BB) | (1 << LBP_HY) | (1 << LBP_CB) | (1 << LBP_CL) | (1 << LBP_EX) | (1 << LBP_IN) | (1 << LBP_NS) | (1 << LBP_OP) | (1 << LBP_QU) | (1 << LBP_IS) | (1 << LBP_NU) | (1 << LBP_PO) | (1 << LBP_PR) | (1 << LBP_SY) | (1 << LBP_H2) | (1 << LBP_H3) | (1 << LBP_JL) | (1 << LBP_JV) | (1 << LBP_JT) | (1 << LBP_SA) | (1 << LBP_ID))))
5709           {
5710             /* ambiguous (alphabetic) ? */
5711             if ((unicode_width[ch] != NULL
5712                  && unicode_width[ch][0] == 'A'
5713                  && ch >= 0x2000
5714                  /* Extra exceptions for compatibility with Unicode LineBreak.txt.  */
5715                  && ch != 0x2022 /* BULLET */
5716                  && ch != 0x203E /* OVERLINE */
5717                  && ch != 0x2126 /* OHM SIGN */
5718                  && ch != 0x2153 /* VULGAR FRACTION ONE THIRD */
5719                  && ch != 0x215C /* VULGAR FRACTION THREE EIGHTHS */
5720                  && ch != 0x215D /* VULGAR FRACTION FIVE EIGHTHS */
5721                  && ch != 0x21B8 /* NORTH WEST ARROW TO LONG BAR */
5722                  && ch != 0x21B9 /* LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR */
5723                  && ch != 0x21E7 /* UPWARDS WHITE ARROW */
5724                  && ch != 0x24FF /* NEGATIVE CIRCLED DIGIT ZERO */
5725                  && ch != 0x273D /* HEAVY TEARDROP-SPOKED ASTERISK */)
5726 #if !REVISION_22
5727                 || ch == 0x00A1 /* INVERTED EXCLAMATION MARK */
5728                 || ch == 0x00A7 /* SECTION SIGN */
5729                 || ch == 0x00A8 /* DIAERESIS */
5730                 || ch == 0x00AA /* FEMININE ORDINAL INDICATOR */
5731                 || ch == 0x00B2 /* SUPERSCRIPT TWO */
5732                 || ch == 0x00B3 /* SUPERSCRIPT THREE */
5733                 || ch == 0x00B6 /* PILCROW SIGN */
5734                 || ch == 0x00B7 /* MIDDLE DOT */
5735                 || ch == 0x00B8 /* CEDILLA */
5736                 || ch == 0x00B9 /* SUPERSCRIPT ONE */
5737                 || ch == 0x00BA /* MASCULINE ORDINAL INDICATOR */
5738                 || ch == 0x00BC /* VULGAR FRACTION ONE QUARTER */
5739                 || ch == 0x00BD /* VULGAR FRACTION ONE HALF */
5740                 || ch == 0x00BE /* VULGAR FRACTION THREE QUARTERS */
5741                 || ch == 0x00BF /* INVERTED QUESTION MARK */
5742                 || ch == 0x00D7 /* MULTIPLICATION SIGN */
5743                 || ch == 0x00F7 /* DIVISION SIGN */
5744                 || ch == 0x02C7 /* CARON */
5745                 || ch == 0x02C9 /* MODIFIER LETTER MACRON */
5746                 || ch == 0x02CA /* MODIFIER LETTER ACUTE ACCENT */
5747                 || ch == 0x02CB /* MODIFIER LETTER GRAVE ACCENT */
5748                 || ch == 0x02CD /* MODIFIER LETTER LOW MACRON */
5749                 || ch == 0x02D0 /* MODIFIER LETTER TRIANGULAR COLON */
5750                 || ch == 0x02D8 /* BREVE */
5751                 || ch == 0x02D9 /* DOT ABOVE */
5752                 || ch == 0x02DA /* RING ABOVE */
5753                 || ch == 0x02DB /* OGONEK */
5754                 || ch == 0x02DD /* DOUBLE ACUTE ACCENT */
5755 #endif
5756                 || ch == 0x24EA /* CIRCLED DIGIT ZERO */
5757                 || (ch >= 0x2780 && ch <= 0x2793) /* DINGBAT ... CIRCLED DIGIT ... */
5758                 /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5759                 || ch == 0x2155 /* VULGAR FRACTION ONE FIFTH */
5760                 || ch == 0x2574 /* BOX DRAWINGS LIGHT LEFT */
5761                 || ch == 0x2616 /* WHITE SHOGI PIECE */
5762                 || ch == 0x2617 /* BLACK SHOGI PIECE */)
5763               attr |= 1 << LBP_AI;
5764             else
5765               attr |= 1 << LBP_AL;
5766             attr &= ~(1 << LBP_CM);
5767           }
5768     }
5769
5770   if (attr == 0)
5771     /* unknown */
5772     attr |= 1 << LBP_XX;
5773
5774   return attr;
5775 }
5776
5777 /* Output the line breaking properties in a human readable format.  */
5778 static void
5779 debug_output_lbp (FILE *stream)
5780 {
5781   unsigned int i;
5782
5783   for (i = 0; i < 0x110000; i++)
5784     {
5785       int attr = get_lbp (i);
5786       if (attr != 1 << LBP_XX)
5787         {
5788           fprintf (stream, "0x%04X", i);
5789 #define PRINT_BIT(attr,bit) \
5790   if (attr & (1 << bit)) fprintf (stream, " " #bit);
5791           PRINT_BIT(attr,LBP_BK);
5792           PRINT_BIT(attr,LBP_CM);
5793           PRINT_BIT(attr,LBP_WJ);
5794           PRINT_BIT(attr,LBP_ZW);
5795           PRINT_BIT(attr,LBP_GL);
5796           PRINT_BIT(attr,LBP_SP);
5797           PRINT_BIT(attr,LBP_B2);
5798           PRINT_BIT(attr,LBP_BA);
5799           PRINT_BIT(attr,LBP_BB);
5800           PRINT_BIT(attr,LBP_HY);
5801           PRINT_BIT(attr,LBP_CB);
5802           PRINT_BIT(attr,LBP_CL);
5803           PRINT_BIT(attr,LBP_EX);
5804           PRINT_BIT(attr,LBP_IN);
5805           PRINT_BIT(attr,LBP_NS);
5806           PRINT_BIT(attr,LBP_OP);
5807           PRINT_BIT(attr,LBP_QU);
5808           PRINT_BIT(attr,LBP_IS);
5809           PRINT_BIT(attr,LBP_NU);
5810           PRINT_BIT(attr,LBP_PO);
5811           PRINT_BIT(attr,LBP_PR);
5812           PRINT_BIT(attr,LBP_SY);
5813           PRINT_BIT(attr,LBP_AI);
5814           PRINT_BIT(attr,LBP_AL);
5815           PRINT_BIT(attr,LBP_H2);
5816           PRINT_BIT(attr,LBP_H3);
5817           PRINT_BIT(attr,LBP_ID);
5818           PRINT_BIT(attr,LBP_JL);
5819           PRINT_BIT(attr,LBP_JV);
5820           PRINT_BIT(attr,LBP_JT);
5821           PRINT_BIT(attr,LBP_SA);
5822           PRINT_BIT(attr,LBP_XX);
5823 #undef PRINT_BIT
5824           fprintf (stream, "\n");
5825         }
5826     }
5827 }
5828
5829 static void
5830 debug_output_lbrk_tables (const char *filename)
5831 {
5832   FILE *stream;
5833
5834   stream = fopen (filename, "w");
5835   if (stream == NULL)
5836     {
5837       fprintf (stderr, "cannot open '%s' for writing\n", filename);
5838       exit (1);
5839     }
5840
5841   debug_output_lbp (stream);
5842
5843   if (ferror (stream) || fclose (stream))
5844     {
5845       fprintf (stderr, "error writing to '%s'\n", filename);
5846       exit (1);
5847     }
5848 }
5849
5850 /* The line breaking property from the LineBreak.txt file.  */
5851 int unicode_org_lbp[0x110000];
5852
5853 /* Stores in unicode_org_lbp[] the line breaking property from the
5854    LineBreak.txt file.  */
5855 static void
5856 fill_org_lbp (const char *linebreak_filename)
5857 {
5858   unsigned int i, j;
5859   FILE *stream;
5860   char field0[FIELDLEN];
5861   char field1[FIELDLEN];
5862   char field2[FIELDLEN];
5863   int lineno = 0;
5864
5865   for (i = 0; i < 0x110000; i++)
5866     unicode_org_lbp[i] = LBP_XX;
5867
5868   stream = fopen (linebreak_filename, "r");
5869   if (stream == NULL)
5870     {
5871       fprintf (stderr, "error during fopen of '%s'\n", linebreak_filename);
5872       exit (1);
5873     }
5874
5875   for (;;)
5876     {
5877       int n;
5878       int c;
5879       int value;
5880
5881       lineno++;
5882       c = getc (stream);
5883       if (c == EOF)
5884         break;
5885       if (c == '#')
5886         {
5887           do c = getc (stream); while (c != EOF && c != '\n');
5888           continue;
5889         }
5890       ungetc (c, stream);
5891       n = getfield (stream, field0, ';');
5892       n += getfield (stream, field1, ' ');
5893       n += getfield (stream, field2, '\n');
5894       if (n == 0)
5895         break;
5896       if (n != 3)
5897         {
5898           fprintf (stderr, "short line in '%s':%d\n", linebreak_filename,
5899                    lineno);
5900           exit (1);
5901         }
5902 #define TRY(bit) else if (strcmp (field1, #bit + 4) == 0) value = bit;
5903       if (false) {}
5904       TRY(LBP_BK)
5905       TRY(LBP_CM)
5906       TRY(LBP_WJ)
5907       TRY(LBP_ZW)
5908       TRY(LBP_GL)
5909       TRY(LBP_SP)
5910       TRY(LBP_B2)
5911       TRY(LBP_BA)
5912       TRY(LBP_BB)
5913       TRY(LBP_HY)
5914       TRY(LBP_CB)
5915       TRY(LBP_CL)
5916       TRY(LBP_EX)
5917       TRY(LBP_IN)
5918       TRY(LBP_NS)
5919       TRY(LBP_OP)
5920       TRY(LBP_QU)
5921       TRY(LBP_IS)
5922       TRY(LBP_NU)
5923       TRY(LBP_PO)
5924       TRY(LBP_PR)
5925       TRY(LBP_SY)
5926       TRY(LBP_AI)
5927       TRY(LBP_AL)
5928       TRY(LBP_H2)
5929       TRY(LBP_H3)
5930       TRY(LBP_ID)
5931       TRY(LBP_JL)
5932       TRY(LBP_JV)
5933       TRY(LBP_JT)
5934       TRY(LBP_SA)
5935       TRY(LBP_XX)
5936 #undef TRY
5937       else if (strcmp (field1, "LF") == 0) value = LBP_BK;
5938       else if (strcmp (field1, "CR") == 0) value = LBP_BK;
5939       else if (strcmp (field1, "NL") == 0) value = LBP_BK;
5940       else if (strcmp (field1, "SG") == 0) value = LBP_XX;
5941       else
5942         {
5943           fprintf (stderr, "unknown property value \"%s\" in '%s':%d\n",
5944                    field1, linebreak_filename, lineno);
5945           exit (1);
5946         }
5947       i = strtoul (field0, NULL, 16);
5948       if (strstr (field0, "..") != NULL)
5949         {
5950           /* Deal with a range.  */
5951           j = strtoul (strstr (field0, "..") + 2, NULL, 16);
5952           for (; i <= j; i++)
5953             unicode_org_lbp[i] = value;
5954         }
5955       else
5956         {
5957           /* Single character line.  */
5958           unicode_org_lbp[i] = value;
5959         }
5960     }
5961   if (ferror (stream) || fclose (stream))
5962     {
5963       fprintf (stderr, "error reading from '%s'\n", linebreak_filename);
5964       exit (1);
5965     }
5966 }
5967
5968 /* Output the line breaking properties in a human readable format.  */
5969 static void
5970 debug_output_org_lbp (FILE *stream)
5971 {
5972   unsigned int i;
5973
5974   for (i = 0; i < 0x110000; i++)
5975     {
5976       int attr = unicode_org_lbp[i];
5977       if (attr != LBP_XX)
5978         {
5979           fprintf (stream, "0x%04X", i);
5980 #define PRINT_BIT(attr,bit) \
5981   if (attr == bit) fprintf (stream, " " #bit);
5982           PRINT_BIT(attr,LBP_BK);
5983           PRINT_BIT(attr,LBP_CM);
5984           PRINT_BIT(attr,LBP_WJ);
5985           PRINT_BIT(attr,LBP_ZW);
5986           PRINT_BIT(attr,LBP_GL);
5987           PRINT_BIT(attr,LBP_SP);
5988           PRINT_BIT(attr,LBP_B2);
5989           PRINT_BIT(attr,LBP_BA);
5990           PRINT_BIT(attr,LBP_BB);
5991           PRINT_BIT(attr,LBP_HY);
5992           PRINT_BIT(attr,LBP_CB);
5993           PRINT_BIT(attr,LBP_CL);
5994           PRINT_BIT(attr,LBP_EX);
5995           PRINT_BIT(attr,LBP_IN);
5996           PRINT_BIT(attr,LBP_NS);
5997           PRINT_BIT(attr,LBP_OP);
5998           PRINT_BIT(attr,LBP_QU);
5999           PRINT_BIT(attr,LBP_IS);
6000           PRINT_BIT(attr,LBP_NU);
6001           PRINT_BIT(attr,LBP_PO);
6002           PRINT_BIT(attr,LBP_PR);
6003           PRINT_BIT(attr,LBP_SY);
6004           PRINT_BIT(attr,LBP_AI);
6005           PRINT_BIT(attr,LBP_AL);
6006           PRINT_BIT(attr,LBP_H2);
6007           PRINT_BIT(attr,LBP_H3);
6008           PRINT_BIT(attr,LBP_ID);
6009           PRINT_BIT(attr,LBP_JL);
6010           PRINT_BIT(attr,LBP_JV);
6011           PRINT_BIT(attr,LBP_JT);
6012           PRINT_BIT(attr,LBP_SA);
6013           PRINT_BIT(attr,LBP_XX);
6014 #undef PRINT_BIT
6015           fprintf (stream, "\n");
6016         }
6017     }
6018 }
6019
6020 static void
6021 debug_output_org_lbrk_tables (const char *filename)
6022 {
6023   FILE *stream;
6024
6025   stream = fopen (filename, "w");
6026   if (stream == NULL)
6027     {
6028       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6029       exit (1);
6030     }
6031
6032   debug_output_org_lbp (stream);
6033
6034   if (ferror (stream) || fclose (stream))
6035     {
6036       fprintf (stderr, "error writing to '%s'\n", filename);
6037       exit (1);
6038     }
6039 }
6040
6041 /* Construction of sparse 3-level tables.  */
6042 #define TABLE lbp_table
6043 #define ELEMENT unsigned char
6044 #define DEFAULT LBP_XX
6045 #define xmalloc malloc
6046 #define xrealloc realloc
6047 #include "3level.h"
6048
6049 static void
6050 output_lbp (FILE *stream1, FILE *stream2)
6051 {
6052   unsigned int i;
6053   struct lbp_table t;
6054   unsigned int level1_offset, level2_offset, level3_offset;
6055
6056   t.p = 7;
6057   t.q = 9;
6058   lbp_table_init (&t);
6059
6060   for (i = 0; i < 0x110000; i++)
6061     {
6062       int attr = get_lbp (i);
6063
6064       /* Now attr should contain exactly one bit.  */
6065       if (attr == 0 || ((attr & (attr - 1)) != 0))
6066         abort ();
6067
6068       if (attr != 1 << LBP_XX)
6069         {
6070           unsigned int log2_attr;
6071           for (log2_attr = 0; attr > 1; attr >>= 1, log2_attr++);
6072
6073           lbp_table_add (&t, i, log2_attr);
6074         }
6075     }
6076
6077   lbp_table_finalize (&t);
6078
6079   level1_offset =
6080     5 * sizeof (uint32_t);
6081   level2_offset =
6082     5 * sizeof (uint32_t)
6083     + t.level1_size * sizeof (uint32_t);
6084   level3_offset =
6085     5 * sizeof (uint32_t)
6086     + t.level1_size * sizeof (uint32_t)
6087     + (t.level2_size << t.q) * sizeof (uint32_t);
6088
6089   for (i = 0; i < 5; i++)
6090     fprintf (stream1, "#define lbrkprop_header_%d %d\n", i,
6091              ((uint32_t *) t.result)[i]);
6092   fprintf (stream1, "\n");
6093   fprintf (stream1, "typedef struct\n");
6094   fprintf (stream1, "  {\n");
6095   fprintf (stream1, "    int level1[%zu];\n", t.level1_size);
6096   fprintf (stream1, "    int level2[%zu << %d];\n", t.level2_size, t.q);
6097   fprintf (stream1, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
6098   fprintf (stream1, "  }\n");
6099   fprintf (stream1, "lbrkprop_t;\n");
6100   fprintf (stream1, "extern const lbrkprop_t unilbrkprop;\n");
6101
6102   fprintf (stream2, "const lbrkprop_t unilbrkprop =\n");
6103   fprintf (stream2, "{\n");
6104   fprintf (stream2, "  {");
6105   if (t.level1_size > 8)
6106     fprintf (stream2, "\n   ");
6107   for (i = 0; i < t.level1_size; i++)
6108     {
6109       uint32_t offset;
6110       if (i > 0 && (i % 8) == 0)
6111         fprintf (stream2, "\n   ");
6112       offset = ((uint32_t *) (t.result + level1_offset))[i];
6113       if (offset == 0)
6114         fprintf (stream2, " %5d", -1);
6115       else
6116         fprintf (stream2, " %5zu",
6117                  (offset - level2_offset) / sizeof (uint32_t));
6118       if (i+1 < t.level1_size)
6119         fprintf (stream2, ",");
6120     }
6121   if (t.level1_size > 8)
6122     fprintf (stream2, "\n ");
6123   fprintf (stream2, " },\n");
6124   fprintf (stream2, "  {");
6125   if (t.level2_size << t.q > 8)
6126     fprintf (stream2, "\n   ");
6127   for (i = 0; i < t.level2_size << t.q; i++)
6128     {
6129       uint32_t offset;
6130       if (i > 0 && (i % 8) == 0)
6131         fprintf (stream2, "\n   ");
6132       offset = ((uint32_t *) (t.result + level2_offset))[i];
6133       if (offset == 0)
6134         fprintf (stream2, " %5d", -1);
6135       else
6136         fprintf (stream2, " %5zu",
6137                  (offset - level3_offset) / sizeof (unsigned char));
6138       if (i+1 < t.level2_size << t.q)
6139         fprintf (stream2, ",");
6140     }
6141   if (t.level2_size << t.q > 8)
6142     fprintf (stream2, "\n ");
6143   fprintf (stream2, " },\n");
6144   fprintf (stream2, "  {");
6145   if (t.level3_size << t.p > 8)
6146     fprintf (stream2, "\n   ");
6147   for (i = 0; i < t.level3_size << t.p; i++)
6148     {
6149       unsigned char value = ((unsigned char *) (t.result + level3_offset))[i];
6150       const char *value_string;
6151       switch (value)
6152         {
6153 #define CASE(x) case x: value_string = #x; break;
6154           CASE(LBP_BK);
6155           CASE(LBP_CM);
6156           CASE(LBP_WJ);
6157           CASE(LBP_ZW);
6158           CASE(LBP_GL);
6159           CASE(LBP_SP);
6160           CASE(LBP_B2);
6161           CASE(LBP_BA);
6162           CASE(LBP_BB);
6163           CASE(LBP_HY);
6164           CASE(LBP_CB);
6165           CASE(LBP_CL);
6166           CASE(LBP_EX);
6167           CASE(LBP_IN);
6168           CASE(LBP_NS);
6169           CASE(LBP_OP);
6170           CASE(LBP_QU);
6171           CASE(LBP_IS);
6172           CASE(LBP_NU);
6173           CASE(LBP_PO);
6174           CASE(LBP_PR);
6175           CASE(LBP_SY);
6176           CASE(LBP_AI);
6177           CASE(LBP_AL);
6178           CASE(LBP_H2);
6179           CASE(LBP_H3);
6180           CASE(LBP_ID);
6181           CASE(LBP_JL);
6182           CASE(LBP_JV);
6183           CASE(LBP_JT);
6184           CASE(LBP_SA);
6185           CASE(LBP_XX);
6186 #undef CASE
6187           default:
6188             abort ();
6189         }
6190       if (i > 0 && (i % 8) == 0)
6191         fprintf (stream2, "\n   ");
6192       fprintf (stream2, " %s%s", value_string,
6193                (i+1 < t.level3_size << t.p ? "," : ""));
6194     }
6195   if (t.level3_size << t.p > 8)
6196     fprintf (stream2, "\n ");
6197   fprintf (stream2, " }\n");
6198   fprintf (stream2, "};\n");
6199 }
6200
6201 static void
6202 output_lbrk_tables (const char *filename1, const char *filename2, const char *version)
6203 {
6204   const char *filenames[2];
6205   FILE *streams[2];
6206   size_t i;
6207
6208   filenames[0] = filename1;
6209   filenames[1] = filename2;
6210
6211   for (i = 0; i < 2; i++)
6212     {
6213       streams[i] = fopen (filenames[i], "w");
6214       if (streams[i] == NULL)
6215         {
6216           fprintf (stderr, "cannot open '%s' for writing\n", filenames[i]);
6217           exit (1);
6218         }
6219     }
6220
6221   for (i = 0; i < 2; i++)
6222     {
6223       FILE *stream = streams[i];
6224
6225       fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
6226       fprintf (stream, "/* Line breaking properties of Unicode characters.  */\n");
6227       fprintf (stream, "/* Generated automatically by gen-lbrk for Unicode %s.  */\n",
6228                version);
6229       fprintf (stream, "\n");
6230
6231       /* Put a GPL header on it.  The gnulib module is under LGPL (although it
6232          still carries the GPL header), and it's gnulib-tool which replaces the
6233          GPL header with an LGPL header.  */
6234       fprintf (stream, "/* Copyright (C) 2000-2002, 2004, 2008 Free Software Foundation, Inc.\n");
6235       fprintf (stream, "\n");
6236       fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
6237       fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
6238       fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
6239       fprintf (stream, "   (at your option) any later version.\n");
6240       fprintf (stream, "\n");
6241       fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
6242       fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
6243       fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
6244       fprintf (stream, "   GNU General Public License for more details.\n");
6245       fprintf (stream, "\n");
6246       fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
6247       fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
6248       fprintf (stream, "\n");
6249     }
6250
6251   output_lbp (streams[0], streams[1]);
6252
6253   for (i = 0; i < 2; i++)
6254     {
6255       if (ferror (streams[i]) || fclose (streams[i]))
6256         {
6257           fprintf (stderr, "error writing to '%s'\n", filenames[i]);
6258           exit (1);
6259         }
6260     }
6261 }
6262
6263 /* ========================================================================= */
6264
6265 /* Word break property.  */
6266
6267 /* Possible values of the Word_Break property.  */
6268 enum
6269 {
6270   WBP_OTHER        = 0,
6271   WBP_CR           = 11,
6272   WBP_LF           = 12,
6273   WBP_NEWLINE      = 10,
6274   WBP_EXTEND       = 8,
6275   WBP_FORMAT       = 9,
6276   WBP_KATAKANA     = 1,
6277   WBP_ALETTER      = 2,
6278   WBP_MIDNUMLET    = 3,
6279   WBP_MIDLETTER    = 4,
6280   WBP_MIDNUM       = 5,
6281   WBP_NUMERIC      = 6,
6282   WBP_EXTENDNUMLET = 7
6283 };
6284
6285 /* Returns the word breaking property for ch, as a bit mask.  */
6286 static int
6287 get_wbp (unsigned int ch)
6288 {
6289   int attr = 0;
6290
6291   if (unicode_attributes[ch].name != NULL)
6292     {
6293       if (ch == 0x000D)
6294         attr |= 1 << WBP_CR;
6295
6296       if (ch == 0x000A)
6297         attr |= 1 << WBP_LF;
6298
6299       if (ch == 0x000B || ch == 0x000C
6300           || ch == 0x0085
6301           || ch == 0x2028 || ch == 0x2029)
6302         attr |= 1 << WBP_NEWLINE;
6303
6304       if (((unicode_properties[ch] >> PROP_GRAPHEME_EXTEND) & 1) != 0
6305           || (unicode_attributes[ch].category != NULL
6306               && strcmp (unicode_attributes[ch].category, "Mc") == 0))
6307         attr |= 1 << WBP_EXTEND;
6308
6309       if (unicode_attributes[ch].category != NULL
6310           && strcmp (unicode_attributes[ch].category, "Cf") == 0
6311           && ch != 0x200C && ch != 0x200D)
6312         attr |= 1 << WBP_FORMAT;
6313
6314       if ((unicode_scripts[ch] < numscripts
6315            && strcmp (scripts[unicode_scripts[ch]], "Katakana") == 0)
6316           || (ch >= 0x3031 && ch <= 0x3035)
6317           || ch == 0x309B || ch == 0x309C || ch == 0x30A0 || ch == 0x30FC
6318           || ch == 0xFF70)
6319         attr |= 1 << WBP_KATAKANA;
6320
6321       if ((((unicode_properties[ch] >> PROP_ALPHABETIC) & 1) != 0
6322            || ch == 0x05F3)
6323           && ((unicode_properties[ch] >> PROP_IDEOGRAPHIC) & 1) == 0
6324           && (attr & (1 << WBP_KATAKANA)) == 0
6325           && ((get_lbp (ch) >> LBP_SA) & 1) == 0
6326           && !(unicode_scripts[ch] < numscripts
6327                && strcmp (scripts[unicode_scripts[ch]], "Hiragana") == 0)
6328           && (attr & (1 << WBP_EXTEND)) == 0)
6329         attr |= 1 << WBP_ALETTER;
6330
6331       if (ch == 0x0027 || ch == 0x002E || ch == 0x2018 || ch == 0x2019
6332           || ch == 0x2024 || ch == 0xFE52 || ch == 0xFF07 || ch == 0xFF0E)
6333         attr |= 1 << WBP_MIDNUMLET;
6334
6335       if (ch == 0x00B7 || ch == 0x05F4 || ch == 0x2027 || ch == 0x003A
6336           || ch == 0x0387 || ch == 0xFE13 || ch == 0xFE55 || ch == 0xFF1A)
6337         attr |= 1 << WBP_MIDLETTER;
6338
6339       if ((((get_lbp (ch) >> LBP_IS) & 1) != 0
6340            || ch == 0x066C || ch == 0xFE50 || ch == 0xFE54 || ch == 0xFF0C
6341            || ch == 0xFF1B)
6342           && ch != 0x003A && ch != 0xFE13 && ch != 0x002E)
6343         attr |= 1 << WBP_MIDNUM;
6344
6345       if (((get_lbp (ch) >> LBP_NU) & 1) != 0
6346           && ch != 0x066C)
6347         attr |= 1 << WBP_NUMERIC;
6348
6349       if (unicode_attributes[ch].category != NULL
6350           && strcmp (unicode_attributes[ch].category, "Pc") == 0)
6351         attr |= 1 << WBP_EXTENDNUMLET;
6352     }
6353
6354   if (attr == 0)
6355     /* other */
6356     attr |= 1 << WBP_OTHER;
6357
6358   return attr;
6359 }
6360
6361 /* Output the word break property in a human readable format.  */
6362 static void
6363 debug_output_wbp (FILE *stream)
6364 {
6365   unsigned int i;
6366
6367   for (i = 0; i < 0x110000; i++)
6368     {
6369       int attr = get_wbp (i);
6370       if (attr != 1 << WBP_OTHER)
6371         {
6372           fprintf (stream, "0x%04X", i);
6373           if (attr & (1 << WBP_CR))
6374             fprintf (stream, " CR");
6375           if (attr & (1 << WBP_LF))
6376             fprintf (stream, " LF");
6377           if (attr & (1 << WBP_NEWLINE))
6378             fprintf (stream, " Newline");
6379           if (attr & (1 << WBP_EXTEND))
6380             fprintf (stream, " Extend");
6381           if (attr & (1 << WBP_FORMAT))
6382             fprintf (stream, " Format");
6383           if (attr & (1 << WBP_KATAKANA))
6384             fprintf (stream, " Katakana");
6385           if (attr & (1 << WBP_ALETTER))
6386             fprintf (stream, " ALetter");
6387           if (attr & (1 << WBP_MIDNUMLET))
6388             fprintf (stream, " MidNumLet");
6389           if (attr & (1 << WBP_MIDLETTER))
6390             fprintf (stream, " MidLetter");
6391           if (attr & (1 << WBP_MIDNUM))
6392             fprintf (stream, " MidNum");
6393           if (attr & (1 << WBP_NUMERIC))
6394             fprintf (stream, " Numeric");
6395           if (attr & (1 << WBP_EXTENDNUMLET))
6396             fprintf (stream, " ExtendNumLet");
6397           fprintf (stream, "\n");
6398         }
6399     }
6400 }
6401
6402 static void
6403 debug_output_wbrk_tables (const char *filename)
6404 {
6405   FILE *stream;
6406
6407   stream = fopen (filename, "w");
6408   if (stream == NULL)
6409     {
6410       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6411       exit (1);
6412     }
6413
6414   debug_output_wbp (stream);
6415
6416   if (ferror (stream) || fclose (stream))
6417     {
6418       fprintf (stderr, "error writing to '%s'\n", filename);
6419       exit (1);
6420     }
6421 }
6422
6423 /* The word break property from the WordBreakProperty.txt file.  */
6424 int unicode_org_wbp[0x110000];
6425
6426 /* Stores in unicode_org_wbp[] the word break property from the
6427    WordBreakProperty.txt file.  */
6428 static void
6429 fill_org_wbp (const char *wordbreakproperty_filename)
6430 {
6431   unsigned int i;
6432   FILE *stream;
6433
6434   for (i = 0; i < 0x110000; i++)
6435     unicode_org_wbp[i] = WBP_OTHER;
6436
6437   stream = fopen (wordbreakproperty_filename, "r");
6438   if (stream == NULL)
6439     {
6440       fprintf (stderr, "error during fopen of '%s'\n", wordbreakproperty_filename);
6441       exit (1);
6442     }
6443
6444   for (;;)
6445     {
6446       char buf[200+1];
6447       unsigned int i1, i2;
6448       char padding[200+1];
6449       char propname[200+1];
6450       int propvalue;
6451
6452       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
6453         break;
6454
6455       if (buf[0] == '\0' || buf[0] == '#')
6456         continue;
6457
6458       if (sscanf (buf, "%X..%X%[ ;]%[^ ]", &i1, &i2, padding, propname) != 4)
6459         {
6460           if (sscanf (buf, "%X%[ ;]%[^ ]", &i1, padding, propname) != 3)
6461             {
6462               fprintf (stderr, "parse error in '%s'\n",
6463                        wordbreakproperty_filename);
6464               exit (1);
6465             }
6466           i2 = i1;
6467         }
6468 #define PROP(name,value) \
6469       if (strcmp (propname, name) == 0) propvalue = value; else
6470       PROP ("CR", WBP_CR)
6471       PROP ("LF", WBP_LF)
6472       PROP ("Newline", WBP_NEWLINE)
6473       PROP ("Extend", WBP_EXTEND)
6474       PROP ("Format", WBP_FORMAT)
6475       PROP ("Katakana", WBP_KATAKANA)
6476       PROP ("ALetter", WBP_ALETTER)
6477       PROP ("MidNumLet", WBP_MIDNUMLET)
6478       PROP ("MidLetter", WBP_MIDLETTER)
6479       PROP ("MidNum", WBP_MIDNUM)
6480       PROP ("Numeric", WBP_NUMERIC)
6481       PROP ("ExtendNumLet", WBP_EXTENDNUMLET)
6482 #undef PROP
6483         {
6484           fprintf (stderr, "unknown property value '%s' in '%s'\n", propname,
6485                    wordbreakproperty_filename);
6486           exit (1);
6487         }
6488       if (!(i1 <= i2 && i2 < 0x110000))
6489         abort ();
6490
6491       for (i = i1; i <= i2; i++)
6492         unicode_org_wbp[i] = propvalue;
6493     }
6494
6495   if (ferror (stream) || fclose (stream))
6496     {
6497       fprintf (stderr, "error reading from '%s'\n", wordbreakproperty_filename);
6498       exit (1);
6499     }
6500 }
6501
6502 /* Output the word break property in a human readable format.  */
6503 static void
6504 debug_output_org_wbp (FILE *stream)
6505 {
6506   unsigned int i;
6507
6508   for (i = 0; i < 0x110000; i++)
6509     {
6510       int propvalue = unicode_org_wbp[i];
6511       if (propvalue != WBP_OTHER)
6512         {
6513           fprintf (stream, "0x%04X", i);
6514 #define PROP(name,value) \
6515           if (propvalue == value) fprintf (stream, " " name); else
6516           PROP ("CR", WBP_CR)
6517           PROP ("LF", WBP_LF)
6518           PROP ("Newline", WBP_NEWLINE)
6519           PROP ("Extend", WBP_EXTEND)
6520           PROP ("Format", WBP_FORMAT)
6521           PROP ("Katakana", WBP_KATAKANA)
6522           PROP ("ALetter", WBP_ALETTER)
6523           PROP ("MidNumLet", WBP_MIDNUMLET)
6524           PROP ("MidLetter", WBP_MIDLETTER)
6525           PROP ("MidNum", WBP_MIDNUM)
6526           PROP ("Numeric", WBP_NUMERIC)
6527           PROP ("ExtendNumLet", WBP_EXTENDNUMLET)
6528 #undef PROP
6529           fprintf (stream, " ??");
6530           fprintf (stream, "\n");
6531         }
6532     }
6533 }
6534
6535 static void
6536 debug_output_org_wbrk_tables (const char *filename)
6537 {
6538   FILE *stream;
6539
6540   stream = fopen (filename, "w");
6541   if (stream == NULL)
6542     {
6543       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6544       exit (1);
6545     }
6546
6547   debug_output_org_wbp (stream);
6548
6549   if (ferror (stream) || fclose (stream))
6550     {
6551       fprintf (stderr, "error writing to '%s'\n", filename);
6552       exit (1);
6553     }
6554 }
6555
6556 /* Construction of sparse 3-level tables.  */
6557 #define TABLE wbp_table
6558 #define ELEMENT unsigned char
6559 #define DEFAULT WBP_OTHER
6560 #define xmalloc malloc
6561 #define xrealloc realloc
6562 #include "3level.h"
6563
6564 static void
6565 output_wbp (FILE *stream)
6566 {
6567   unsigned int i;
6568   struct wbp_table t;
6569   unsigned int level1_offset, level2_offset, level3_offset;
6570
6571   t.p = 7;
6572   t.q = 9;
6573   wbp_table_init (&t);
6574
6575   for (i = 0; i < 0x110000; i++)
6576     {
6577       int attr = get_wbp (i);
6578
6579       /* Now attr should contain exactly one bit.  */
6580       if (attr == 0 || ((attr & (attr - 1)) != 0))
6581         abort ();
6582
6583       if (attr != 1 << WBP_OTHER)
6584         {
6585           unsigned int log2_attr;
6586           for (log2_attr = 0; attr > 1; attr >>= 1, log2_attr++);
6587
6588           wbp_table_add (&t, i, log2_attr);
6589         }
6590     }
6591
6592   wbp_table_finalize (&t);
6593
6594   level1_offset =
6595     5 * sizeof (uint32_t);
6596   level2_offset =
6597     5 * sizeof (uint32_t)
6598     + t.level1_size * sizeof (uint32_t);
6599   level3_offset =
6600     5 * sizeof (uint32_t)
6601     + t.level1_size * sizeof (uint32_t)
6602     + (t.level2_size << t.q) * sizeof (uint32_t);
6603
6604   for (i = 0; i < 5; i++)
6605     fprintf (stream, "#define wbrkprop_header_%d %d\n", i,
6606              ((uint32_t *) t.result)[i]);
6607   fprintf (stream, "\n");
6608   fprintf (stream, "typedef struct\n");
6609   fprintf (stream, "  {\n");
6610   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
6611   fprintf (stream, "    int level2[%zu << %d];\n", t.level2_size, t.q);
6612   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
6613   fprintf (stream, "  }\n");
6614   fprintf (stream, "wbrkprop_t;\n");
6615   fprintf (stream, "static const wbrkprop_t uniwbrkprop =\n");
6616   fprintf (stream, "{\n");
6617   fprintf (stream, "  {");
6618   if (t.level1_size > 8)
6619     fprintf (stream, "\n   ");
6620   for (i = 0; i < t.level1_size; i++)
6621     {
6622       uint32_t offset;
6623       if (i > 0 && (i % 8) == 0)
6624         fprintf (stream, "\n   ");
6625       offset = ((uint32_t *) (t.result + level1_offset))[i];
6626       if (offset == 0)
6627         fprintf (stream, " %5d", -1);
6628       else
6629         fprintf (stream, " %5zu",
6630                  (offset - level2_offset) / sizeof (uint32_t));
6631       if (i+1 < t.level1_size)
6632         fprintf (stream, ",");
6633     }
6634   if (t.level1_size > 8)
6635     fprintf (stream, "\n ");
6636   fprintf (stream, " },\n");
6637   fprintf (stream, "  {");
6638   if (t.level2_size << t.q > 8)
6639     fprintf (stream, "\n   ");
6640   for (i = 0; i < t.level2_size << t.q; i++)
6641     {
6642       uint32_t offset;
6643       if (i > 0 && (i % 8) == 0)
6644         fprintf (stream, "\n   ");
6645       offset = ((uint32_t *) (t.result + level2_offset))[i];
6646       if (offset == 0)
6647         fprintf (stream, " %5d", -1);
6648       else
6649         fprintf (stream, " %5zu",
6650                  (offset - level3_offset) / sizeof (unsigned char));
6651       if (i+1 < t.level2_size << t.q)
6652         fprintf (stream, ",");
6653     }
6654   if (t.level2_size << t.q > 8)
6655     fprintf (stream, "\n ");
6656   fprintf (stream, " },\n");
6657   fprintf (stream, "  {");
6658   if (t.level3_size << t.p > 4)
6659     fprintf (stream, "\n   ");
6660   for (i = 0; i < t.level3_size << t.p; i++)
6661     {
6662       unsigned char value = ((unsigned char *) (t.result + level3_offset))[i];
6663       const char *value_string;
6664       switch (value)
6665         {
6666 #define CASE(x) case x: value_string = #x; break;
6667           CASE(WBP_OTHER);
6668           CASE(WBP_CR);
6669           CASE(WBP_LF);
6670           CASE(WBP_NEWLINE);
6671           CASE(WBP_EXTEND);
6672           CASE(WBP_FORMAT);
6673           CASE(WBP_KATAKANA);
6674           CASE(WBP_ALETTER);
6675           CASE(WBP_MIDNUMLET);
6676           CASE(WBP_MIDLETTER);
6677           CASE(WBP_MIDNUM);
6678           CASE(WBP_NUMERIC);
6679           CASE(WBP_EXTENDNUMLET);
6680 #undef CASE
6681           default:
6682             abort ();
6683         }
6684       if (i > 0 && (i % 4) == 0)
6685         fprintf (stream, "\n   ");
6686       fprintf (stream, " %s%s", value_string,
6687                (i+1 < t.level3_size << t.p ? "," : ""));
6688     }
6689   if (t.level3_size << t.p > 4)
6690     fprintf (stream, "\n ");
6691   fprintf (stream, " }\n");
6692   fprintf (stream, "};\n");
6693 }
6694
6695 static void
6696 output_wbrk_tables (const char *filename, const char *version)
6697 {
6698   FILE *stream;
6699
6700   stream = fopen (filename, "w");
6701   if (stream == NULL)
6702     {
6703       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6704       exit (1);
6705     }
6706
6707   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
6708   fprintf (stream, "/* Line breaking properties of Unicode characters.  */\n");
6709   fprintf (stream, "/* Generated automatically by gen-uni-tables for Unicode %s.  */\n",
6710            version);
6711   fprintf (stream, "\n");
6712
6713   /* Put a GPL header on it.  The gnulib module is under LGPL (although it
6714      still carries the GPL header), and it's gnulib-tool which replaces the
6715      GPL header with an LGPL header.  */
6716   fprintf (stream, "/* Copyright (C) 2000-2002, 2004, 2007-2009 Free Software Foundation, Inc.\n");
6717   fprintf (stream, "\n");
6718   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
6719   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
6720   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
6721   fprintf (stream, "   (at your option) any later version.\n");
6722   fprintf (stream, "\n");
6723   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
6724   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
6725   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
6726   fprintf (stream, "   GNU General Public License for more details.\n");
6727   fprintf (stream, "\n");
6728   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
6729   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
6730   fprintf (stream, "\n");
6731
6732   output_wbp (stream);
6733
6734   if (ferror (stream) || fclose (stream))
6735     {
6736       fprintf (stderr, "error writing to '%s'\n", filename);
6737       exit (1);
6738     }
6739 }
6740
6741 /* ========================================================================= */
6742
6743 /* Output the test for a simple character mapping table to the given file.  */
6744
6745 static void
6746 output_simple_mapping_test (const char *filename,
6747                             const char *function_name,
6748                             unsigned int (*func) (unsigned int),
6749                             const char *version)
6750 {
6751   FILE *stream;
6752   bool need_comma;
6753   unsigned int ch;
6754
6755   stream = fopen (filename, "w");
6756   if (stream == NULL)
6757     {
6758       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6759       exit (1);
6760     }
6761
6762   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
6763   fprintf (stream, "/* Test the Unicode character mapping functions.\n");
6764   fprintf (stream, "   Copyright (C) 2009 Free Software Foundation, Inc.\n");
6765   fprintf (stream, "\n");
6766   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
6767   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
6768   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
6769   fprintf (stream, "   (at your option) any later version.\n");
6770   fprintf (stream, "\n");
6771   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
6772   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
6773   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
6774   fprintf (stream, "   GNU General Public License for more details.\n");
6775   fprintf (stream, "\n");
6776   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
6777   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
6778   fprintf (stream, "\n");
6779   fprintf (stream, "/* Generated automatically by gen-case.c for Unicode %s.  */\n",
6780            version);
6781   fprintf (stream, "\n");
6782   fprintf (stream, "#include \"test-mapping-part1.h\"\n");
6783   fprintf (stream, "\n");
6784
6785   need_comma = false;
6786   for (ch = 0; ch < 0x110000; ch++)
6787     {
6788       unsigned int value = func (ch);
6789
6790       if (value != ch)
6791         {
6792           if (need_comma)
6793             fprintf (stream, ",\n");
6794           fprintf (stream, "    { 0x%04X, 0x%04X }", ch, value);
6795           need_comma = true;
6796         }
6797     }
6798   if (need_comma)
6799     fprintf (stream, "\n");
6800
6801   fprintf (stream, "\n");
6802   fprintf (stream, "#define MAP(c) %s (c)\n", function_name);
6803   fprintf (stream, "#include \"test-mapping-part2.h\"\n");
6804
6805   if (ferror (stream) || fclose (stream))
6806     {
6807       fprintf (stderr, "error writing to '%s'\n", filename);
6808       exit (1);
6809     }
6810 }
6811
6812 /* Construction of sparse 3-level tables.  */
6813 #define TABLE mapping_table
6814 #define ELEMENT int32_t
6815 #define DEFAULT 0
6816 #define xmalloc malloc
6817 #define xrealloc realloc
6818 #include "3level.h"
6819
6820 /* Output a simple character mapping table to the given file.  */
6821
6822 static void
6823 output_simple_mapping (const char *filename,
6824                        unsigned int (*func) (unsigned int),
6825                        const char *version)
6826 {
6827   FILE *stream;
6828   unsigned int ch, i;
6829   struct mapping_table t;
6830   unsigned int level1_offset, level2_offset, level3_offset;
6831
6832   stream = fopen (filename, "w");
6833   if (stream == NULL)
6834     {
6835       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6836       exit (1);
6837     }
6838
6839   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
6840   fprintf (stream, "/* Simple character mapping of Unicode characters.  */\n");
6841   fprintf (stream, "/* Generated automatically by gen-case.c for Unicode %s.  */\n",
6842            version);
6843
6844   t.p = 7;
6845   t.q = 9;
6846   mapping_table_init (&t);
6847
6848   for (ch = 0; ch < 0x110000; ch++)
6849     {
6850       int value = (int) func (ch) - (int) ch;
6851
6852       mapping_table_add (&t, ch, value);
6853     }
6854
6855   mapping_table_finalize (&t);
6856
6857   /* Offsets in t.result, in memory of this process.  */
6858   level1_offset =
6859     5 * sizeof (uint32_t);
6860   level2_offset =
6861     5 * sizeof (uint32_t)
6862     + t.level1_size * sizeof (uint32_t);
6863   level3_offset =
6864     5 * sizeof (uint32_t)
6865     + t.level1_size * sizeof (uint32_t)
6866     + (t.level2_size << t.q) * sizeof (uint32_t);
6867
6868   for (i = 0; i < 5; i++)
6869     fprintf (stream, "#define mapping_header_%d %d\n", i,
6870              ((uint32_t *) t.result)[i]);
6871   fprintf (stream, "static const\n");
6872   fprintf (stream, "struct\n");
6873   fprintf (stream, "  {\n");
6874   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
6875   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
6876   fprintf (stream, "    int level3[%zu << %d];\n", t.level3_size, t.p);
6877   fprintf (stream, "  }\n");
6878   fprintf (stream, "u_mapping =\n");
6879   fprintf (stream, "{\n");
6880   fprintf (stream, "  {");
6881   if (t.level1_size > 8)
6882     fprintf (stream, "\n   ");
6883   for (i = 0; i < t.level1_size; i++)
6884     {
6885       uint32_t offset;
6886       if (i > 0 && (i % 8) == 0)
6887         fprintf (stream, "\n   ");
6888       offset = ((uint32_t *) (t.result + level1_offset))[i];
6889       if (offset == 0)
6890         fprintf (stream, " %5d", -1);
6891       else
6892         fprintf (stream, " %5zu",
6893                  (offset - level2_offset) / sizeof (uint32_t));
6894       if (i+1 < t.level1_size)
6895         fprintf (stream, ",");
6896     }
6897   if (t.level1_size > 8)
6898     fprintf (stream, "\n ");
6899   fprintf (stream, " },\n");
6900   fprintf (stream, "  {");
6901   if (t.level2_size << t.q > 8)
6902     fprintf (stream, "\n   ");
6903   for (i = 0; i < t.level2_size << t.q; i++)
6904     {
6905       uint32_t offset;
6906       if (i > 0 && (i % 8) == 0)
6907         fprintf (stream, "\n   ");
6908       offset = ((uint32_t *) (t.result + level2_offset))[i];
6909       if (offset == 0)
6910         fprintf (stream, " %5d", -1);
6911       else
6912         fprintf (stream, " %5zu",
6913                  (offset - level3_offset) / sizeof (int32_t));
6914       if (i+1 < t.level2_size << t.q)
6915         fprintf (stream, ",");
6916     }
6917   if (t.level2_size << t.q > 8)
6918     fprintf (stream, "\n ");
6919   fprintf (stream, " },\n");
6920   fprintf (stream, "  {");
6921   if (t.level3_size << t.p > 8)
6922     fprintf (stream, "\n   ");
6923   for (i = 0; i < t.level3_size << t.p; i++)
6924     {
6925       if (i > 0 && (i % 8) == 0)
6926         fprintf (stream, "\n   ");
6927       fprintf (stream, " %5d", ((int32_t *) (t.result + level3_offset))[i]);
6928       if (i+1 < t.level3_size << t.p)
6929         fprintf (stream, ",");
6930     }
6931   if (t.level3_size << t.p > 8)
6932     fprintf (stream, "\n ");
6933   fprintf (stream, " }\n");
6934   fprintf (stream, "};\n");
6935
6936   if (ferror (stream) || fclose (stream))
6937     {
6938       fprintf (stderr, "error writing to '%s'\n", filename);
6939       exit (1);
6940     }
6941 }
6942
6943 /* ========================================================================= */
6944
6945 int
6946 main (int argc, char * argv[])
6947 {
6948   const char *unicodedata_filename;
6949   const char *proplist_filename;
6950   const char *derivedproplist_filename;
6951   const char *scripts_filename;
6952   const char *blocks_filename;
6953   const char *proplist30_filename;
6954   const char *eastasianwidth_filename;
6955   const char *linebreak_filename;
6956   const char *wordbreakproperty_filename;
6957   const char *version;
6958
6959   if (argc != 11)
6960     {
6961       fprintf (stderr, "Usage: %s UnicodeData.txt PropList.txt DerivedCoreProperties.txt Scripts.txt Blocks.txt PropList-3.0.1.txt EastAsianWidth.txt LineBreak.txt WordBreakProperty.txt version\n",
6962                argv[0]);
6963       exit (1);
6964     }
6965
6966   unicodedata_filename = argv[1];
6967   proplist_filename = argv[2];
6968   derivedproplist_filename = argv[3];
6969   scripts_filename = argv[4];
6970   blocks_filename = argv[5];
6971   proplist30_filename = argv[6];
6972   eastasianwidth_filename = argv[7];
6973   linebreak_filename = argv[8];
6974   wordbreakproperty_filename = argv[9];
6975   version = argv[10];
6976
6977   fill_attributes (unicodedata_filename);
6978   clear_properties ();
6979   fill_properties (proplist_filename);
6980   fill_properties (derivedproplist_filename);
6981   fill_properties30 (proplist30_filename);
6982   fill_scripts (scripts_filename);
6983   fill_blocks (blocks_filename);
6984   fill_width (eastasianwidth_filename);
6985   fill_org_lbp (linebreak_filename);
6986   fill_org_wbp (wordbreakproperty_filename);
6987
6988   output_categories (version);
6989   output_category ("unictype/categ_of.h", version);
6990   output_combclass ("unictype/combining.h", version);
6991   output_bidi_category ("unictype/bidi_of.h", version);
6992   output_decimal_digit_test ("../tests/unictype/test-decdigit.h", version);
6993   output_decimal_digit ("unictype/decdigit.h", version);
6994   output_digit_test ("../tests/unictype/test-digit.h", version);
6995   output_digit ("unictype/digit.h", version);
6996   output_numeric_test ("../tests/unictype/test-numeric.h", version);
6997   output_numeric ("unictype/numeric.h", version);
6998   output_mirror ("unictype/mirror.h", version);
6999   output_properties (version);
7000   output_scripts (version);
7001   output_scripts_byname (version);
7002   output_blocks (version);
7003   output_ident_properties (version);
7004   output_old_ctype (version);
7005
7006   debug_output_lbrk_tables ("unilbrk/lbrkprop.txt");
7007   debug_output_org_lbrk_tables ("unilbrk/lbrkprop_org.txt");
7008   output_lbrk_tables ("unilbrk/lbrkprop1.h", "unilbrk/lbrkprop2.h", version);
7009
7010   debug_output_wbrk_tables ("uniwbrk/wbrkprop.txt");
7011   debug_output_org_wbrk_tables ("uniwbrk/wbrkprop_org.txt");
7012   output_wbrk_tables ("uniwbrk/wbrkprop.h", version);
7013
7014   output_simple_mapping_test ("../tests/unicase/test-uc_toupper.c", "uc_toupper", to_upper, version);
7015   output_simple_mapping_test ("../tests/unicase/test-uc_tolower.c", "uc_tolower", to_lower, version);
7016   output_simple_mapping_test ("../tests/unicase/test-uc_totitle.c", "uc_totitle", to_title, version);
7017   output_simple_mapping ("unicase/toupper.h", to_upper, version);
7018   output_simple_mapping ("unicase/tolower.h", to_lower, version);
7019   output_simple_mapping ("unicase/totitle.h", to_title, version);
7020
7021   return 0;
7022 }
7023
7024 /*
7025  * For Emacs M-x compile
7026  * Local Variables:
7027  * compile-command: "
7028    gcc -O -Wall gen-uni-tables.c -Iunictype -o gen-uni-tables && \
7029    ./gen-uni-tables \
7030         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.1.0/ucd/UnicodeData.txt \
7031         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.1.0/ucd/PropList.txt \
7032         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.1.0/ucd/DerivedCoreProperties.txt \
7033         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.1.0/ucd/Scripts.txt \
7034         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.1.0/ucd/Blocks.txt \
7035         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/3.0.1/PropList-3.0.1.txt \
7036         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.1.0/ucd/EastAsianWidth.txt \
7037         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.1.0/ucd/LineBreak.txt \
7038         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.1.0/ucd/auxiliary/WordBreakProperty.txt \
7039         5.1.0
7040    "
7041  * End:
7042  */