unictype/scripts: Reduce the size of the 'data' segment.
[pspp] / 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    decomposition/composition and case mapping tables from a UnicodeData file.
4    Copyright (C) 2000-2002, 2004, 2007-2011 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                       /usr/local/share/Unidata/GraphemeBreakProperty.txt \
31                       /usr/local/share/Unidata/CompositionExclusions.txt \
32                       /usr/local/share/Unidata/SpecialCasing.txt \
33                       /usr/local/share/Unidata/CaseFolding.txt \
34                       6.0.0
35  */
36
37 #include <stdbool.h>
38 #include <stdint.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43
44 /* ========================================================================= */
45
46 /* Reading UnicodeData.txt.  */
47 /* See UCD.html.  */
48
49 /* This structure represents one line in the UnicodeData.txt file.  */
50 struct unicode_attribute
51 {
52   const char *name;           /* Character name */
53   const char *category;       /* General category */
54   const char *combining;      /* Canonical combining class */
55   const char *bidi;           /* Bidirectional category */
56   const char *decomposition;  /* Character decomposition mapping */
57   const char *decdigit;       /* Decimal digit value */
58   const char *digit;          /* Digit value */
59   const char *numeric;        /* Numeric value */
60   bool mirrored;              /* mirrored */
61   const char *oldname;        /* Old Unicode 1.0 name */
62   const char *comment;        /* Comment */
63   unsigned int upper;         /* Uppercase mapping */
64   unsigned int lower;         /* Lowercase mapping */
65   unsigned int title;         /* Titlecase mapping */
66 };
67
68 /* Missing fields are represented with "" for strings, and NONE for
69    characters.  */
70 #define NONE (~(unsigned int)0)
71
72 /* The entire contents of the UnicodeData.txt file.  */
73 struct unicode_attribute unicode_attributes [0x110000];
74
75 /* Stores in unicode_attributes[i] the values from the given fields.  */
76 static void
77 fill_attribute (unsigned int i,
78                 const char *field1, const char *field2,
79                 const char *field3, const char *field4,
80                 const char *field5, const char *field6,
81                 const char *field7, const char *field8,
82                 const char *field9, const char *field10,
83                 const char *field11, const char *field12,
84                 const char *field13, const char *field14)
85 {
86   struct unicode_attribute * uni;
87
88   if (i >= 0x110000)
89     {
90       fprintf (stderr, "index too large\n");
91       exit (1);
92     }
93   if (strcmp (field2, "Cs") == 0)
94     /* Surrogates are UTF-16 artefacts, not real characters. Ignore them.  */
95     return;
96   uni = &unicode_attributes[i];
97   /* Copy the strings.  */
98   uni->name          = strdup (field1);
99   uni->category      = (field2[0] == '\0' ? "" : strdup (field2));
100   uni->combining     = (field3[0] == '\0' ? "" : strdup (field3));
101   uni->bidi          = (field4[0] == '\0' ? "" : strdup (field4));
102   uni->decomposition = (field5[0] == '\0' ? "" : strdup (field5));
103   uni->decdigit      = (field6[0] == '\0' ? "" : strdup (field6));
104   uni->digit         = (field7[0] == '\0' ? "" : strdup (field7));
105   uni->numeric       = (field8[0] == '\0' ? "" : strdup (field8));
106   uni->mirrored      = (field9[0] == 'Y');
107   uni->oldname       = (field10[0] == '\0' ? "" : strdup (field10));
108   uni->comment       = (field11[0] == '\0' ? "" : strdup (field11));
109   uni->upper = (field12[0] =='\0' ? NONE : strtoul (field12, NULL, 16));
110   uni->lower = (field13[0] =='\0' ? NONE : strtoul (field13, NULL, 16));
111   uni->title = (field14[0] =='\0' ? NONE : strtoul (field14, NULL, 16));
112 }
113
114 /* Maximum length of a field in the UnicodeData.txt file.  */
115 #define FIELDLEN 120
116
117 /* Reads the next field from STREAM.  The buffer BUFFER has size FIELDLEN.
118    Reads up to (but excluding) DELIM.
119    Returns 1 when a field was successfully read, otherwise 0.  */
120 static int
121 getfield (FILE *stream, char *buffer, int delim)
122 {
123   int count = 0;
124   int c;
125
126   for (; (c = getc (stream)), (c != EOF && c != delim); )
127     {
128       /* The original unicode.org UnicodeData.txt file happens to have
129          CR/LF line terminators.  Silently convert to LF.  */
130       if (c == '\r')
131         continue;
132
133       /* Put c into the buffer.  */
134       if (++count >= FIELDLEN - 1)
135         {
136           fprintf (stderr, "field longer than expected, increase FIELDLEN\n");
137           exit (1);
138         }
139       *buffer++ = c;
140     }
141
142   if (c == EOF)
143     return 0;
144
145   *buffer = '\0';
146   return 1;
147 }
148
149 /* Stores in unicode_attributes[] the entire contents of the UnicodeData.txt
150    file.  */
151 static void
152 fill_attributes (const char *unicodedata_filename)
153 {
154   unsigned int i, j;
155   FILE *stream;
156   char field0[FIELDLEN];
157   char field1[FIELDLEN];
158   char field2[FIELDLEN];
159   char field3[FIELDLEN];
160   char field4[FIELDLEN];
161   char field5[FIELDLEN];
162   char field6[FIELDLEN];
163   char field7[FIELDLEN];
164   char field8[FIELDLEN];
165   char field9[FIELDLEN];
166   char field10[FIELDLEN];
167   char field11[FIELDLEN];
168   char field12[FIELDLEN];
169   char field13[FIELDLEN];
170   char field14[FIELDLEN];
171   int lineno = 0;
172
173   for (i = 0; i < 0x110000; i++)
174     unicode_attributes[i].name = NULL;
175
176   stream = fopen (unicodedata_filename, "r");
177   if (stream == NULL)
178     {
179       fprintf (stderr, "error during fopen of '%s'\n", unicodedata_filename);
180       exit (1);
181     }
182
183   for (;;)
184     {
185       int n;
186
187       lineno++;
188       n = getfield (stream, field0, ';');
189       n += getfield (stream, field1, ';');
190       n += getfield (stream, field2, ';');
191       n += getfield (stream, field3, ';');
192       n += getfield (stream, field4, ';');
193       n += getfield (stream, field5, ';');
194       n += getfield (stream, field6, ';');
195       n += getfield (stream, field7, ';');
196       n += getfield (stream, field8, ';');
197       n += getfield (stream, field9, ';');
198       n += getfield (stream, field10, ';');
199       n += getfield (stream, field11, ';');
200       n += getfield (stream, field12, ';');
201       n += getfield (stream, field13, ';');
202       n += getfield (stream, field14, '\n');
203       if (n == 0)
204         break;
205       if (n != 15)
206         {
207           fprintf (stderr, "short line in '%s':%d\n",
208                    unicodedata_filename, lineno);
209           exit (1);
210         }
211       i = strtoul (field0, NULL, 16);
212       if (field1[0] == '<'
213           && strlen (field1) >= 9
214           && strcmp (field1 + strlen (field1) - 8, ", First>") == 0)
215         {
216           /* Deal with a range. */
217           lineno++;
218           n = getfield (stream, field0, ';');
219           n += getfield (stream, field1, ';');
220           n += getfield (stream, field2, ';');
221           n += getfield (stream, field3, ';');
222           n += getfield (stream, field4, ';');
223           n += getfield (stream, field5, ';');
224           n += getfield (stream, field6, ';');
225           n += getfield (stream, field7, ';');
226           n += getfield (stream, field8, ';');
227           n += getfield (stream, field9, ';');
228           n += getfield (stream, field10, ';');
229           n += getfield (stream, field11, ';');
230           n += getfield (stream, field12, ';');
231           n += getfield (stream, field13, ';');
232           n += getfield (stream, field14, '\n');
233           if (n != 15)
234             {
235               fprintf (stderr, "missing end range in '%s':%d\n",
236                        unicodedata_filename, lineno);
237               exit (1);
238             }
239           if (!(field1[0] == '<'
240                 && strlen (field1) >= 8
241                 && strcmp (field1 + strlen (field1) - 7, ", Last>") == 0))
242             {
243               fprintf (stderr, "missing end range in '%s':%d\n",
244                        unicodedata_filename, lineno);
245               exit (1);
246             }
247           field1[strlen (field1) - 7] = '\0';
248           j = strtoul (field0, NULL, 16);
249           for (; i <= j; i++)
250             fill_attribute (i, field1+1, field2, field3, field4, field5,
251                                field6, field7, field8, field9, field10,
252                                field11, field12, field13, field14);
253         }
254       else
255         {
256           /* Single character line */
257           fill_attribute (i, field1, field2, field3, field4, field5,
258                              field6, field7, field8, field9, field10,
259                              field11, field12, field13, field14);
260         }
261     }
262   if (ferror (stream) || fclose (stream))
263     {
264       fprintf (stderr, "error reading from '%s'\n", unicodedata_filename);
265       exit (1);
266     }
267 }
268
269 /* ========================================================================= */
270
271 /* General category.  */
272 /* See Unicode 3.0 book, section 4.5,
273        UCD.html.  */
274
275 static bool
276 is_category_L (unsigned int ch)
277 {
278   return (unicode_attributes[ch].name != NULL
279           && unicode_attributes[ch].category[0] == 'L');
280 }
281
282 static bool
283 is_category_Lu (unsigned int ch)
284 {
285   return (unicode_attributes[ch].name != NULL
286           && unicode_attributes[ch].category[0] == 'L'
287           && unicode_attributes[ch].category[1] == 'u');
288 }
289
290 static bool
291 is_category_Ll (unsigned int ch)
292 {
293   return (unicode_attributes[ch].name != NULL
294           && unicode_attributes[ch].category[0] == 'L'
295           && unicode_attributes[ch].category[1] == 'l');
296 }
297
298 static bool
299 is_category_Lt (unsigned int ch)
300 {
301   return (unicode_attributes[ch].name != NULL
302           && unicode_attributes[ch].category[0] == 'L'
303           && unicode_attributes[ch].category[1] == 't');
304 }
305
306 static bool
307 is_category_Lm (unsigned int ch)
308 {
309   return (unicode_attributes[ch].name != NULL
310           && unicode_attributes[ch].category[0] == 'L'
311           && unicode_attributes[ch].category[1] == 'm');
312 }
313
314 static bool
315 is_category_Lo (unsigned int ch)
316 {
317   return (unicode_attributes[ch].name != NULL
318           && unicode_attributes[ch].category[0] == 'L'
319           && unicode_attributes[ch].category[1] == 'o');
320 }
321
322 static bool
323 is_category_M (unsigned int ch)
324 {
325   return (unicode_attributes[ch].name != NULL
326           && unicode_attributes[ch].category[0] == 'M');
327 }
328
329 static bool
330 is_category_Mn (unsigned int ch)
331 {
332   return (unicode_attributes[ch].name != NULL
333           && unicode_attributes[ch].category[0] == 'M'
334           && unicode_attributes[ch].category[1] == 'n');
335 }
336
337 static bool
338 is_category_Mc (unsigned int ch)
339 {
340   return (unicode_attributes[ch].name != NULL
341           && unicode_attributes[ch].category[0] == 'M'
342           && unicode_attributes[ch].category[1] == 'c');
343 }
344
345 static bool
346 is_category_Me (unsigned int ch)
347 {
348   return (unicode_attributes[ch].name != NULL
349           && unicode_attributes[ch].category[0] == 'M'
350           && unicode_attributes[ch].category[1] == 'e');
351 }
352
353 static bool
354 is_category_N (unsigned int ch)
355 {
356   return (unicode_attributes[ch].name != NULL
357           && unicode_attributes[ch].category[0] == 'N');
358 }
359
360 static bool
361 is_category_Nd (unsigned int ch)
362 {
363   return (unicode_attributes[ch].name != NULL
364           && unicode_attributes[ch].category[0] == 'N'
365           && unicode_attributes[ch].category[1] == 'd');
366 }
367
368 static bool
369 is_category_Nl (unsigned int ch)
370 {
371   return (unicode_attributes[ch].name != NULL
372           && unicode_attributes[ch].category[0] == 'N'
373           && unicode_attributes[ch].category[1] == 'l');
374 }
375
376 static bool
377 is_category_No (unsigned int ch)
378 {
379   return (unicode_attributes[ch].name != NULL
380           && unicode_attributes[ch].category[0] == 'N'
381           && unicode_attributes[ch].category[1] == 'o');
382 }
383
384 static bool
385 is_category_P (unsigned int ch)
386 {
387   return (unicode_attributes[ch].name != NULL
388           && unicode_attributes[ch].category[0] == 'P');
389 }
390
391 static bool
392 is_category_Pc (unsigned int ch)
393 {
394   return (unicode_attributes[ch].name != NULL
395           && unicode_attributes[ch].category[0] == 'P'
396           && unicode_attributes[ch].category[1] == 'c');
397 }
398
399 static bool
400 is_category_Pd (unsigned int ch)
401 {
402   return (unicode_attributes[ch].name != NULL
403           && unicode_attributes[ch].category[0] == 'P'
404           && unicode_attributes[ch].category[1] == 'd');
405 }
406
407 static bool
408 is_category_Ps (unsigned int ch)
409 {
410   return (unicode_attributes[ch].name != NULL
411           && unicode_attributes[ch].category[0] == 'P'
412           && unicode_attributes[ch].category[1] == 's');
413 }
414
415 static bool
416 is_category_Pe (unsigned int ch)
417 {
418   return (unicode_attributes[ch].name != NULL
419           && unicode_attributes[ch].category[0] == 'P'
420           && unicode_attributes[ch].category[1] == 'e');
421 }
422
423 static bool
424 is_category_Pi (unsigned int ch)
425 {
426   return (unicode_attributes[ch].name != NULL
427           && unicode_attributes[ch].category[0] == 'P'
428           && unicode_attributes[ch].category[1] == 'i');
429 }
430
431 static bool
432 is_category_Pf (unsigned int ch)
433 {
434   return (unicode_attributes[ch].name != NULL
435           && unicode_attributes[ch].category[0] == 'P'
436           && unicode_attributes[ch].category[1] == 'f');
437 }
438
439 static bool
440 is_category_Po (unsigned int ch)
441 {
442   return (unicode_attributes[ch].name != NULL
443           && unicode_attributes[ch].category[0] == 'P'
444           && unicode_attributes[ch].category[1] == 'o');
445 }
446
447 static bool
448 is_category_S (unsigned int ch)
449 {
450   return (unicode_attributes[ch].name != NULL
451           && unicode_attributes[ch].category[0] == 'S');
452 }
453
454 static bool
455 is_category_Sm (unsigned int ch)
456 {
457   return (unicode_attributes[ch].name != NULL
458           && unicode_attributes[ch].category[0] == 'S'
459           && unicode_attributes[ch].category[1] == 'm');
460 }
461
462 static bool
463 is_category_Sc (unsigned int ch)
464 {
465   return (unicode_attributes[ch].name != NULL
466           && unicode_attributes[ch].category[0] == 'S'
467           && unicode_attributes[ch].category[1] == 'c');
468 }
469
470 static bool
471 is_category_Sk (unsigned int ch)
472 {
473   return (unicode_attributes[ch].name != NULL
474           && unicode_attributes[ch].category[0] == 'S'
475           && unicode_attributes[ch].category[1] == 'k');
476 }
477
478 static bool
479 is_category_So (unsigned int ch)
480 {
481   return (unicode_attributes[ch].name != NULL
482           && unicode_attributes[ch].category[0] == 'S'
483           && unicode_attributes[ch].category[1] == 'o');
484 }
485
486 static bool
487 is_category_Z (unsigned int ch)
488 {
489   return (unicode_attributes[ch].name != NULL
490           && unicode_attributes[ch].category[0] == 'Z');
491 }
492
493 static bool
494 is_category_Zs (unsigned int ch)
495 {
496   return (unicode_attributes[ch].name != NULL
497           && unicode_attributes[ch].category[0] == 'Z'
498           && unicode_attributes[ch].category[1] == 's');
499 }
500
501 static bool
502 is_category_Zl (unsigned int ch)
503 {
504   return (unicode_attributes[ch].name != NULL
505           && unicode_attributes[ch].category[0] == 'Z'
506           && unicode_attributes[ch].category[1] == 'l');
507 }
508
509 static bool
510 is_category_Zp (unsigned int ch)
511 {
512   return (unicode_attributes[ch].name != NULL
513           && unicode_attributes[ch].category[0] == 'Z'
514           && unicode_attributes[ch].category[1] == 'p');
515 }
516
517 static bool
518 is_category_C (unsigned int ch)
519 {
520   return (unicode_attributes[ch].name == NULL
521           || unicode_attributes[ch].category[0] == 'C');
522 }
523
524 static bool
525 is_category_Cc (unsigned int ch)
526 {
527   return (unicode_attributes[ch].name != NULL
528           && unicode_attributes[ch].category[0] == 'C'
529           && unicode_attributes[ch].category[1] == 'c');
530 }
531
532 static bool
533 is_category_Cf (unsigned int ch)
534 {
535   return (unicode_attributes[ch].name != NULL
536           && unicode_attributes[ch].category[0] == 'C'
537           && unicode_attributes[ch].category[1] == 'f');
538 }
539
540 static bool
541 is_category_Cs (unsigned int ch)
542 {
543   return (ch >= 0xd800 && ch < 0xe000);
544 }
545
546 static bool
547 is_category_Co (unsigned int ch)
548 {
549   return (unicode_attributes[ch].name != NULL
550           && unicode_attributes[ch].category[0] == 'C'
551           && unicode_attributes[ch].category[1] == 'o');
552 }
553
554 static bool
555 is_category_Cn (unsigned int ch)
556 {
557   return (unicode_attributes[ch].name == NULL
558           && !(ch >= 0xd800 && ch < 0xe000));
559 }
560
561 /* Output a boolean property in a human readable format.  */
562 static void
563 debug_output_predicate (const char *filename, bool (*predicate) (unsigned int))
564 {
565   FILE *stream;
566   unsigned int ch;
567
568   stream = fopen (filename, "w");
569   if (stream == NULL)
570     {
571       fprintf (stderr, "cannot open '%s' for writing\n", filename);
572       exit (1);
573     }
574
575 #if 0 /* This yields huge text output.  */
576   for (ch = 0; ch < 0x110000; ch++)
577     if (predicate (ch))
578       {
579         fprintf (stream, "0x%04X\n", ch);
580       }
581 #else
582   for (ch = 0; ch < 0x110000; ch++)
583     if (predicate (ch))
584       {
585         unsigned int first = ch;
586         unsigned int last;
587
588         while (ch + 1 < 0x110000 && predicate (ch + 1))
589           ch++;
590         last = ch;
591         if (first < last)
592           fprintf (stream, "0x%04X..0x%04X\n", first, last);
593         else
594           fprintf (stream, "0x%04X\n", ch);
595       }
596 #endif
597
598   if (ferror (stream) || fclose (stream))
599     {
600       fprintf (stderr, "error writing to '%s'\n", filename);
601       exit (1);
602     }
603 }
604
605 /* Output the unit test for a boolean property.  */
606 static void
607 output_predicate_test (const char *filename, bool (*predicate) (unsigned int), const char *expression)
608 {
609   FILE *stream;
610   bool need_comma;
611   unsigned int ch;
612
613   stream = fopen (filename, "w");
614   if (stream == NULL)
615     {
616       fprintf (stderr, "cannot open '%s' for writing\n", filename);
617       exit (1);
618     }
619
620   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
621   fprintf (stream, "/* Test the Unicode character type functions.\n");
622   fprintf (stream, "   Copyright (C) 2007 Free Software Foundation, Inc.\n");
623   fprintf (stream, "\n");
624   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
625   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
626   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
627   fprintf (stream, "   (at your option) any later version.\n");
628   fprintf (stream, "\n");
629   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
630   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
631   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
632   fprintf (stream, "   GNU General Public License for more details.\n");
633   fprintf (stream, "\n");
634   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
635   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
636   fprintf (stream, "\n");
637   fprintf (stream, "#include \"test-predicate-part1.h\"\n");
638   fprintf (stream, "\n");
639
640   need_comma = false;
641   for (ch = 0; ch < 0x110000; ch++)
642     if (predicate (ch))
643       {
644         unsigned int first = ch;
645         unsigned int last;
646
647         while (ch + 1 < 0x110000 && predicate (ch + 1))
648           ch++;
649         last = ch;
650         if (need_comma)
651           fprintf (stream, ",\n");
652         fprintf (stream, "    { 0x%04X, 0x%04X }", first, last);
653         need_comma = true;
654       }
655   if (need_comma)
656     fprintf (stream, "\n");
657
658   fprintf (stream, "\n");
659   fprintf (stream, "#define PREDICATE(c) %s\n", expression);
660   fprintf (stream, "#include \"test-predicate-part2.h\"\n");
661
662   if (ferror (stream) || fclose (stream))
663     {
664       fprintf (stderr, "error writing to '%s'\n", filename);
665       exit (1);
666     }
667 }
668
669 /* Construction of sparse 3-level tables.  */
670 #define TABLE predicate_table
671 #define xmalloc malloc
672 #define xrealloc realloc
673 #include "3levelbit.h"
674
675 /* Output a boolean property in a three-level bitmap.  */
676 static void
677 output_predicate (const char *filename, bool (*predicate) (unsigned int), const char *name, const char *comment, const char *version)
678 {
679   FILE *stream;
680   unsigned int ch, i;
681   struct predicate_table t;
682   unsigned int level1_offset, level2_offset, level3_offset;
683
684   stream = fopen (filename, "w");
685   if (stream == NULL)
686     {
687       fprintf (stderr, "cannot open '%s' for writing\n", filename);
688       exit (1);
689     }
690
691   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
692   fprintf (stream, "/* %s of Unicode characters.  */\n", comment);
693   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
694            version);
695
696   t.p = 4; /* or: 5 */
697   t.q = 7; /* or: 6 */
698   predicate_table_init (&t);
699
700   for (ch = 0; ch < 0x110000; ch++)
701     if (predicate (ch))
702       predicate_table_add (&t, ch);
703
704   predicate_table_finalize (&t);
705
706   /* Offsets in t.result, in memory of this process.  */
707   level1_offset =
708     5 * sizeof (uint32_t);
709   level2_offset =
710     5 * sizeof (uint32_t)
711     + t.level1_size * sizeof (uint32_t);
712   level3_offset =
713     5 * sizeof (uint32_t)
714     + t.level1_size * sizeof (uint32_t)
715     + (t.level2_size << t.q) * sizeof (uint32_t);
716
717   for (i = 0; i < 5; i++)
718     if (i != 1)
719       fprintf (stream, "#define header_%d %d\n", i,
720                ((uint32_t *) t.result)[i]);
721
722   fprintf (stream, "static const\n");
723   fprintf (stream, "struct\n");
724   fprintf (stream, "  {\n");
725   fprintf (stream, "    int header[1];\n");
726   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
727   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
728   fprintf (stream, "    /*unsigned*/ int level3[%zu << %d];\n", t.level3_size, t.p);
729   fprintf (stream, "  }\n");
730   fprintf (stream, "%s =\n", name);
731   fprintf (stream, "{\n");
732   fprintf (stream, "  { %d },\n", ((uint32_t *) t.result)[1]);
733   fprintf (stream, "  {");
734   if (t.level1_size > 1)
735     fprintf (stream, "\n   ");
736   for (i = 0; i < t.level1_size; i++)
737     {
738       uint32_t offset;
739       if (i > 0 && (i % 1) == 0)
740         fprintf (stream, "\n   ");
741       offset = ((uint32_t *) (t.result + level1_offset))[i];
742       if (offset == 0)
743         fprintf (stream, " %5d", -1);
744       else
745         fprintf (stream, " %5zu * sizeof (int) / sizeof (short) + %5zu",
746                  1 + t.level1_size, (offset - level2_offset) / sizeof (uint32_t));
747       if (i+1 < t.level1_size)
748         fprintf (stream, ",");
749     }
750   if (t.level1_size > 1)
751     fprintf (stream, "\n ");
752   fprintf (stream, " },\n");
753   fprintf (stream, "  {");
754   if (t.level2_size << t.q > 1)
755     fprintf (stream, "\n   ");
756   for (i = 0; i < t.level2_size << t.q; i++)
757     {
758       uint32_t offset;
759       if (i > 0 && (i % 1) == 0)
760         fprintf (stream, "\n   ");
761       offset = ((uint32_t *) (t.result + level2_offset))[i];
762       if (offset == 0)
763         fprintf (stream, " %5d", -1);
764       else
765         fprintf (stream, " %5zu + %5zu * sizeof (short) / sizeof (int) + %5zu",
766                  1 + t.level1_size, t.level2_size << t.q, (offset - level3_offset) / sizeof (uint32_t));
767       if (i+1 < t.level2_size << t.q)
768         fprintf (stream, ",");
769     }
770   if (t.level2_size << t.q > 1)
771     fprintf (stream, "\n ");
772   fprintf (stream, " },\n");
773   fprintf (stream, "  {");
774   if (t.level3_size << t.p > 4)
775     fprintf (stream, "\n   ");
776   for (i = 0; i < t.level3_size << t.p; i++)
777     {
778       if (i > 0 && (i % 4) == 0)
779         fprintf (stream, "\n   ");
780       fprintf (stream, " 0x%08X",
781                ((uint32_t *) (t.result + level3_offset))[i]);
782       if (i+1 < t.level3_size << t.p)
783         fprintf (stream, ",");
784     }
785   if (t.level3_size << t.p > 4)
786     fprintf (stream, "\n ");
787   fprintf (stream, " }\n");
788   fprintf (stream, "};\n");
789
790   if (ferror (stream) || fclose (stream))
791     {
792       fprintf (stderr, "error writing to '%s'\n", filename);
793       exit (1);
794     }
795 }
796
797 /* Output all categories.  */
798 static void
799 output_categories (const char *version)
800 {
801 #define CATEGORY(C) \
802   debug_output_predicate ("unictype/categ_" #C ".txt", is_category_ ## C); \
803   output_predicate_test ("../tests/unictype/test-categ_" #C ".c", is_category_ ## C, "uc_is_general_category (c, UC_CATEGORY_" #C ")"); \
804   output_predicate ("unictype/categ_" #C ".h", is_category_ ## C, "u_categ_" #C, "Categories", version);
805   CATEGORY (L)
806   CATEGORY (Lu)
807   CATEGORY (Ll)
808   CATEGORY (Lt)
809   CATEGORY (Lm)
810   CATEGORY (Lo)
811   CATEGORY (M)
812   CATEGORY (Mn)
813   CATEGORY (Mc)
814   CATEGORY (Me)
815   CATEGORY (N)
816   CATEGORY (Nd)
817   CATEGORY (Nl)
818   CATEGORY (No)
819   CATEGORY (P)
820   CATEGORY (Pc)
821   CATEGORY (Pd)
822   CATEGORY (Ps)
823   CATEGORY (Pe)
824   CATEGORY (Pi)
825   CATEGORY (Pf)
826   CATEGORY (Po)
827   CATEGORY (S)
828   CATEGORY (Sm)
829   CATEGORY (Sc)
830   CATEGORY (Sk)
831   CATEGORY (So)
832   CATEGORY (Z)
833   CATEGORY (Zs)
834   CATEGORY (Zl)
835   CATEGORY (Zp)
836   CATEGORY (C)
837   CATEGORY (Cc)
838   CATEGORY (Cf)
839   CATEGORY (Cs)
840   CATEGORY (Co)
841   CATEGORY (Cn)
842 #undef CATEGORY
843 }
844
845 enum
846 {
847   UC_CATEGORY_MASK_L  = 0x0000001f,
848   UC_CATEGORY_MASK_Lu = 0x00000001,
849   UC_CATEGORY_MASK_Ll = 0x00000002,
850   UC_CATEGORY_MASK_Lt = 0x00000004,
851   UC_CATEGORY_MASK_Lm = 0x00000008,
852   UC_CATEGORY_MASK_Lo = 0x00000010,
853   UC_CATEGORY_MASK_M  = 0x000000e0,
854   UC_CATEGORY_MASK_Mn = 0x00000020,
855   UC_CATEGORY_MASK_Mc = 0x00000040,
856   UC_CATEGORY_MASK_Me = 0x00000080,
857   UC_CATEGORY_MASK_N  = 0x00000700,
858   UC_CATEGORY_MASK_Nd = 0x00000100,
859   UC_CATEGORY_MASK_Nl = 0x00000200,
860   UC_CATEGORY_MASK_No = 0x00000400,
861   UC_CATEGORY_MASK_P  = 0x0003f800,
862   UC_CATEGORY_MASK_Pc = 0x00000800,
863   UC_CATEGORY_MASK_Pd = 0x00001000,
864   UC_CATEGORY_MASK_Ps = 0x00002000,
865   UC_CATEGORY_MASK_Pe = 0x00004000,
866   UC_CATEGORY_MASK_Pi = 0x00008000,
867   UC_CATEGORY_MASK_Pf = 0x00010000,
868   UC_CATEGORY_MASK_Po = 0x00020000,
869   UC_CATEGORY_MASK_S  = 0x003c0000,
870   UC_CATEGORY_MASK_Sm = 0x00040000,
871   UC_CATEGORY_MASK_Sc = 0x00080000,
872   UC_CATEGORY_MASK_Sk = 0x00100000,
873   UC_CATEGORY_MASK_So = 0x00200000,
874   UC_CATEGORY_MASK_Z  = 0x01c00000,
875   UC_CATEGORY_MASK_Zs = 0x00400000,
876   UC_CATEGORY_MASK_Zl = 0x00800000,
877   UC_CATEGORY_MASK_Zp = 0x01000000,
878   UC_CATEGORY_MASK_C  = 0x3e000000,
879   UC_CATEGORY_MASK_Cc = 0x02000000,
880   UC_CATEGORY_MASK_Cf = 0x04000000,
881   UC_CATEGORY_MASK_Cs = 0x08000000,
882   UC_CATEGORY_MASK_Co = 0x10000000,
883   UC_CATEGORY_MASK_Cn = 0x20000000
884 };
885
886 static int
887 general_category_byname (const char *category_name)
888 {
889   if (category_name[0] != '\0'
890       && (category_name[1] == '\0' || category_name[2] == '\0'))
891     switch (category_name[0])
892       {
893       case 'L':
894         switch (category_name[1])
895           {
896           case '\0': return UC_CATEGORY_MASK_L;
897           case 'u': return UC_CATEGORY_MASK_Lu;
898           case 'l': return UC_CATEGORY_MASK_Ll;
899           case 't': return UC_CATEGORY_MASK_Lt;
900           case 'm': return UC_CATEGORY_MASK_Lm;
901           case 'o': return UC_CATEGORY_MASK_Lo;
902           }
903         break;
904       case 'M':
905         switch (category_name[1])
906           {
907           case '\0': return UC_CATEGORY_MASK_M;
908           case 'n': return UC_CATEGORY_MASK_Mn;
909           case 'c': return UC_CATEGORY_MASK_Mc;
910           case 'e': return UC_CATEGORY_MASK_Me;
911           }
912         break;
913       case 'N':
914         switch (category_name[1])
915           {
916           case '\0': return UC_CATEGORY_MASK_N;
917           case 'd': return UC_CATEGORY_MASK_Nd;
918           case 'l': return UC_CATEGORY_MASK_Nl;
919           case 'o': return UC_CATEGORY_MASK_No;
920           }
921         break;
922       case 'P':
923         switch (category_name[1])
924           {
925           case '\0': return UC_CATEGORY_MASK_P;
926           case 'c': return UC_CATEGORY_MASK_Pc;
927           case 'd': return UC_CATEGORY_MASK_Pd;
928           case 's': return UC_CATEGORY_MASK_Ps;
929           case 'e': return UC_CATEGORY_MASK_Pe;
930           case 'i': return UC_CATEGORY_MASK_Pi;
931           case 'f': return UC_CATEGORY_MASK_Pf;
932           case 'o': return UC_CATEGORY_MASK_Po;
933           }
934         break;
935       case 'S':
936         switch (category_name[1])
937           {
938           case '\0': return UC_CATEGORY_MASK_S;
939           case 'm': return UC_CATEGORY_MASK_Sm;
940           case 'c': return UC_CATEGORY_MASK_Sc;
941           case 'k': return UC_CATEGORY_MASK_Sk;
942           case 'o': return UC_CATEGORY_MASK_So;
943           }
944         break;
945       case 'Z':
946         switch (category_name[1])
947           {
948           case '\0': return UC_CATEGORY_MASK_Z;
949           case 's': return UC_CATEGORY_MASK_Zs;
950           case 'l': return UC_CATEGORY_MASK_Zl;
951           case 'p': return UC_CATEGORY_MASK_Zp;
952           }
953         break;
954       case 'C':
955         switch (category_name[1])
956           {
957           case '\0': return UC_CATEGORY_MASK_C;
958           case 'c': return UC_CATEGORY_MASK_Cc;
959           case 'f': return UC_CATEGORY_MASK_Cf;
960           case 's': return UC_CATEGORY_MASK_Cs;
961           case 'o': return UC_CATEGORY_MASK_Co;
962           case 'n': return UC_CATEGORY_MASK_Cn;
963           }
964         break;
965       }
966   /* Invalid category name.  */
967   abort ();
968 }
969
970 /* Construction of sparse 3-level tables.  */
971 #define TABLE category_table
972 #define ELEMENT uint8_t
973 #define DEFAULT 29 /* = log2(UC_CATEGORY_MASK_Cn) */
974 #define xmalloc malloc
975 #define xrealloc realloc
976 #include "3level.h"
977
978 /* Output the per-character category table.  */
979 static void
980 output_category (const char *filename, const char *version)
981 {
982   FILE *stream;
983   unsigned int ch, i;
984   struct category_table t;
985   unsigned int level1_offset, level2_offset, level3_offset;
986   uint16_t *level3_packed;
987
988   stream = fopen (filename, "w");
989   if (stream == NULL)
990     {
991       fprintf (stderr, "cannot open '%s' for writing\n", filename);
992       exit (1);
993     }
994
995   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
996   fprintf (stream, "/* Categories of Unicode characters.  */\n");
997   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
998            version);
999
1000   t.p = 7;
1001   t.q = 9;
1002   category_table_init (&t);
1003
1004   for (ch = 0; ch < 0x110000; ch++)
1005     {
1006       int value;
1007       unsigned int log2_value;
1008
1009       if (is_category_Cs (ch))
1010         value = UC_CATEGORY_MASK_Cs;
1011       else if (unicode_attributes[ch].name != NULL)
1012         value = general_category_byname (unicode_attributes[ch].category);
1013       else
1014         continue;
1015
1016       /* Now value should contain exactly one bit.  */
1017       if (value == 0 || ((value & (value - 1)) != 0))
1018         abort ();
1019
1020       for (log2_value = 0; value > 1; value >>= 1, log2_value++);
1021
1022       category_table_add (&t, ch, log2_value);
1023     }
1024
1025   category_table_finalize (&t);
1026
1027   /* Offsets in t.result, in memory of this process.  */
1028   level1_offset =
1029     5 * sizeof (uint32_t);
1030   level2_offset =
1031     5 * sizeof (uint32_t)
1032     + t.level1_size * sizeof (uint32_t);
1033   level3_offset =
1034     5 * sizeof (uint32_t)
1035     + t.level1_size * sizeof (uint32_t)
1036     + (t.level2_size << t.q) * sizeof (uint32_t);
1037
1038   for (i = 0; i < 5; i++)
1039     fprintf (stream, "#define category_header_%d %d\n", i,
1040              ((uint32_t *) t.result)[i]);
1041   fprintf (stream, "static const\n");
1042   fprintf (stream, "struct\n");
1043   fprintf (stream, "  {\n");
1044   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1045   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1046   fprintf (stream, "    unsigned short level3[%zu * %d + 1];\n", t.level3_size,
1047            (1 << t.p) * 5 / 16);
1048   fprintf (stream, "  }\n");
1049   fprintf (stream, "u_category =\n");
1050   fprintf (stream, "{\n");
1051   fprintf (stream, "  {");
1052   if (t.level1_size > 8)
1053     fprintf (stream, "\n   ");
1054   for (i = 0; i < t.level1_size; i++)
1055     {
1056       uint32_t offset;
1057       if (i > 0 && (i % 8) == 0)
1058         fprintf (stream, "\n   ");
1059       offset = ((uint32_t *) (t.result + level1_offset))[i];
1060       if (offset == 0)
1061         fprintf (stream, " %5d", -1);
1062       else
1063         fprintf (stream, " %5zu",
1064                  (offset - level2_offset) / sizeof (uint32_t));
1065       if (i+1 < t.level1_size)
1066         fprintf (stream, ",");
1067     }
1068   if (t.level1_size > 8)
1069     fprintf (stream, "\n ");
1070   fprintf (stream, " },\n");
1071   fprintf (stream, "  {");
1072   if (t.level2_size << t.q > 8)
1073     fprintf (stream, "\n   ");
1074   for (i = 0; i < t.level2_size << t.q; i++)
1075     {
1076       uint32_t offset;
1077       if (i > 0 && (i % 8) == 0)
1078         fprintf (stream, "\n   ");
1079       offset = ((uint32_t *) (t.result + level2_offset))[i];
1080       if (offset == 0)
1081         fprintf (stream, " %5d", -1);
1082       else
1083         fprintf (stream, " %5zu",
1084                  (offset - level3_offset) / sizeof (uint8_t));
1085       if (i+1 < t.level2_size << t.q)
1086         fprintf (stream, ",");
1087     }
1088   if (t.level2_size << t.q > 8)
1089     fprintf (stream, "\n ");
1090   fprintf (stream, " },\n");
1091   /* Pack the level3 array.  Each entry needs 5 bits only.  Use 16-bit units,
1092      not 32-bit units, in order to make the lookup function easier.  */
1093   level3_packed =
1094     (uint16_t *)
1095     calloc ((t.level3_size << t.p) * 5 / 16 + 1, sizeof (uint16_t));
1096   for (i = 0; i < t.level3_size << t.p; i++)
1097     {
1098       unsigned int j = (i * 5) / 16;
1099       unsigned int k = (i * 5) % 16;
1100       uint32_t value = ((unsigned char *) (t.result + level3_offset))[i];
1101       value = level3_packed[j] | (level3_packed[j+1] << 16) | (value << k);
1102       level3_packed[j] = value & 0xffff;
1103       level3_packed[j+1] = value >> 16;
1104     }
1105   fprintf (stream, "  {");
1106   if ((t.level3_size << t.p) * 5 / 16 + 1 > 8)
1107     fprintf (stream, "\n   ");
1108   for (i = 0; i < (t.level3_size << t.p) * 5 / 16 + 1; i++)
1109     {
1110       if (i > 0 && (i % 8) == 0)
1111         fprintf (stream, "\n   ");
1112       fprintf (stream, " 0x%04x", level3_packed[i]);
1113       if (i+1 < (t.level3_size << t.p) * 5 / 16 + 1)
1114         fprintf (stream, ",");
1115     }
1116   if ((t.level3_size << t.p) * 5 / 16 + 1 > 8)
1117     fprintf (stream, "\n ");
1118   fprintf (stream, " }\n");
1119   free (level3_packed);
1120   fprintf (stream, "};\n");
1121
1122   if (ferror (stream) || fclose (stream))
1123     {
1124       fprintf (stderr, "error writing to '%s'\n", filename);
1125       exit (1);
1126     }
1127 }
1128
1129 /* ========================================================================= */
1130
1131 /* Canonical combining class.  */
1132 /* See Unicode 3.0 book, section 4.2,
1133        UCD.html.  */
1134
1135 /* Construction of sparse 3-level tables.  */
1136 #define TABLE combclass_table
1137 #define ELEMENT uint8_t
1138 #define DEFAULT 0
1139 #define xmalloc malloc
1140 #define xrealloc realloc
1141 #include "3level.h"
1142
1143 /* Output the per-character combining class table.  */
1144 static void
1145 output_combclass (const char *filename, const char *version)
1146 {
1147   FILE *stream;
1148   unsigned int ch, i;
1149   struct combclass_table t;
1150   unsigned int level1_offset, level2_offset, level3_offset;
1151
1152   stream = fopen (filename, "w");
1153   if (stream == NULL)
1154     {
1155       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1156       exit (1);
1157     }
1158
1159   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1160   fprintf (stream, "/* Combining class of Unicode characters.  */\n");
1161   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
1162            version);
1163
1164   t.p = 7;
1165   t.q = 9;
1166   combclass_table_init (&t);
1167
1168   for (ch = 0; ch < 0x110000; ch++)
1169     if (unicode_attributes[ch].name != NULL)
1170       {
1171         int value = atoi (unicode_attributes[ch].combining);
1172         if (!(value >= 0 && value <= 255))
1173           abort ();
1174         combclass_table_add (&t, ch, value);
1175       }
1176
1177   combclass_table_finalize (&t);
1178
1179   /* Offsets in t.result, in memory of this process.  */
1180   level1_offset =
1181     5 * sizeof (uint32_t);
1182   level2_offset =
1183     5 * sizeof (uint32_t)
1184     + t.level1_size * sizeof (uint32_t);
1185   level3_offset =
1186     5 * sizeof (uint32_t)
1187     + t.level1_size * sizeof (uint32_t)
1188     + (t.level2_size << t.q) * sizeof (uint32_t);
1189
1190   for (i = 0; i < 5; i++)
1191     fprintf (stream, "#define combclass_header_%d %d\n", i,
1192              ((uint32_t *) t.result)[i]);
1193   fprintf (stream, "static const\n");
1194   fprintf (stream, "struct\n");
1195   fprintf (stream, "  {\n");
1196   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1197   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1198   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
1199   fprintf (stream, "  }\n");
1200   fprintf (stream, "u_combclass =\n");
1201   fprintf (stream, "{\n");
1202   fprintf (stream, "  {");
1203   if (t.level1_size > 8)
1204     fprintf (stream, "\n   ");
1205   for (i = 0; i < t.level1_size; i++)
1206     {
1207       uint32_t offset;
1208       if (i > 0 && (i % 8) == 0)
1209         fprintf (stream, "\n   ");
1210       offset = ((uint32_t *) (t.result + level1_offset))[i];
1211       if (offset == 0)
1212         fprintf (stream, " %5d", -1);
1213       else
1214         fprintf (stream, " %5zu",
1215                  (offset - level2_offset) / sizeof (uint32_t));
1216       if (i+1 < t.level1_size)
1217         fprintf (stream, ",");
1218     }
1219   if (t.level1_size > 8)
1220     fprintf (stream, "\n ");
1221   fprintf (stream, " },\n");
1222   fprintf (stream, "  {");
1223   if (t.level2_size << t.q > 8)
1224     fprintf (stream, "\n   ");
1225   for (i = 0; i < t.level2_size << t.q; i++)
1226     {
1227       uint32_t offset;
1228       if (i > 0 && (i % 8) == 0)
1229         fprintf (stream, "\n   ");
1230       offset = ((uint32_t *) (t.result + level2_offset))[i];
1231       if (offset == 0)
1232         fprintf (stream, " %5d", -1);
1233       else
1234         fprintf (stream, " %5zu",
1235                  (offset - level3_offset) / sizeof (uint8_t));
1236       if (i+1 < t.level2_size << t.q)
1237         fprintf (stream, ",");
1238     }
1239   if (t.level2_size << t.q > 8)
1240     fprintf (stream, "\n ");
1241   fprintf (stream, " },\n");
1242   fprintf (stream, "  {");
1243   if (t.level3_size << t.p > 8)
1244     fprintf (stream, "\n   ");
1245   for (i = 0; i < t.level3_size << t.p; i++)
1246     {
1247       if (i > 0 && (i % 8) == 0)
1248         fprintf (stream, "\n   ");
1249       fprintf (stream, " %3d", ((uint8_t *) (t.result + level3_offset))[i]);
1250       if (i+1 < t.level3_size << t.p)
1251         fprintf (stream, ",");
1252     }
1253   if (t.level3_size << t.p > 8)
1254     fprintf (stream, "\n ");
1255   fprintf (stream, " }\n");
1256   fprintf (stream, "};\n");
1257
1258   if (ferror (stream) || fclose (stream))
1259     {
1260       fprintf (stderr, "error writing to '%s'\n", filename);
1261       exit (1);
1262     }
1263 }
1264
1265 /* ========================================================================= */
1266
1267 /* Bidirectional category.  */
1268 /* See Unicode 3.0 book, section 4.3,
1269        UCD.html.  */
1270
1271 enum
1272 {
1273   UC_BIDI_L,   /* Left-to-Right */
1274   UC_BIDI_LRE, /* Left-to-Right Embedding */
1275   UC_BIDI_LRO, /* Left-to-Right Override */
1276   UC_BIDI_R,   /* Right-to-Left */
1277   UC_BIDI_AL,  /* Right-to-Left Arabic */
1278   UC_BIDI_RLE, /* Right-to-Left Embedding */
1279   UC_BIDI_RLO, /* Right-to-Left Override */
1280   UC_BIDI_PDF, /* Pop Directional Format */
1281   UC_BIDI_EN,  /* European Number */
1282   UC_BIDI_ES,  /* European Number Separator */
1283   UC_BIDI_ET,  /* European Number Terminator */
1284   UC_BIDI_AN,  /* Arabic Number */
1285   UC_BIDI_CS,  /* Common Number Separator */
1286   UC_BIDI_NSM, /* Non-Spacing Mark */
1287   UC_BIDI_BN,  /* Boundary Neutral */
1288   UC_BIDI_B,   /* Paragraph Separator */
1289   UC_BIDI_S,   /* Segment Separator */
1290   UC_BIDI_WS,  /* Whitespace */
1291   UC_BIDI_ON   /* Other Neutral */
1292 };
1293
1294 static int
1295 bidi_category_byname (const char *category_name)
1296 {
1297   switch (category_name[0])
1298     {
1299     case 'A':
1300       switch (category_name[1])
1301         {
1302         case 'L':
1303           if (category_name[2] == '\0')
1304             return UC_BIDI_AL;
1305           break;
1306         case 'N':
1307           if (category_name[2] == '\0')
1308             return UC_BIDI_AN;
1309           break;
1310         }
1311       break;
1312     case 'B':
1313       switch (category_name[1])
1314         {
1315         case '\0':
1316           return UC_BIDI_B;
1317         case 'N':
1318           if (category_name[2] == '\0')
1319             return UC_BIDI_BN;
1320           break;
1321         }
1322       break;
1323     case 'C':
1324       switch (category_name[1])
1325         {
1326         case 'S':
1327           if (category_name[2] == '\0')
1328             return UC_BIDI_CS;
1329           break;
1330         }
1331       break;
1332     case 'E':
1333       switch (category_name[1])
1334         {
1335         case 'N':
1336           if (category_name[2] == '\0')
1337             return UC_BIDI_EN;
1338           break;
1339         case 'S':
1340           if (category_name[2] == '\0')
1341             return UC_BIDI_ES;
1342           break;
1343         case 'T':
1344           if (category_name[2] == '\0')
1345             return UC_BIDI_ET;
1346           break;
1347         }
1348       break;
1349     case 'L':
1350       switch (category_name[1])
1351         {
1352         case '\0':
1353           return UC_BIDI_L;
1354         case 'R':
1355           switch (category_name[2])
1356             {
1357             case 'E':
1358               if (category_name[3] == '\0')
1359                 return UC_BIDI_LRE;
1360               break;
1361             case 'O':
1362               if (category_name[3] == '\0')
1363                 return UC_BIDI_LRO;
1364               break;
1365             }
1366           break;
1367         }
1368       break;
1369     case 'N':
1370       switch (category_name[1])
1371         {
1372         case 'S':
1373           switch (category_name[2])
1374             {
1375             case 'M':
1376               if (category_name[3] == '\0')
1377                 return UC_BIDI_NSM;
1378               break;
1379             }
1380           break;
1381         }
1382       break;
1383     case 'O':
1384       switch (category_name[1])
1385         {
1386         case 'N':
1387           if (category_name[2] == '\0')
1388             return UC_BIDI_ON;
1389           break;
1390         }
1391       break;
1392     case 'P':
1393       switch (category_name[1])
1394         {
1395         case 'D':
1396           switch (category_name[2])
1397             {
1398             case 'F':
1399               if (category_name[3] == '\0')
1400                 return UC_BIDI_PDF;
1401               break;
1402             }
1403           break;
1404         }
1405       break;
1406     case 'R':
1407       switch (category_name[1])
1408         {
1409         case '\0':
1410           return UC_BIDI_R;
1411         case 'L':
1412           switch (category_name[2])
1413             {
1414             case 'E':
1415               if (category_name[3] == '\0')
1416                 return UC_BIDI_RLE;
1417               break;
1418             case 'O':
1419               if (category_name[3] == '\0')
1420                 return UC_BIDI_RLO;
1421               break;
1422             }
1423           break;
1424         }
1425       break;
1426     case 'S':
1427       if (category_name[1] == '\0')
1428         return UC_BIDI_S;
1429       break;
1430     case 'W':
1431       switch (category_name[1])
1432         {
1433         case 'S':
1434           if (category_name[2] == '\0')
1435             return UC_BIDI_WS;
1436           break;
1437         }
1438       break;
1439     }
1440   /* Invalid bidi category name.  */
1441   abort ();
1442 }
1443
1444 static int
1445 get_bidi_category (unsigned int ch)
1446 {
1447   if (unicode_attributes[ch].name != NULL)
1448     return bidi_category_byname (unicode_attributes[ch].bidi);
1449   else
1450     {
1451       /* The bidi category of unassigned characters depends on the range.
1452          See UTR #9 and DerivedBidiClass.txt.  */
1453       if ((ch >= 0x0590 && ch <= 0x05FF)
1454           || (ch >= 0x07FB && ch <= 0x08FF)
1455           || (ch >= 0xFB37 && ch <= 0xFB45)
1456           || (ch >= 0x10800 && ch <= 0x10FFF))
1457         return UC_BIDI_R;
1458       else if ((ch >= 0x0600 && ch <= 0x07BF)
1459                || (ch >= 0x2064 && ch <= 0x2069)
1460                || (ch >= 0xFBB2 && ch <= 0xFDCF)
1461                || (ch >= 0xFDFE && ch <= 0xFEFE))
1462         return UC_BIDI_AL;
1463       else if ((ch >= 0xFDD0 && ch <= 0xFDEF)
1464                || (ch >= 0xFFF0 && ch <= 0xFFFF)
1465                || (ch & 0xFFFF) == 0xFFFE
1466                || (ch & 0xFFFF) == 0xFFFF
1467                || (ch >= 0xE0000 && ch <= 0xE0FFF))
1468         return UC_BIDI_BN;
1469       else
1470         return UC_BIDI_L;
1471     }
1472 }
1473
1474 /* Construction of sparse 3-level tables.  */
1475 #define TABLE bidi_category_table
1476 #define ELEMENT uint8_t
1477 #define DEFAULT UC_BIDI_L
1478 #define xmalloc malloc
1479 #define xrealloc realloc
1480 #include "3level.h"
1481
1482 /* Output the per-character bidi category table.  */
1483 static void
1484 output_bidi_category (const char *filename, const char *version)
1485 {
1486   FILE *stream;
1487   unsigned int ch, i;
1488   struct bidi_category_table t;
1489   unsigned int level1_offset, level2_offset, level3_offset;
1490   uint16_t *level3_packed;
1491
1492   stream = fopen (filename, "w");
1493   if (stream == NULL)
1494     {
1495       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1496       exit (1);
1497     }
1498
1499   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1500   fprintf (stream, "/* Bidi categories of Unicode characters.  */\n");
1501   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
1502            version);
1503
1504   t.p = 7;
1505   t.q = 9;
1506   bidi_category_table_init (&t);
1507
1508   for (ch = 0; ch < 0x110000; ch++)
1509     {
1510       int value = get_bidi_category (ch);
1511
1512       bidi_category_table_add (&t, ch, value);
1513     }
1514
1515   bidi_category_table_finalize (&t);
1516
1517   /* Offsets in t.result, in memory of this process.  */
1518   level1_offset =
1519     5 * sizeof (uint32_t);
1520   level2_offset =
1521     5 * sizeof (uint32_t)
1522     + t.level1_size * sizeof (uint32_t);
1523   level3_offset =
1524     5 * sizeof (uint32_t)
1525     + t.level1_size * sizeof (uint32_t)
1526     + (t.level2_size << t.q) * sizeof (uint32_t);
1527
1528   for (i = 0; i < 5; i++)
1529     fprintf (stream, "#define bidi_category_header_%d %d\n", i,
1530              ((uint32_t *) t.result)[i]);
1531   fprintf (stream, "static const\n");
1532   fprintf (stream, "struct\n");
1533   fprintf (stream, "  {\n");
1534   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1535   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1536   fprintf (stream, "    unsigned short level3[%zu * %d + 1];\n", t.level3_size,
1537            (1 << t.p) * 5 / 16);
1538   fprintf (stream, "  }\n");
1539   fprintf (stream, "u_bidi_category =\n");
1540   fprintf (stream, "{\n");
1541   fprintf (stream, "  {");
1542   if (t.level1_size > 8)
1543     fprintf (stream, "\n   ");
1544   for (i = 0; i < t.level1_size; i++)
1545     {
1546       uint32_t offset;
1547       if (i > 0 && (i % 8) == 0)
1548         fprintf (stream, "\n   ");
1549       offset = ((uint32_t *) (t.result + level1_offset))[i];
1550       if (offset == 0)
1551         fprintf (stream, " %5d", -1);
1552       else
1553         fprintf (stream, " %5zu",
1554                  (offset - level2_offset) / sizeof (uint32_t));
1555       if (i+1 < t.level1_size)
1556         fprintf (stream, ",");
1557     }
1558   if (t.level1_size > 8)
1559     fprintf (stream, "\n ");
1560   fprintf (stream, " },\n");
1561   fprintf (stream, "  {");
1562   if (t.level2_size << t.q > 8)
1563     fprintf (stream, "\n   ");
1564   for (i = 0; i < t.level2_size << t.q; i++)
1565     {
1566       uint32_t offset;
1567       if (i > 0 && (i % 8) == 0)
1568         fprintf (stream, "\n   ");
1569       offset = ((uint32_t *) (t.result + level2_offset))[i];
1570       if (offset == 0)
1571         fprintf (stream, " %5d", -1);
1572       else
1573         fprintf (stream, " %5zu",
1574                  (offset - level3_offset) / sizeof (uint8_t));
1575       if (i+1 < t.level2_size << t.q)
1576         fprintf (stream, ",");
1577     }
1578   if (t.level2_size << t.q > 8)
1579     fprintf (stream, "\n ");
1580   fprintf (stream, " },\n");
1581   /* Pack the level3 array.  Each entry needs 5 bits only.  Use 16-bit units,
1582      not 32-bit units, in order to make the lookup function easier.  */
1583   level3_packed =
1584     (uint16_t *)
1585     calloc ((t.level3_size << t.p) * 5 / 16 + 1, sizeof (uint16_t));
1586   for (i = 0; i < t.level3_size << t.p; i++)
1587     {
1588       unsigned int j = (i * 5) / 16;
1589       unsigned int k = (i * 5) % 16;
1590       uint32_t value = ((unsigned char *) (t.result + level3_offset))[i];
1591       value = level3_packed[j] | (level3_packed[j+1] << 16) | (value << k);
1592       level3_packed[j] = value & 0xffff;
1593       level3_packed[j+1] = value >> 16;
1594     }
1595   fprintf (stream, "  {");
1596   if ((t.level3_size << t.p) * 5 / 16 + 1 > 8)
1597     fprintf (stream, "\n   ");
1598   for (i = 0; i < (t.level3_size << t.p) * 5 / 16 + 1; i++)
1599     {
1600       if (i > 0 && (i % 8) == 0)
1601         fprintf (stream, "\n   ");
1602       fprintf (stream, " 0x%04x", level3_packed[i]);
1603       if (i+1 < (t.level3_size << t.p) * 5 / 16 + 1)
1604         fprintf (stream, ",");
1605     }
1606   if ((t.level3_size << t.p) * 5 / 16 + 1 > 8)
1607     fprintf (stream, "\n ");
1608   fprintf (stream, " }\n");
1609   free (level3_packed);
1610   fprintf (stream, "};\n");
1611
1612   if (ferror (stream) || fclose (stream))
1613     {
1614       fprintf (stderr, "error writing to '%s'\n", filename);
1615       exit (1);
1616     }
1617 }
1618
1619 /* ========================================================================= */
1620
1621 /* Decimal digit value.  */
1622 /* See Unicode 3.0 book, section 4.6.  */
1623
1624 static int
1625 get_decdigit_value (unsigned int ch)
1626 {
1627   if (unicode_attributes[ch].name != NULL
1628       && unicode_attributes[ch].decdigit[0] != '\0')
1629     return atoi (unicode_attributes[ch].decdigit);
1630   return -1;
1631 }
1632
1633 /* Construction of sparse 3-level tables.  */
1634 #define TABLE decdigit_table
1635 #define ELEMENT uint8_t
1636 #define DEFAULT 0
1637 #define xmalloc malloc
1638 #define xrealloc realloc
1639 #include "3level.h"
1640
1641 /* Output the unit test for the per-character decimal digit value table.  */
1642 static void
1643 output_decimal_digit_test (const char *filename, const char *version)
1644 {
1645   FILE *stream;
1646   bool need_comma;
1647   unsigned int ch;
1648
1649   stream = fopen (filename, "w");
1650   if (stream == NULL)
1651     {
1652       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1653       exit (1);
1654     }
1655
1656   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1657   fprintf (stream, "/* Decimal digit values of Unicode characters.  */\n");
1658   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
1659            version);
1660
1661   need_comma = false;
1662   for (ch = 0; ch < 0x110000; ch++)
1663     {
1664       int value = get_decdigit_value (ch);
1665
1666       if (!(value >= -1 && value < 10))
1667         abort ();
1668
1669       if (value >= 0)
1670         {
1671           if (need_comma)
1672             fprintf (stream, ",\n");
1673           fprintf (stream, "    { 0x%04X, %d }", ch, value);
1674           need_comma = true;
1675         }
1676     }
1677   if (need_comma)
1678     fprintf (stream, "\n");
1679
1680   if (ferror (stream) || fclose (stream))
1681     {
1682       fprintf (stderr, "error writing to '%s'\n", filename);
1683       exit (1);
1684     }
1685 }
1686
1687 /* Output the per-character decimal digit value table.  */
1688 static void
1689 output_decimal_digit (const char *filename, const char *version)
1690 {
1691   FILE *stream;
1692   unsigned int ch, i;
1693   struct decdigit_table t;
1694   unsigned int level1_offset, level2_offset, level3_offset;
1695
1696   stream = fopen (filename, "w");
1697   if (stream == NULL)
1698     {
1699       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1700       exit (1);
1701     }
1702
1703   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1704   fprintf (stream, "/* Decimal digit values of Unicode characters.  */\n");
1705   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
1706            version);
1707
1708   t.p = 7;
1709   t.q = 9;
1710   decdigit_table_init (&t);
1711
1712   for (ch = 0; ch < 0x110000; ch++)
1713     {
1714       int value = 1 + get_decdigit_value (ch);
1715
1716       if (!(value >= 0 && value <= 10))
1717         abort ();
1718
1719       decdigit_table_add (&t, ch, value);
1720     }
1721
1722   decdigit_table_finalize (&t);
1723
1724   /* Offsets in t.result, in memory of this process.  */
1725   level1_offset =
1726     5 * sizeof (uint32_t);
1727   level2_offset =
1728     5 * sizeof (uint32_t)
1729     + t.level1_size * sizeof (uint32_t);
1730   level3_offset =
1731     5 * sizeof (uint32_t)
1732     + t.level1_size * sizeof (uint32_t)
1733     + (t.level2_size << t.q) * sizeof (uint32_t);
1734
1735   for (i = 0; i < 5; i++)
1736     fprintf (stream, "#define decdigit_header_%d %d\n", i,
1737              ((uint32_t *) t.result)[i]);
1738   fprintf (stream, "static const\n");
1739   fprintf (stream, "struct\n");
1740   fprintf (stream, "  {\n");
1741   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1742   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1743   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size,
1744            t.p - 1);
1745   fprintf (stream, "  }\n");
1746   fprintf (stream, "u_decdigit =\n");
1747   fprintf (stream, "{\n");
1748   fprintf (stream, "  {");
1749   if (t.level1_size > 8)
1750     fprintf (stream, "\n   ");
1751   for (i = 0; i < t.level1_size; i++)
1752     {
1753       uint32_t offset;
1754       if (i > 0 && (i % 8) == 0)
1755         fprintf (stream, "\n   ");
1756       offset = ((uint32_t *) (t.result + level1_offset))[i];
1757       if (offset == 0)
1758         fprintf (stream, " %5d", -1);
1759       else
1760         fprintf (stream, " %5zu",
1761                  (offset - level2_offset) / sizeof (uint32_t));
1762       if (i+1 < t.level1_size)
1763         fprintf (stream, ",");
1764     }
1765   if (t.level1_size > 8)
1766     fprintf (stream, "\n ");
1767   fprintf (stream, " },\n");
1768   fprintf (stream, "  {");
1769   if (t.level2_size << t.q > 8)
1770     fprintf (stream, "\n   ");
1771   for (i = 0; i < t.level2_size << t.q; i++)
1772     {
1773       uint32_t offset;
1774       if (i > 0 && (i % 8) == 0)
1775         fprintf (stream, "\n   ");
1776       offset = ((uint32_t *) (t.result + level2_offset))[i];
1777       if (offset == 0)
1778         fprintf (stream, " %5d", -1);
1779       else
1780         fprintf (stream, " %5zu",
1781                  (offset - level3_offset) / sizeof (uint8_t));
1782       if (i+1 < t.level2_size << t.q)
1783         fprintf (stream, ",");
1784     }
1785   if (t.level2_size << t.q > 8)
1786     fprintf (stream, "\n ");
1787   fprintf (stream, " },\n");
1788   /* Pack the level3 array.  Each entry needs 4 bits only.  */
1789   fprintf (stream, "  {");
1790   if (t.level3_size << (t.p - 1) > 8)
1791     fprintf (stream, "\n   ");
1792   for (i = 0; i < t.level3_size << (t.p - 1); i++)
1793     {
1794       if (i > 0 && (i % 8) == 0)
1795         fprintf (stream, "\n   ");
1796       fprintf (stream, " 0x%02x",
1797                ((uint8_t *) (t.result + level3_offset))[2*i]
1798                + (((uint8_t *) (t.result + level3_offset))[2*i+1] << 4));
1799       if (i+1 < t.level3_size << (t.p - 1))
1800         fprintf (stream, ",");
1801     }
1802   if (t.level3_size << (t.p - 1) > 8)
1803     fprintf (stream, "\n ");
1804   fprintf (stream, " }\n");
1805   fprintf (stream, "};\n");
1806
1807   if (ferror (stream) || fclose (stream))
1808     {
1809       fprintf (stderr, "error writing to '%s'\n", filename);
1810       exit (1);
1811     }
1812 }
1813
1814 /* ========================================================================= */
1815
1816 /* Digit value.  */
1817 /* See Unicode 3.0 book, section 4.6.  */
1818
1819 static int
1820 get_digit_value (unsigned int ch)
1821 {
1822   if (unicode_attributes[ch].name != NULL
1823       && unicode_attributes[ch].digit[0] != '\0')
1824     return atoi (unicode_attributes[ch].digit);
1825   return -1;
1826 }
1827
1828 /* Output the unit test for the per-character digit value table.  */
1829 static void
1830 output_digit_test (const char *filename, const char *version)
1831 {
1832   FILE *stream;
1833   bool need_comma;
1834   unsigned int ch;
1835
1836   stream = fopen (filename, "w");
1837   if (stream == NULL)
1838     {
1839       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1840       exit (1);
1841     }
1842
1843   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1844   fprintf (stream, "/* Digit values of Unicode characters.  */\n");
1845   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
1846            version);
1847
1848   need_comma = false;
1849   for (ch = 0; ch < 0x110000; ch++)
1850     {
1851       int value = get_digit_value (ch);
1852
1853       if (!(value >= -1 && value < 10))
1854         abort ();
1855
1856       if (value >= 0)
1857         {
1858           if (need_comma)
1859             fprintf (stream, ",\n");
1860           fprintf (stream, "    { 0x%04X, %d }", ch, value);
1861           need_comma = true;
1862         }
1863     }
1864   if (need_comma)
1865     fprintf (stream, "\n");
1866
1867   if (ferror (stream) || fclose (stream))
1868     {
1869       fprintf (stderr, "error writing to '%s'\n", filename);
1870       exit (1);
1871     }
1872 }
1873
1874 /* Output the per-character digit value table.  */
1875 static void
1876 output_digit (const char *filename, const char *version)
1877 {
1878   FILE *stream;
1879   unsigned int ch, i;
1880   struct decdigit_table t;
1881   unsigned int level1_offset, level2_offset, level3_offset;
1882
1883   stream = fopen (filename, "w");
1884   if (stream == NULL)
1885     {
1886       fprintf (stderr, "cannot open '%s' for writing\n", filename);
1887       exit (1);
1888     }
1889
1890   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
1891   fprintf (stream, "/* Digit values of Unicode characters.  */\n");
1892   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
1893            version);
1894
1895   t.p = 7;
1896   t.q = 9;
1897   decdigit_table_init (&t);
1898
1899   for (ch = 0; ch < 0x110000; ch++)
1900     {
1901       int value = 1 + get_digit_value (ch);
1902
1903       if (!(value >= 0 && value <= 10))
1904         abort ();
1905
1906       decdigit_table_add (&t, ch, value);
1907     }
1908
1909   decdigit_table_finalize (&t);
1910
1911   /* Offsets in t.result, in memory of this process.  */
1912   level1_offset =
1913     5 * sizeof (uint32_t);
1914   level2_offset =
1915     5 * sizeof (uint32_t)
1916     + t.level1_size * sizeof (uint32_t);
1917   level3_offset =
1918     5 * sizeof (uint32_t)
1919     + t.level1_size * sizeof (uint32_t)
1920     + (t.level2_size << t.q) * sizeof (uint32_t);
1921
1922   for (i = 0; i < 5; i++)
1923     fprintf (stream, "#define digit_header_%d %d\n", i,
1924              ((uint32_t *) t.result)[i]);
1925   fprintf (stream, "static const\n");
1926   fprintf (stream, "struct\n");
1927   fprintf (stream, "  {\n");
1928   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
1929   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
1930   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size,
1931            t.p - 1);
1932   fprintf (stream, "  }\n");
1933   fprintf (stream, "u_digit =\n");
1934   fprintf (stream, "{\n");
1935   fprintf (stream, "  {");
1936   if (t.level1_size > 8)
1937     fprintf (stream, "\n   ");
1938   for (i = 0; i < t.level1_size; i++)
1939     {
1940       uint32_t offset;
1941       if (i > 0 && (i % 8) == 0)
1942         fprintf (stream, "\n   ");
1943       offset = ((uint32_t *) (t.result + level1_offset))[i];
1944       if (offset == 0)
1945         fprintf (stream, " %5d", -1);
1946       else
1947         fprintf (stream, " %5zu",
1948                  (offset - level2_offset) / sizeof (uint32_t));
1949       if (i+1 < t.level1_size)
1950         fprintf (stream, ",");
1951     }
1952   if (t.level1_size > 8)
1953     fprintf (stream, "\n ");
1954   fprintf (stream, " },\n");
1955   fprintf (stream, "  {");
1956   if (t.level2_size << t.q > 8)
1957     fprintf (stream, "\n   ");
1958   for (i = 0; i < t.level2_size << t.q; i++)
1959     {
1960       uint32_t offset;
1961       if (i > 0 && (i % 8) == 0)
1962         fprintf (stream, "\n   ");
1963       offset = ((uint32_t *) (t.result + level2_offset))[i];
1964       if (offset == 0)
1965         fprintf (stream, " %5d", -1);
1966       else
1967         fprintf (stream, " %5zu",
1968                  (offset - level3_offset) / sizeof (uint8_t));
1969       if (i+1 < t.level2_size << t.q)
1970         fprintf (stream, ",");
1971     }
1972   if (t.level2_size << t.q > 8)
1973     fprintf (stream, "\n ");
1974   fprintf (stream, " },\n");
1975   /* Pack the level3 array.  Each entry needs 4 bits only.  */
1976   fprintf (stream, "  {");
1977   if (t.level3_size << (t.p - 1) > 8)
1978     fprintf (stream, "\n   ");
1979   for (i = 0; i < t.level3_size << (t.p - 1); i++)
1980     {
1981       if (i > 0 && (i % 8) == 0)
1982         fprintf (stream, "\n   ");
1983       fprintf (stream, " 0x%02x",
1984                ((uint8_t *) (t.result + level3_offset))[2*i]
1985                + (((uint8_t *) (t.result + level3_offset))[2*i+1] << 4));
1986       if (i+1 < t.level3_size << (t.p - 1))
1987         fprintf (stream, ",");
1988     }
1989   if (t.level3_size << (t.p - 1) > 8)
1990     fprintf (stream, "\n ");
1991   fprintf (stream, " }\n");
1992   fprintf (stream, "};\n");
1993
1994   if (ferror (stream) || fclose (stream))
1995     {
1996       fprintf (stderr, "error writing to '%s'\n", filename);
1997       exit (1);
1998     }
1999 }
2000
2001 /* ========================================================================= */
2002
2003 /* Numeric value.  */
2004 /* See Unicode 3.0 book, section 4.6.  */
2005
2006 typedef struct { int numerator; int denominator; } uc_fraction_t;
2007
2008 static uc_fraction_t
2009 get_numeric_value (unsigned int ch)
2010 {
2011   uc_fraction_t value;
2012
2013   if (unicode_attributes[ch].name != NULL
2014       && unicode_attributes[ch].numeric[0] != '\0')
2015     {
2016       const char *str = unicode_attributes[ch].numeric;
2017       /* str is of the form "integer" or "integer/posinteger".  */
2018       value.numerator = atoi (str);
2019       if (strchr (str, '/') != NULL)
2020         value.denominator = atoi (strchr (str, '/') + 1);
2021       else
2022         value.denominator = 1;
2023     }
2024   else
2025     {
2026       value.numerator = 0;
2027       value.denominator = 0;
2028     }
2029   return value;
2030 }
2031
2032 /* Output the unit test for the per-character numeric value table.  */
2033 static void
2034 output_numeric_test (const char *filename, const char *version)
2035 {
2036   FILE *stream;
2037   bool need_comma;
2038   unsigned int ch;
2039
2040   stream = fopen (filename, "w");
2041   if (stream == NULL)
2042     {
2043       fprintf (stderr, "cannot open '%s' for writing\n", filename);
2044       exit (1);
2045     }
2046
2047   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
2048   fprintf (stream, "/* Numeric values of Unicode characters.  */\n");
2049   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
2050            version);
2051
2052   need_comma = false;
2053   for (ch = 0; ch < 0x110000; ch++)
2054     {
2055       uc_fraction_t value = get_numeric_value (ch);
2056
2057       if (value.numerator != 0 || value.denominator != 0)
2058         {
2059           if (need_comma)
2060             fprintf (stream, ",\n");
2061           fprintf (stream, "    { 0x%04X, %d, %d }",
2062                    ch, value.numerator, value.denominator);
2063           need_comma = true;
2064         }
2065     }
2066   if (need_comma)
2067     fprintf (stream, "\n");
2068
2069   if (ferror (stream) || fclose (stream))
2070     {
2071       fprintf (stderr, "error writing to '%s'\n", filename);
2072       exit (1);
2073     }
2074 }
2075
2076 /* Construction of sparse 3-level tables.  */
2077 #define TABLE numeric_table
2078 #define ELEMENT uint8_t
2079 #define DEFAULT 0
2080 #define xmalloc malloc
2081 #define xrealloc realloc
2082 #include "3level.h"
2083
2084 /* Output the per-character numeric value table.  */
2085 static void
2086 output_numeric (const char *filename, const char *version)
2087 {
2088   FILE *stream;
2089   uc_fraction_t fractions[128];
2090   unsigned int nfractions;
2091   unsigned int ch, i, j;
2092   struct numeric_table t;
2093   unsigned int level1_offset, level2_offset, level3_offset;
2094   uint16_t *level3_packed;
2095
2096   stream = fopen (filename, "w");
2097   if (stream == NULL)
2098     {
2099       fprintf (stderr, "cannot open '%s' for writing\n", filename);
2100       exit (1);
2101     }
2102
2103   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
2104   fprintf (stream, "/* Numeric values of Unicode characters.  */\n");
2105   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
2106            version);
2107
2108   /* Create table of occurring fractions.  */
2109   nfractions = 0;
2110   for (ch = 0; ch < 0x110000; ch++)
2111     {
2112       uc_fraction_t value = get_numeric_value (ch);
2113
2114       for (i = 0; i < nfractions; i++)
2115         if (value.numerator == fractions[i].numerator
2116             && value.denominator == fractions[i].denominator)
2117           break;
2118       if (i == nfractions)
2119         {
2120           if (nfractions == 128)
2121             abort ();
2122           for (i = 0; i < nfractions; i++)
2123             if (value.denominator < fractions[i].denominator
2124                 || (value.denominator == fractions[i].denominator
2125                     && value.numerator < fractions[i].numerator))
2126               break;
2127           for (j = nfractions; j > i; j--)
2128             fractions[j] = fractions[j - 1];
2129           fractions[i] = value;
2130           nfractions++;
2131         }
2132     }
2133
2134   fprintf (stream, "static const uc_fraction_t u_numeric_values[%d] =\n",
2135            nfractions);
2136   fprintf (stream, "{\n");
2137   for (i = 0; i < nfractions; i++)
2138     {
2139       fprintf (stream, "  { %d, %d }", fractions[i].numerator,
2140                fractions[i].denominator);
2141       if (i+1 < nfractions)
2142         fprintf (stream, ",");
2143       fprintf (stream, "\n");
2144     }
2145   fprintf (stream, "};\n");
2146
2147   t.p = 7;
2148   t.q = 9;
2149   numeric_table_init (&t);
2150
2151   for (ch = 0; ch < 0x110000; ch++)
2152     {
2153       uc_fraction_t value = get_numeric_value (ch);
2154
2155       for (i = 0; i < nfractions; i++)
2156         if (value.numerator == fractions[i].numerator
2157             && value.denominator == fractions[i].denominator)
2158           break;
2159       if (i == nfractions)
2160         abort ();
2161
2162       numeric_table_add (&t, ch, i);
2163     }
2164
2165   numeric_table_finalize (&t);
2166
2167   /* Offsets in t.result, in memory of this process.  */
2168   level1_offset =
2169     5 * sizeof (uint32_t);
2170   level2_offset =
2171     5 * sizeof (uint32_t)
2172     + t.level1_size * sizeof (uint32_t);
2173   level3_offset =
2174     5 * sizeof (uint32_t)
2175     + t.level1_size * sizeof (uint32_t)
2176     + (t.level2_size << t.q) * sizeof (uint32_t);
2177
2178   for (i = 0; i < 5; i++)
2179     fprintf (stream, "#define numeric_header_%d %d\n", i,
2180              ((uint32_t *) t.result)[i]);
2181   fprintf (stream, "static const\n");
2182   fprintf (stream, "struct\n");
2183   fprintf (stream, "  {\n");
2184   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
2185   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
2186   fprintf (stream, "    unsigned short level3[%zu * %d + 1];\n", t.level3_size,
2187            (1 << t.p) * 7 / 16);
2188   fprintf (stream, "  }\n");
2189   fprintf (stream, "u_numeric =\n");
2190   fprintf (stream, "{\n");
2191   fprintf (stream, "  {");
2192   if (t.level1_size > 8)
2193     fprintf (stream, "\n   ");
2194   for (i = 0; i < t.level1_size; i++)
2195     {
2196       uint32_t offset;
2197       if (i > 0 && (i % 8) == 0)
2198         fprintf (stream, "\n   ");
2199       offset = ((uint32_t *) (t.result + level1_offset))[i];
2200       if (offset == 0)
2201         fprintf (stream, " %5d", -1);
2202       else
2203         fprintf (stream, " %5zu",
2204                  (offset - level2_offset) / sizeof (uint32_t));
2205       if (i+1 < t.level1_size)
2206         fprintf (stream, ",");
2207     }
2208   if (t.level1_size > 8)
2209     fprintf (stream, "\n ");
2210   fprintf (stream, " },\n");
2211   fprintf (stream, "  {");
2212   if (t.level2_size << t.q > 8)
2213     fprintf (stream, "\n   ");
2214   for (i = 0; i < t.level2_size << t.q; i++)
2215     {
2216       uint32_t offset;
2217       if (i > 0 && (i % 8) == 0)
2218         fprintf (stream, "\n   ");
2219       offset = ((uint32_t *) (t.result + level2_offset))[i];
2220       if (offset == 0)
2221         fprintf (stream, " %5d", -1);
2222       else
2223         fprintf (stream, " %5zu",
2224                  (offset - level3_offset) / sizeof (uint8_t));
2225       if (i+1 < t.level2_size << t.q)
2226         fprintf (stream, ",");
2227     }
2228   if (t.level2_size << t.q > 8)
2229     fprintf (stream, "\n ");
2230   fprintf (stream, " },\n");
2231   /* Pack the level3 array.  Each entry needs 7 bits only.  Use 16-bit units,
2232      not 32-bit units, in order to make the lookup function easier.  */
2233   level3_packed =
2234     (uint16_t *)
2235     calloc ((t.level3_size << t.p) * 7 / 16 + 1, sizeof (uint16_t));
2236   for (i = 0; i < t.level3_size << t.p; i++)
2237     {
2238       unsigned int j = (i * 7) / 16;
2239       unsigned int k = (i * 7) % 16;
2240       uint32_t value = ((unsigned char *) (t.result + level3_offset))[i];
2241       value = level3_packed[j] | (level3_packed[j+1] << 16) | (value << k);
2242       level3_packed[j] = value & 0xffff;
2243       level3_packed[j+1] = value >> 16;
2244     }
2245   fprintf (stream, "  {");
2246   if ((t.level3_size << t.p) * 7 / 16 + 1 > 8)
2247     fprintf (stream, "\n   ");
2248   for (i = 0; i < (t.level3_size << t.p) * 7 / 16 + 1; i++)
2249     {
2250       if (i > 0 && (i % 8) == 0)
2251         fprintf (stream, "\n   ");
2252       fprintf (stream, " 0x%04x", level3_packed[i]);
2253       if (i+1 < (t.level3_size << t.p) * 7 / 16 + 1)
2254         fprintf (stream, ",");
2255     }
2256   if ((t.level3_size << t.p) * 7 / 16 + 1 > 8)
2257     fprintf (stream, "\n ");
2258   fprintf (stream, " }\n");
2259   free (level3_packed);
2260   fprintf (stream, "};\n");
2261
2262   if (ferror (stream) || fclose (stream))
2263     {
2264       fprintf (stderr, "error writing to '%s'\n", filename);
2265       exit (1);
2266     }
2267 }
2268
2269 /* ========================================================================= */
2270
2271 /* Mirrored.  */
2272 /* See Unicode 3.0 book, section 4.7,
2273        UAX #9.  */
2274
2275 /* List of mirrored character pairs.  This is a subset of the characters
2276    having the BidiMirrored property.  */
2277 static unsigned int mirror_pairs[][2] =
2278 {
2279   { 0x0028, 0x0029 },
2280   { 0x003C, 0x003E },
2281   { 0x005B, 0x005D },
2282   { 0x007B, 0x007D },
2283   { 0x00AB, 0x00BB },
2284   { 0x2039, 0x203A },
2285   { 0x2045, 0x2046 },
2286   { 0x207D, 0x207E },
2287   { 0x208D, 0x208E },
2288   { 0x2208, 0x220B },
2289   { 0x220A, 0x220D },
2290   { 0x223C, 0x223D },
2291   { 0x2243, 0x22CD },
2292   { 0x2252, 0x2253 },
2293   { 0x2254, 0x2255 },
2294   { 0x2264, 0x2265 },
2295   { 0x2266, 0x2267 },
2296   { 0x226A, 0x226B },
2297   { 0x2276, 0x2277 },
2298   { 0x2278, 0x2279 },
2299   { 0x227A, 0x227B },
2300   { 0x227C, 0x227D },
2301   { 0x2282, 0x2283 },
2302   { 0x2286, 0x2287 },
2303   { 0x228F, 0x2290 },
2304   { 0x2291, 0x2292 },
2305   { 0x22A2, 0x22A3 },
2306   { 0x22B0, 0x22B1 },
2307   { 0x22B2, 0x22B3 },
2308   { 0x22B4, 0x22B5 },
2309   { 0x22B6, 0x22B7 },
2310   { 0x22C9, 0x22CA },
2311   { 0x22CB, 0x22CC },
2312   { 0x22D0, 0x22D1 },
2313   { 0x22D6, 0x22D7 },
2314   { 0x22D8, 0x22D9 },
2315   { 0x22DA, 0x22DB },
2316   { 0x22DC, 0x22DD },
2317   { 0x22DE, 0x22DF },
2318   { 0x22F0, 0x22F1 },
2319   { 0x2308, 0x2309 },
2320   { 0x230A, 0x230B },
2321   { 0x2329, 0x232A },
2322   { 0x3008, 0x3009 },
2323   { 0x300A, 0x300B },
2324   { 0x300C, 0x300D },
2325   { 0x300E, 0x300F },
2326   { 0x3010, 0x3011 },
2327   { 0x3014, 0x3015 },
2328   { 0x3016, 0x3017 },
2329   { 0x3018, 0x3019 },
2330   { 0x301A, 0x301B }
2331 };
2332
2333 static int
2334 get_mirror_value (unsigned int ch)
2335 {
2336   bool mirrored;
2337   unsigned int mirror_char;
2338   unsigned int i;
2339
2340   mirrored = (unicode_attributes[ch].name != NULL
2341               && unicode_attributes[ch].mirrored);
2342   mirror_char = 0xfffd;
2343   for (i = 0; i < sizeof (mirror_pairs) / sizeof (mirror_pairs[0]); i++)
2344     if (ch == mirror_pairs[i][0])
2345       {
2346         mirror_char = mirror_pairs[i][1];
2347         break;
2348       }
2349     else if (ch == mirror_pairs[i][1])
2350       {
2351         mirror_char = mirror_pairs[i][0];
2352         break;
2353       }
2354   if (mirrored)
2355     return (int) mirror_char - (int) ch;
2356   else
2357     {
2358       if (mirror_char != 0xfffd)
2359         abort ();
2360       return 0;
2361     }
2362 }
2363
2364 /* Construction of sparse 3-level tables.  */
2365 #define TABLE mirror_table
2366 #define ELEMENT int32_t
2367 #define DEFAULT 0
2368 #define xmalloc malloc
2369 #define xrealloc realloc
2370 #include "3level.h"
2371
2372 /* Output the per-character mirror table.  */
2373 static void
2374 output_mirror (const char *filename, const char *version)
2375 {
2376   FILE *stream;
2377   unsigned int ch, i;
2378   struct mirror_table t;
2379   unsigned int level1_offset, level2_offset, level3_offset;
2380
2381   stream = fopen (filename, "w");
2382   if (stream == NULL)
2383     {
2384       fprintf (stderr, "cannot open '%s' for writing\n", filename);
2385       exit (1);
2386     }
2387
2388   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
2389   fprintf (stream, "/* Mirrored Unicode characters.  */\n");
2390   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
2391            version);
2392
2393   t.p = 7;
2394   t.q = 9;
2395   mirror_table_init (&t);
2396
2397   for (ch = 0; ch < 0x110000; ch++)
2398     {
2399       int value = get_mirror_value (ch);
2400
2401       mirror_table_add (&t, ch, value);
2402     }
2403
2404   mirror_table_finalize (&t);
2405
2406   /* Offsets in t.result, in memory of this process.  */
2407   level1_offset =
2408     5 * sizeof (uint32_t);
2409   level2_offset =
2410     5 * sizeof (uint32_t)
2411     + t.level1_size * sizeof (uint32_t);
2412   level3_offset =
2413     5 * sizeof (uint32_t)
2414     + t.level1_size * sizeof (uint32_t)
2415     + (t.level2_size << t.q) * sizeof (uint32_t);
2416
2417   for (i = 0; i < 5; i++)
2418     fprintf (stream, "#define mirror_header_%d %d\n", i,
2419              ((uint32_t *) t.result)[i]);
2420   fprintf (stream, "static const\n");
2421   fprintf (stream, "struct\n");
2422   fprintf (stream, "  {\n");
2423   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
2424   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
2425   fprintf (stream, "    int level3[%zu << %d];\n", t.level3_size, t.p);
2426   fprintf (stream, "  }\n");
2427   fprintf (stream, "u_mirror =\n");
2428   fprintf (stream, "{\n");
2429   fprintf (stream, "  {");
2430   if (t.level1_size > 8)
2431     fprintf (stream, "\n   ");
2432   for (i = 0; i < t.level1_size; i++)
2433     {
2434       uint32_t offset;
2435       if (i > 0 && (i % 8) == 0)
2436         fprintf (stream, "\n   ");
2437       offset = ((uint32_t *) (t.result + level1_offset))[i];
2438       if (offset == 0)
2439         fprintf (stream, " %5d", -1);
2440       else
2441         fprintf (stream, " %5zu",
2442                  (offset - level2_offset) / sizeof (uint32_t));
2443       if (i+1 < t.level1_size)
2444         fprintf (stream, ",");
2445     }
2446   if (t.level1_size > 8)
2447     fprintf (stream, "\n ");
2448   fprintf (stream, " },\n");
2449   fprintf (stream, "  {");
2450   if (t.level2_size << t.q > 8)
2451     fprintf (stream, "\n   ");
2452   for (i = 0; i < t.level2_size << t.q; i++)
2453     {
2454       uint32_t offset;
2455       if (i > 0 && (i % 8) == 0)
2456         fprintf (stream, "\n   ");
2457       offset = ((uint32_t *) (t.result + level2_offset))[i];
2458       if (offset == 0)
2459         fprintf (stream, " %5d", -1);
2460       else
2461         fprintf (stream, " %5zu",
2462                  (offset - level3_offset) / sizeof (int32_t));
2463       if (i+1 < t.level2_size << t.q)
2464         fprintf (stream, ",");
2465     }
2466   if (t.level2_size << t.q > 8)
2467     fprintf (stream, "\n ");
2468   fprintf (stream, " },\n");
2469   fprintf (stream, "  {");
2470   if (t.level3_size << t.p > 8)
2471     fprintf (stream, "\n   ");
2472   for (i = 0; i < t.level3_size << t.p; i++)
2473     {
2474       if (i > 0 && (i % 8) == 0)
2475         fprintf (stream, "\n   ");
2476       fprintf (stream, " %5d", ((int32_t *) (t.result + level3_offset))[i]);
2477       if (i+1 < t.level3_size << t.p)
2478         fprintf (stream, ",");
2479     }
2480   if (t.level3_size << t.p > 8)
2481     fprintf (stream, "\n ");
2482   fprintf (stream, " }\n");
2483   fprintf (stream, "};\n");
2484
2485   if (ferror (stream) || fclose (stream))
2486     {
2487       fprintf (stderr, "error writing to '%s'\n", filename);
2488       exit (1);
2489     }
2490 }
2491
2492 /* ========================================================================= */
2493
2494 /* Particular values of the word break property.  */
2495
2496 static bool
2497 is_WBP_MIDNUMLET (unsigned int ch)
2498 {
2499   return (ch == 0x0027 || ch == 0x002E || ch == 0x2018 || ch == 0x2019
2500           || ch == 0x2024 || ch == 0xFE52 || ch == 0xFF07 || ch == 0xFF0E);
2501 }
2502
2503 static bool
2504 is_WBP_MIDLETTER (unsigned int ch)
2505 {
2506   return (ch == 0x00B7 || ch == 0x05F4 || ch == 0x2027 || ch == 0x003A
2507           || ch == 0x0387 || ch == 0xFE13 || ch == 0xFE55 || ch == 0xFF1A);
2508 }
2509
2510 /* ========================================================================= */
2511
2512 /* Properties.  */
2513
2514 /* Reading PropList.txt and DerivedCoreProperties.txt.  */
2515 enum
2516 {
2517   /* PropList.txt */
2518   PROP_WHITE_SPACE,
2519   PROP_BIDI_CONTROL,
2520   PROP_JOIN_CONTROL,
2521   PROP_DASH,
2522   PROP_HYPHEN,
2523   PROP_QUOTATION_MARK,
2524   PROP_TERMINAL_PUNCTUATION,
2525   PROP_OTHER_MATH,
2526   PROP_HEX_DIGIT,
2527   PROP_ASCII_HEX_DIGIT,
2528   PROP_OTHER_ALPHABETIC,
2529   PROP_IDEOGRAPHIC,
2530   PROP_DIACRITIC,
2531   PROP_EXTENDER,
2532   PROP_OTHER_LOWERCASE,
2533   PROP_OTHER_UPPERCASE,
2534   PROP_NONCHARACTER_CODE_POINT,
2535   PROP_OTHER_GRAPHEME_EXTEND,
2536   PROP_IDS_BINARY_OPERATOR,
2537   PROP_IDS_TRINARY_OPERATOR,
2538   PROP_RADICAL,
2539   PROP_UNIFIED_IDEOGRAPH,
2540   PROP_OTHER_DEFAULT_IGNORABLE_CODE_POINT,
2541   PROP_DEPRECATED,
2542   PROP_SOFT_DOTTED,
2543   PROP_LOGICAL_ORDER_EXCEPTION,
2544   PROP_OTHER_ID_START,
2545   PROP_OTHER_ID_CONTINUE,
2546   PROP_STERM,
2547   PROP_VARIATION_SELECTOR,
2548   PROP_PATTERN_WHITE_SPACE,
2549   PROP_PATTERN_SYNTAX,
2550   /* DerivedCoreProperties.txt */
2551   PROP_MATH,
2552   PROP_ALPHABETIC,
2553   PROP_LOWERCASE,
2554   PROP_UPPERCASE,
2555   PROP_CASED,
2556   PROP_CASE_IGNORABLE,
2557   PROP_CHANGES_WHEN_LOWERCASED,
2558   PROP_CHANGES_WHEN_UPPERCASED,
2559   PROP_CHANGES_WHEN_TITLECASED,
2560   PROP_CHANGES_WHEN_CASEFOLDED,
2561   PROP_CHANGES_WHEN_CASEMAPPED,
2562   PROP_ID_START,
2563   PROP_ID_CONTINUE,
2564   PROP_XID_START,
2565   PROP_XID_CONTINUE,
2566   PROP_DEFAULT_IGNORABLE_CODE_POINT,
2567   PROP_GRAPHEME_EXTEND,
2568   PROP_GRAPHEME_BASE,
2569   PROP_GRAPHEME_LINK
2570 };
2571 unsigned long long unicode_properties[0x110000];
2572
2573 static void
2574 clear_properties (void)
2575 {
2576   unsigned int i;
2577
2578   for (i = 0; i < 0x110000; i++)
2579     unicode_properties[i] = 0;
2580 }
2581
2582 /* Stores in unicode_properties[] the properties from the
2583    PropList.txt or DerivedCoreProperties.txt file.  */
2584 static void
2585 fill_properties (const char *proplist_filename)
2586 {
2587   unsigned int i;
2588   FILE *stream;
2589
2590   stream = fopen (proplist_filename, "r");
2591   if (stream == NULL)
2592     {
2593       fprintf (stderr, "error during fopen of '%s'\n", proplist_filename);
2594       exit (1);
2595     }
2596
2597   for (;;)
2598     {
2599       char buf[200+1];
2600       unsigned int i1, i2;
2601       char padding[200+1];
2602       char propname[200+1];
2603       unsigned int propvalue;
2604
2605       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
2606         break;
2607
2608       if (buf[0] == '\0' || buf[0] == '#')
2609         continue;
2610
2611       if (sscanf (buf, "%X..%X%[ ;]%[^ ]", &i1, &i2, padding, propname) != 4)
2612         {
2613           if (sscanf (buf, "%X%[ ;]%[^ ]", &i1, padding, propname) != 3)
2614             {
2615               fprintf (stderr, "parse error in '%s'\n", proplist_filename);
2616               exit (1);
2617             }
2618           i2 = i1;
2619         }
2620 #define PROP(name,value) \
2621       if (strcmp (propname, name) == 0) propvalue = value; else
2622       /* PropList.txt */
2623       PROP ("White_Space", PROP_WHITE_SPACE)
2624       PROP ("Bidi_Control", PROP_BIDI_CONTROL)
2625       PROP ("Join_Control", PROP_JOIN_CONTROL)
2626       PROP ("Dash", PROP_DASH)
2627       PROP ("Hyphen", PROP_HYPHEN)
2628       PROP ("Quotation_Mark", PROP_QUOTATION_MARK)
2629       PROP ("Terminal_Punctuation", PROP_TERMINAL_PUNCTUATION)
2630       PROP ("Other_Math", PROP_OTHER_MATH)
2631       PROP ("Hex_Digit", PROP_HEX_DIGIT)
2632       PROP ("ASCII_Hex_Digit", PROP_ASCII_HEX_DIGIT)
2633       PROP ("Other_Alphabetic", PROP_OTHER_ALPHABETIC)
2634       PROP ("Ideographic", PROP_IDEOGRAPHIC)
2635       PROP ("Diacritic", PROP_DIACRITIC)
2636       PROP ("Extender", PROP_EXTENDER)
2637       PROP ("Other_Lowercase", PROP_OTHER_LOWERCASE)
2638       PROP ("Other_Uppercase", PROP_OTHER_UPPERCASE)
2639       PROP ("Noncharacter_Code_Point", PROP_NONCHARACTER_CODE_POINT)
2640       PROP ("Other_Grapheme_Extend", PROP_OTHER_GRAPHEME_EXTEND)
2641       PROP ("IDS_Binary_Operator", PROP_IDS_BINARY_OPERATOR)
2642       PROP ("IDS_Trinary_Operator", PROP_IDS_TRINARY_OPERATOR)
2643       PROP ("Radical", PROP_RADICAL)
2644       PROP ("Unified_Ideograph", PROP_UNIFIED_IDEOGRAPH)
2645       PROP ("Other_Default_Ignorable_Code_Point", PROP_OTHER_DEFAULT_IGNORABLE_CODE_POINT)
2646       PROP ("Deprecated", PROP_DEPRECATED)
2647       PROP ("Soft_Dotted", PROP_SOFT_DOTTED)
2648       PROP ("Logical_Order_Exception", PROP_LOGICAL_ORDER_EXCEPTION)
2649       PROP ("Other_ID_Start", PROP_OTHER_ID_START)
2650       PROP ("Other_ID_Continue", PROP_OTHER_ID_CONTINUE)
2651       PROP ("STerm", PROP_STERM)
2652       PROP ("Variation_Selector", PROP_VARIATION_SELECTOR)
2653       PROP ("Pattern_White_Space", PROP_PATTERN_WHITE_SPACE)
2654       PROP ("Pattern_Syntax", PROP_PATTERN_SYNTAX)
2655       /* DerivedCoreProperties.txt */
2656       PROP ("Math", PROP_MATH)
2657       PROP ("Alphabetic", PROP_ALPHABETIC)
2658       PROP ("Lowercase", PROP_LOWERCASE)
2659       PROP ("Uppercase", PROP_UPPERCASE)
2660       PROP ("Cased", PROP_CASED)
2661       PROP ("Case_Ignorable", PROP_CASE_IGNORABLE)
2662       PROP ("Changes_When_Lowercased", PROP_CHANGES_WHEN_LOWERCASED)
2663       PROP ("Changes_When_Uppercased", PROP_CHANGES_WHEN_UPPERCASED)
2664       PROP ("Changes_When_Titlecased", PROP_CHANGES_WHEN_TITLECASED)
2665       PROP ("Changes_When_Casefolded", PROP_CHANGES_WHEN_CASEFOLDED)
2666       PROP ("Changes_When_Casemapped", PROP_CHANGES_WHEN_CASEMAPPED)
2667       PROP ("ID_Start", PROP_ID_START)
2668       PROP ("ID_Continue", PROP_ID_CONTINUE)
2669       PROP ("XID_Start", PROP_XID_START)
2670       PROP ("XID_Continue", PROP_XID_CONTINUE)
2671       PROP ("Default_Ignorable_Code_Point", PROP_DEFAULT_IGNORABLE_CODE_POINT)
2672       PROP ("Grapheme_Extend", PROP_GRAPHEME_EXTEND)
2673       PROP ("Grapheme_Base", PROP_GRAPHEME_BASE)
2674       PROP ("Grapheme_Link", PROP_GRAPHEME_LINK)
2675 #undef PROP
2676         {
2677           fprintf (stderr, "unknown property named '%s' in '%s'\n", propname,
2678                    proplist_filename);
2679           exit (1);
2680         }
2681       if (!(i1 <= i2 && i2 < 0x110000))
2682         abort ();
2683
2684       for (i = i1; i <= i2; i++)
2685         unicode_properties[i] |= 1ULL << propvalue;
2686     }
2687
2688   if (ferror (stream) || fclose (stream))
2689     {
2690       fprintf (stderr, "error reading from '%s'\n", proplist_filename);
2691       exit (1);
2692     }
2693 }
2694
2695 /* Stores in array the given property from the Unicode 3.0 PropList.txt
2696    file.  */
2697 static void
2698 fill_property30 (char array[0x110000], const char *proplist_filename, const char *property_name)
2699 {
2700   unsigned int i;
2701   FILE *stream;
2702   char buf[100+1];
2703
2704   for (i = 0; i < 0x110000; i++)
2705     array[i] = 0;
2706
2707   stream = fopen (proplist_filename, "r");
2708   if (stream == NULL)
2709     {
2710       fprintf (stderr, "error during fopen of '%s'\n", proplist_filename);
2711       exit (1);
2712     }
2713
2714   /* Search for the "Property dump for: ..." line.  */
2715   do
2716     {
2717       if (fscanf (stream, "%100[^\n]\n", buf) < 1)
2718         {
2719           fprintf (stderr, "no property found in '%s'\n", proplist_filename);
2720           exit (1);
2721         }
2722     }
2723   while (strstr (buf, property_name) == NULL);
2724
2725   for (;;)
2726     {
2727       unsigned int i1, i2;
2728
2729       if (fscanf (stream, "%100[^\n]\n", buf) < 1)
2730         break;
2731       if (buf[0] == '*')
2732         break;
2733       if (strlen (buf) >= 10 && buf[4] == '.' && buf[5] == '.')
2734         {
2735           if (sscanf (buf, "%4X..%4X", &i1, &i2) < 2)
2736             {
2737               fprintf (stderr, "parse error in property in '%s'\n",
2738                        proplist_filename);
2739               exit (1);
2740             }
2741         }
2742       else if (strlen (buf) >= 4)
2743         {
2744           if (sscanf (buf, "%4X", &i1) < 1)
2745             {
2746               fprintf (stderr, "parse error in property in '%s'\n",
2747                        proplist_filename);
2748               exit (1);
2749             }
2750           i2 = i1;
2751         }
2752       else
2753         {
2754           fprintf (stderr, "parse error in property in '%s'\n",
2755                    proplist_filename);
2756           exit (1);
2757         }
2758       if (!(i1 <= i2 && i2 < 0x110000))
2759         abort ();
2760       for (i = i1; i <= i2; i++)
2761         array[i] = 1;
2762     }
2763   if (ferror (stream) || fclose (stream))
2764     {
2765       fprintf (stderr, "error reading from '%s'\n", proplist_filename);
2766       exit (1);
2767     }
2768 }
2769
2770 /* Properties from Unicode 3.0 PropList.txt file.  */
2771
2772 /* The paired punctuation property from the PropList.txt file.  */
2773 char unicode_pairedpunctuation[0x110000];
2774
2775 /* The left of pair property from the PropList.txt file.  */
2776 char unicode_leftofpair[0x110000];
2777
2778 static void
2779 fill_properties30 (const char *proplist30_filename)
2780 {
2781   fill_property30 (unicode_pairedpunctuation, proplist30_filename, "(Paired Punctuation)");
2782   fill_property30 (unicode_leftofpair, proplist30_filename, "(Left of Pair)");
2783 }
2784
2785 /* ------------------------------------------------------------------------- */
2786
2787 /* See PropList.txt, UCD.html.  */
2788 static bool
2789 is_property_white_space (unsigned int ch)
2790 {
2791   return ((unicode_properties[ch] & (1ULL << PROP_WHITE_SPACE)) != 0);
2792 }
2793
2794 /* See Unicode 3.0 book, section 4.10,
2795        PropList.txt, UCD.html,
2796        DerivedCoreProperties.txt, UCD.html.  */
2797 static bool
2798 is_property_alphabetic (unsigned int ch)
2799 {
2800   bool result1 =
2801     is_category_L (ch)
2802     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_ALPHABETIC)) != 0)
2803     /* For some reason, the following are listed as having property
2804        Alphabetic but not as having property Other_Alphabetic.  */
2805     || (ch >= 0x16EE && ch <= 0x16F0) /* RUNIC SYMBOLS */
2806     || (ch >= 0x2160 && ch <= 0x2182) /* ROMAN NUMERALS */
2807     || (ch >= 0x2185 && ch <= 0x2188) /* ROMAN NUMERALS */
2808     || (ch >= 0x24D0 && ch <= 0x24E9) /* CIRCLED LATIN SMALL LETTER */
2809     || (ch == 0x3007) /* IDEOGRAPHIC NUMBER ZERO */
2810     || (ch >= 0x3021 && ch <= 0x3029) /* HANGZHOU NUMERAL */
2811     || (ch >= 0x3038 && ch <= 0x303A) /* HANGZHOU NUMERAL */
2812     || (ch >= 0xA6E6 && ch <= 0xA6EF) /* BAMUM LETTERS */
2813     || (ch >= 0x10140 && ch <= 0x10174) /* GREEK ACROPHONICS */
2814     || (ch == 0x10341) /* GOTHIC LETTER NINETY */
2815     || (ch == 0x1034A) /* GOTHIC LETTER NINE HUNDRED */
2816     || (ch >= 0x103D1 && ch <= 0x103D5) /* OLD PERSIAN NUMBERS */
2817     || (ch >= 0x12400 && ch <= 0x12462); /* CUNEIFORM NUMERIC SIGNS */
2818   bool result2 =
2819     ((unicode_properties[ch] & (1ULL << PROP_ALPHABETIC)) != 0);
2820
2821   if (result1 != result2)
2822     abort ();
2823   return result1;
2824 }
2825
2826 /* See PropList.txt, UCD.html.  */
2827 static bool
2828 is_property_other_alphabetic (unsigned int ch)
2829 {
2830   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_ALPHABETIC)) != 0);
2831 }
2832
2833 /* See PropList.txt, UCD.html.  */
2834 static bool
2835 is_property_not_a_character (unsigned int ch)
2836 {
2837   return ((unicode_properties[ch] & (1ULL << PROP_NONCHARACTER_CODE_POINT)) != 0);
2838 }
2839
2840 /* See PropList.txt, UCD.html,
2841        DerivedCoreProperties.txt, UCD.html.  */
2842 static bool
2843 is_property_default_ignorable_code_point (unsigned int ch)
2844 {
2845   bool result1 =
2846     (is_category_Cf (ch)
2847      && !(ch >= 0xFFF9 && ch <= 0xFFFB) /* Annotations */
2848      && !((ch >= 0x0600 && ch <= 0x0603) || ch == 0x06DD || ch == 0x070F)
2849      /* For some reason, the following are not listed as having property
2850         Default_Ignorable_Code_Point.  */
2851      && !(ch == 0x110BD))
2852     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_DEFAULT_IGNORABLE_CODE_POINT)) != 0)
2853     || ((unicode_properties[ch] & (1ULL << PROP_VARIATION_SELECTOR)) != 0);
2854   bool result2 =
2855     ((unicode_properties[ch] & (1ULL << PROP_DEFAULT_IGNORABLE_CODE_POINT)) != 0);
2856
2857   if (result1 != result2)
2858     abort ();
2859   return result1;
2860 }
2861
2862 /* See PropList.txt, UCD.html.  */
2863 static bool
2864 is_property_other_default_ignorable_code_point (unsigned int ch)
2865 {
2866   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_DEFAULT_IGNORABLE_CODE_POINT)) != 0);
2867 }
2868
2869 /* See PropList.txt, UCD.html.  */
2870 static bool
2871 is_property_deprecated (unsigned int ch)
2872 {
2873   return ((unicode_properties[ch] & (1ULL << PROP_DEPRECATED)) != 0);
2874 }
2875
2876 /* See PropList.txt, UCD.html.  */
2877 static bool
2878 is_property_logical_order_exception (unsigned int ch)
2879 {
2880   return ((unicode_properties[ch] & (1ULL << PROP_LOGICAL_ORDER_EXCEPTION)) != 0);
2881 }
2882
2883 /* See PropList.txt, UCD.html.  */
2884 static bool
2885 is_property_variation_selector (unsigned int ch)
2886 {
2887   return ((unicode_properties[ch] & (1ULL << PROP_VARIATION_SELECTOR)) != 0);
2888 }
2889
2890 /* See PropList-3.0.1.txt.  */
2891 static bool
2892 is_property_private_use (unsigned int ch)
2893 {
2894   /* Determined through "grep 'Private Use,' UnicodeData-3.1.0.txt".  */
2895   return (ch >= 0xE000 && ch <= 0xF8FF)
2896          || (ch >= 0xF0000 && ch <= 0xFFFFD)
2897          || (ch >= 0x100000 && ch <= 0x10FFFD);
2898 }
2899
2900 /* See PropList-3.0.1.txt.  */
2901 static bool
2902 is_property_unassigned_code_value (unsigned int ch)
2903 {
2904   return (is_category_Cn (ch) && !is_property_not_a_character (ch));
2905 }
2906
2907 /* See PropList.txt, UCD.html,
2908        DerivedCoreProperties.txt, UCD.html.  */
2909 static bool
2910 is_property_uppercase (unsigned int ch)
2911 {
2912   bool result1 =
2913     is_category_Lu (ch)
2914     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_UPPERCASE)) != 0);
2915   bool result2 =
2916     ((unicode_properties[ch] & (1ULL << PROP_UPPERCASE)) != 0);
2917
2918   if (result1 != result2)
2919     abort ();
2920   return result1;
2921 }
2922
2923 /* See PropList.txt, UCD.html.  */
2924 static bool
2925 is_property_other_uppercase (unsigned int ch)
2926 {
2927   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_UPPERCASE)) != 0);
2928 }
2929
2930 /* See PropList.txt, UCD.html,
2931        DerivedCoreProperties.txt, UCD.html.  */
2932 static bool
2933 is_property_lowercase (unsigned int ch)
2934 {
2935   bool result1 =
2936     is_category_Ll (ch)
2937     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_LOWERCASE)) != 0);
2938   bool result2 =
2939     ((unicode_properties[ch] & (1ULL << PROP_LOWERCASE)) != 0);
2940
2941   if (result1 != result2)
2942     abort ();
2943   return result1;
2944 }
2945
2946 /* See PropList.txt, UCD.html.  */
2947 static bool
2948 is_property_other_lowercase (unsigned int ch)
2949 {
2950   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_LOWERCASE)) != 0);
2951 }
2952
2953 /* See PropList-3.0.1.txt.  */
2954 static bool
2955 is_property_titlecase (unsigned int ch)
2956 {
2957   return is_category_Lt (ch);
2958 }
2959
2960 /* See DerivedCoreProperties.txt.  */
2961 static bool
2962 is_property_cased (unsigned int ch)
2963 {
2964   bool result1 = (is_property_lowercase (ch)
2965                   || is_property_uppercase (ch)
2966                   || is_category_Lt (ch));
2967   bool result2 = ((unicode_properties[ch] & (1ULL << PROP_CASED)) != 0);
2968
2969   if (result1 != result2)
2970     abort ();
2971   return result1;
2972 }
2973
2974 /* See DerivedCoreProperties.txt.  */
2975 static bool
2976 is_property_case_ignorable (unsigned int ch)
2977 {
2978   bool result1 = (is_WBP_MIDLETTER (ch) || is_WBP_MIDNUMLET (ch)
2979                   || is_category_Mn (ch)
2980                   || is_category_Me (ch)
2981                   || is_category_Cf (ch)
2982                   || is_category_Lm (ch)
2983                   || is_category_Sk (ch));
2984   bool result2 = ((unicode_properties[ch] & (1ULL << PROP_CASE_IGNORABLE)) != 0);
2985
2986   if (result1 != result2)
2987     abort ();
2988   return result1;
2989 }
2990
2991 /* See DerivedCoreProperties.txt.  */
2992 static bool
2993 is_property_changes_when_lowercased (unsigned int ch)
2994 {
2995   bool result1 = ((unicode_properties[ch] & (1ULL << PROP_CHANGES_WHEN_LOWERCASED)) != 0);
2996   bool result2 = (unicode_attributes[ch].name != NULL
2997                   && unicode_attributes[ch].lower != NONE
2998                   && unicode_attributes[ch].lower != ch);
2999
3000   if (result1 != result2)
3001     abort ();
3002   return result1;
3003 }
3004
3005 /* See DerivedCoreProperties.txt.  */
3006 static bool
3007 is_property_changes_when_uppercased (unsigned int ch)
3008 {
3009   return ((unicode_properties[ch] & (1ULL << PROP_CHANGES_WHEN_UPPERCASED)) != 0);
3010 }
3011
3012 /* See DerivedCoreProperties.txt.  */
3013 static bool
3014 is_property_changes_when_titlecased (unsigned int ch)
3015 {
3016   return ((unicode_properties[ch] & (1ULL << PROP_CHANGES_WHEN_TITLECASED)) != 0);
3017 }
3018
3019 /* See DerivedCoreProperties.txt.  */
3020 static bool
3021 is_property_changes_when_casefolded (unsigned int ch)
3022 {
3023   return ((unicode_properties[ch] & (1ULL << PROP_CHANGES_WHEN_CASEFOLDED)) != 0);
3024 }
3025
3026 /* See DerivedCoreProperties.txt.  */
3027 static bool
3028 is_property_changes_when_casemapped (unsigned int ch)
3029 {
3030   return ((unicode_properties[ch] & (1ULL << PROP_CHANGES_WHEN_CASEMAPPED)) != 0);
3031 }
3032
3033 /* See PropList.txt, UCD.html.  */
3034 static bool
3035 is_property_soft_dotted (unsigned int ch)
3036 {
3037   return ((unicode_properties[ch] & (1ULL << PROP_SOFT_DOTTED)) != 0);
3038 }
3039
3040 /* See DerivedCoreProperties.txt, UCD.html.  */
3041 static bool
3042 is_property_id_start (unsigned int ch)
3043 {
3044   return ((unicode_properties[ch] & (1ULL << PROP_ID_START)) != 0);
3045 }
3046
3047 /* See PropList.txt, UCD.html.  */
3048 static bool
3049 is_property_other_id_start (unsigned int ch)
3050 {
3051   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_ID_START)) != 0);
3052 }
3053
3054 /* See DerivedCoreProperties.txt, UCD.html.  */
3055 static bool
3056 is_property_id_continue (unsigned int ch)
3057 {
3058   return ((unicode_properties[ch] & (1ULL << PROP_ID_CONTINUE)) != 0);
3059 }
3060
3061 /* See PropList.txt, UCD.html.  */
3062 static bool
3063 is_property_other_id_continue (unsigned int ch)
3064 {
3065   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_ID_CONTINUE)) != 0);
3066 }
3067
3068 /* See DerivedCoreProperties.txt, UCD.html.  */
3069 static bool
3070 is_property_xid_start (unsigned int ch)
3071 {
3072   return ((unicode_properties[ch] & (1ULL << PROP_XID_START)) != 0);
3073 }
3074
3075 /* See DerivedCoreProperties.txt, UCD.html.  */
3076 static bool
3077 is_property_xid_continue (unsigned int ch)
3078 {
3079   return ((unicode_properties[ch] & (1ULL << PROP_XID_CONTINUE)) != 0);
3080 }
3081
3082 /* See PropList.txt, UCD.html.  */
3083 static bool
3084 is_property_pattern_white_space (unsigned int ch)
3085 {
3086   return ((unicode_properties[ch] & (1ULL << PROP_PATTERN_WHITE_SPACE)) != 0);
3087 }
3088
3089 /* See PropList.txt, UCD.html.  */
3090 static bool
3091 is_property_pattern_syntax (unsigned int ch)
3092 {
3093   return ((unicode_properties[ch] & (1ULL << PROP_PATTERN_SYNTAX)) != 0);
3094 }
3095
3096 /* See PropList.txt, UCD.html.  */
3097 static bool
3098 is_property_join_control (unsigned int ch)
3099 {
3100   return ((unicode_properties[ch] & (1ULL << PROP_JOIN_CONTROL)) != 0);
3101 }
3102
3103 /* See DerivedCoreProperties.txt, UCD.html.  */
3104 static bool
3105 is_property_grapheme_base (unsigned int ch)
3106 {
3107   return ((unicode_properties[ch] & (1ULL << PROP_GRAPHEME_BASE)) != 0);
3108 }
3109
3110 /* See DerivedCoreProperties.txt, UCD.html.  */
3111 static bool
3112 is_property_grapheme_extend (unsigned int ch)
3113 {
3114   return ((unicode_properties[ch] & (1ULL << PROP_GRAPHEME_EXTEND)) != 0);
3115 }
3116
3117 /* See PropList.txt, UCD.html.  */
3118 static bool
3119 is_property_other_grapheme_extend (unsigned int ch)
3120 {
3121   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_GRAPHEME_EXTEND)) != 0);
3122 }
3123
3124 /* See DerivedCoreProperties.txt, UCD.html.  */
3125 static bool
3126 is_property_grapheme_link (unsigned int ch)
3127 {
3128   return ((unicode_properties[ch] & (1ULL << PROP_GRAPHEME_LINK)) != 0);
3129 }
3130
3131 /* See PropList.txt, UCD.html.  */
3132 static bool
3133 is_property_bidi_control (unsigned int ch)
3134 {
3135   return ((unicode_properties[ch] & (1ULL << PROP_BIDI_CONTROL)) != 0);
3136 }
3137
3138 /* See PropList-3.0.1.txt.  */
3139 static bool
3140 is_property_bidi_left_to_right (unsigned int ch)
3141 {
3142   return (get_bidi_category (ch) == UC_BIDI_L);
3143 }
3144
3145 /* See PropList-3.0.1.txt.  */
3146 static bool
3147 is_property_bidi_hebrew_right_to_left (unsigned int ch)
3148 {
3149   return (get_bidi_category (ch) == UC_BIDI_R);
3150 }
3151
3152 /* See PropList-3.0.1.txt.  */
3153 static bool
3154 is_property_bidi_arabic_right_to_left (unsigned int ch)
3155 {
3156   return (get_bidi_category (ch) == UC_BIDI_AL);
3157 }
3158
3159 /* See PropList-3.0.1.txt.  */
3160 static bool
3161 is_property_bidi_european_digit (unsigned int ch)
3162 {
3163   return (get_bidi_category (ch) == UC_BIDI_EN);
3164 }
3165
3166 /* See PropList-3.0.1.txt.  */
3167 static bool
3168 is_property_bidi_eur_num_separator (unsigned int ch)
3169 {
3170   return (get_bidi_category (ch) == UC_BIDI_ES);
3171 }
3172
3173 /* See PropList-3.0.1.txt.  */
3174 static bool
3175 is_property_bidi_eur_num_terminator (unsigned int ch)
3176 {
3177   return (get_bidi_category (ch) == UC_BIDI_ET);
3178 }
3179
3180 /* See PropList-3.0.1.txt.  */
3181 static bool
3182 is_property_bidi_arabic_digit (unsigned int ch)
3183 {
3184   return (get_bidi_category (ch) == UC_BIDI_AN);
3185 }
3186
3187 /* See PropList-3.0.1.txt.  */
3188 static bool
3189 is_property_bidi_common_separator (unsigned int ch)
3190 {
3191   return (get_bidi_category (ch) == UC_BIDI_CS);
3192 }
3193
3194 /* See PropList-3.0.1.txt.  */
3195 static bool
3196 is_property_bidi_block_separator (unsigned int ch)
3197 {
3198   return (get_bidi_category (ch) == UC_BIDI_B);
3199 }
3200
3201 /* See PropList-3.0.1.txt.  */
3202 static bool
3203 is_property_bidi_segment_separator (unsigned int ch)
3204 {
3205   return (get_bidi_category (ch) == UC_BIDI_S);
3206 }
3207
3208 /* See PropList-3.0.1.txt.  */
3209 static bool
3210 is_property_bidi_whitespace (unsigned int ch)
3211 {
3212   return (get_bidi_category (ch) == UC_BIDI_WS);
3213 }
3214
3215 /* See PropList-3.0.1.txt.  */
3216 static bool
3217 is_property_bidi_non_spacing_mark (unsigned int ch)
3218 {
3219   return (get_bidi_category (ch) == UC_BIDI_NSM);
3220 }
3221
3222 /* See PropList-3.0.1.txt.  */
3223 static bool
3224 is_property_bidi_boundary_neutral (unsigned int ch)
3225 {
3226   return (get_bidi_category (ch) == UC_BIDI_BN);
3227 }
3228
3229 /* See PropList-3.0.1.txt.  */
3230 static bool
3231 is_property_bidi_pdf (unsigned int ch)
3232 {
3233   return (get_bidi_category (ch) == UC_BIDI_PDF);
3234 }
3235
3236 /* See PropList-3.0.1.txt.  */
3237 static bool
3238 is_property_bidi_embedding_or_override (unsigned int ch)
3239 {
3240   int category = get_bidi_category (ch);
3241   return (category == UC_BIDI_LRE || category == UC_BIDI_LRO
3242           || category == UC_BIDI_RLE || category == UC_BIDI_RLO);
3243 }
3244
3245 /* See PropList-3.0.1.txt.  */
3246 static bool
3247 is_property_bidi_other_neutral (unsigned int ch)
3248 {
3249   return (get_bidi_category (ch) == UC_BIDI_ON);
3250 }
3251
3252 /* See PropList.txt, UCD.html.  */
3253 static bool
3254 is_property_hex_digit (unsigned int ch)
3255 {
3256   return ((unicode_properties[ch] & (1ULL << PROP_HEX_DIGIT)) != 0);
3257 }
3258
3259 /* See PropList.txt, UCD.html.  */
3260 static bool
3261 is_property_ascii_hex_digit (unsigned int ch)
3262 {
3263   return ((unicode_properties[ch] & (1ULL << PROP_ASCII_HEX_DIGIT)) != 0);
3264 }
3265
3266 /* See Unicode 3.0 book, section 4.10,
3267        PropList.txt, UCD.html.  */
3268 static bool
3269 is_property_ideographic (unsigned int ch)
3270 {
3271   return ((unicode_properties[ch] & (1ULL << PROP_IDEOGRAPHIC)) != 0);
3272 }
3273
3274 /* See PropList.txt, UCD.html.  */
3275 static bool
3276 is_property_unified_ideograph (unsigned int ch)
3277 {
3278   return ((unicode_properties[ch] & (1ULL << PROP_UNIFIED_IDEOGRAPH)) != 0);
3279 }
3280
3281 /* See PropList.txt, UCD.html.  */
3282 static bool
3283 is_property_radical (unsigned int ch)
3284 {
3285   return ((unicode_properties[ch] & (1ULL << PROP_RADICAL)) != 0);
3286 }
3287
3288 /* See PropList.txt, UCD.html.  */
3289 static bool
3290 is_property_ids_binary_operator (unsigned int ch)
3291 {
3292   return ((unicode_properties[ch] & (1ULL << PROP_IDS_BINARY_OPERATOR)) != 0);
3293 }
3294
3295 /* See PropList.txt, UCD.html.  */
3296 static bool
3297 is_property_ids_trinary_operator (unsigned int ch)
3298 {
3299   return ((unicode_properties[ch] & (1ULL << PROP_IDS_TRINARY_OPERATOR)) != 0);
3300 }
3301
3302 /* See PropList-3.0.1.txt.  */
3303 static bool
3304 is_property_zero_width (unsigned int ch)
3305 {
3306   return is_category_Cf (ch)
3307          || (unicode_attributes[ch].name != NULL
3308              && strstr (unicode_attributes[ch].name, "ZERO WIDTH") != NULL);
3309 }
3310
3311 /* See PropList-3.0.1.txt.  */
3312 static bool
3313 is_property_space (unsigned int ch)
3314 {
3315   return is_category_Zs (ch);
3316 }
3317
3318 /* See PropList-3.0.1.txt.  */
3319 static bool
3320 is_property_non_break (unsigned int ch)
3321 {
3322   /* This is exactly the set of characters having line breaking
3323      property GL.  */
3324   return (ch == 0x00A0 /* NO-BREAK SPACE */
3325           || ch == 0x034F /* COMBINING GRAPHEME JOINER */
3326           || ch == 0x035C /* COMBINING DOUBLE BREVE BELOW */
3327           || ch == 0x035D /* COMBINING DOUBLE BREVE */
3328           || ch == 0x035E /* COMBINING DOUBLE MACRON */
3329           || ch == 0x035F /* COMBINING DOUBLE MACRON BELOW */
3330           || ch == 0x0360 /* COMBINING DOUBLE TILDE */
3331           || ch == 0x0361 /* COMBINING DOUBLE INVERTED BREVE */
3332           || ch == 0x0362 /* COMBINING DOUBLE RIGHTWARDS ARROW BELOW */
3333           || ch == 0x0F08 /* TIBETAN MARK SBRUL SHAD */
3334           || ch == 0x0F0C /* TIBETAN MARK DELIMITER TSHEG BSTAR */
3335           || ch == 0x0F12 /* TIBETAN MARK RGYA GRAM SHAD */
3336           || ch == 0x180E /* MONGOLIAN VOWEL SEPARATOR */
3337           || ch == 0x2007 /* FIGURE SPACE */
3338           || ch == 0x2011 /* NON-BREAKING HYPHEN */
3339           || ch == 0x202F /* NARROW NO-BREAK SPACE */);
3340 }
3341
3342 /* See PropList-3.0.1.txt.  */
3343 static bool
3344 is_property_iso_control (unsigned int ch)
3345 {
3346   bool result1 =
3347     (unicode_attributes[ch].name != NULL
3348      && strcmp (unicode_attributes[ch].name, "<control>") == 0);
3349   bool result2 =
3350     is_category_Cc (ch);
3351
3352   if (result1 != result2)
3353     abort ();
3354   return result1;
3355 }
3356
3357 /* See PropList-3.0.1.txt.  */
3358 static bool
3359 is_property_format_control (unsigned int ch)
3360 {
3361   return (is_category_Cf (ch)
3362           && get_bidi_category (ch) == UC_BIDI_BN
3363           && !is_property_join_control (ch)
3364           && ch != 0xFEFF);
3365 }
3366
3367 /* See PropList.txt, UCD.html.  */
3368 static bool
3369 is_property_dash (unsigned int ch)
3370 {
3371   return ((unicode_properties[ch] & (1ULL << PROP_DASH)) != 0);
3372 }
3373
3374 /* See PropList.txt, UCD.html.  */
3375 static bool
3376 is_property_hyphen (unsigned int ch)
3377 {
3378   return ((unicode_properties[ch] & (1ULL << PROP_HYPHEN)) != 0);
3379 }
3380
3381 /* See PropList-3.0.1.txt.  */
3382 static bool
3383 is_property_punctuation (unsigned int ch)
3384 {
3385   return is_category_P (ch);
3386 }
3387
3388 /* See PropList-3.0.1.txt.  */
3389 static bool
3390 is_property_line_separator (unsigned int ch)
3391 {
3392   return is_category_Zl (ch);
3393 }
3394
3395 /* See PropList-3.0.1.txt.  */
3396 static bool
3397 is_property_paragraph_separator (unsigned int ch)
3398 {
3399   return is_category_Zp (ch);
3400 }
3401
3402 /* See PropList.txt, UCD.html.  */
3403 static bool
3404 is_property_quotation_mark (unsigned int ch)
3405 {
3406   return ((unicode_properties[ch] & (1ULL << PROP_QUOTATION_MARK)) != 0);
3407 }
3408
3409 /* See PropList.txt, UCD.html.  */
3410 static bool
3411 is_property_sentence_terminal (unsigned int ch)
3412 {
3413   return ((unicode_properties[ch] & (1ULL << PROP_STERM)) != 0);
3414 }
3415
3416 /* See PropList.txt, UCD.html.  */
3417 static bool
3418 is_property_terminal_punctuation (unsigned int ch)
3419 {
3420   return ((unicode_properties[ch] & (1ULL << PROP_TERMINAL_PUNCTUATION)) != 0);
3421 }
3422
3423 /* See PropList-3.0.1.txt.  */
3424 static bool
3425 is_property_currency_symbol (unsigned int ch)
3426 {
3427   return is_category_Sc (ch);
3428 }
3429
3430 /* See Unicode 3.0 book, section 4.9,
3431        PropList.txt, UCD.html,
3432        DerivedCoreProperties.txt, UCD.html.  */
3433 static bool
3434 is_property_math (unsigned int ch)
3435 {
3436   bool result1 =
3437     is_category_Sm (ch)
3438     || ((unicode_properties[ch] & (1ULL << PROP_OTHER_MATH)) != 0);
3439   bool result2 =
3440     ((unicode_properties[ch] & (1ULL << PROP_MATH)) != 0);
3441
3442   if (result1 != result2)
3443     abort ();
3444   return result1;
3445 }
3446
3447 /* See PropList.txt, UCD.html.  */
3448 static bool
3449 is_property_other_math (unsigned int ch)
3450 {
3451   return ((unicode_properties[ch] & (1ULL << PROP_OTHER_MATH)) != 0);
3452 }
3453
3454 /* See PropList-3.0.1.txt.  */
3455 static bool
3456 is_property_paired_punctuation (unsigned int ch)
3457 {
3458   return unicode_pairedpunctuation[ch];
3459 }
3460
3461 /* See PropList-3.0.1.txt.  */
3462 static bool
3463 is_property_left_of_pair (unsigned int ch)
3464 {
3465   return unicode_leftofpair[ch];
3466 }
3467
3468 /* See PropList-3.0.1.txt.  */
3469 static bool
3470 is_property_combining (unsigned int ch)
3471 {
3472   return (unicode_attributes[ch].name != NULL
3473           && (strcmp (unicode_attributes[ch].combining, "0") != 0
3474               || is_category_Mc (ch)
3475               || is_category_Me (ch)
3476               || is_category_Mn (ch)));
3477 }
3478
3479 #if 0 /* same as is_property_bidi_non_spacing_mark */
3480 /* See PropList-3.0.1.txt.  */
3481 static bool
3482 is_property_non_spacing (unsigned int ch)
3483 {
3484   return (unicode_attributes[ch].name != NULL
3485           && get_bidi_category (ch) == UC_BIDI_NSM);
3486 }
3487 #endif
3488
3489 /* See PropList-3.0.1.txt.  */
3490 static bool
3491 is_property_composite (unsigned int ch)
3492 {
3493   /* This definition differs from the one in PropList-3.0.1.txt, but is more
3494      logical in some sense.  */
3495   if (ch >= 0xAC00 && ch <= 0xD7A4) /* Hangul Syllables */
3496     return true;
3497   if (unicode_attributes[ch].name != NULL
3498       && unicode_attributes[ch].decomposition != NULL)
3499     {
3500       /* Test whether the decomposition contains more than one character,
3501          and the first is not a space.  */
3502       const char *decomp = unicode_attributes[ch].decomposition;
3503       if (decomp[0] == '<')
3504         {
3505           decomp = strchr (decomp, '>') + 1;
3506           if (decomp[0] == ' ')
3507             decomp++;
3508         }
3509       return strchr (decomp, ' ') != NULL && strncmp (decomp, "0020 ", 5) != 0;
3510     }
3511   return false;
3512 }
3513
3514 /* See PropList-3.0.1.txt.  */
3515 static bool
3516 is_property_decimal_digit (unsigned int ch)
3517 {
3518   return is_category_Nd (ch);
3519 }
3520
3521 /* See PropList-3.0.1.txt.  */
3522 static bool
3523 is_property_numeric (unsigned int ch)
3524 {
3525   return ((get_numeric_value (ch)).denominator > 0)
3526          || (ch == 0x09F8) /* BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR */
3527          || (ch == 0x2183); /* ROMAN NUMERAL REVERSED ONE HUNDRED */
3528 }
3529
3530 /* See PropList.txt, UCD.html.  */
3531 static bool
3532 is_property_diacritic (unsigned int ch)
3533 {
3534   return ((unicode_properties[ch] & (1ULL << PROP_DIACRITIC)) != 0);
3535 }
3536
3537 /* See PropList.txt, UCD.html.  */
3538 static bool
3539 is_property_extender (unsigned int ch)
3540 {
3541   return ((unicode_properties[ch] & (1ULL << PROP_EXTENDER)) != 0);
3542 }
3543
3544 /* See PropList-3.0.1.txt.  */
3545 static bool
3546 is_property_ignorable_control (unsigned int ch)
3547 {
3548   return ((is_category_Cc (ch) && get_bidi_category (ch) == UC_BIDI_BN)
3549           || is_category_Cf (ch))
3550          && ch != 0x0000;
3551 }
3552
3553 /* ------------------------------------------------------------------------- */
3554
3555 /* Output all properties.  */
3556 static void
3557 output_properties (const char *version)
3558 {
3559 #define PROPERTY(P) \
3560   debug_output_predicate ("unictype/pr_" #P ".txt", is_property_ ## P); \
3561   output_predicate_test ("../tests/unictype/test-pr_" #P ".c", is_property_ ## P, "uc_is_property_" #P " (c)"); \
3562   output_predicate ("unictype/pr_" #P ".h", is_property_ ## P, "u_property_" #P, "Properties", version);
3563   PROPERTY(white_space)
3564   PROPERTY(alphabetic)
3565   PROPERTY(other_alphabetic)
3566   PROPERTY(not_a_character)
3567   PROPERTY(default_ignorable_code_point)
3568   PROPERTY(other_default_ignorable_code_point)
3569   PROPERTY(deprecated)
3570   PROPERTY(logical_order_exception)
3571   PROPERTY(variation_selector)
3572   PROPERTY(private_use)
3573   PROPERTY(unassigned_code_value)
3574   PROPERTY(uppercase)
3575   PROPERTY(other_uppercase)
3576   PROPERTY(lowercase)
3577   PROPERTY(other_lowercase)
3578   PROPERTY(titlecase)
3579   PROPERTY(cased)
3580   PROPERTY(case_ignorable)
3581   PROPERTY(changes_when_lowercased)
3582   PROPERTY(changes_when_uppercased)
3583   PROPERTY(changes_when_titlecased)
3584   PROPERTY(changes_when_casefolded)
3585   PROPERTY(changes_when_casemapped)
3586   PROPERTY(soft_dotted)
3587   PROPERTY(id_start)
3588   PROPERTY(other_id_start)
3589   PROPERTY(id_continue)
3590   PROPERTY(other_id_continue)
3591   PROPERTY(xid_start)
3592   PROPERTY(xid_continue)
3593   PROPERTY(pattern_white_space)
3594   PROPERTY(pattern_syntax)
3595   PROPERTY(join_control)
3596   PROPERTY(grapheme_base)
3597   PROPERTY(grapheme_extend)
3598   PROPERTY(other_grapheme_extend)
3599   PROPERTY(grapheme_link)
3600   PROPERTY(bidi_control)
3601   PROPERTY(bidi_left_to_right)
3602   PROPERTY(bidi_hebrew_right_to_left)
3603   PROPERTY(bidi_arabic_right_to_left)
3604   PROPERTY(bidi_european_digit)
3605   PROPERTY(bidi_eur_num_separator)
3606   PROPERTY(bidi_eur_num_terminator)
3607   PROPERTY(bidi_arabic_digit)
3608   PROPERTY(bidi_common_separator)
3609   PROPERTY(bidi_block_separator)
3610   PROPERTY(bidi_segment_separator)
3611   PROPERTY(bidi_whitespace)
3612   PROPERTY(bidi_non_spacing_mark)
3613   PROPERTY(bidi_boundary_neutral)
3614   PROPERTY(bidi_pdf)
3615   PROPERTY(bidi_embedding_or_override)
3616   PROPERTY(bidi_other_neutral)
3617   PROPERTY(hex_digit)
3618   PROPERTY(ascii_hex_digit)
3619   PROPERTY(ideographic)
3620   PROPERTY(unified_ideograph)
3621   PROPERTY(radical)
3622   PROPERTY(ids_binary_operator)
3623   PROPERTY(ids_trinary_operator)
3624   PROPERTY(zero_width)
3625   PROPERTY(space)
3626   PROPERTY(non_break)
3627   PROPERTY(iso_control)
3628   PROPERTY(format_control)
3629   PROPERTY(dash)
3630   PROPERTY(hyphen)
3631   PROPERTY(punctuation)
3632   PROPERTY(line_separator)
3633   PROPERTY(paragraph_separator)
3634   PROPERTY(quotation_mark)
3635   PROPERTY(sentence_terminal)
3636   PROPERTY(terminal_punctuation)
3637   PROPERTY(currency_symbol)
3638   PROPERTY(math)
3639   PROPERTY(other_math)
3640   PROPERTY(paired_punctuation)
3641   PROPERTY(left_of_pair)
3642   PROPERTY(combining)
3643   PROPERTY(composite)
3644   PROPERTY(decimal_digit)
3645   PROPERTY(numeric)
3646   PROPERTY(diacritic)
3647   PROPERTY(extender)
3648   PROPERTY(ignorable_control)
3649 #undef PROPERTY
3650 }
3651
3652 /* ========================================================================= */
3653
3654 /* Scripts.  */
3655
3656 static const char *scripts[256];
3657 static unsigned int numscripts;
3658
3659 static uint8_t unicode_scripts[0x110000];
3660
3661 static void
3662 fill_scripts (const char *scripts_filename)
3663 {
3664   FILE *stream;
3665   unsigned int i;
3666
3667   stream = fopen (scripts_filename, "r");
3668   if (stream == NULL)
3669     {
3670       fprintf (stderr, "error during fopen of '%s'\n", scripts_filename);
3671       exit (1);
3672     }
3673
3674   numscripts = 0;
3675
3676   for (i = 0; i < 0x110000; i++)
3677     unicode_scripts[i] = (uint8_t)~(uint8_t)0;
3678
3679   for (;;)
3680     {
3681       char buf[200+1];
3682       unsigned int i1, i2;
3683       char padding[200+1];
3684       char scriptname[200+1];
3685       int script;
3686
3687       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
3688         break;
3689
3690       if (buf[0] == '\0' || buf[0] == '#')
3691         continue;
3692
3693       if (sscanf (buf, "%X..%X%[ ;]%[^ ]", &i1, &i2, padding, scriptname) != 4)
3694         {
3695           if (sscanf (buf, "%X%[ ;]%[^ ]", &i1, padding, scriptname) != 3)
3696             {
3697               fprintf (stderr, "parse error in '%s'\n", scripts_filename);
3698               exit (1);
3699             }
3700           i2 = i1;
3701         }
3702       if (i2 < i1)
3703         abort ();
3704       if (i2 >= 0x110000)
3705         abort ();
3706
3707       for (script = numscripts - 1; script >= 0; script--)
3708         if (strcmp (scripts[script], scriptname) == 0)
3709           break;
3710       if (script < 0)
3711         {
3712           scripts[numscripts] = strdup (scriptname);
3713           script = numscripts;
3714           numscripts++;
3715           if (numscripts == 256)
3716             abort ();
3717         }
3718
3719       for (i = i1; i <= i2; i++)
3720         {
3721           if (unicode_scripts[i] != (uint8_t)~(uint8_t)0)
3722             fprintf (stderr, "0x%04X belongs to multiple scripts\n", i);
3723           unicode_scripts[i] = script;
3724         }
3725     }
3726
3727   if (ferror (stream) || fclose (stream))
3728     {
3729       fprintf (stderr, "error reading from '%s'\n", scripts_filename);
3730       exit (1);
3731     }
3732 }
3733
3734 /* Construction of sparse 3-level tables.  */
3735 #define TABLE script_table
3736 #define ELEMENT uint8_t
3737 #define DEFAULT (uint8_t)~(uint8_t)0
3738 #define xmalloc malloc
3739 #define xrealloc realloc
3740 #include "3level.h"
3741
3742 static void
3743 output_scripts (const char *version)
3744 {
3745   const char *filename = "unictype/scripts.h";
3746   FILE *stream;
3747   unsigned int ch, s, i;
3748   struct script_table t;
3749   unsigned int level1_offset, level2_offset, level3_offset;
3750
3751   typedef struct
3752   {
3753     const char *lowercase_name;
3754   }
3755   scriptinfo_t;
3756   scriptinfo_t scriptinfo[256];
3757
3758   stream = fopen (filename, "w");
3759   if (stream == NULL)
3760     {
3761       fprintf (stderr, "cannot open '%s' for writing\n", filename);
3762       exit (1);
3763     }
3764
3765   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
3766   fprintf (stream, "/* Unicode scripts.  */\n");
3767   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
3768            version);
3769
3770   for (s = 0; s < numscripts; s++)
3771     {
3772       char *lcp = strdup (scripts[s]);
3773       char *cp;
3774
3775       for (cp = lcp; *cp != '\0'; cp++)
3776         if (*cp >= 'A' && *cp <= 'Z')
3777           *cp += 'a' - 'A';
3778
3779       scriptinfo[s].lowercase_name = lcp;
3780     }
3781
3782   for (s = 0; s < numscripts; s++)
3783     {
3784       fprintf (stream, "static const uc_interval_t script_%s_intervals[] =\n",
3785                scriptinfo[s].lowercase_name);
3786       fprintf (stream, "{\n");
3787       i = 0;
3788       for (ch = 0; ch < 0x110000; ch++)
3789         if (unicode_scripts[ch] == s)
3790           {
3791             unsigned int start;
3792             unsigned int end;
3793
3794             start = ch;
3795             while (ch + 1 < 0x110000 && unicode_scripts[ch + 1] == s)
3796               ch++;
3797             end = ch;
3798
3799             if (i > 0)
3800               fprintf (stream, ",\n");
3801             if (start == end)
3802               fprintf (stream, "  { 0x%04X, 1, 1 }", start);
3803             else
3804               fprintf (stream, "  { 0x%04X, 1, 0 }, { 0x%04X, 0, 1 }",
3805                        start, end);
3806             i++;
3807           }
3808       fprintf (stream, "\n");
3809       fprintf (stream, "};\n");
3810     }
3811
3812   fprintf (stream, "static const uc_script_t scripts[%d] =\n", numscripts);
3813   fprintf (stream, "{\n");
3814   for (s = 0; s < numscripts; s++)
3815     {
3816       fprintf (stream, "  {\n");
3817       fprintf (stream, "    sizeof (script_%s_intervals) / sizeof (uc_interval_t),\n",
3818                scriptinfo[s].lowercase_name);
3819       fprintf (stream, "    script_%s_intervals,\n",
3820                scriptinfo[s].lowercase_name);
3821       fprintf (stream, "    \"%s\"\n", scripts[s]);
3822       fprintf (stream, "  }");
3823       if (s+1 < numscripts)
3824         fprintf (stream, ",");
3825       fprintf (stream, "\n");
3826     }
3827   fprintf (stream, "};\n");
3828
3829   t.p = 7;
3830   t.q = 9;
3831   script_table_init (&t);
3832
3833   for (ch = 0; ch < 0x110000; ch++)
3834     {
3835       unsigned int s = unicode_scripts[ch];
3836       if (s != (uint8_t)~(uint8_t)0)
3837         script_table_add (&t, ch, s);
3838     }
3839
3840   script_table_finalize (&t);
3841
3842   /* Offsets in t.result, in memory of this process.  */
3843   level1_offset =
3844     5 * sizeof (uint32_t);
3845   level2_offset =
3846     5 * sizeof (uint32_t)
3847     + t.level1_size * sizeof (uint32_t);
3848   level3_offset =
3849     5 * sizeof (uint32_t)
3850     + t.level1_size * sizeof (uint32_t)
3851     + (t.level2_size << t.q) * sizeof (uint32_t);
3852
3853   for (i = 0; i < 5; i++)
3854     fprintf (stream, "#define script_header_%d %d\n", i,
3855              ((uint32_t *) t.result)[i]);
3856   fprintf (stream, "static const\n");
3857   fprintf (stream, "struct\n");
3858   fprintf (stream, "  {\n");
3859   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
3860   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
3861   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
3862   fprintf (stream, "  }\n");
3863   fprintf (stream, "u_script =\n");
3864   fprintf (stream, "{\n");
3865   fprintf (stream, "  {");
3866   if (t.level1_size > 8)
3867     fprintf (stream, "\n   ");
3868   for (i = 0; i < t.level1_size; i++)
3869     {
3870       uint32_t offset;
3871       if (i > 0 && (i % 8) == 0)
3872         fprintf (stream, "\n   ");
3873       offset = ((uint32_t *) (t.result + level1_offset))[i];
3874       if (offset == 0)
3875         fprintf (stream, " %5d", -1);
3876       else
3877         fprintf (stream, " %5zu",
3878                  (offset - level2_offset) / sizeof (uint32_t));
3879       if (i+1 < t.level1_size)
3880         fprintf (stream, ",");
3881     }
3882   if (t.level1_size > 8)
3883     fprintf (stream, "\n ");
3884   fprintf (stream, " },\n");
3885   fprintf (stream, "  {");
3886   if (t.level2_size << t.q > 8)
3887     fprintf (stream, "\n   ");
3888   for (i = 0; i < t.level2_size << t.q; i++)
3889     {
3890       uint32_t offset;
3891       if (i > 0 && (i % 8) == 0)
3892         fprintf (stream, "\n   ");
3893       offset = ((uint32_t *) (t.result + level2_offset))[i];
3894       if (offset == 0)
3895         fprintf (stream, " %5d", -1);
3896       else
3897         fprintf (stream, " %5zu",
3898                  (offset - level3_offset) / sizeof (uint8_t));
3899       if (i+1 < t.level2_size << t.q)
3900         fprintf (stream, ",");
3901     }
3902   if (t.level2_size << t.q > 8)
3903     fprintf (stream, "\n ");
3904   fprintf (stream, " },\n");
3905   fprintf (stream, "  {");
3906   if (t.level3_size << t.p > 8)
3907     fprintf (stream, "\n   ");
3908   for (i = 0; i < t.level3_size << t.p; i++)
3909     {
3910       if (i > 0 && (i % 8) == 0)
3911         fprintf (stream, "\n   ");
3912       fprintf (stream, " %3d", ((uint8_t *) (t.result + level3_offset))[i]);
3913       if (i+1 < t.level3_size << t.p)
3914         fprintf (stream, ",");
3915     }
3916   if (t.level3_size << t.p > 8)
3917     fprintf (stream, "\n ");
3918   fprintf (stream, " }\n");
3919   fprintf (stream, "};\n");
3920
3921   if (ferror (stream) || fclose (stream))
3922     {
3923       fprintf (stderr, "error writing to '%s'\n", filename);
3924       exit (1);
3925     }
3926 }
3927
3928 static void
3929 output_scripts_byname (const char *version)
3930 {
3931   const char *filename = "unictype/scripts_byname.gperf";
3932   FILE *stream;
3933   unsigned int s;
3934
3935   stream = fopen (filename, "w");
3936   if (stream == NULL)
3937     {
3938       fprintf (stderr, "cannot open '%s' for writing\n", filename);
3939       exit (1);
3940     }
3941
3942   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
3943   fprintf (stream, "/* Unicode scripts.  */\n");
3944   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
3945            version);
3946   fprintf (stream, "struct named_script { int name; unsigned int index; };\n");
3947   fprintf (stream, "%%struct-type\n");
3948   fprintf (stream, "%%language=ANSI-C\n");
3949   fprintf (stream, "%%define hash-function-name scripts_hash\n");
3950   fprintf (stream, "%%define lookup-function-name uc_script_lookup\n");
3951   fprintf (stream, "%%readonly-tables\n");
3952   fprintf (stream, "%%global-table\n");
3953   fprintf (stream, "%%define word-array-name script_names\n");
3954   fprintf (stream, "%%pic\n");
3955   fprintf (stream, "%%define string-pool-name script_stringpool\n");
3956   fprintf (stream, "%%%%\n");
3957   for (s = 0; s < numscripts; s++)
3958     fprintf (stream, "%s, %u\n", scripts[s], s);
3959
3960   if (ferror (stream) || fclose (stream))
3961     {
3962       fprintf (stderr, "error writing to '%s'\n", filename);
3963       exit (1);
3964     }
3965 }
3966
3967 /* ========================================================================= */
3968
3969 /* Blocks.  */
3970
3971 typedef struct { unsigned int start; unsigned int end; const char *name; }
3972   block_t;
3973 static block_t blocks[256];
3974 static unsigned int numblocks;
3975
3976 static void
3977 fill_blocks (const char *blocks_filename)
3978 {
3979   FILE *stream;
3980
3981   stream = fopen (blocks_filename, "r");
3982   if (stream == NULL)
3983     {
3984       fprintf (stderr, "error during fopen of '%s'\n", blocks_filename);
3985       exit (1);
3986     }
3987
3988   for (;;)
3989     {
3990       char buf[200+1];
3991       unsigned int i1, i2;
3992       char padding[200+1];
3993       char blockname[200+1];
3994
3995       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
3996         break;
3997
3998       if (buf[0] == '\0' || buf[0] == '#')
3999         continue;
4000
4001       if (sscanf (buf, "%X..%X%[ ;]%[^\r]", &i1, &i2, padding, blockname) != 4)
4002         {
4003           fprintf (stderr, "parse error in '%s'\n", blocks_filename);
4004           exit (1);
4005         }
4006       blocks[numblocks].start = i1;
4007       blocks[numblocks].end = i2;
4008       blocks[numblocks].name = strdup (blockname);
4009       /* It must be sorted.  */
4010       if (numblocks > 0 && !(blocks[numblocks-1].end < blocks[numblocks].start))
4011         abort ();
4012       numblocks++;
4013       if (numblocks == 256)
4014         abort ();
4015     }
4016
4017   if (ferror (stream) || fclose (stream))
4018     {
4019       fprintf (stderr, "error reading from '%s'\n", blocks_filename);
4020       exit (1);
4021     }
4022 }
4023
4024 /* Return the smallest block index among the blocks for characters >= ch.  */
4025 static unsigned int
4026 block_first_index (unsigned int ch)
4027 {
4028   /* Binary search.  */
4029   unsigned int lo = 0;
4030   unsigned int hi = numblocks;
4031   /* Invariants:
4032      All blocks[i], i < lo, have blocks[i].end < ch,
4033      all blocks[i], i >= hi, have blocks[i].end >= ch.  */
4034   while (lo < hi)
4035     {
4036       unsigned int mid = (lo + hi) / 2; /* >= lo, < hi */
4037       if (blocks[mid].end < ch)
4038         lo = mid + 1;
4039       else
4040         hi = mid;
4041     }
4042   return hi;
4043 }
4044
4045 /* Return the largest block index among the blocks for characters <= ch,
4046    plus 1.  */
4047 static unsigned int
4048 block_last_index (unsigned int ch)
4049 {
4050   /* Binary search.  */
4051   unsigned int lo = 0;
4052   unsigned int hi = numblocks;
4053   /* Invariants:
4054      All blocks[i], i < lo, have blocks[i].start <= ch,
4055      all blocks[i], i >= hi, have blocks[i].start > ch.  */
4056   while (lo < hi)
4057     {
4058       unsigned int mid = (lo + hi) / 2; /* >= lo, < hi */
4059       if (blocks[mid].start <= ch)
4060         lo = mid + 1;
4061       else
4062         hi = mid;
4063     }
4064   return hi;
4065 }
4066
4067 static void
4068 output_blocks (const char *version)
4069 {
4070   const char *filename = "unictype/blocks.h";
4071   const unsigned int shift = 8; /* bits to shift away for array access */
4072   const unsigned int threshold = 0x30000; /* cut-off table here to save space */
4073   FILE *stream;
4074   unsigned int i;
4075   unsigned int i1;
4076
4077   stream = fopen (filename, "w");
4078   if (stream == NULL)
4079     {
4080       fprintf (stderr, "cannot open '%s' for writing\n", filename);
4081       exit (1);
4082     }
4083
4084   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
4085   fprintf (stream, "/* Unicode blocks.  */\n");
4086   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
4087            version);
4088
4089   fprintf (stream, "static const uc_block_t blocks[] =\n");
4090   fprintf (stream, "{\n");
4091   for (i = 0; i < numblocks; i++)
4092     {
4093       fprintf (stream, "  { 0x%04X, 0x%04X, \"%s\" }", blocks[i].start,
4094                blocks[i].end, blocks[i].name);
4095       if (i+1 < numblocks)
4096         fprintf (stream, ",");
4097       fprintf (stream, "\n");
4098     }
4099   fprintf (stream, "};\n");
4100   fprintf (stream, "#define blocks_level1_shift %d\n", shift);
4101   fprintf (stream, "#define blocks_level1_threshold 0x%04X\n", threshold);
4102   fprintf (stream, "static const uint8_t blocks_level1[%d * 2] =\n",
4103            threshold >> shift);
4104   fprintf (stream, "{\n");
4105   for (i1 = 0; i1 < (threshold >> shift); i1++)
4106     {
4107       unsigned int first_index = block_first_index (i1 << shift);
4108       unsigned int last_index = block_last_index (((i1 + 1) << shift) - 1);
4109       fprintf (stream, "  %3d, %3d", first_index, last_index);
4110       if (i1+1 < (threshold >> shift))
4111         fprintf (stream, ",");
4112       fprintf (stream, "\n");
4113     }
4114   fprintf (stream, "};\n");
4115   fprintf (stream, "#define blocks_upper_first_index %d\n",
4116            block_first_index (threshold));
4117   fprintf (stream, "#define blocks_upper_last_index %d\n",
4118            block_last_index (0x10FFFF));
4119
4120   if (ferror (stream) || fclose (stream))
4121     {
4122       fprintf (stderr, "error writing to '%s'\n", filename);
4123       exit (1);
4124     }
4125 }
4126
4127 /* ========================================================================= */
4128
4129 /* C and Java syntax.  */
4130
4131 enum
4132 {
4133   UC_IDENTIFIER_START,    /* valid as first or subsequent character */
4134   UC_IDENTIFIER_VALID,    /* valid as subsequent character only */
4135   UC_IDENTIFIER_INVALID,  /* not valid */
4136   UC_IDENTIFIER_IGNORABLE /* ignorable (Java only) */
4137 };
4138
4139 /* ISO C 99 section 6.4.(3).  */
4140 static bool
4141 is_c_whitespace (unsigned int ch)
4142 {
4143   return (ch == ' ' /* space */
4144           || ch == '\t' /* horizontal tab */
4145           || ch == '\n' || ch == '\r' /* new-line */
4146           || ch == '\v' /* vertical tab */
4147           || ch == '\f'); /* form-feed */
4148 }
4149
4150 /* ISO C 99 section 6.4.2.1 and appendix D.  */
4151 static int
4152 c_ident_category (unsigned int ch)
4153 {
4154   /* Section 6.4.2.1.  */
4155   if (ch >= '0' && ch <= '9')
4156     return UC_IDENTIFIER_VALID;
4157   if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_')
4158     return UC_IDENTIFIER_START;
4159   /* Appendix D.  */
4160   if (0
4161       /* Latin */
4162       || (ch == 0x00AA)
4163       || (ch == 0x00BA)
4164       || (ch >= 0x00C0 && ch <= 0x00D6)
4165       || (ch >= 0x00D8 && ch <= 0x00F6)
4166       || (ch >= 0x00F8 && ch <= 0x01F5)
4167       || (ch >= 0x01FA && ch <= 0x0217)
4168       || (ch >= 0x0250 && ch <= 0x02A8)
4169       || (ch >= 0x1E00 && ch <= 0x1E9B)
4170       || (ch >= 0x1EA0 && ch <= 0x1EF9)
4171       || (ch == 0x207F)
4172       /* Greek */
4173       || (ch == 0x0386)
4174       || (ch >= 0x0388 && ch <= 0x038A)
4175       || (ch == 0x038C)
4176       || (ch >= 0x038E && ch <= 0x03A1)
4177       || (ch >= 0x03A3 && ch <= 0x03CE)
4178       || (ch >= 0x03D0 && ch <= 0x03D6)
4179       || (ch == 0x03DA)
4180       || (ch == 0x03DC)
4181       || (ch == 0x03DE)
4182       || (ch == 0x03E0)
4183       || (ch >= 0x03E2 && ch <= 0x03F3)
4184       || (ch >= 0x1F00 && ch <= 0x1F15)
4185       || (ch >= 0x1F18 && ch <= 0x1F1D)
4186       || (ch >= 0x1F20 && ch <= 0x1F45)
4187       || (ch >= 0x1F48 && ch <= 0x1F4D)
4188       || (ch >= 0x1F50 && ch <= 0x1F57)
4189       || (ch == 0x1F59)
4190       || (ch == 0x1F5B)
4191       || (ch == 0x1F5D)
4192       || (ch >= 0x1F5F && ch <= 0x1F7D)
4193       || (ch >= 0x1F80 && ch <= 0x1FB4)
4194       || (ch >= 0x1FB6 && ch <= 0x1FBC)
4195       || (ch >= 0x1FC2 && ch <= 0x1FC4)
4196       || (ch >= 0x1FC6 && ch <= 0x1FCC)
4197       || (ch >= 0x1FD0 && ch <= 0x1FD3)
4198       || (ch >= 0x1FD6 && ch <= 0x1FDB)
4199       || (ch >= 0x1FE0 && ch <= 0x1FEC)
4200       || (ch >= 0x1FF2 && ch <= 0x1FF4)
4201       || (ch >= 0x1FF6 && ch <= 0x1FFC)
4202       /* Cyrillic */
4203       || (ch >= 0x0401 && ch <= 0x040C)
4204       || (ch >= 0x040E && ch <= 0x044F)
4205       || (ch >= 0x0451 && ch <= 0x045C)
4206       || (ch >= 0x045E && ch <= 0x0481)
4207       || (ch >= 0x0490 && ch <= 0x04C4)
4208       || (ch >= 0x04C7 && ch <= 0x04C8)
4209       || (ch >= 0x04CB && ch <= 0x04CC)
4210       || (ch >= 0x04D0 && ch <= 0x04EB)
4211       || (ch >= 0x04EE && ch <= 0x04F5)
4212       || (ch >= 0x04F8 && ch <= 0x04F9)
4213       /* Armenian */
4214       || (ch >= 0x0531 && ch <= 0x0556)
4215       || (ch >= 0x0561 && ch <= 0x0587)
4216       /* Hebrew */
4217       || (ch >= 0x05B0 && ch <= 0x05B9)
4218       || (ch >= 0x05BB && ch <= 0x05BD)
4219       || (ch == 0x05BF)
4220       || (ch >= 0x05C1 && ch <= 0x05C2)
4221       || (ch >= 0x05D0 && ch <= 0x05EA)
4222       || (ch >= 0x05F0 && ch <= 0x05F2)
4223       /* Arabic */
4224       || (ch >= 0x0621 && ch <= 0x063A)
4225       || (ch >= 0x0640 && ch <= 0x0652)
4226       || (ch >= 0x0670 && ch <= 0x06B7)
4227       || (ch >= 0x06BA && ch <= 0x06BE)
4228       || (ch >= 0x06C0 && ch <= 0x06CE)
4229       || (ch >= 0x06D0 && ch <= 0x06DC)
4230       || (ch >= 0x06E5 && ch <= 0x06E8)
4231       || (ch >= 0x06EA && ch <= 0x06ED)
4232       /* Devanagari */
4233       || (ch >= 0x0901 && ch <= 0x0903)
4234       || (ch >= 0x0905 && ch <= 0x0939)
4235       || (ch >= 0x093E && ch <= 0x094D)
4236       || (ch >= 0x0950 && ch <= 0x0952)
4237       || (ch >= 0x0958 && ch <= 0x0963)
4238       /* Bengali */
4239       || (ch >= 0x0981 && ch <= 0x0983)
4240       || (ch >= 0x0985 && ch <= 0x098C)
4241       || (ch >= 0x098F && ch <= 0x0990)
4242       || (ch >= 0x0993 && ch <= 0x09A8)
4243       || (ch >= 0x09AA && ch <= 0x09B0)
4244       || (ch == 0x09B2)
4245       || (ch >= 0x09B6 && ch <= 0x09B9)
4246       || (ch >= 0x09BE && ch <= 0x09C4)
4247       || (ch >= 0x09C7 && ch <= 0x09C8)
4248       || (ch >= 0x09CB && ch <= 0x09CD)
4249       || (ch >= 0x09DC && ch <= 0x09DD)
4250       || (ch >= 0x09DF && ch <= 0x09E3)
4251       || (ch >= 0x09F0 && ch <= 0x09F1)
4252       /* Gurmukhi */
4253       || (ch == 0x0A02)
4254       || (ch >= 0x0A05 && ch <= 0x0A0A)
4255       || (ch >= 0x0A0F && ch <= 0x0A10)
4256       || (ch >= 0x0A13 && ch <= 0x0A28)
4257       || (ch >= 0x0A2A && ch <= 0x0A30)
4258       || (ch >= 0x0A32 && ch <= 0x0A33)
4259       || (ch >= 0x0A35 && ch <= 0x0A36)
4260       || (ch >= 0x0A38 && ch <= 0x0A39)
4261       || (ch >= 0x0A3E && ch <= 0x0A42)
4262       || (ch >= 0x0A47 && ch <= 0x0A48)
4263       || (ch >= 0x0A4B && ch <= 0x0A4D)
4264       || (ch >= 0x0A59 && ch <= 0x0A5C)
4265       || (ch == 0x0A5E)
4266       || (ch == 0x0A74)
4267       /* Gujarati */
4268       || (ch >= 0x0A81 && ch <= 0x0A83)
4269       || (ch >= 0x0A85 && ch <= 0x0A8B)
4270       || (ch == 0x0A8D)
4271       || (ch >= 0x0A8F && ch <= 0x0A91)
4272       || (ch >= 0x0A93 && ch <= 0x0AA8)
4273       || (ch >= 0x0AAA && ch <= 0x0AB0)
4274       || (ch >= 0x0AB2 && ch <= 0x0AB3)
4275       || (ch >= 0x0AB5 && ch <= 0x0AB9)
4276       || (ch >= 0x0ABD && ch <= 0x0AC5)
4277       || (ch >= 0x0AC7 && ch <= 0x0AC9)
4278       || (ch >= 0x0ACB && ch <= 0x0ACD)
4279       || (ch == 0x0AD0)
4280       || (ch == 0x0AE0)
4281       /* Oriya */
4282       || (ch >= 0x0B01 && ch <= 0x0B03)
4283       || (ch >= 0x0B05 && ch <= 0x0B0C)
4284       || (ch >= 0x0B0F && ch <= 0x0B10)
4285       || (ch >= 0x0B13 && ch <= 0x0B28)
4286       || (ch >= 0x0B2A && ch <= 0x0B30)
4287       || (ch >= 0x0B32 && ch <= 0x0B33)
4288       || (ch >= 0x0B36 && ch <= 0x0B39)
4289       || (ch >= 0x0B3E && ch <= 0x0B43)
4290       || (ch >= 0x0B47 && ch <= 0x0B48)
4291       || (ch >= 0x0B4B && ch <= 0x0B4D)
4292       || (ch >= 0x0B5C && ch <= 0x0B5D)
4293       || (ch >= 0x0B5F && ch <= 0x0B61)
4294       /* Tamil */
4295       || (ch >= 0x0B82 && ch <= 0x0B83)
4296       || (ch >= 0x0B85 && ch <= 0x0B8A)
4297       || (ch >= 0x0B8E && ch <= 0x0B90)
4298       || (ch >= 0x0B92 && ch <= 0x0B95)
4299       || (ch >= 0x0B99 && ch <= 0x0B9A)
4300       || (ch == 0x0B9C)
4301       || (ch >= 0x0B9E && ch <= 0x0B9F)
4302       || (ch >= 0x0BA3 && ch <= 0x0BA4)
4303       || (ch >= 0x0BA8 && ch <= 0x0BAA)
4304       || (ch >= 0x0BAE && ch <= 0x0BB5)
4305       || (ch >= 0x0BB7 && ch <= 0x0BB9)
4306       || (ch >= 0x0BBE && ch <= 0x0BC2)
4307       || (ch >= 0x0BC6 && ch <= 0x0BC8)
4308       || (ch >= 0x0BCA && ch <= 0x0BCD)
4309       /* Telugu */
4310       || (ch >= 0x0C01 && ch <= 0x0C03)
4311       || (ch >= 0x0C05 && ch <= 0x0C0C)
4312       || (ch >= 0x0C0E && ch <= 0x0C10)
4313       || (ch >= 0x0C12 && ch <= 0x0C28)
4314       || (ch >= 0x0C2A && ch <= 0x0C33)
4315       || (ch >= 0x0C35 && ch <= 0x0C39)
4316       || (ch >= 0x0C3E && ch <= 0x0C44)
4317       || (ch >= 0x0C46 && ch <= 0x0C48)
4318       || (ch >= 0x0C4A && ch <= 0x0C4D)
4319       || (ch >= 0x0C60 && ch <= 0x0C61)
4320       /* Kannada */
4321       || (ch >= 0x0C82 && ch <= 0x0C83)
4322       || (ch >= 0x0C85 && ch <= 0x0C8C)
4323       || (ch >= 0x0C8E && ch <= 0x0C90)
4324       || (ch >= 0x0C92 && ch <= 0x0CA8)
4325       || (ch >= 0x0CAA && ch <= 0x0CB3)
4326       || (ch >= 0x0CB5 && ch <= 0x0CB9)
4327       || (ch >= 0x0CBE && ch <= 0x0CC4)
4328       || (ch >= 0x0CC6 && ch <= 0x0CC8)
4329       || (ch >= 0x0CCA && ch <= 0x0CCD)
4330       || (ch == 0x0CDE)
4331       || (ch >= 0x0CE0 && ch <= 0x0CE1)
4332       /* Malayalam */
4333       || (ch >= 0x0D02 && ch <= 0x0D03)
4334       || (ch >= 0x0D05 && ch <= 0x0D0C)
4335       || (ch >= 0x0D0E && ch <= 0x0D10)
4336       || (ch >= 0x0D12 && ch <= 0x0D28)
4337       || (ch >= 0x0D2A && ch <= 0x0D39)
4338       || (ch >= 0x0D3E && ch <= 0x0D43)
4339       || (ch >= 0x0D46 && ch <= 0x0D48)
4340       || (ch >= 0x0D4A && ch <= 0x0D4D)
4341       || (ch >= 0x0D60 && ch <= 0x0D61)
4342       /* Thai */
4343       || (ch >= 0x0E01 && ch <= 0x0E3A)
4344       || (ch >= 0x0E40 && ch <= 0x0E5B)
4345       /* Lao */
4346       || (ch >= 0x0E81 && ch <= 0x0E82)
4347       || (ch == 0x0E84)
4348       || (ch >= 0x0E87 && ch <= 0x0E88)
4349       || (ch == 0x0E8A)
4350       || (ch == 0x0E8D)
4351       || (ch >= 0x0E94 && ch <= 0x0E97)
4352       || (ch >= 0x0E99 && ch <= 0x0E9F)
4353       || (ch >= 0x0EA1 && ch <= 0x0EA3)
4354       || (ch == 0x0EA5)
4355       || (ch == 0x0EA7)
4356       || (ch >= 0x0EAA && ch <= 0x0EAB)
4357       || (ch >= 0x0EAD && ch <= 0x0EAE)
4358       || (ch >= 0x0EB0 && ch <= 0x0EB9)
4359       || (ch >= 0x0EBB && ch <= 0x0EBD)
4360       || (ch >= 0x0EC0 && ch <= 0x0EC4)
4361       || (ch == 0x0EC6)
4362       || (ch >= 0x0EC8 && ch <= 0x0ECD)
4363       || (ch >= 0x0EDC && ch <= 0x0EDD)
4364       /* Tibetan */
4365       || (ch == 0x0F00)
4366       || (ch >= 0x0F18 && ch <= 0x0F19)
4367       || (ch == 0x0F35)
4368       || (ch == 0x0F37)
4369       || (ch == 0x0F39)
4370       || (ch >= 0x0F3E && ch <= 0x0F47)
4371       || (ch >= 0x0F49 && ch <= 0x0F69)
4372       || (ch >= 0x0F71 && ch <= 0x0F84)
4373       || (ch >= 0x0F86 && ch <= 0x0F8B)
4374       || (ch >= 0x0F90 && ch <= 0x0F95)
4375       || (ch == 0x0F97)
4376       || (ch >= 0x0F99 && ch <= 0x0FAD)
4377       || (ch >= 0x0FB1 && ch <= 0x0FB7)
4378       || (ch == 0x0FB9)
4379       /* Georgian */
4380       || (ch >= 0x10A0 && ch <= 0x10C5)
4381       || (ch >= 0x10D0 && ch <= 0x10F6)
4382       /* Hiragana */
4383       || (ch >= 0x3041 && ch <= 0x3093)
4384       || (ch >= 0x309B && ch <= 0x309C)
4385       /* Katakana */
4386       || (ch >= 0x30A1 && ch <= 0x30F6)
4387       || (ch >= 0x30FB && ch <= 0x30FC)
4388       /* Bopomofo */
4389       || (ch >= 0x3105 && ch <= 0x312C)
4390       /* CJK Unified Ideographs */
4391       || (ch >= 0x4E00 && ch <= 0x9FA5)
4392       /* Hangul */
4393       || (ch >= 0xAC00 && ch <= 0xD7A3)
4394       /* Digits */
4395       || (ch >= 0x0660 && ch <= 0x0669)
4396       || (ch >= 0x06F0 && ch <= 0x06F9)
4397       || (ch >= 0x0966 && ch <= 0x096F)
4398       || (ch >= 0x09E6 && ch <= 0x09EF)
4399       || (ch >= 0x0A66 && ch <= 0x0A6F)
4400       || (ch >= 0x0AE6 && ch <= 0x0AEF)
4401       || (ch >= 0x0B66 && ch <= 0x0B6F)
4402       || (ch >= 0x0BE7 && ch <= 0x0BEF)
4403       || (ch >= 0x0C66 && ch <= 0x0C6F)
4404       || (ch >= 0x0CE6 && ch <= 0x0CEF)
4405       || (ch >= 0x0D66 && ch <= 0x0D6F)
4406       || (ch >= 0x0E50 && ch <= 0x0E59)
4407       || (ch >= 0x0ED0 && ch <= 0x0ED9)
4408       || (ch >= 0x0F20 && ch <= 0x0F33)
4409       /* Special characters */
4410       || (ch == 0x00B5)
4411       || (ch == 0x00B7)
4412       || (ch >= 0x02B0 && ch <= 0x02B8)
4413       || (ch == 0x02BB)
4414       || (ch >= 0x02BD && ch <= 0x02C1)
4415       || (ch >= 0x02D0 && ch <= 0x02D1)
4416       || (ch >= 0x02E0 && ch <= 0x02E4)
4417       || (ch == 0x037A)
4418       || (ch == 0x0559)
4419       || (ch == 0x093D)
4420       || (ch == 0x0B3D)
4421       || (ch == 0x1FBE)
4422       || (ch >= 0x203F && ch <= 0x2040)
4423       || (ch == 0x2102)
4424       || (ch == 0x2107)
4425       || (ch >= 0x210A && ch <= 0x2113)
4426       || (ch == 0x2115)
4427       || (ch >= 0x2118 && ch <= 0x211D)
4428       || (ch == 0x2124)
4429       || (ch == 0x2126)
4430       || (ch == 0x2128)
4431       || (ch >= 0x212A && ch <= 0x2131)
4432       || (ch >= 0x2133 && ch <= 0x2138)
4433       || (ch >= 0x2160 && ch <= 0x2182)
4434       || (ch >= 0x3005 && ch <= 0x3007)
4435       || (ch >= 0x3021 && ch <= 0x3029)
4436      )
4437     return UC_IDENTIFIER_START;
4438   return UC_IDENTIFIER_INVALID;
4439 }
4440
4441 /* The Java Language Specification, 3rd edition, Â§3.6.
4442    http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#95710  */
4443 static bool
4444 is_java_whitespace (unsigned int ch)
4445 {
4446   return (ch == ' ' || ch == '\t' || ch == '\f'
4447           || ch == '\n' || ch == '\r');
4448 }
4449
4450 /* The Java Language Specification, 3rd edition, Â§3.8.
4451    http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#40625
4452    and Character.isJavaIdentifierStart and Character.isJavaIdentifierPart  */
4453 static int
4454 java_ident_category (unsigned int ch)
4455 {
4456   /* FIXME: Check this against Sun's JDK implementation.  */
4457   if (is_category_L (ch) /* = Character.isLetter(ch) */
4458       || is_category_Nl (ch) /* = Character.getType(ch)==LETTER_NUMBER */
4459       || is_category_Sc (ch) /* currency symbol */
4460       || is_category_Pc (ch) /* connector punctuation */
4461      )
4462     return UC_IDENTIFIER_START;
4463   if (is_category_Nd (ch) /* digit */
4464       || is_category_Mc (ch) /* combining mark */
4465       || is_category_Mn (ch) /* non-spacing mark */
4466      )
4467     return UC_IDENTIFIER_VALID;
4468   if ((ch >= 0x0000 && ch <= 0x0008)
4469       || (ch >= 0x000E && ch <= 0x001B)
4470       || (ch >= 0x007F && ch <= 0x009F)
4471       || is_category_Cf (ch) /* = Character.getType(ch)==FORMAT */
4472      )
4473     return UC_IDENTIFIER_IGNORABLE;
4474   return UC_IDENTIFIER_INVALID;
4475 }
4476
4477 /* Construction of sparse 3-level tables.  */
4478 #define TABLE identsyntax_table
4479 #define ELEMENT uint8_t
4480 #define DEFAULT UC_IDENTIFIER_INVALID
4481 #define xmalloc malloc
4482 #define xrealloc realloc
4483 #include "3level.h"
4484
4485 /* Output an identifier syntax categorization in a three-level bitmap.  */
4486 static void
4487 output_ident_category (const char *filename, int (*predicate) (unsigned int), const char *name, const char *version)
4488 {
4489   FILE *stream;
4490   unsigned int ch, i;
4491   struct identsyntax_table t;
4492   unsigned int level1_offset, level2_offset, level3_offset;
4493
4494   stream = fopen (filename, "w");
4495   if (stream == NULL)
4496     {
4497       fprintf (stderr, "cannot open '%s' for writing\n", filename);
4498       exit (1);
4499     }
4500
4501   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
4502   fprintf (stream, "/* Language syntax properties of Unicode characters.  */\n");
4503   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
4504            version);
4505
4506   t.p = 7; /* or 8 */
4507   t.q = 5; /* or 4 */
4508   identsyntax_table_init (&t);
4509
4510   for (ch = 0; ch < 0x110000; ch++)
4511     {
4512       int syntaxcode = predicate (ch);
4513       if (syntaxcode != UC_IDENTIFIER_INVALID)
4514         identsyntax_table_add (&t, ch, syntaxcode);
4515     }
4516
4517   identsyntax_table_finalize (&t);
4518
4519   /* Offsets in t.result, in memory of this process.  */
4520   level1_offset =
4521     5 * sizeof (uint32_t);
4522   level2_offset =
4523     5 * sizeof (uint32_t)
4524     + t.level1_size * sizeof (uint32_t);
4525   level3_offset =
4526     5 * sizeof (uint32_t)
4527     + t.level1_size * sizeof (uint32_t)
4528     + (t.level2_size << t.q) * sizeof (uint32_t);
4529
4530   for (i = 0; i < 5; i++)
4531     fprintf (stream, "#define identsyntax_header_%d %d\n", i,
4532              ((uint32_t *) t.result)[i]);
4533   fprintf (stream, "static const\n");
4534   fprintf (stream, "struct\n");
4535   fprintf (stream, "  {\n");
4536   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
4537   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
4538   fprintf (stream, "    unsigned short level3[%zu * %d];\n", t.level3_size,
4539            (1 << t.p) * 2 / 16);
4540   fprintf (stream, "  }\n");
4541   fprintf (stream, "%s =\n", name);
4542   fprintf (stream, "{\n");
4543   fprintf (stream, "  {");
4544   if (t.level1_size > 8)
4545     fprintf (stream, "\n   ");
4546   for (i = 0; i < t.level1_size; i++)
4547     {
4548       uint32_t offset;
4549       if (i > 0 && (i % 8) == 0)
4550         fprintf (stream, "\n   ");
4551       offset = ((uint32_t *) (t.result + level1_offset))[i];
4552       if (offset == 0)
4553         fprintf (stream, " %5d", -1);
4554       else
4555         fprintf (stream, " %5zu",
4556                  (offset - level2_offset) / sizeof (uint32_t));
4557       if (i+1 < t.level1_size)
4558         fprintf (stream, ",");
4559     }
4560   if (t.level1_size > 8)
4561     fprintf (stream, "\n ");
4562   fprintf (stream, " },\n");
4563   fprintf (stream, "  {");
4564   if (t.level2_size << t.q > 8)
4565     fprintf (stream, "\n   ");
4566   for (i = 0; i < t.level2_size << t.q; i++)
4567     {
4568       uint32_t offset;
4569       if (i > 0 && (i % 8) == 0)
4570         fprintf (stream, "\n   ");
4571       offset = ((uint32_t *) (t.result + level2_offset))[i];
4572       if (offset == 0)
4573         fprintf (stream, " %5d", -1);
4574       else
4575         fprintf (stream, " %5zu",
4576                  (offset - level3_offset) / sizeof (uint8_t));
4577       if (i+1 < t.level2_size << t.q)
4578         fprintf (stream, ",");
4579     }
4580   if (t.level2_size << t.q > 8)
4581     fprintf (stream, "\n ");
4582   fprintf (stream, " },\n");
4583   /* Pack the level3 array.  Each entry needs 2 bits only.  */
4584   fprintf (stream, "  {");
4585   if ((t.level3_size << t.p) * 2 / 16 > 8)
4586     fprintf (stream, "\n   ");
4587   for (i = 0; i < (t.level3_size << t.p) * 2 / 16; i++)
4588     {
4589       if (i > 0 && (i % 8) == 0)
4590         fprintf (stream, "\n   ");
4591       fprintf (stream, " 0x%04x",
4592                (((uint8_t *) (t.result + level3_offset))[8 * i] << 0)
4593                | (((uint8_t *) (t.result + level3_offset))[8 * i + 1] << 2)
4594                | (((uint8_t *) (t.result + level3_offset))[8 * i + 2] << 4)
4595                | (((uint8_t *) (t.result + level3_offset))[8 * i + 3] << 6)
4596                | (((uint8_t *) (t.result + level3_offset))[8 * i + 4] << 8)
4597                | (((uint8_t *) (t.result + level3_offset))[8 * i + 5] << 10)
4598                | (((uint8_t *) (t.result + level3_offset))[8 * i + 6] << 12)
4599                | (((uint8_t *) (t.result + level3_offset))[8 * i + 7] << 14));
4600       if (i+1 < (t.level3_size << t.p) * 2 / 16)
4601         fprintf (stream, ",");
4602     }
4603   if ((t.level3_size << t.p) * 2 / 16 > 8)
4604     fprintf (stream, "\n ");
4605   fprintf (stream, " }\n");
4606   fprintf (stream, "};\n");
4607
4608   if (ferror (stream) || fclose (stream))
4609     {
4610       fprintf (stderr, "error writing to '%s'\n", filename);
4611       exit (1);
4612     }
4613 }
4614
4615 static void
4616 output_ident_properties (const char *version)
4617 {
4618 #define PROPERTY(P) \
4619   debug_output_predicate ("unictype/sy_" #P ".txt", is_ ## P); \
4620   output_predicate_test ("../tests/unictype/test-sy_" #P ".c", is_ ## P, "uc_is_" #P " (c)"); \
4621   output_predicate ("unictype/sy_" #P ".h", is_ ## P, "u_" #P, "Language syntax properties", version);
4622   PROPERTY(c_whitespace)
4623   PROPERTY(java_whitespace)
4624 #undef PROPERTY
4625
4626   output_ident_category ("unictype/sy_c_ident.h", c_ident_category, "u_c_ident", version);
4627   output_ident_category ("unictype/sy_java_ident.h", java_ident_category, "u_java_ident", version);
4628 }
4629
4630 /* ========================================================================= */
4631
4632 /* Like ISO C <ctype.h> and <wctype.h>.  Compatible to glibc's
4633    glibc/localedata/locales/i18n file, generated by
4634    glibc/localedata/gen-unicode-ctype.c.  */
4635
4636 /* Character mappings.  */
4637
4638 static unsigned int
4639 to_upper (unsigned int ch)
4640 {
4641   if (unicode_attributes[ch].name != NULL
4642       && unicode_attributes[ch].upper != NONE)
4643     return unicode_attributes[ch].upper;
4644   else
4645     return ch;
4646 }
4647
4648 static unsigned int
4649 to_lower (unsigned int ch)
4650 {
4651   if (unicode_attributes[ch].name != NULL
4652       && unicode_attributes[ch].lower != NONE)
4653     return unicode_attributes[ch].lower;
4654   else
4655     return ch;
4656 }
4657
4658 static unsigned int
4659 to_title (unsigned int ch)
4660 {
4661   if (unicode_attributes[ch].name != NULL
4662       && unicode_attributes[ch].title != NONE)
4663     return unicode_attributes[ch].title;
4664   else
4665     return ch;
4666 }
4667
4668 /* Character class properties.  */
4669
4670 static bool
4671 is_upper (unsigned int ch)
4672 {
4673   return (to_lower (ch) != ch);
4674 }
4675
4676 static bool
4677 is_lower (unsigned int ch)
4678 {
4679   return (to_upper (ch) != ch)
4680          /* <U00DF> is lowercase, but without simple to_upper mapping.  */
4681          || (ch == 0x00DF);
4682 }
4683
4684 static bool
4685 is_alpha (unsigned int ch)
4686 {
4687   return (unicode_attributes[ch].name != NULL
4688           && ((unicode_attributes[ch].category[0] == 'L'
4689                /* Theppitak Karoonboonyanan <thep@links.nectec.or.th> says
4690                   <U0E2F>, <U0E46> should belong to is_punct.  */
4691                && (ch != 0x0E2F) && (ch != 0x0E46))
4692               /* Theppitak Karoonboonyanan <thep@links.nectec.or.th> says
4693                  <U0E31>, <U0E34>..<U0E3A>, <U0E47>..<U0E4E> are is_alpha.  */
4694               || (ch == 0x0E31)
4695               || (ch >= 0x0E34 && ch <= 0x0E3A)
4696               || (ch >= 0x0E47 && ch <= 0x0E4E)
4697               /* Avoid warning for <U0345>.  */
4698               || (ch == 0x0345)
4699               /* Avoid warnings for <U2160>..<U217F>.  */
4700               || (unicode_attributes[ch].category[0] == 'N'
4701                   && unicode_attributes[ch].category[1] == 'l')
4702               /* Avoid warnings for <U24B6>..<U24E9>.  */
4703               || (unicode_attributes[ch].category[0] == 'S'
4704                   && unicode_attributes[ch].category[1] == 'o'
4705                   && strstr (unicode_attributes[ch].name, " LETTER ")
4706                      != NULL)
4707               /* Consider all the non-ASCII digits as alphabetic.
4708                  ISO C 99 forbids us to have them in category "digit",
4709                  but we want iswalnum to return true on them.  */
4710               || (unicode_attributes[ch].category[0] == 'N'
4711                   && unicode_attributes[ch].category[1] == 'd'
4712                   && !(ch >= 0x0030 && ch <= 0x0039))));
4713 }
4714
4715 static bool
4716 is_digit (unsigned int ch)
4717 {
4718 #if 0
4719   return (unicode_attributes[ch].name != NULL
4720           && unicode_attributes[ch].category[0] == 'N'
4721           && unicode_attributes[ch].category[1] == 'd');
4722   /* Note: U+0BE7..U+0BEF and U+1369..U+1371 are digit systems without
4723      a zero.  Must add <0> in front of them by hand.  */
4724 #else
4725   /* SUSV2 gives us some freedom for the "digit" category, but ISO C 99
4726      takes it away:
4727      7.25.2.1.5:
4728         The iswdigit function tests for any wide character that corresponds
4729         to a decimal-digit character (as defined in 5.2.1).
4730      5.2.1:
4731         the 10 decimal digits 0 1 2 3 4 5 6 7 8 9
4732    */
4733   return (ch >= 0x0030 && ch <= 0x0039);
4734 #endif
4735 }
4736
4737 static bool
4738 is_outdigit (unsigned int ch)
4739 {
4740   return (ch >= 0x0030 && ch <= 0x0039);
4741 }
4742
4743 static bool
4744 is_alnum (unsigned int ch)
4745 {
4746   return is_alpha (ch) || is_digit (ch);
4747 }
4748
4749 static bool
4750 is_blank (unsigned int ch)
4751 {
4752   return (ch == 0x0009 /* '\t' */
4753           /* Category Zs without mention of "<noBreak>" */
4754           || (unicode_attributes[ch].name != NULL
4755               && unicode_attributes[ch].category[0] == 'Z'
4756               && unicode_attributes[ch].category[1] == 's'
4757               && !strstr (unicode_attributes[ch].decomposition, "<noBreak>")));
4758 }
4759
4760 static bool
4761 is_space (unsigned int ch)
4762 {
4763   /* Don't make U+00A0 a space. Non-breaking space means that all programs
4764      should treat it like a punctuation character, not like a space. */
4765   return (ch == 0x0020 /* ' ' */
4766           || ch == 0x000C /* '\f' */
4767           || ch == 0x000A /* '\n' */
4768           || ch == 0x000D /* '\r' */
4769           || ch == 0x0009 /* '\t' */
4770           || ch == 0x000B /* '\v' */
4771           /* Categories Zl, Zp, and Zs without mention of "<noBreak>" */
4772           || (unicode_attributes[ch].name != NULL
4773               && unicode_attributes[ch].category[0] == 'Z'
4774               && (unicode_attributes[ch].category[1] == 'l'
4775                   || unicode_attributes[ch].category[1] == 'p'
4776                   || (unicode_attributes[ch].category[1] == 's'
4777                       && !strstr (unicode_attributes[ch].decomposition,
4778                                   "<noBreak>")))));
4779 }
4780
4781 static bool
4782 is_cntrl (unsigned int ch)
4783 {
4784   return (unicode_attributes[ch].name != NULL
4785           && (strcmp (unicode_attributes[ch].name, "<control>") == 0
4786               /* Categories Zl and Zp */
4787               || (unicode_attributes[ch].category[0] == 'Z'
4788                   && (unicode_attributes[ch].category[1] == 'l'
4789                       || unicode_attributes[ch].category[1] == 'p'))));
4790 }
4791
4792 static bool
4793 is_xdigit (unsigned int ch)
4794 {
4795 #if 0
4796   return is_digit (ch)
4797          || (ch >= 0x0041 && ch <= 0x0046)
4798          || (ch >= 0x0061 && ch <= 0x0066);
4799 #else
4800   /* SUSV2 gives us some freedom for the "xdigit" category, but ISO C 99
4801      takes it away:
4802      7.25.2.1.12:
4803         The iswxdigit function tests for any wide character that corresponds
4804         to a hexadecimal-digit character (as defined in 6.4.4.1).
4805      6.4.4.1:
4806         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
4807    */
4808   return (ch >= 0x0030 && ch <= 0x0039)
4809          || (ch >= 0x0041 && ch <= 0x0046)
4810          || (ch >= 0x0061 && ch <= 0x0066);
4811 #endif
4812 }
4813
4814 static bool
4815 is_graph (unsigned int ch)
4816 {
4817   return (unicode_attributes[ch].name != NULL
4818           && strcmp (unicode_attributes[ch].name, "<control>")
4819           && !is_space (ch));
4820 }
4821
4822 static bool
4823 is_print (unsigned int ch)
4824 {
4825   return (unicode_attributes[ch].name != NULL
4826           && strcmp (unicode_attributes[ch].name, "<control>")
4827           /* Categories Zl and Zp */
4828           && !(unicode_attributes[ch].name != NULL
4829                && unicode_attributes[ch].category[0] == 'Z'
4830                && (unicode_attributes[ch].category[1] == 'l'
4831                    || unicode_attributes[ch].category[1] == 'p')));
4832 }
4833
4834 static bool
4835 is_punct (unsigned int ch)
4836 {
4837 #if 0
4838   return (unicode_attributes[ch].name != NULL
4839           && unicode_attributes[ch].category[0] == 'P');
4840 #else
4841   /* The traditional POSIX definition of punctuation is every graphic,
4842      non-alphanumeric character.  */
4843   return (is_graph (ch) && !is_alpha (ch) && !is_digit (ch));
4844 #endif
4845 }
4846
4847 /* Output all properties.  */
4848 static void
4849 output_old_ctype (const char *version)
4850 {
4851 #define PROPERTY(P) \
4852   debug_output_predicate ("unictype/ctype_" #P ".txt", is_ ## P); \
4853   output_predicate_test ("../tests/unictype/test-ctype_" #P ".c", is_ ## P, "uc_is_" #P " (c)"); \
4854   output_predicate ("unictype/ctype_" #P ".h", is_ ## P, "u_is_" #P, "ISO C <ctype.h> like properties", version);
4855   PROPERTY(alnum)
4856   PROPERTY(alpha)
4857   PROPERTY(cntrl)
4858   PROPERTY(digit)
4859   PROPERTY(graph)
4860   PROPERTY(lower)
4861   PROPERTY(print)
4862   PROPERTY(punct)
4863   PROPERTY(space)
4864   PROPERTY(upper)
4865   PROPERTY(xdigit)
4866   PROPERTY(blank)
4867 #undef PROPERTY
4868 }
4869
4870 #if 0
4871
4872 static bool
4873 is_combining (unsigned int ch)
4874 {
4875   /* Up to Unicode 3.0.1 we took the Combining property from the PropList.txt
4876      file. In 3.0.1 it was identical to the union of the general categories
4877      "Mn", "Mc", "Me". In Unicode 3.1 this property has been dropped from the
4878      PropList.txt file, so we take the latter definition.  */
4879   return (unicode_attributes[ch].name != NULL
4880           && unicode_attributes[ch].category[0] == 'M'
4881           && (unicode_attributes[ch].category[1] == 'n'
4882               || unicode_attributes[ch].category[1] == 'c'
4883               || unicode_attributes[ch].category[1] == 'e'));
4884 }
4885
4886 static bool
4887 is_combining_level3 (unsigned int ch)
4888 {
4889   return is_combining (ch)
4890          && !(unicode_attributes[ch].combining[0] != '\0'
4891               && unicode_attributes[ch].combining[0] != '0'
4892               && strtoul (unicode_attributes[ch].combining, NULL, 10) >= 200);
4893 }
4894
4895 /* Return the UCS symbol string for a Unicode character.  */
4896 static const char *
4897 ucs_symbol (unsigned int i)
4898 {
4899   static char buf[11+1];
4900
4901   sprintf (buf, (i < 0x10000 ? "<U%04X>" : "<U%08X>"), i);
4902   return buf;
4903 }
4904
4905 /* Return the UCS symbol range string for a Unicode characters interval.  */
4906 static const char *
4907 ucs_symbol_range (unsigned int low, unsigned int high)
4908 {
4909   static char buf[24+1];
4910
4911   strcpy (buf, ucs_symbol (low));
4912   strcat (buf, "..");
4913   strcat (buf, ucs_symbol (high));
4914   return buf;
4915 }
4916
4917 /* Output a character class (= property) table.  */
4918
4919 static void
4920 output_charclass (FILE *stream, const char *classname,
4921                   bool (*func) (unsigned int))
4922 {
4923   char table[0x110000];
4924   unsigned int i;
4925   bool need_semicolon;
4926   const int max_column = 75;
4927   int column;
4928
4929   for (i = 0; i < 0x110000; i++)
4930     table[i] = (int) func (i);
4931
4932   fprintf (stream, "%s ", classname);
4933   need_semicolon = false;
4934   column = 1000;
4935   for (i = 0; i < 0x110000; )
4936     {
4937       if (!table[i])
4938         i++;
4939       else
4940         {
4941           unsigned int low, high;
4942           char buf[25];
4943
4944           low = i;
4945           do
4946             i++;
4947           while (i < 0x110000 && table[i]);
4948           high = i - 1;
4949
4950           if (low == high)
4951             strcpy (buf, ucs_symbol (low));
4952           else
4953             strcpy (buf, ucs_symbol_range (low, high));
4954
4955           if (need_semicolon)
4956             {
4957               fprintf (stream, ";");
4958               column++;
4959             }
4960
4961           if (column + strlen (buf) > max_column)
4962             {
4963               fprintf (stream, "/\n   ");
4964               column = 3;
4965             }
4966
4967           fprintf (stream, "%s", buf);
4968           column += strlen (buf);
4969           need_semicolon = true;
4970         }
4971     }
4972   fprintf (stream, "\n");
4973 }
4974
4975 /* Output a character mapping table.  */
4976
4977 static void
4978 output_charmap (FILE *stream, const char *mapname,
4979                 unsigned int (*func) (unsigned int))
4980 {
4981   char table[0x110000];
4982   unsigned int i;
4983   bool need_semicolon;
4984   const int max_column = 75;
4985   int column;
4986
4987   for (i = 0; i < 0x110000; i++)
4988     table[i] = (func (i) != i);
4989
4990   fprintf (stream, "%s ", mapname);
4991   need_semicolon = false;
4992   column = 1000;
4993   for (i = 0; i < 0x110000; i++)
4994     if (table[i])
4995       {
4996         char buf[25+1];
4997
4998         strcpy (buf, "(");
4999         strcat (buf, ucs_symbol (i));
5000         strcat (buf, ",");
5001         strcat (buf, ucs_symbol (func (i)));
5002         strcat (buf, ")");
5003
5004         if (need_semicolon)
5005           {
5006             fprintf (stream, ";");
5007             column++;
5008           }
5009
5010         if (column + strlen (buf) > max_column)
5011           {
5012             fprintf (stream, "/\n   ");
5013             column = 3;
5014           }
5015
5016         fprintf (stream, "%s", buf);
5017         column += strlen (buf);
5018         need_semicolon = true;
5019       }
5020   fprintf (stream, "\n");
5021 }
5022
5023 /* Output the width table.  */
5024
5025 static void
5026 output_widthmap (FILE *stream)
5027 {
5028 }
5029
5030 /* Output the tables to the given file.  */
5031
5032 static void
5033 output_tables (const char *filename, const char *version)
5034 {
5035   FILE *stream;
5036   unsigned int ch;
5037
5038   stream = fopen (filename, "w");
5039   if (stream == NULL)
5040     {
5041       fprintf (stderr, "cannot open '%s' for writing\n", filename);
5042       exit (1);
5043     }
5044
5045   fprintf (stream, "escape_char /\n");
5046   fprintf (stream, "comment_char %%\n");
5047   fprintf (stream, "\n");
5048   fprintf (stream, "%% Generated automatically by gen-unicode-ctype for Unicode %s.\n",
5049            version);
5050   fprintf (stream, "\n");
5051
5052   fprintf (stream, "LC_IDENTIFICATION\n");
5053   fprintf (stream, "title     \"Unicode %s FDCC-set\"\n", version);
5054   fprintf (stream, "source    \"UnicodeData.txt, PropList.txt\"\n");
5055   fprintf (stream, "address   \"\"\n");
5056   fprintf (stream, "contact   \"\"\n");
5057   fprintf (stream, "email     \"bug-glibc@gnu.org\"\n");
5058   fprintf (stream, "tel       \"\"\n");
5059   fprintf (stream, "fax       \"\"\n");
5060   fprintf (stream, "language  \"\"\n");
5061   fprintf (stream, "territory \"Earth\"\n");
5062   fprintf (stream, "revision  \"%s\"\n", version);
5063   {
5064     time_t now;
5065     char date[11];
5066     now = time (NULL);
5067     strftime (date, sizeof (date), "%Y-%m-%d", gmtime (&now));
5068     fprintf (stream, "date      \"%s\"\n", date);
5069   }
5070   fprintf (stream, "category  \"unicode:2001\";LC_CTYPE\n");
5071   fprintf (stream, "END LC_IDENTIFICATION\n");
5072   fprintf (stream, "\n");
5073
5074   /* Verifications. */
5075   for (ch = 0; ch < 0x110000; ch++)
5076     {
5077       /* toupper restriction: "Only characters specified for the keywords
5078          lower and upper shall be specified.  */
5079       if (to_upper (ch) != ch && !(is_lower (ch) || is_upper (ch)))
5080         fprintf (stderr,
5081                  "%s is not upper|lower but toupper(0x%04X) = 0x%04X\n",
5082                  ucs_symbol (ch), ch, to_upper (ch));
5083
5084       /* tolower restriction: "Only characters specified for the keywords
5085          lower and upper shall be specified.  */
5086       if (to_lower (ch) != ch && !(is_lower (ch) || is_upper (ch)))
5087         fprintf (stderr,
5088                  "%s is not upper|lower but tolower(0x%04X) = 0x%04X\n",
5089                  ucs_symbol (ch), ch, to_lower (ch));
5090
5091       /* alpha restriction: "Characters classified as either upper or lower
5092          shall automatically belong to this class.  */
5093       if ((is_lower (ch) || is_upper (ch)) && !is_alpha (ch))
5094         fprintf (stderr, "%s is upper|lower but not alpha\n", ucs_symbol (ch));
5095
5096       /* alpha restriction: "No character specified for the keywords cntrl,
5097          digit, punct or space shall be specified."  */
5098       if (is_alpha (ch) && is_cntrl (ch))
5099         fprintf (stderr, "%s is alpha and cntrl\n", ucs_symbol (ch));
5100       if (is_alpha (ch) && is_digit (ch))
5101         fprintf (stderr, "%s is alpha and digit\n", ucs_symbol (ch));
5102       if (is_alpha (ch) && is_punct (ch))
5103         fprintf (stderr, "%s is alpha and punct\n", ucs_symbol (ch));
5104       if (is_alpha (ch) && is_space (ch))
5105         fprintf (stderr, "%s is alpha and space\n", ucs_symbol (ch));
5106
5107       /* space restriction: "No character specified for the keywords upper,
5108          lower, alpha, digit, graph or xdigit shall be specified."
5109          upper, lower, alpha already checked above.  */
5110       if (is_space (ch) && is_digit (ch))
5111         fprintf (stderr, "%s is space and digit\n", ucs_symbol (ch));
5112       if (is_space (ch) && is_graph (ch))
5113         fprintf (stderr, "%s is space and graph\n", ucs_symbol (ch));
5114       if (is_space (ch) && is_xdigit (ch))
5115         fprintf (stderr, "%s is space and xdigit\n", ucs_symbol (ch));
5116
5117       /* cntrl restriction: "No character specified for the keywords upper,
5118          lower, alpha, digit, punct, graph, print or xdigit shall be
5119          specified."  upper, lower, alpha already checked above.  */
5120       if (is_cntrl (ch) && is_digit (ch))
5121         fprintf (stderr, "%s is cntrl and digit\n", ucs_symbol (ch));
5122       if (is_cntrl (ch) && is_punct (ch))
5123         fprintf (stderr, "%s is cntrl and punct\n", ucs_symbol (ch));
5124       if (is_cntrl (ch) && is_graph (ch))
5125         fprintf (stderr, "%s is cntrl and graph\n", ucs_symbol (ch));
5126       if (is_cntrl (ch) && is_print (ch))
5127         fprintf (stderr, "%s is cntrl and print\n", ucs_symbol (ch));
5128       if (is_cntrl (ch) && is_xdigit (ch))
5129         fprintf (stderr, "%s is cntrl and xdigit\n", ucs_symbol (ch));
5130
5131       /* punct restriction: "No character specified for the keywords upper,
5132          lower, alpha, digit, cntrl, xdigit or as the <space> character shall
5133          be specified."  upper, lower, alpha, cntrl already checked above.  */
5134       if (is_punct (ch) && is_digit (ch))
5135         fprintf (stderr, "%s is punct and digit\n", ucs_symbol (ch));
5136       if (is_punct (ch) && is_xdigit (ch))
5137         fprintf (stderr, "%s is punct and xdigit\n", ucs_symbol (ch));
5138       if (is_punct (ch) && (ch == 0x0020))
5139         fprintf (stderr, "%s is punct\n", ucs_symbol (ch));
5140
5141       /* graph restriction: "No character specified for the keyword cntrl
5142          shall be specified."  Already checked above.  */
5143
5144       /* print restriction: "No character specified for the keyword cntrl
5145          shall be specified."  Already checked above.  */
5146
5147       /* graph - print relation: differ only in the <space> character.
5148          How is this possible if there are more than one space character?!
5149          I think susv2/xbd/locale.html should speak of "space characters",
5150          not "space character".  */
5151       if (is_print (ch) && !(is_graph (ch) || /* ch == 0x0020 */ is_space (ch)))
5152         fprintf (stderr,
5153                  "%s is print but not graph|<space>\n", ucs_symbol (ch));
5154       if (!is_print (ch) && (is_graph (ch) || ch == 0x0020))
5155         fprintf (stderr,
5156                  "%s is graph|<space> but not print\n", ucs_symbol (ch));
5157     }
5158
5159   fprintf (stream, "LC_CTYPE\n");
5160   output_charclass (stream, "upper", is_upper);
5161   output_charclass (stream, "lower", is_lower);
5162   output_charclass (stream, "alpha", is_alpha);
5163   output_charclass (stream, "digit", is_digit);
5164   output_charclass (stream, "outdigit", is_outdigit);
5165   output_charclass (stream, "blank", is_blank);
5166   output_charclass (stream, "space", is_space);
5167   output_charclass (stream, "cntrl", is_cntrl);
5168   output_charclass (stream, "punct", is_punct);
5169   output_charclass (stream, "xdigit", is_xdigit);
5170   output_charclass (stream, "graph", is_graph);
5171   output_charclass (stream, "print", is_print);
5172   output_charclass (stream, "class \"combining\";", is_combining);
5173   output_charclass (stream, "class \"combining_level3\";", is_combining_level3);
5174   output_charmap (stream, "toupper", to_upper);
5175   output_charmap (stream, "tolower", to_lower);
5176   output_charmap (stream, "map \"totitle\";", to_title);
5177   output_widthmap (stream);
5178   fprintf (stream, "END LC_CTYPE\n");
5179
5180   if (ferror (stream) || fclose (stream))
5181     {
5182       fprintf (stderr, "error writing to '%s'\n", filename);
5183       exit (1);
5184     }
5185 }
5186
5187 #endif
5188
5189 /* ========================================================================= */
5190
5191 /* The width property from the EastAsianWidth.txt file.
5192    Each is NULL (unassigned) or "N", "A", "H", "W", "F", "Na".  */
5193 const char * unicode_width[0x110000];
5194
5195 /* Stores in unicode_width[] the width property from the EastAsianWidth.txt
5196    file.  */
5197 static void
5198 fill_width (const char *width_filename)
5199 {
5200   unsigned int i, j;
5201   FILE *stream;
5202   char field0[FIELDLEN];
5203   char field1[FIELDLEN];
5204   char field2[FIELDLEN];
5205   int lineno = 0;
5206
5207   for (i = 0; i < 0x110000; i++)
5208     unicode_width[i] = (unicode_attributes[i].name != NULL ? "N" : NULL);
5209
5210   stream = fopen (width_filename, "r");
5211   if (stream == NULL)
5212     {
5213       fprintf (stderr, "error during fopen of '%s'\n", width_filename);
5214       exit (1);
5215     }
5216
5217   for (;;)
5218     {
5219       int n;
5220       int c;
5221
5222       lineno++;
5223       c = getc (stream);
5224       if (c == EOF)
5225         break;
5226       if (c == '#')
5227         {
5228           do c = getc (stream); while (c != EOF && c != '\n');
5229           continue;
5230         }
5231       ungetc (c, stream);
5232       n = getfield (stream, field0, ';');
5233       n += getfield (stream, field1, ' ');
5234       n += getfield (stream, field2, '\n');
5235       if (n == 0)
5236         break;
5237       if (n != 3)
5238         {
5239           fprintf (stderr, "short line in '%s':%d\n", width_filename, lineno);
5240           exit (1);
5241         }
5242       i = strtoul (field0, NULL, 16);
5243       if (strstr (field0, "..") != NULL)
5244         {
5245           /* Deal with a range.  */
5246           j = strtoul (strstr (field0, "..") + 2, NULL, 16);
5247           for (; i <= j; i++)
5248             unicode_width[i] = strdup (field1);
5249         }
5250       else
5251         {
5252           /* Single character line.  */
5253           unicode_width[i] = strdup (field1);
5254         }
5255     }
5256   if (ferror (stream) || fclose (stream))
5257     {
5258       fprintf (stderr, "error reading from '%s'\n", width_filename);
5259       exit (1);
5260     }
5261 }
5262
5263 /* ========================================================================= */
5264
5265 /* Non-spacing attribute and width.  */
5266
5267 /* The non-spacing attribute table consists of:
5268    - Non-spacing characters; generated from PropList.txt or
5269      "grep '^[^;]*;[^;]*;[^;]*;[^;]*;NSM;' UnicodeData.txt"
5270    - Format control characters; generated from
5271      "grep '^[^;]*;[^;]*;Cf;' UnicodeData.txt"
5272    - Zero width characters; generated from
5273      "grep '^[^;]*;ZERO WIDTH ' UnicodeData.txt"
5274  */
5275
5276 static bool
5277 is_nonspacing (unsigned int ch)
5278 {
5279   return (unicode_attributes[ch].name != NULL
5280           && (get_bidi_category (ch) == UC_BIDI_NSM
5281               || is_category_Cc (ch) || is_category_Cf (ch)
5282               || strncmp (unicode_attributes[ch].name, "ZERO WIDTH ", 11) == 0));
5283 }
5284
5285 static void
5286 output_nonspacing_property (const char *filename)
5287 {
5288   FILE *stream;
5289   int ind[0x110000 / 0x200];
5290   unsigned int i;
5291   unsigned int i_max;
5292   int next_ind;
5293
5294   stream = fopen (filename, "w");
5295   if (stream == NULL)
5296     {
5297       fprintf (stderr, "cannot open '%s' for writing\n", filename);
5298       exit (1);
5299     }
5300
5301   next_ind = 0;
5302   for (i = 0; i < 0x110000 / 0x200; i++)
5303     {
5304       bool nontrivial = false;
5305       unsigned int ch;
5306
5307       if (i != 0xe0000 / 0x200) /* The 0xe0000 block is handled by code.  */
5308         for (ch = i * 0x200; ch < (i + 1) * 0x200; ch++)
5309           if (is_nonspacing (ch))
5310             {
5311               nontrivial = true;
5312               break;
5313             }
5314       if (nontrivial)
5315         ind[i] = next_ind++;
5316       else
5317         ind[i] = -1;
5318     }
5319
5320   fprintf (stream, "static const unsigned char nonspacing_table_data[%d*64] = {\n",
5321            next_ind);
5322   i_max = 0;
5323   for (i = 0; i < 0x110000 / 0x200; i++)
5324     {
5325       bool nontrivial = (ind[i] >= 0);
5326
5327       if (nontrivial)
5328         {
5329           unsigned int j;
5330
5331           fprintf (stream, "  /* 0x%04x-0x%04x */\n", i * 0x200, (i + 1) * 0x200 - 1);
5332           for (j = 0; j < 8; j++)
5333             {
5334               unsigned int k;
5335
5336               fprintf (stream, " ");
5337               for (k = 0; k < 8; k++)
5338                 {
5339                   unsigned int l;
5340                   unsigned char bits = 0;
5341
5342                   for (l = 0; l < 8; l++)
5343                     {
5344                       unsigned int ch = i * 0x200 + j * 0x40 + k * 8 + l;
5345
5346                       if (is_nonspacing (ch))
5347                         bits |= 1 << l;
5348                     }
5349                   fprintf (stream, " 0x%02x%c", bits,
5350                            ind[i] + 1 == next_ind && j == 8 - 1 && k == 8 - 1 ? ' ' : ',');
5351                 }
5352               fprintf (stream, " /* 0x%04x-0x%04x */\n",
5353                        i * 0x200 + j * 0x40, i * 0x200 + (j + 1) * 0x40 - 1);
5354             }
5355           i_max = i;
5356         }
5357     }
5358   fprintf (stream, "};\n");
5359
5360   i_max = ((i_max + 8 - 1) / 8) * 8;
5361   fprintf (stream, "static const signed char nonspacing_table_ind[%u] = {\n",
5362            i_max);
5363   {
5364     unsigned int j;
5365
5366     for (j = 0; j < i_max / 8; j++)
5367       {
5368         unsigned int k;
5369
5370         fprintf (stream, " ");
5371         for (k = 0; k < 8; k++)
5372           {
5373             i = j * 8 + k;
5374             fprintf (stream, " %2d%c", ind[i],
5375                      j == i_max / 8 - 1 && k == 8 - 1 ? ' ' : ',');
5376           }
5377         fprintf (stream, " /* 0x%04x-0x%04x */\n",
5378                  j * 8 * 0x200, (j + 1) * 8 * 0x200 - 1);
5379       }
5380   }
5381   fprintf (stream, "};\n");
5382
5383   if (ferror (stream) || fclose (stream))
5384     {
5385       fprintf (stderr, "error writing to '%s'\n", filename);
5386       exit (1);
5387     }
5388 }
5389
5390 /* Returns the width of ch as one of 0, '0', '1', '2', 'A'.  */
5391 static char
5392 symbolic_width (unsigned int ch)
5393 {
5394   /* Test for unassigned character.  */
5395   if (is_property_unassigned_code_value (ch))
5396     {
5397       /* Unicode TR#11 section "Unassigned and Private-Use Characters".  */
5398       if (ch >= 0xE000 && ch <= 0xF8FF) /* Private Use */
5399         return 'A';
5400       if ((ch >= 0x4E00 && ch <= 0x9FFF) /* CJK Unified Ideographs block */
5401           || (ch >= 0x3400 && ch <= 0x4DBF) /* CJK Unified Ideographs Extension A block */
5402           || (ch >= 0xF900 && ch <= 0xFAFF) /* CJK Compatibility Ideographs block */
5403           || (ch >= 0x20000 && ch <= 0x2FFFF) /* Supplementary Ideographic Plane */
5404           || (ch >= 0x30000 && ch <= 0x3FFFF) /* Tertiary Ideographic Plane */)
5405         return '2';
5406       return 0;
5407     }
5408   else
5409     {
5410       /* Test for non-spacing or control character.  */
5411       if (is_category_Cc (ch) && ch < 0x00A0)
5412         return 0;
5413       if (is_nonspacing (ch))
5414         return '0';
5415       /* Test for double-width character.  */
5416       if (unicode_width[ch] != NULL
5417           && (strcmp (unicode_width[ch], "W") == 0
5418               || strcmp (unicode_width[ch], "F") == 0))
5419         return '2';
5420       /* Test for half-width character.  */
5421       if (unicode_width[ch] != NULL
5422           && strcmp (unicode_width[ch], "H") == 0)
5423         return '1';
5424     }
5425   /* In ancient CJK encodings, Cyrillic and most other characters are
5426      double-width as well.  */
5427   if (ch >= 0x00A1 && ch < 0x10000)
5428     return 'A';
5429   return '1';
5430 }
5431
5432 static void
5433 output_width_property_test (const char *filename)
5434 {
5435   FILE *stream;
5436   unsigned int interval_start, interval_end, ch;
5437   char interval_value;
5438
5439   stream = fopen (filename, "w");
5440   if (stream == NULL)
5441     {
5442       fprintf (stderr, "cannot open '%s' for writing\n", filename);
5443       exit (1);
5444     }
5445
5446   interval_value = 0;
5447   interval_start = interval_end = 0; /* avoid GCC warning */
5448   for (ch = 0; ch < 0x110000; ch++)
5449     {
5450       char value = symbolic_width (ch);
5451       if (value != 0) /* skip Cc control characters and unassigned characters */
5452         {
5453           if (value == interval_value)
5454             /* Extend the interval.  */
5455             interval_end = ch;
5456           else
5457             {
5458               /* Terminate the interval.  */
5459               if (interval_value != 0)
5460                 {
5461                   if (interval_end == interval_start)
5462                     fprintf (stream, "%04X\t\t%c\n", interval_start, interval_value);
5463                   else
5464                     fprintf (stream, "%04X..%04X\t%c\n", interval_start, interval_end, interval_value);
5465                 }
5466               /* Start a new interval.  */
5467               interval_start = interval_end = ch;
5468               interval_value = value;
5469             }
5470         }
5471     }
5472   /* Terminate the last interval.  */
5473   if (interval_value != 0)
5474     {
5475       if (interval_end == interval_start)
5476         fprintf (stream, "%04X\t\t%c\n", interval_start, interval_value);
5477       else
5478         fprintf (stream, "%04X..%04X\t%c\n", interval_start, interval_end, interval_value);
5479     }
5480
5481   if (ferror (stream) || fclose (stream))
5482     {
5483       fprintf (stderr, "error writing to '%s'\n", filename);
5484       exit (1);
5485     }
5486 }
5487
5488 /* ========================================================================= */
5489
5490 /* Line breaking classification.
5491    Updated for Unicode TR #14 revision 26.  */
5492
5493 enum
5494 {
5495   /* Values >= 25 are resolved at run time. */
5496   LBP_BK = 25, /* mandatory break */
5497 /*LBP_CR,         carriage return - not used here because it's a DOSism */
5498 /*LBP_LF,         line feed - not used here because it's a DOSism */
5499   LBP_CM = 26, /* attached characters and combining marks */
5500 /*LBP_NL,         next line - not used here because it's equivalent to LBP_BK */
5501 /*LBP_SG,         surrogates - not used here because they are not characters */
5502   LBP_WJ =  0, /* word joiner */
5503   LBP_ZW = 27, /* zero width space */
5504   LBP_GL =  1, /* non-breaking (glue) */
5505   LBP_SP = 28, /* space */
5506   LBP_B2 =  2, /* break opportunity before and after */
5507   LBP_BA =  3, /* break opportunity after */
5508   LBP_BB =  4, /* break opportunity before */
5509   LBP_HY =  5, /* hyphen */
5510   LBP_CB = 29, /* contingent break opportunity */
5511   LBP_CL =  6, /* closing punctuation */
5512   LBP_CP =  7, /* closing parenthesis */
5513   LBP_EX =  8, /* exclamation/interrogation */
5514   LBP_IN =  9, /* inseparable */
5515   LBP_NS = 10, /* non starter */
5516   LBP_OP = 11, /* opening punctuation */
5517   LBP_QU = 12, /* ambiguous quotation */
5518   LBP_IS = 13, /* infix separator (numeric) */
5519   LBP_NU = 14, /* numeric */
5520   LBP_PO = 15, /* postfix (numeric) */
5521   LBP_PR = 16, /* prefix (numeric) */
5522   LBP_SY = 17, /* symbols allowing breaks */
5523   LBP_AI = 30, /* ambiguous (alphabetic or ideograph) */
5524   LBP_AL = 18, /* ordinary alphabetic and symbol characters */
5525   LBP_H2 = 19, /* Hangul LV syllable */
5526   LBP_H3 = 20, /* Hangul LVT syllable */
5527   LBP_ID = 21, /* ideographic */
5528   LBP_JL = 22, /* Hangul L Jamo */
5529   LBP_JV = 23, /* Hangul V Jamo */
5530   LBP_JT = 24, /* Hangul T Jamo */
5531   LBP_SA = 31, /* complex context (South East Asian) */
5532   LBP_XX = 32  /* unknown */
5533 };
5534
5535 /* Returns the line breaking classification for ch, as a bit mask.  */
5536 static int64_t
5537 get_lbp (unsigned int ch)
5538 {
5539   int64_t attr = 0;
5540
5541   if (unicode_attributes[ch].name != NULL)
5542     {
5543       /* mandatory break */
5544       if (ch == 0x000A || ch == 0x000D || ch == 0x0085 /* newline */
5545           || ch == 0x000C /* form feed */
5546           || ch == 0x000B /* line tabulation */
5547           || ch == 0x2028 /* LINE SEPARATOR */
5548           || ch == 0x2029 /* PARAGRAPH SEPARATOR */)
5549         attr |= (int64_t) 1 << LBP_BK;
5550
5551       if (ch == 0x2060 /* WORD JOINER */
5552           || ch == 0xFEFF /* ZERO WIDTH NO-BREAK SPACE */)
5553         attr |= (int64_t) 1 << LBP_WJ;
5554
5555       /* zero width space */
5556       if (ch == 0x200B /* ZERO WIDTH SPACE */)
5557         attr |= (int64_t) 1 << LBP_ZW;
5558
5559       /* non-breaking (glue) */
5560       if (ch == 0x00A0 /* NO-BREAK SPACE */
5561           || ch == 0x202F /* NARROW NO-BREAK SPACE */
5562           || ch == 0x180E /* MONGOLIAN VOWEL SEPARATOR */
5563           || ch == 0x034F /* COMBINING GRAPHEME JOINER */
5564           || ch == 0x2007 /* FIGURE SPACE */
5565           || ch == 0x2011 /* NON-BREAKING HYPHEN */
5566           || ch == 0x0F08 /* TIBETAN MARK SBRUL SHAD */
5567           || ch == 0x0F0C /* TIBETAN MARK DELIMITER TSHEG BSTAR */
5568           || ch == 0x0F12 /* TIBETAN MARK RGYA GRAM SHAD */
5569           || (ch >= 0x035C && ch <= 0x0362) /* COMBINING DOUBLE ... */
5570           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5571           || ch == 0x0FD9 /* TIBETAN MARK LEADING MCHAN RTAGS */
5572           || ch == 0x0FDA /* TIBETAN MARK TRAILING MCHAN RTAGS */)
5573         attr |= (int64_t) 1 << LBP_GL;
5574
5575       /* space */
5576       if (ch == 0x0020 /* SPACE */)
5577         attr |= (int64_t) 1 << LBP_SP;
5578
5579       /* break opportunity before and after */
5580       if (ch == 0x2014 /* EM DASH */)
5581         attr |= (int64_t) 1 << LBP_B2;
5582
5583       /* break opportunity after */
5584       if (/* Breaking Spaces */
5585           ch == 0x1680 /* OGHAM SPACE MARK */
5586           || ch == 0x2000 /* EN QUAD */
5587           || ch == 0x2001 /* EM QUAD */
5588           || ch == 0x2002 /* EN SPACE */
5589           || ch == 0x2003 /* EM SPACE */
5590           || ch == 0x2004 /* THREE-PER-EM SPACE */
5591           || ch == 0x2005 /* FOUR-PER-EM SPACE */
5592           || ch == 0x2006 /* SIX-PER-EM SPACE */
5593           || ch == 0x2008 /* PUNCTUATION SPACE */
5594           || ch == 0x2009 /* THIN SPACE */
5595           || ch == 0x200A /* HAIR SPACE */
5596           || ch == 0x205F /* MEDIUM MATHEMATICAL SPACE */
5597           /* Tabs */
5598           || ch == 0x0009 /* tab */
5599           /* Conditional Hyphens */
5600           || ch == 0x00AD /* SOFT HYPHEN */
5601           /* Breaking Hyphens */
5602           || ch == 0x058A /* ARMENIAN HYPHEN */
5603           || ch == 0x1400 /* CANADIAN SYLLABICS HYPHEN */
5604           || ch == 0x2010 /* HYPHEN */
5605           || ch == 0x2012 /* FIGURE DASH */
5606           || ch == 0x2013 /* EN DASH */
5607           /* Visible Word Dividers */
5608           || ch == 0x05BE /* HEBREW PUNCTUATION MAQAF */
5609           || ch == 0x0F0B /* TIBETAN MARK INTERSYLLABIC TSHEG */
5610           || ch == 0x1361 /* ETHIOPIC WORDSPACE */
5611           || ch == 0x17D8 /* KHMER SIGN BEYYAL */
5612           || ch == 0x17DA /* KHMER SIGN KOOMUUT */
5613           || ch == 0x2027 /* HYPHENATION POINT */
5614           || ch == 0x007C /* VERTICAL LINE */
5615           /* Historic Word Separators */
5616           || ch == 0x16EB /* RUNIC SINGLE PUNCTUATION */
5617           || ch == 0x16EC /* RUNIC MULTIPLE PUNCTUATION */
5618           || ch == 0x16ED /* RUNIC CROSS PUNCTUATION */
5619           || ch == 0x2056 /* THREE DOT PUNCTUATION */
5620           || ch == 0x2058 /* FOUR DOT PUNCTUATION */
5621           || ch == 0x2059 /* FIVE DOT PUNCTUATION */
5622           || ch == 0x205A /* TWO DOT PUNCTUATION */
5623           || ch == 0x205B /* FOUR DOT MARK */
5624           || ch == 0x205D /* TRICOLON */
5625           || ch == 0x205E /* VERTICAL FOUR DOTS */
5626           || ch == 0x2E19 /* PALM BRANCH */
5627           || ch == 0x2E2A /* TWO DOTS OVER ONE DOT PUNCTUATION */
5628           || ch == 0x2E2B /* ONE DOT OVER TWO DOTS PUNCTUATION */
5629           || ch == 0x2E2C /* SQUARED FOUR DOT PUNCTUATION */
5630           || ch == 0x2E2D /* FIVE DOT PUNCTUATION */
5631           || ch == 0x2E30 /* RING POINT */
5632           || ch == 0x2E31 /* WORD SEPARATOR MIDDLE DOT */
5633           || ch == 0x10100 /* AEGEAN WORD SEPARATOR LINE */
5634           || ch == 0x10101 /* AEGEAN WORD SEPARATOR DOT */
5635           || ch == 0x10102 /* AEGEAN CHECK MARK */
5636           || ch == 0x1039F /* UGARITIC WORD DIVIDER */
5637           || ch == 0x103D0 /* OLD PERSIAN WORD DIVIDER */
5638           || ch == 0x1091F /* PHOENICIAN WORD SEPARATOR */
5639           || ch == 0x12470 /* CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER */
5640           /* Dandas */
5641           || ch == 0x0964 /* DEVANAGARI DANDA */
5642           || ch == 0x0965 /* DEVANAGARI DOUBLE DANDA */
5643           || ch == 0x0E5A /* THAI CHARACTER ANGKHANKHU */
5644           || ch == 0x0E5B /* THAI CHARACTER KHOMUT */
5645           || ch == 0x104A /* MYANMAR SIGN LITTLE SECTION */
5646           || ch == 0x104B /* MYANMAR SIGN SECTION */
5647           || ch == 0x1735 /* PHILIPPINE SINGLE PUNCTUATION */
5648           || ch == 0x1736 /* PHILIPPINE DOUBLE PUNCTUATION */
5649           || ch == 0x17D4 /* KHMER SIGN KHAN */
5650           || ch == 0x17D5 /* KHMER SIGN BARIYOOSAN */
5651           || ch == 0x1B5E /* BALINESE CARIK SIKI */
5652           || ch == 0x1B5F /* BALINESE CARIK PAREREN */
5653           || ch == 0xA8CE /* SAURASHTRA DANDA */
5654           || ch == 0xA8CF /* SAURASHTRA DOUBLE DANDA */
5655           || ch == 0xAA5D /* CHAM PUNCTUATION DANDA */
5656           || ch == 0xAA5E /* CHAM PUNCTUATION DOUBLE DANDA */
5657           || ch == 0xAA5F /* CHAM PUNCTUATION TRIPLE DANDA */
5658           || ch == 0x10A56 /* KHAROSHTHI PUNCTUATION DANDA */
5659           || ch == 0x10A57 /* KHAROSHTHI PUNCTUATION DOUBLE DANDA */
5660           /* Tibetan */
5661           || ch == 0x0F34 /* TIBETAN MARK BSDUS RTAGS */
5662           || ch == 0x0F7F /* TIBETAN SIGN RNAM BCAD */
5663           || ch == 0x0F85 /* TIBETAN MARK PALUTA */
5664           || ch == 0x0FBE /* TIBETAN KU RU KHA */
5665           || ch == 0x0FBF /* TIBETAN KU RU KHA BZHI MIG CAN */
5666           || ch == 0x0FD2 /* TIBETAN MARK NYIS TSHEG */
5667           /* Other Terminating Punctuation */
5668           || ch == 0x1804 /* MONGOLIAN COLON */
5669           || ch == 0x1805 /* MONGOLIAN FOUR DOTS */
5670           || ch == 0x1B5A /* BALINESE PANTI */
5671           || ch == 0x1B5B /* BALINESE PAMADA */
5672           || ch == 0x1B5D /* BALINESE CARIK PAMUNGKAH */
5673           || ch == 0x1B60 /* BALINESE PAMENENG */
5674           || ch == 0x1C3B /* LEPCHA PUNCTUATION TA-ROL */
5675           || ch == 0x1C3C /* LEPCHA PUNCTUATION NYET THYOOM TA-ROL */
5676           || ch == 0x1C3D /* LEPCHA PUNCTUATION CER-WA */
5677           || ch == 0x1C3E /* LEPCHA PUNCTUATION TSHOOK CER-WA */
5678           || ch == 0x1C3F /* LEPCHA PUNCTUATION TSHOOK */
5679           || ch == 0x1C7E /* OL CHIKI PUNCTUATION MUCAAD */
5680           || ch == 0x1C7F /* OL CHIKI PUNCTUATION DOUBLE MUCAAD */
5681           || ch == 0x2CFA /* COPTIC OLD NUBIAN DIRECT QUESTION MARK */
5682           || ch == 0x2CFB /* COPTIC OLD NUBIAN INDIRECT QUESTION MARK */
5683           || ch == 0x2CFC /* COPTIC OLD NUBIAN VERSE DIVIDER */
5684           || ch == 0x2CFF /* COPTIC MORPHOLOGICAL DIVIDER */
5685           || (ch >= 0x2E0E && ch <= 0x2E15) /* EDITORIAL CORONIS .. UPWARDS ANCORA */
5686           || ch == 0x2E17 /* DOUBLE OBLIQUE HYPHEN */
5687           || ch == 0xA60D /* VAI COMMA */
5688           || ch == 0xA60F /* VAI QUESTION MARK */
5689           || ch == 0xA92E /* KAYAH LI SIGN CWI */
5690           || ch == 0xA92F /* KAYAH LI SIGN SHYA */
5691           || ch == 0x10A50 /* KHAROSHTHI PUNCTUATION DOT */
5692           || ch == 0x10A51 /* KHAROSHTHI PUNCTUATION SMALL CIRCLE */
5693           || ch == 0x10A52 /* KHAROSHTHI PUNCTUATION CIRCLE */
5694           || ch == 0x10A53 /* KHAROSHTHI PUNCTUATION CRESCENT BAR */
5695           || ch == 0x10A54 /* KHAROSHTHI PUNCTUATION MANGALAM */
5696           || ch == 0x10A55 /* KHAROSHTHI PUNCTUATION LOTUS */
5697           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5698           || ch == 0x2D70 /* TIFINAGH SEPARATOR MARK */
5699           || ch == 0xA4FE /* LISU PUNCTUATION COMMA */
5700           || ch == 0xA4FF /* LISU PUNCTUATION FULL STOP */
5701           || ch == 0xA6F3 /* BAMUM FULL STOP */
5702           || ch == 0xA6F4 /* BAMUM COLON */
5703           || ch == 0xA6F5 /* BAMUM COMMA */
5704           || ch == 0xA6F6 /* BAMUM SEMICOLON */
5705           || ch == 0xA6F7 /* BAMUM QUESTION MARK */
5706           || ch == 0xA9C7 /* JAVANESE PADA PANGKAT */
5707           || ch == 0xA9C8 /* JAVANESE PADA LINGSA */
5708           || ch == 0xA9C9 /* JAVANESE PADA LUNGSI */
5709           || ch == 0xABEB /* MEETEI MAYEK CHEIKHEI */
5710           || ch == 0x10857 /* IMPERIAL ARAMAIC SECTION SIGN */
5711           || ch == 0x10B39 /* AVESTAN ABBREVIATION MARK */
5712           || ch == 0x10B3A /* TINY TWO DOTS OVER ONE DOT PUNCTUATION */
5713           || ch == 0x10B3B /* SMALL TWO DOTS OVER ONE DOT PUNCTUATION */
5714           || ch == 0x10B3C /* LARGE TWO DOTS OVER ONE DOT PUNCTUATION */
5715           || ch == 0x10B3D /* LARGE ONE DOT OVER TWO DOTS PUNCTUATION */
5716           || ch == 0x10B3E /* LARGE TWO RINGS OVER ONE RING PUNCTUATION */
5717           || ch == 0x10B3F /* LARGE ONE RING OVER TWO RINGS PUNCTUATION */
5718           || ch == 0x11047 /* BRAHMI DANDA */
5719           || ch == 0x11048 /* BRAHMI DOUBLE DANDA */
5720           || ch == 0x110BE /* KAITHI SECTION MARK */
5721           || ch == 0x110BF /* KAITHI DOUBLE SECTION MARK */
5722           || ch == 0x110C0 /* KAITHI DANDA */
5723           || ch == 0x110C1 /* KAITHI DOUBLE DANDA */
5724           || ch == 0x12471 /* CUNEIFORM PUNCTUATION SIGN VERTICAL COLON */
5725           || ch == 0x12472 /* CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON */
5726           || ch == 0x12473 /* CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON */)
5727         attr |= (int64_t) 1 << LBP_BA;
5728
5729       /* break opportunity before */
5730       if (ch == 0x00B4 /* ACUTE ACCENT */
5731           || ch == 0x1FFD /* GREEK OXIA */
5732           || ch == 0x02DF /* MODIFIER LETTER CROSS ACCENT */
5733           || ch == 0x02C8 /* MODIFIER LETTER VERTICAL LINE */
5734           || ch == 0x02CC /* MODIFIER LETTER LOW VERTICAL LINE */
5735           || ch == 0x0F01 /* TIBETAN MARK GTER YIG MGO TRUNCATED A */
5736           || ch == 0x0F02 /* TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA */
5737           || ch == 0x0F03 /* TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA */
5738           || ch == 0x0F04 /* TIBETAN MARK INITIAL YIG MGO MDUN MA */
5739           || ch == 0x0F06 /* TIBETAN MARK CARET YIG MGO PHUR SHAD MA */
5740           || ch == 0x0F07 /* TIBETAN MARK YIG MGO TSHEG SHAD MA */
5741           || ch == 0x0F09 /* TIBETAN MARK BSKUR YIG MGO */
5742           || ch == 0x0F0A /* TIBETAN MARK BKA- SHOG YIG MGO */
5743           || ch == 0x0FD0 /* TIBETAN MARK BSKA- SHOG GI MGO RGYAN */
5744           || ch == 0x0FD1 /* TIBETAN MARK MNYAM YIG GI MGO RGYAN */
5745           || ch == 0x0FD3 /* TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA */
5746           || ch == 0xA874 /* PHAGS-PA SINGLE HEAD MARK */
5747           || ch == 0xA875 /* PHAGS-PA DOUBLE HEAD MARK */
5748           || ch == 0x1806 /* MONGOLIAN TODO SOFT HYPHEN */)
5749         attr |= (int64_t) 1 << LBP_BB;
5750
5751       /* hyphen */
5752       if (ch == 0x002D /* HYPHEN-MINUS */)
5753         attr |= (int64_t) 1 << LBP_HY;
5754
5755       /* contingent break opportunity */
5756       if (ch == 0xFFFC /* OBJECT REPLACEMENT CHARACTER */)
5757         attr |= (int64_t) 1 << LBP_CB;
5758
5759       /* closing parenthesis */
5760       if (ch == 0x0029 /* RIGHT PARENTHESIS */
5761           || ch == 0x005D /* RIGHT SQUARE BRACKET */)
5762         attr |= (int64_t) 1 << LBP_CP;
5763
5764       /* closing punctuation */
5765       if ((unicode_attributes[ch].category[0] == 'P'
5766            && unicode_attributes[ch].category[1] == 'e'
5767            && !(attr & ((int64_t) 1 << LBP_CP)))
5768           || ch == 0x3001 /* IDEOGRAPHIC COMMA */
5769           || ch == 0x3002 /* IDEOGRAPHIC FULL STOP */
5770           || ch == 0xFE11 /* PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA */
5771           || ch == 0xFE12 /* PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP */
5772           || ch == 0xFE50 /* SMALL COMMA */
5773           || ch == 0xFE52 /* SMALL FULL STOP */
5774           || ch == 0xFF0C /* FULLWIDTH COMMA */
5775           || ch == 0xFF0E /* FULLWIDTH FULL STOP */
5776           || ch == 0xFF61 /* HALFWIDTH IDEOGRAPHIC FULL STOP */
5777           || ch == 0xFF64 /* HALFWIDTH IDEOGRAPHIC COMMA */
5778           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5779           || ch == 0x1325B /* EGYPTIAN HIEROGLYPH O006D */
5780           || ch == 0x1325C /* EGYPTIAN HIEROGLYPH O006E */
5781           || ch == 0x1325D /* EGYPTIAN HIEROGLYPH O006F */
5782           || ch == 0x13282 /* EGYPTIAN HIEROGLYPH O033A */
5783           || ch == 0x13287 /* EGYPTIAN HIEROGLYPH O036B */
5784           || ch == 0x13289 /* EGYPTIAN HIEROGLYPH O036D */
5785           || ch == 0x1337A /* EGYPTIAN HIEROGLYPH V011B */
5786           || ch == 0x1337B /* EGYPTIAN HIEROGLYPH V011C */)
5787         attr |= (int64_t) 1 << LBP_CL;
5788
5789       /* exclamation/interrogation */
5790       if (ch == 0x0021 /* EXCLAMATION MARK */
5791           || ch == 0x003F /* QUESTION MARK */
5792           || ch == 0x05C6 /* HEBREW PUNCTUATION NUN HAFUKHA */
5793           || ch == 0x061B /* ARABIC SEMICOLON */
5794           || ch == 0x061E /* ARABIC TRIPLE DOT PUNCTUATION MARK */
5795           || ch == 0x061F /* ARABIC QUESTION MARK */
5796           || ch == 0x06D4 /* ARABIC FULL STOP */
5797           || ch == 0x07F9 /* NKO EXCLAMATION MARK */
5798           || ch == 0x0F0D /* TIBETAN MARK SHAD */
5799           || ch == 0x0F0E /* TIBETAN MARK NYIS SHAD */
5800           || ch == 0x0F0F /* TIBETAN MARK TSHEG SHAD */
5801           || ch == 0x0F10 /* TIBETAN MARK NYIS TSHEG SHAD */
5802           || ch == 0x0F11 /* TIBETAN MARK RIN CHEN SPUNGS SHAD */
5803           || ch == 0x0F14 /* TIBETAN MARK GTER TSHEG */
5804           || ch == 0x1802 /* MONGOLIAN COMMA */
5805           || ch == 0x1803 /* MONGOLIAN FULL STOP */
5806           || ch == 0x1808 /* MONGOLIAN MANCHU COMMA */
5807           || ch == 0x1809 /* MONGOLIAN MANCHU FULL STOP */
5808           || ch == 0x1944 /* LIMBU EXCLAMATION MARK */
5809           || ch == 0x1945 /* LIMBU QUESTION MARK */
5810           || ch == 0x2762 /* HEAVY EXCLAMATION MARK ORNAMENT */
5811           || ch == 0x2763 /* HEAVY HEART EXCLAMATION MARK ORNAMENT */
5812           || ch == 0x2CF9 /* COPTIC OLD NUBIAN FULL STOP */
5813           || ch == 0x2CFE /* COPTIC FULL STOP */
5814           || ch == 0x2E2E /* REVERSED QUESTION MARK */
5815           || ch == 0xA60E /* VAI FULL STOP */
5816           || ch == 0xA876 /* PHAGS-PA MARK SHAD */
5817           || ch == 0xA877 /* PHAGS-PA MARK DOUBLE SHAD */
5818           || ch == 0xFE15 /* PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK */
5819           || ch == 0xFE16 /* PRESENTATION FORM FOR VERTICAL QUESTION MARK */
5820           || ch == 0xFE56 /* SMALL QUESTION MARK */
5821           || ch == 0xFE57 /* SMALL EXCLAMATION MARK */
5822           || ch == 0xFF01 /* FULLWIDTH EXCLAMATION MARK */
5823           || ch == 0xFF1F /* FULLWIDTH QUESTION MARK */)
5824         attr |= (int64_t) 1 << LBP_EX;
5825
5826       /* inseparable */
5827       if (ch == 0x2024 /* ONE DOT LEADER */
5828           || ch == 0x2025 /* TWO DOT LEADER */
5829           || ch == 0x2026 /* HORIZONTAL ELLIPSIS */
5830           || ch == 0xFE19 /* PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS */)
5831         attr |= (int64_t) 1 << LBP_IN;
5832
5833       /* non starter */
5834       if (ch == 0x17D6 /* KHMER SIGN CAMNUC PII KUUH */
5835           || ch == 0x203C /* DOUBLE EXCLAMATION MARK */
5836           || ch == 0x203D /* INTERROBANG */
5837           || ch == 0x2047 /* DOUBLE QUESTION MARK */
5838           || ch == 0x2048 /* QUESTION EXCLAMATION MARK */
5839           || ch == 0x2049 /* EXCLAMATION QUESTION MARK */
5840           || ch == 0x3005 /* IDEOGRAPHIC ITERATION MARK */
5841           || ch == 0x301C /* WAVE DASH */
5842           || ch == 0x303C /* MASU MARK */
5843           || ch == 0x303B /* VERTICAL IDEOGRAPHIC ITERATION MARK */
5844           || ch == 0x309B /* KATAKANA-HIRAGANA VOICED SOUND MARK */
5845           || ch == 0x309C /* KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
5846           || ch == 0x309D /* HIRAGANA ITERATION MARK */
5847           || ch == 0x309E /* HIRAGANA VOICED ITERATION MARK */
5848           || ch == 0x30A0 /* KATAKANA-HIRAGANA DOUBLE HYPHEN */
5849           || ch == 0x30FB /* KATAKANA MIDDLE DOT */
5850           || ch == 0x30FC /* KATAKANA-HIRAGANA PROLONGED SOUND MARK */
5851           || ch == 0x30FD /* KATAKANA ITERATION MARK */
5852           || ch == 0x30FE /* KATAKANA VOICED ITERATION MARK */
5853           || ch == 0xA015 /* YI SYLLABLE WU */
5854           || ch == 0xFE54 /* SMALL SEMICOLON */
5855           || ch == 0xFE55 /* SMALL COLON */
5856           || ch == 0xFF1A /* FULLWIDTH COLON */
5857           || ch == 0xFF1B /* FULLWIDTH SEMICOLON */
5858           || ch == 0xFF65 /* HALFWIDTH KATAKANA MIDDLE DOT */
5859           || ch == 0xFF70 /* HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */
5860           || ch == 0xFF9E /* HALFWIDTH KATAKANA VOICED SOUND MARK */
5861           || ch == 0xFF9F /* HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */
5862           || strstr (unicode_attributes[ch].name, "HIRAGANA LETTER SMALL ") != NULL
5863           || strstr (unicode_attributes[ch].name, "KATAKANA LETTER SMALL ") != NULL)
5864         attr |= (int64_t) 1 << LBP_NS;
5865
5866       /* opening punctuation */
5867       if ((unicode_attributes[ch].category[0] == 'P'
5868            && unicode_attributes[ch].category[1] == 's')
5869           || ch == 0x00A1 /* INVERTED EXCLAMATION MARK */
5870           || ch == 0x00BF /* INVERTED QUESTION MARK */
5871           || ch == 0x2E18 /* INVERTED INTERROBANG */
5872           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5873           || ch == 0x13258 /* EGYPTIAN HIEROGLYPH O006A */
5874           || ch == 0x13259 /* EGYPTIAN HIEROGLYPH O006B */
5875           || ch == 0x1325A /* EGYPTIAN HIEROGLYPH O006C */
5876           || ch == 0x13286 /* EGYPTIAN HIEROGLYPH O036A */
5877           || ch == 0x13288 /* EGYPTIAN HIEROGLYPH O036C */
5878           || ch == 0x13379 /* EGYPTIAN HIEROGLYPH V011A */)
5879         attr |= (int64_t) 1 << LBP_OP;
5880
5881       /* ambiguous quotation */
5882       if ((unicode_attributes[ch].category[0] == 'P'
5883            && (unicode_attributes[ch].category[1] == 'f'
5884                || unicode_attributes[ch].category[1] == 'i'))
5885           || ch == 0x0022 /* QUOTATION MARK */
5886           || ch == 0x0027 /* APOSTROPHE */
5887           || ch == 0x275B /* HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT */
5888           || ch == 0x275C /* HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT */
5889           || ch == 0x275D /* HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT */
5890           || ch == 0x275E /* HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT */
5891           || ch == 0x2E00 /* RIGHT ANGLE SUBSTITUTION MARKER */
5892           || ch == 0x2E01 /* RIGHT ANGLE DOTTED SUBSTITUTION MARKER */
5893           || ch == 0x2E06 /* RAISED INTERPOLATION MARKER */
5894           || ch == 0x2E07 /* RAISED DOTTED INTERPOLATION MARKER */
5895           || ch == 0x2E08 /* DOTTED TRANSPOSITION MARKER */
5896           || ch == 0x2E0B /* RAISED SQUARE */)
5897         attr |= (int64_t) 1 << LBP_QU;
5898
5899       /* infix separator (numeric) */
5900       if (ch == 0x002C /* COMMA */
5901           || ch == 0x002E /* FULL STOP */
5902           || ch == 0x003A /* COLON */
5903           || ch == 0x003B /* SEMICOLON */
5904           || ch == 0x037E /* GREEK QUESTION MARK */
5905           || ch == 0x0589 /* ARMENIAN FULL STOP */
5906           || ch == 0x060C /* ARABIC COMMA */
5907           || ch == 0x060D /* ARABIC DATE SEPARATOR */
5908           || ch == 0x07F8 /* NKO COMMA */
5909           || ch == 0x2044 /* FRACTION SLASH */
5910           || ch == 0xFE10 /* PRESENTATION FORM FOR VERTICAL COMMA */
5911           || ch == 0xFE13 /* PRESENTATION FORM FOR VERTICAL COLON */
5912           || ch == 0xFE14 /* PRESENTATION FORM FOR VERTICAL SEMICOLON */)
5913         attr |= (int64_t) 1 << LBP_IS;
5914
5915       /* numeric */
5916       if ((unicode_attributes[ch].category[0] == 'N'
5917            && unicode_attributes[ch].category[1] == 'd'
5918            && strstr (unicode_attributes[ch].name, "FULLWIDTH") == NULL)
5919           || ch == 0x066B /* ARABIC DECIMAL SEPARATOR */
5920           || ch == 0x066C /* ARABIC THOUSANDS SEPARATOR */)
5921         attr |= (int64_t) 1 << LBP_NU;
5922
5923       /* postfix (numeric) */
5924       if (ch == 0x0025 /* PERCENT SIGN */
5925           || ch == 0x00A2 /* CENT SIGN */
5926           || ch == 0x00B0 /* DEGREE SIGN */
5927           || ch == 0x060B /* AFGHANI SIGN */
5928           || ch == 0x066A /* ARABIC PERCENT SIGN */
5929           || ch == 0x2030 /* PER MILLE SIGN */
5930           || ch == 0x2031 /* PER TEN THOUSAND SIGN */
5931           || ch == 0x2032 /* PRIME */
5932           || ch == 0x2033 /* DOUBLE PRIME */
5933           || ch == 0x2034 /* TRIPLE PRIME */
5934           || ch == 0x2035 /* REVERSED PRIME */
5935           || ch == 0x2036 /* REVERSED DOUBLE PRIME */
5936           || ch == 0x2037 /* REVERSED TRIPLE PRIME */
5937           || ch == 0x20A7 /* PESETA SIGN */
5938           || ch == 0x2103 /* DEGREE CELSIUS */
5939           || ch == 0x2109 /* DEGREE FAHRENHEIT */
5940           || ch == 0xFDFC /* RIAL SIGN */
5941           || ch == 0xFE6A /* SMALL PERCENT SIGN */
5942           || ch == 0xFF05 /* FULLWIDTH PERCENT SIGN */
5943           || ch == 0xFFE0 /* FULLWIDTH DIGIT ZERO */
5944           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5945           || ch == 0x0609 /* ARABIC-INDIC PER MILLE SIGN */
5946           || ch == 0x060A /* ARABIC-INDIC PER TEN THOUSAND SIGN */
5947           || ch == 0x09F2 /* BENGALI RUPEE MARK */
5948           || ch == 0x09F3 /* BENGALI RUPEE SIGN */
5949           || ch == 0x09F9 /* BENGALI CURRENCY DENOMINATOR SIXTEEN */
5950           || ch == 0x0D79 /* MALAYALAM DATE MARK */
5951           || ch == 0x20B6 /* LIVRE TOURNOIS SIGN */
5952           || ch == 0xA838 /* NORTH INDIC RUPEE MARK */)
5953         attr |= (int64_t) 1 << LBP_PO;
5954
5955       /* prefix (numeric) */
5956       if ((unicode_attributes[ch].category[0] == 'S'
5957            && unicode_attributes[ch].category[1] == 'c')
5958           || ch == 0x002B /* PLUS SIGN */
5959           || ch == 0x005C /* REVERSE SOLIDUS */
5960           || ch == 0x00B1 /* PLUS-MINUS SIGN */
5961           || ch == 0x2116 /* NUMERO SIGN */
5962           || ch == 0x2212 /* MINUS SIGN */
5963           || ch == 0x2213 /* MINUS-OR-PLUS SIGN */)
5964         if (!(attr & ((int64_t) 1 << LBP_PO)))
5965           attr |= (int64_t) 1 << LBP_PR;
5966
5967       /* symbols allowing breaks */
5968       if (ch == 0x002F /* SOLIDUS */)
5969         attr |= (int64_t) 1 << LBP_SY;
5970
5971       if (ch >= 0xAC00 && ch <= 0xD7A3 && ((ch - 0xAC00) % 28) == 0)
5972         attr |= (int64_t) 1 << LBP_H2;
5973
5974       if (ch >= 0xAC00 && ch <= 0xD7A3 && ((ch - 0xAC00) % 28) != 0)
5975         attr |= (int64_t) 1 << LBP_H3;
5976
5977       if ((ch >= 0x1100 && ch <= 0x115F) || (ch >= 0xA960 && ch <= 0xA97C))
5978         attr |= (int64_t) 1 << LBP_JL;
5979
5980       if ((ch >= 0x1160 && ch <= 0x11A7) || (ch >= 0xD7B0 && ch <= 0xD7C6))
5981         attr |= (int64_t) 1 << LBP_JV;
5982
5983       if ((ch >= 0x11A8 && ch <= 0x11FF) || (ch >= 0xD7CB && ch <= 0xD7FB))
5984         attr |= (int64_t) 1 << LBP_JT;
5985
5986       /* complex context (South East Asian) */
5987       if (((unicode_attributes[ch].category[0] == 'C'
5988             && unicode_attributes[ch].category[1] == 'f')
5989            || (unicode_attributes[ch].category[0] == 'L'
5990                && (unicode_attributes[ch].category[1] == 'm'
5991                    || unicode_attributes[ch].category[1] == 'o'))
5992            || (unicode_attributes[ch].category[0] == 'M'
5993                && (unicode_attributes[ch].category[1] == 'c'
5994                    || unicode_attributes[ch].category[1] == 'n')
5995                && ch != 0x1A7F /* TAI THAM COMBINING CRYPTOGRAMMIC DOT */)
5996            /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5997            || ch == 0x109E /* MYANMAR SYMBOL SHAN ONE */
5998            || ch == 0x109F /* MYANMAR SYMBOL SHAN EXCLAMATION */
5999            || ch == 0x19DA /* NEW TAI LUE THAM DIGIT ONE */
6000            || ch == 0x19DE /* NEW TAI LUE SIGN LAE */
6001            || ch == 0x19DF /* NEW TAI LUE SIGN LAEV */
6002            || (ch >= 0x1AA0 && ch <= 0x1AAD) /* TAI THAM SIGN */
6003            || (ch >= 0xAA77 && ch <= 0xAA79) /* MYANMAR SYMBOL AITON */
6004            || (ch >= 0xAADE && ch <= 0xAADF) /* TAI VIET SYMBOL */)
6005           && ((ch >= 0x0E00 && ch <= 0x0EFF) /* Thai, Lao */
6006               || (ch >= 0x1000 && ch <= 0x109F) /* Myanmar */
6007               || (ch >= 0x1780 && ch <= 0x17FF) /* Khmer */
6008               || (ch >= 0x1950 && ch <= 0x19DF) /* Tai Le, New Tai Lue */
6009               || (ch >= 0x1A20 && ch <= 0x1AAF) /* Tai Tham */
6010               || (ch >= 0xAA60 && ch <= 0xAADF) /* Myanmar Extended-A, Tai Viet */))
6011         attr |= (int64_t) 1 << LBP_SA;
6012
6013       /* attached characters and combining marks */
6014       if ((unicode_attributes[ch].category[0] == 'M'
6015            && (unicode_attributes[ch].category[1] == 'c'
6016                || unicode_attributes[ch].category[1] == 'e'
6017                || unicode_attributes[ch].category[1] == 'n'))
6018           || (unicode_attributes[ch].category[0] == 'C'
6019               && (unicode_attributes[ch].category[1] == 'c'
6020                   || unicode_attributes[ch].category[1] == 'f')
6021               && ch != 0x110BD /* KAITHI NUMBER SIGN */))
6022         if (!(attr & (((int64_t) 1 << LBP_BK) | ((int64_t) 1 << LBP_BA) | ((int64_t) 1 << LBP_GL) | ((int64_t) 1 << LBP_SA) | ((int64_t) 1 << LBP_WJ) | ((int64_t) 1 << LBP_ZW))))
6023           attr |= (int64_t) 1 << LBP_CM;
6024
6025       /* ideographic */
6026       if ((ch >= 0x2E80 && ch <= 0x2FFF) /* CJK RADICAL, KANGXI RADICAL, IDEOGRAPHIC DESCRIPTION */
6027           || ch == 0x3000 /* IDEOGRAPHIC SPACE */
6028           || (ch >= 0x3040 && ch <= 0x309F) /* HIRAGANA */
6029           || (ch >= 0x30A0 && ch <= 0x30FF) /* KATAKANA */
6030           || (ch >= 0x3400 && ch <= 0x4DBF) /* CJK Ideograph Extension A */
6031           || (ch >= 0x4E00 && ch <= 0x9FFF) /* CJK Ideograph */
6032           || (ch >= 0xF900 && ch <= 0xFAD9) /* CJK COMPATIBILITY IDEOGRAPH */
6033           || (ch >= 0xA000 && ch <= 0xA48F) /* YI SYLLABLE */
6034           || (ch >= 0xA490 && ch <= 0xA4CF) /* YI RADICAL */
6035           || ch == 0xFE62 /* SMALL PLUS SIGN */
6036           || ch == 0xFE63 /* SMALL HYPHEN-MINUS */
6037           || ch == 0xFE64 /* SMALL LESS-THAN SIGN */
6038           || ch == 0xFE65 /* SMALL GREATER-THAN SIGN */
6039           || ch == 0xFE66 /* SMALL EQUALS SIGN */
6040           || (ch >= 0xFF10 && ch <= 0xFF19) /* FULLWIDTH DIGIT */
6041           || (ch >= 0x20000 && ch <= 0x2A6D6) /* CJK Ideograph Extension B */
6042           || (ch >= 0x2F800 && ch <= 0x2FA1D) /* CJK COMPATIBILITY IDEOGRAPH */
6043           || strstr (unicode_attributes[ch].name, "FULLWIDTH LATIN ") != NULL
6044           || (ch >= 0x3000 && ch <= 0x33FF
6045               && !(attr & (((int64_t) 1 << LBP_CM) | ((int64_t) 1 << LBP_NS) | ((int64_t) 1 << LBP_OP) | ((int64_t) 1 << LBP_CL) | ((int64_t) 1 << LBP_CP))))
6046           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
6047           || ch == 0xFE30 /* PRESENTATION FORM FOR VERTICAL TWO DOT LEADER */
6048           || ch == 0xFE31 /* PRESENTATION FORM FOR VERTICAL EM DASH */
6049           || ch == 0xFE32 /* PRESENTATION FORM FOR VERTICAL EN DASH */
6050           || ch == 0xFE33 /* PRESENTATION FORM FOR VERTICAL LOW LINE */
6051           || ch == 0xFE34 /* PRESENTATION FORM FOR VERTICAL WAVY LOW LINE */
6052           || ch == 0xFE45 /* SESAME DOT */
6053           || ch == 0xFE46 /* WHITE SESAME DOT */
6054           || ch == 0xFE49 /* DASHED OVERLINE */
6055           || ch == 0xFE4A /* CENTRELINE OVERLINE */
6056           || ch == 0xFE4B /* WAVY OVERLINE */
6057           || ch == 0xFE4C /* DOUBLE WAVY OVERLINE */
6058           || ch == 0xFE4D /* DASHED LOW LINE */
6059           || ch == 0xFE4E /* CENTRELINE LOW LINE */
6060           || ch == 0xFE4F /* WAVY LOW LINE */
6061           || ch == 0xFE51 /* SMALL IDEOGRAPHIC COMMA */
6062           || ch == 0xFE58 /* SMALL EM DASH */
6063           || ch == 0xFE5F /* SMALL NUMBER SIGN */
6064           || ch == 0xFE60 /* SMALL AMPERSAND */
6065           || ch == 0xFE61 /* SMALL ASTERISK */
6066           || ch == 0xFE68 /* SMALL REVERSE SOLIDUS */
6067           || ch == 0xFE6B /* SMALL COMMERCIAL AT */
6068           || ch == 0xFF02 /* FULLWIDTH QUOTATION MARK */
6069           || ch == 0xFF03 /* FULLWIDTH NUMBER SIGN */
6070           || ch == 0xFF06 /* FULLWIDTH AMPERSAND */
6071           || ch == 0xFF07 /* FULLWIDTH APOSTROPHE */
6072           || ch == 0xFF0A /* FULLWIDTH ASTERISK */
6073           || ch == 0xFF0B /* FULLWIDTH PLUS SIGN */
6074           || ch == 0xFF0D /* FULLWIDTH HYPHEN-MINUS */
6075           || ch == 0xFF0F /* FULLWIDTH SOLIDUS */
6076           || ch == 0xFF1C /* FULLWIDTH LESS-THAN SIGN */
6077           || ch == 0xFF1D /* FULLWIDTH EQUALS SIGN */
6078           || ch == 0xFF1E /* FULLWIDTH GREATER-THAN SIGN */
6079           || ch == 0xFF20 /* FULLWIDTH COMMERCIAL AT */
6080           || ch == 0xFF3C /* FULLWIDTH REVERSE SOLIDUS */
6081           || ch == 0xFF3E /* FULLWIDTH CIRCUMFLEX ACCENT */
6082           || ch == 0xFF3F /* FULLWIDTH LOW LINE */
6083           || ch == 0xFF40 /* FULLWIDTH GRAVE ACCENT */
6084           || ch == 0xFF5C /* FULLWIDTH VERTICAL LINE */
6085           || ch == 0xFF5E /* FULLWIDTH TILDE */
6086           || ch == 0xFFE2 /* FULLWIDTH NOT SIGN */
6087           || ch == 0xFFE3 /* FULLWIDTH MACRON */
6088           || ch == 0xFFE4 /* FULLWIDTH BROKEN BAR */
6089           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
6090           || (ch >= 0x1B000 && ch <= 0x1B001) /* Kana Supplement */
6091           || (ch >= 0x1F200 && ch <= 0x1F248) /* Enclosed Ideographic Supplement */
6092           || (ch >= 0x1F250 && ch <= 0x1F251) /* Enclosed Ideographic Supplement */
6093           || (ch >= 0x2A700 && ch <= 0x2B734) /* CJK Ideograph Extension C */
6094           || (ch >= 0x2B740 && ch <= 0x2B81D) /* CJK Ideograph Extension D */)
6095         if (!(attr & (((int64_t) 1 << LBP_NS) | ((int64_t) 1 << LBP_CM))))
6096           {
6097             /* ambiguous (ideograph) ? */
6098             if ((unicode_width[ch] != NULL
6099                  && unicode_width[ch][0] == 'A'
6100                  && ch >= 0x2000)
6101                 || ch == 0x24EA /* CIRCLED DIGIT ZERO */
6102                 || (ch >= 0x2780 && ch <= 0x2793) /* DINGBAT ... CIRCLED DIGIT ... */)
6103               attr |= (int64_t) 1 << LBP_AI;
6104             else
6105               attr |= (int64_t) 1 << LBP_ID;
6106           }
6107
6108       /* ordinary alphabetic and symbol characters */
6109       if ((unicode_attributes[ch].category[0] == 'L'
6110            && (unicode_attributes[ch].category[1] == 'u'
6111                || unicode_attributes[ch].category[1] == 'l'
6112                || unicode_attributes[ch].category[1] == 't'
6113                || unicode_attributes[ch].category[1] == 'm'
6114                || unicode_attributes[ch].category[1] == 'o'))
6115           || (unicode_attributes[ch].category[0] == 'S'
6116               && (unicode_attributes[ch].category[1] == 'm'
6117                   || unicode_attributes[ch].category[1] == 'k'
6118                   || unicode_attributes[ch].category[1] == 'o'))
6119           || (unicode_attributes[ch].category[0] == 'N'
6120               && (unicode_attributes[ch].category[1] == 'l'
6121                   || unicode_attributes[ch].category[1] == 'o'))
6122           || (unicode_attributes[ch].category[0] == 'P'
6123               && (unicode_attributes[ch].category[1] == 'c'
6124                   || unicode_attributes[ch].category[1] == 'd'
6125                   || unicode_attributes[ch].category[1] == 'o'))
6126           || ch == 0x0600 /* ARABIC NUMBER SIGN */
6127           || ch == 0x0601 /* ARABIC SIGN SANAH */
6128           || ch == 0x0602 /* ARABIC FOOTNOTE MARKER */
6129           || ch == 0x0603 /* ARABIC SIGN SAFHA */
6130           || ch == 0x06DD /* ARABIC END OF AYAH */
6131           || ch == 0x070F /* SYRIAC ABBREVIATION MARK */
6132           || ch == 0x2061 /* FUNCTION APPLICATION */
6133           || ch == 0x2062 /* INVISIBLE TIMES */
6134           || ch == 0x2063 /* INVISIBLE SEPARATOR */
6135           || ch == 0x2064 /* INVISIBLE PLUS */
6136           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
6137           || ch == 0x110BD /* KAITHI NUMBER SIGN */)
6138         if (!(attr & (((int64_t) 1 << LBP_GL) | ((int64_t) 1 << LBP_B2) | ((int64_t) 1 << LBP_BA) | ((int64_t) 1 << LBP_BB) | ((int64_t) 1 << LBP_HY) | ((int64_t) 1 << LBP_CB) | ((int64_t) 1 << LBP_CL) | ((int64_t) 1 << LBP_CP) | ((int64_t) 1 << LBP_EX) | ((int64_t) 1 << LBP_IN) | ((int64_t) 1 << LBP_NS) | ((int64_t) 1 << LBP_OP) | ((int64_t) 1 << LBP_QU) | ((int64_t) 1 << LBP_IS) | ((int64_t) 1 << LBP_NU) | ((int64_t) 1 << LBP_PO) | ((int64_t) 1 << LBP_PR) | ((int64_t) 1 << LBP_SY) | ((int64_t) 1 << LBP_H2) | ((int64_t) 1 << LBP_H3) | ((int64_t) 1 << LBP_JL) | ((int64_t) 1 << LBP_JV) | ((int64_t) 1 << LBP_JT) | ((int64_t) 1 << LBP_SA) | ((int64_t) 1 << LBP_ID))))
6139           {
6140             /* ambiguous (alphabetic) ? */
6141             if ((unicode_width[ch] != NULL
6142                  && unicode_width[ch][0] == 'A'
6143                  && ch >= 0x2000
6144                  /* Extra exceptions for compatibility with Unicode LineBreak.txt.  */
6145                  && ch != 0x2022 /* BULLET */
6146                  && ch != 0x203E /* OVERLINE */
6147                  && ch != 0x2126 /* OHM SIGN */
6148                  && ch != 0x2153 /* VULGAR FRACTION ONE THIRD */
6149                  && ch != 0x215C /* VULGAR FRACTION THREE EIGHTHS */
6150                  && ch != 0x215D /* VULGAR FRACTION FIVE EIGHTHS */
6151                  && ch != 0x21B8 /* NORTH WEST ARROW TO LONG BAR */
6152                  && ch != 0x21B9 /* LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR */
6153                  && ch != 0x21E7 /* UPWARDS WHITE ARROW */
6154                  && ch != 0x24FF /* NEGATIVE CIRCLED DIGIT ZERO */
6155                  && ch != 0x273D /* HEAVY TEARDROP-SPOKED ASTERISK */)
6156                 || ch == 0x00A7 /* SECTION SIGN */
6157                 || ch == 0x00A8 /* DIAERESIS */
6158                 || ch == 0x00AA /* FEMININE ORDINAL INDICATOR */
6159                 || ch == 0x00B2 /* SUPERSCRIPT TWO */
6160                 || ch == 0x00B3 /* SUPERSCRIPT THREE */
6161                 || ch == 0x00B6 /* PILCROW SIGN */
6162                 || ch == 0x00B7 /* MIDDLE DOT */
6163                 || ch == 0x00B8 /* CEDILLA */
6164                 || ch == 0x00B9 /* SUPERSCRIPT ONE */
6165                 || ch == 0x00BA /* MASCULINE ORDINAL INDICATOR */
6166                 || ch == 0x00BC /* VULGAR FRACTION ONE QUARTER */
6167                 || ch == 0x00BD /* VULGAR FRACTION ONE HALF */
6168                 || ch == 0x00BE /* VULGAR FRACTION THREE QUARTERS */
6169                 || ch == 0x00D7 /* MULTIPLICATION SIGN */
6170                 || ch == 0x00F7 /* DIVISION SIGN */
6171                 || ch == 0x02C7 /* CARON */
6172                 || ch == 0x02C9 /* MODIFIER LETTER MACRON */
6173                 || ch == 0x02CA /* MODIFIER LETTER ACUTE ACCENT */
6174                 || ch == 0x02CB /* MODIFIER LETTER GRAVE ACCENT */
6175                 || ch == 0x02CD /* MODIFIER LETTER LOW MACRON */
6176                 || ch == 0x02D0 /* MODIFIER LETTER TRIANGULAR COLON */
6177                 || ch == 0x02D8 /* BREVE */
6178                 || ch == 0x02D9 /* DOT ABOVE */
6179                 || ch == 0x02DA /* RING ABOVE */
6180                 || ch == 0x02DB /* OGONEK */
6181                 || ch == 0x02DD /* DOUBLE ACUTE ACCENT */
6182                 || ch == 0x24EA /* CIRCLED DIGIT ZERO */
6183                 || (ch >= 0x2780 && ch <= 0x2793) /* DINGBAT ... CIRCLED DIGIT ... */
6184                 /* Extra characters for compatibility with Unicode LineBreak.txt.  */
6185                 || ch == 0x2155 /* VULGAR FRACTION ONE FIFTH */
6186                 || ch == 0x2574 /* BOX DRAWINGS LIGHT LEFT */
6187                 || ch == 0x2616 /* WHITE SHOGI PIECE */
6188                 || ch == 0x2617 /* BLACK SHOGI PIECE */)
6189               attr |= (int64_t) 1 << LBP_AI;
6190             else
6191               attr |= (int64_t) 1 << LBP_AL;
6192             attr &= ~((int64_t) 1 << LBP_CM);
6193           }
6194     }
6195   else
6196     {
6197       /* Unassigned character.  */
6198       if ((ch >= 0x3400 && ch <= 0x4DBF) /* CJK Unified Ideographs Extension A */
6199           || (ch >= 0x4E00 && ch <= 0x9FFF) /* CJK Unified Ideographs */
6200           || (ch >= 0xF900 && ch <= 0xFAFF) /* CJK Compatibility Ideographs */
6201           || (ch >= 0x20000 && ch <= 0x2A6FF) /* CJK Unified Ideographs Extension B */
6202           || (ch >= 0x2A700 && ch <= 0x2F7FF) /* CJK Unified Ideographs Extension C,
6203                                                  Supplementary Ideographic Plane (Plane 2) outside of blocks */
6204           || (ch >= 0x2F800 && ch <= 0x2FFFD) /* CJK Compatibility Ideographs Supplement,
6205                                                  Supplementary Ideographic Plane (Plane 2) outside of blocks */
6206           || (ch >= 0x30000 && ch <= 0x3FFFD) /* Tertiary Ideographic Plane (Plane 3) outside of blocks */)
6207         attr |= (int64_t) 1 << LBP_ID;
6208     }
6209
6210   if (attr == 0)
6211     /* unknown */
6212     attr |= (int64_t) 1 << LBP_XX;
6213
6214   return attr;
6215 }
6216
6217 /* Output the line breaking properties in a human readable format.  */
6218 static void
6219 debug_output_lbp (FILE *stream)
6220 {
6221   unsigned int i;
6222
6223   for (i = 0; i < 0x110000; i++)
6224     {
6225       int64_t attr = get_lbp (i);
6226       if (attr != (int64_t) 1 << LBP_XX)
6227         {
6228           fprintf (stream, "0x%04X", i);
6229 #define PRINT_BIT(attr,bit) \
6230   if (attr & ((int64_t) 1 << bit)) fprintf (stream, " " #bit);
6231           PRINT_BIT(attr,LBP_BK);
6232           PRINT_BIT(attr,LBP_CM);
6233           PRINT_BIT(attr,LBP_WJ);
6234           PRINT_BIT(attr,LBP_ZW);
6235           PRINT_BIT(attr,LBP_GL);
6236           PRINT_BIT(attr,LBP_SP);
6237           PRINT_BIT(attr,LBP_B2);
6238           PRINT_BIT(attr,LBP_BA);
6239           PRINT_BIT(attr,LBP_BB);
6240           PRINT_BIT(attr,LBP_HY);
6241           PRINT_BIT(attr,LBP_CB);
6242           PRINT_BIT(attr,LBP_CL);
6243           PRINT_BIT(attr,LBP_CP);
6244           PRINT_BIT(attr,LBP_EX);
6245           PRINT_BIT(attr,LBP_IN);
6246           PRINT_BIT(attr,LBP_NS);
6247           PRINT_BIT(attr,LBP_OP);
6248           PRINT_BIT(attr,LBP_QU);
6249           PRINT_BIT(attr,LBP_IS);
6250           PRINT_BIT(attr,LBP_NU);
6251           PRINT_BIT(attr,LBP_PO);
6252           PRINT_BIT(attr,LBP_PR);
6253           PRINT_BIT(attr,LBP_SY);
6254           PRINT_BIT(attr,LBP_AI);
6255           PRINT_BIT(attr,LBP_AL);
6256           PRINT_BIT(attr,LBP_H2);
6257           PRINT_BIT(attr,LBP_H3);
6258           PRINT_BIT(attr,LBP_ID);
6259           PRINT_BIT(attr,LBP_JL);
6260           PRINT_BIT(attr,LBP_JV);
6261           PRINT_BIT(attr,LBP_JT);
6262           PRINT_BIT(attr,LBP_SA);
6263           PRINT_BIT(attr,LBP_XX);
6264 #undef PRINT_BIT
6265           fprintf (stream, "\n");
6266         }
6267     }
6268 }
6269
6270 static void
6271 debug_output_lbrk_tables (const char *filename)
6272 {
6273   FILE *stream;
6274
6275   stream = fopen (filename, "w");
6276   if (stream == NULL)
6277     {
6278       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6279       exit (1);
6280     }
6281
6282   debug_output_lbp (stream);
6283
6284   if (ferror (stream) || fclose (stream))
6285     {
6286       fprintf (stderr, "error writing to '%s'\n", filename);
6287       exit (1);
6288     }
6289 }
6290
6291 /* The line breaking property from the LineBreak.txt file.  */
6292 int unicode_org_lbp[0x110000];
6293
6294 /* Stores in unicode_org_lbp[] the line breaking property from the
6295    LineBreak.txt file.  */
6296 static void
6297 fill_org_lbp (const char *linebreak_filename)
6298 {
6299   unsigned int i, j;
6300   FILE *stream;
6301   char field0[FIELDLEN];
6302   char field1[FIELDLEN];
6303   char field2[FIELDLEN];
6304   int lineno = 0;
6305
6306   for (i = 0; i < 0x110000; i++)
6307     unicode_org_lbp[i] = LBP_XX;
6308
6309   stream = fopen (linebreak_filename, "r");
6310   if (stream == NULL)
6311     {
6312       fprintf (stderr, "error during fopen of '%s'\n", linebreak_filename);
6313       exit (1);
6314     }
6315
6316   for (;;)
6317     {
6318       int n;
6319       int c;
6320       int value;
6321
6322       lineno++;
6323       c = getc (stream);
6324       if (c == EOF)
6325         break;
6326       if (c == '#')
6327         {
6328           do c = getc (stream); while (c != EOF && c != '\n');
6329           continue;
6330         }
6331       ungetc (c, stream);
6332       n = getfield (stream, field0, ';');
6333       n += getfield (stream, field1, ' ');
6334       n += getfield (stream, field2, '\n');
6335       if (n == 0)
6336         break;
6337       if (n != 3)
6338         {
6339           fprintf (stderr, "short line in '%s':%d\n", linebreak_filename,
6340                    lineno);
6341           exit (1);
6342         }
6343 #define TRY(bit) else if (strcmp (field1, #bit + 4) == 0) value = bit;
6344       if (false) {}
6345       TRY(LBP_BK)
6346       TRY(LBP_CM)
6347       TRY(LBP_WJ)
6348       TRY(LBP_ZW)
6349       TRY(LBP_GL)
6350       TRY(LBP_SP)
6351       TRY(LBP_B2)
6352       TRY(LBP_BA)
6353       TRY(LBP_BB)
6354       TRY(LBP_HY)
6355       TRY(LBP_CB)
6356       TRY(LBP_CL)
6357       TRY(LBP_CP)
6358       TRY(LBP_EX)
6359       TRY(LBP_IN)
6360       TRY(LBP_NS)
6361       TRY(LBP_OP)
6362       TRY(LBP_QU)
6363       TRY(LBP_IS)
6364       TRY(LBP_NU)
6365       TRY(LBP_PO)
6366       TRY(LBP_PR)
6367       TRY(LBP_SY)
6368       TRY(LBP_AI)
6369       TRY(LBP_AL)
6370       TRY(LBP_H2)
6371       TRY(LBP_H3)
6372       TRY(LBP_ID)
6373       TRY(LBP_JL)
6374       TRY(LBP_JV)
6375       TRY(LBP_JT)
6376       TRY(LBP_SA)
6377       TRY(LBP_XX)
6378 #undef TRY
6379       else if (strcmp (field1, "LF") == 0) value = LBP_BK;
6380       else if (strcmp (field1, "CR") == 0) value = LBP_BK;
6381       else if (strcmp (field1, "NL") == 0) value = LBP_BK;
6382       else if (strcmp (field1, "SG") == 0) value = LBP_XX;
6383       else
6384         {
6385           fprintf (stderr, "unknown property value \"%s\" in '%s':%d\n",
6386                    field1, linebreak_filename, lineno);
6387           exit (1);
6388         }
6389       i = strtoul (field0, NULL, 16);
6390       if (strstr (field0, "..") != NULL)
6391         {
6392           /* Deal with a range.  */
6393           j = strtoul (strstr (field0, "..") + 2, NULL, 16);
6394           for (; i <= j; i++)
6395             unicode_org_lbp[i] = value;
6396         }
6397       else
6398         {
6399           /* Single character line.  */
6400           unicode_org_lbp[i] = value;
6401         }
6402     }
6403   if (ferror (stream) || fclose (stream))
6404     {
6405       fprintf (stderr, "error reading from '%s'\n", linebreak_filename);
6406       exit (1);
6407     }
6408 }
6409
6410 /* Output the line breaking properties in a human readable format.  */
6411 static void
6412 debug_output_org_lbp (FILE *stream)
6413 {
6414   unsigned int i;
6415
6416   for (i = 0; i < 0x110000; i++)
6417     {
6418       int attr = unicode_org_lbp[i];
6419       if (attr != LBP_XX)
6420         {
6421           fprintf (stream, "0x%04X", i);
6422 #define PRINT_BIT(attr,bit) \
6423   if (attr == bit) fprintf (stream, " " #bit);
6424           PRINT_BIT(attr,LBP_BK);
6425           PRINT_BIT(attr,LBP_CM);
6426           PRINT_BIT(attr,LBP_WJ);
6427           PRINT_BIT(attr,LBP_ZW);
6428           PRINT_BIT(attr,LBP_GL);
6429           PRINT_BIT(attr,LBP_SP);
6430           PRINT_BIT(attr,LBP_B2);
6431           PRINT_BIT(attr,LBP_BA);
6432           PRINT_BIT(attr,LBP_BB);
6433           PRINT_BIT(attr,LBP_HY);
6434           PRINT_BIT(attr,LBP_CB);
6435           PRINT_BIT(attr,LBP_CL);
6436           PRINT_BIT(attr,LBP_CP);
6437           PRINT_BIT(attr,LBP_EX);
6438           PRINT_BIT(attr,LBP_IN);
6439           PRINT_BIT(attr,LBP_NS);
6440           PRINT_BIT(attr,LBP_OP);
6441           PRINT_BIT(attr,LBP_QU);
6442           PRINT_BIT(attr,LBP_IS);
6443           PRINT_BIT(attr,LBP_NU);
6444           PRINT_BIT(attr,LBP_PO);
6445           PRINT_BIT(attr,LBP_PR);
6446           PRINT_BIT(attr,LBP_SY);
6447           PRINT_BIT(attr,LBP_AI);
6448           PRINT_BIT(attr,LBP_AL);
6449           PRINT_BIT(attr,LBP_H2);
6450           PRINT_BIT(attr,LBP_H3);
6451           PRINT_BIT(attr,LBP_ID);
6452           PRINT_BIT(attr,LBP_JL);
6453           PRINT_BIT(attr,LBP_JV);
6454           PRINT_BIT(attr,LBP_JT);
6455           PRINT_BIT(attr,LBP_SA);
6456           PRINT_BIT(attr,LBP_XX);
6457 #undef PRINT_BIT
6458           fprintf (stream, "\n");
6459         }
6460     }
6461 }
6462
6463 static void
6464 debug_output_org_lbrk_tables (const char *filename)
6465 {
6466   FILE *stream;
6467
6468   stream = fopen (filename, "w");
6469   if (stream == NULL)
6470     {
6471       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6472       exit (1);
6473     }
6474
6475   debug_output_org_lbp (stream);
6476
6477   if (ferror (stream) || fclose (stream))
6478     {
6479       fprintf (stderr, "error writing to '%s'\n", filename);
6480       exit (1);
6481     }
6482 }
6483
6484 /* Construction of sparse 3-level tables.  */
6485 #define TABLE lbp_table
6486 #define ELEMENT unsigned char
6487 #define DEFAULT LBP_XX
6488 #define xmalloc malloc
6489 #define xrealloc realloc
6490 #include "3level.h"
6491
6492 static void
6493 output_lbp (FILE *stream1, FILE *stream2)
6494 {
6495   unsigned int i;
6496   struct lbp_table t;
6497   unsigned int level1_offset, level2_offset, level3_offset;
6498
6499   t.p = 7;
6500   t.q = 9;
6501   lbp_table_init (&t);
6502
6503   for (i = 0; i < 0x110000; i++)
6504     {
6505       int64_t attr = get_lbp (i);
6506
6507       /* Now attr should contain exactly one bit.  */
6508       if (attr == 0 || ((attr & (attr - 1)) != 0))
6509         abort ();
6510
6511       if (attr != (int64_t) 1 << LBP_XX)
6512         {
6513           unsigned int log2_attr;
6514           for (log2_attr = 0; attr > 1; attr >>= 1, log2_attr++);
6515
6516           lbp_table_add (&t, i, log2_attr);
6517         }
6518     }
6519
6520   lbp_table_finalize (&t);
6521
6522   level1_offset =
6523     5 * sizeof (uint32_t);
6524   level2_offset =
6525     5 * sizeof (uint32_t)
6526     + t.level1_size * sizeof (uint32_t);
6527   level3_offset =
6528     5 * sizeof (uint32_t)
6529     + t.level1_size * sizeof (uint32_t)
6530     + (t.level2_size << t.q) * sizeof (uint32_t);
6531
6532   for (i = 0; i < 5; i++)
6533     fprintf (stream1, "#define lbrkprop_header_%d %d\n", i,
6534              ((uint32_t *) t.result)[i]);
6535   fprintf (stream1, "\n");
6536   fprintf (stream1, "typedef struct\n");
6537   fprintf (stream1, "  {\n");
6538   fprintf (stream1, "    int level1[%zu];\n", t.level1_size);
6539   fprintf (stream1, "    int level2[%zu << %d];\n", t.level2_size, t.q);
6540   fprintf (stream1, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
6541   fprintf (stream1, "  }\n");
6542   fprintf (stream1, "lbrkprop_t;\n");
6543   fprintf (stream1, "extern const lbrkprop_t unilbrkprop;\n");
6544
6545   fprintf (stream2, "const lbrkprop_t unilbrkprop =\n");
6546   fprintf (stream2, "{\n");
6547   fprintf (stream2, "  {");
6548   if (t.level1_size > 8)
6549     fprintf (stream2, "\n   ");
6550   for (i = 0; i < t.level1_size; i++)
6551     {
6552       uint32_t offset;
6553       if (i > 0 && (i % 8) == 0)
6554         fprintf (stream2, "\n   ");
6555       offset = ((uint32_t *) (t.result + level1_offset))[i];
6556       if (offset == 0)
6557         fprintf (stream2, " %5d", -1);
6558       else
6559         fprintf (stream2, " %5zu",
6560                  (offset - level2_offset) / sizeof (uint32_t));
6561       if (i+1 < t.level1_size)
6562         fprintf (stream2, ",");
6563     }
6564   if (t.level1_size > 8)
6565     fprintf (stream2, "\n ");
6566   fprintf (stream2, " },\n");
6567   fprintf (stream2, "  {");
6568   if (t.level2_size << t.q > 8)
6569     fprintf (stream2, "\n   ");
6570   for (i = 0; i < t.level2_size << t.q; i++)
6571     {
6572       uint32_t offset;
6573       if (i > 0 && (i % 8) == 0)
6574         fprintf (stream2, "\n   ");
6575       offset = ((uint32_t *) (t.result + level2_offset))[i];
6576       if (offset == 0)
6577         fprintf (stream2, " %5d", -1);
6578       else
6579         fprintf (stream2, " %5zu",
6580                  (offset - level3_offset) / sizeof (unsigned char));
6581       if (i+1 < t.level2_size << t.q)
6582         fprintf (stream2, ",");
6583     }
6584   if (t.level2_size << t.q > 8)
6585     fprintf (stream2, "\n ");
6586   fprintf (stream2, " },\n");
6587   fprintf (stream2, "  {");
6588   if (t.level3_size << t.p > 8)
6589     fprintf (stream2, "\n   ");
6590   for (i = 0; i < t.level3_size << t.p; i++)
6591     {
6592       unsigned char value = ((unsigned char *) (t.result + level3_offset))[i];
6593       const char *value_string;
6594       switch (value)
6595         {
6596 #define CASE(x) case x: value_string = #x; break;
6597           CASE(LBP_BK);
6598           CASE(LBP_CM);
6599           CASE(LBP_WJ);
6600           CASE(LBP_ZW);
6601           CASE(LBP_GL);
6602           CASE(LBP_SP);
6603           CASE(LBP_B2);
6604           CASE(LBP_BA);
6605           CASE(LBP_BB);
6606           CASE(LBP_HY);
6607           CASE(LBP_CB);
6608           CASE(LBP_CL);
6609           CASE(LBP_CP);
6610           CASE(LBP_EX);
6611           CASE(LBP_IN);
6612           CASE(LBP_NS);
6613           CASE(LBP_OP);
6614           CASE(LBP_QU);
6615           CASE(LBP_IS);
6616           CASE(LBP_NU);
6617           CASE(LBP_PO);
6618           CASE(LBP_PR);
6619           CASE(LBP_SY);
6620           CASE(LBP_AI);
6621           CASE(LBP_AL);
6622           CASE(LBP_H2);
6623           CASE(LBP_H3);
6624           CASE(LBP_ID);
6625           CASE(LBP_JL);
6626           CASE(LBP_JV);
6627           CASE(LBP_JT);
6628           CASE(LBP_SA);
6629           CASE(LBP_XX);
6630 #undef CASE
6631           default:
6632             abort ();
6633         }
6634       if (i > 0 && (i % 8) == 0)
6635         fprintf (stream2, "\n   ");
6636       fprintf (stream2, " %s%s", value_string,
6637                (i+1 < t.level3_size << t.p ? "," : ""));
6638     }
6639   if (t.level3_size << t.p > 8)
6640     fprintf (stream2, "\n ");
6641   fprintf (stream2, " }\n");
6642   fprintf (stream2, "};\n");
6643 }
6644
6645 static void
6646 output_lbrk_tables (const char *filename1, const char *filename2, const char *version)
6647 {
6648   const char *filenames[2];
6649   FILE *streams[2];
6650   size_t i;
6651
6652   filenames[0] = filename1;
6653   filenames[1] = filename2;
6654
6655   for (i = 0; i < 2; i++)
6656     {
6657       streams[i] = fopen (filenames[i], "w");
6658       if (streams[i] == NULL)
6659         {
6660           fprintf (stderr, "cannot open '%s' for writing\n", filenames[i]);
6661           exit (1);
6662         }
6663     }
6664
6665   for (i = 0; i < 2; i++)
6666     {
6667       FILE *stream = streams[i];
6668
6669       fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
6670       fprintf (stream, "/* Line breaking properties of Unicode characters.  */\n");
6671       fprintf (stream, "/* Generated automatically by gen-lbrk for Unicode %s.  */\n",
6672                version);
6673       fprintf (stream, "\n");
6674
6675       /* Put a GPL header on it.  The gnulib module is under LGPL (although it
6676          still carries the GPL header), and it's gnulib-tool which replaces the
6677          GPL header with an LGPL header.  */
6678       fprintf (stream, "/* Copyright (C) 2000-2002, 2004, 2008 Free Software Foundation, Inc.\n");
6679       fprintf (stream, "\n");
6680       fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
6681       fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
6682       fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
6683       fprintf (stream, "   (at your option) any later version.\n");
6684       fprintf (stream, "\n");
6685       fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
6686       fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
6687       fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
6688       fprintf (stream, "   GNU General Public License for more details.\n");
6689       fprintf (stream, "\n");
6690       fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
6691       fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
6692       fprintf (stream, "\n");
6693     }
6694
6695   output_lbp (streams[0], streams[1]);
6696
6697   for (i = 0; i < 2; i++)
6698     {
6699       if (ferror (streams[i]) || fclose (streams[i]))
6700         {
6701           fprintf (stderr, "error writing to '%s'\n", filenames[i]);
6702           exit (1);
6703         }
6704     }
6705 }
6706
6707 /* ========================================================================= */
6708
6709 /* Word break property.
6710    Updated for Unicode TR #29 revision 17.  */
6711
6712 /* Possible values of the Word_Break property.  */
6713 enum
6714 {
6715   WBP_OTHER        = 0,
6716   WBP_CR           = 11,
6717   WBP_LF           = 12,
6718   WBP_NEWLINE      = 10,
6719   WBP_EXTEND       = 8,
6720   WBP_FORMAT       = 9,
6721   WBP_KATAKANA     = 1,
6722   WBP_ALETTER      = 2,
6723   WBP_MIDNUMLET    = 3,
6724   WBP_MIDLETTER    = 4,
6725   WBP_MIDNUM       = 5,
6726   WBP_NUMERIC      = 6,
6727   WBP_EXTENDNUMLET = 7
6728 };
6729
6730 /* Returns the word breaking property for ch, as a bit mask.  */
6731 static int
6732 get_wbp (unsigned int ch)
6733 {
6734   int attr = 0;
6735
6736   if (unicode_attributes[ch].name != NULL)
6737     {
6738       if (ch == 0x000D)
6739         attr |= 1 << WBP_CR;
6740
6741       if (ch == 0x000A)
6742         attr |= 1 << WBP_LF;
6743
6744       if (ch == 0x000B || ch == 0x000C
6745           || ch == 0x0085
6746           || ch == 0x2028 || ch == 0x2029)
6747         attr |= 1 << WBP_NEWLINE;
6748
6749       if (((unicode_properties[ch] >> PROP_GRAPHEME_EXTEND) & 1) != 0
6750           || (unicode_attributes[ch].category != NULL
6751               && strcmp (unicode_attributes[ch].category, "Mc") == 0))
6752         attr |= 1 << WBP_EXTEND;
6753
6754       if (unicode_attributes[ch].category != NULL
6755           && strcmp (unicode_attributes[ch].category, "Cf") == 0
6756           && ch != 0x200B && ch != 0x200C && ch != 0x200D)
6757         attr |= 1 << WBP_FORMAT;
6758
6759       if ((unicode_scripts[ch] < numscripts
6760            && strcmp (scripts[unicode_scripts[ch]], "Katakana") == 0)
6761           || (ch >= 0x3031 && ch <= 0x3035)
6762           || ch == 0x309B || ch == 0x309C || ch == 0x30A0 || ch == 0x30FC
6763           || ch == 0xFF70)
6764         attr |= 1 << WBP_KATAKANA;
6765
6766       if ((((unicode_properties[ch] >> PROP_ALPHABETIC) & 1) != 0
6767            || ch == 0x05F3)
6768           && ((unicode_properties[ch] >> PROP_IDEOGRAPHIC) & 1) == 0
6769           && (attr & (1 << WBP_KATAKANA)) == 0
6770           && ((get_lbp (ch) >> LBP_SA) & 1) == 0
6771           && !(unicode_scripts[ch] < numscripts
6772                && strcmp (scripts[unicode_scripts[ch]], "Hiragana") == 0)
6773           && (attr & (1 << WBP_EXTEND)) == 0)
6774         attr |= 1 << WBP_ALETTER;
6775
6776       if (is_WBP_MIDNUMLET (ch))
6777         attr |= 1 << WBP_MIDNUMLET;
6778
6779       if (is_WBP_MIDLETTER (ch))
6780         attr |= 1 << WBP_MIDLETTER;
6781
6782       if ((((get_lbp (ch) >> LBP_IS) & 1) != 0
6783            || ch == 0x066C || ch == 0xFE50 || ch == 0xFE54 || ch == 0xFF0C
6784            || ch == 0xFF1B)
6785           && ch != 0x003A && ch != 0xFE13 && ch != 0x002E)
6786         attr |= 1 << WBP_MIDNUM;
6787
6788       if (((get_lbp (ch) >> LBP_NU) & 1) != 0
6789           && ch != 0x066C)
6790         attr |= 1 << WBP_NUMERIC;
6791
6792       if (unicode_attributes[ch].category != NULL
6793           && strcmp (unicode_attributes[ch].category, "Pc") == 0)
6794         attr |= 1 << WBP_EXTENDNUMLET;
6795     }
6796
6797   if (attr == 0)
6798     /* other */
6799     attr |= 1 << WBP_OTHER;
6800
6801   return attr;
6802 }
6803
6804 /* Output the word break property in a human readable format.  */
6805 static void
6806 debug_output_wbp (FILE *stream)
6807 {
6808   unsigned int i;
6809
6810   for (i = 0; i < 0x110000; i++)
6811     {
6812       int attr = get_wbp (i);
6813       if (attr != 1 << WBP_OTHER)
6814         {
6815           fprintf (stream, "0x%04X", i);
6816           if (attr & (1 << WBP_CR))
6817             fprintf (stream, " CR");
6818           if (attr & (1 << WBP_LF))
6819             fprintf (stream, " LF");
6820           if (attr & (1 << WBP_NEWLINE))
6821             fprintf (stream, " Newline");
6822           if (attr & (1 << WBP_EXTEND))
6823             fprintf (stream, " Extend");
6824           if (attr & (1 << WBP_FORMAT))
6825             fprintf (stream, " Format");
6826           if (attr & (1 << WBP_KATAKANA))
6827             fprintf (stream, " Katakana");
6828           if (attr & (1 << WBP_ALETTER))
6829             fprintf (stream, " ALetter");
6830           if (attr & (1 << WBP_MIDNUMLET))
6831             fprintf (stream, " MidNumLet");
6832           if (attr & (1 << WBP_MIDLETTER))
6833             fprintf (stream, " MidLetter");
6834           if (attr & (1 << WBP_MIDNUM))
6835             fprintf (stream, " MidNum");
6836           if (attr & (1 << WBP_NUMERIC))
6837             fprintf (stream, " Numeric");
6838           if (attr & (1 << WBP_EXTENDNUMLET))
6839             fprintf (stream, " ExtendNumLet");
6840           fprintf (stream, "\n");
6841         }
6842     }
6843 }
6844
6845 static void
6846 debug_output_wbrk_tables (const char *filename)
6847 {
6848   FILE *stream;
6849
6850   stream = fopen (filename, "w");
6851   if (stream == NULL)
6852     {
6853       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6854       exit (1);
6855     }
6856
6857   debug_output_wbp (stream);
6858
6859   if (ferror (stream) || fclose (stream))
6860     {
6861       fprintf (stderr, "error writing to '%s'\n", filename);
6862       exit (1);
6863     }
6864 }
6865
6866 /* The word break property from the WordBreakProperty.txt file.  */
6867 int unicode_org_wbp[0x110000];
6868
6869 /* Stores in unicode_org_wbp[] the word break property from the
6870    WordBreakProperty.txt file.  */
6871 static void
6872 fill_org_wbp (const char *wordbreakproperty_filename)
6873 {
6874   unsigned int i;
6875   FILE *stream;
6876
6877   for (i = 0; i < 0x110000; i++)
6878     unicode_org_wbp[i] = WBP_OTHER;
6879
6880   stream = fopen (wordbreakproperty_filename, "r");
6881   if (stream == NULL)
6882     {
6883       fprintf (stderr, "error during fopen of '%s'\n", wordbreakproperty_filename);
6884       exit (1);
6885     }
6886
6887   for (;;)
6888     {
6889       char buf[200+1];
6890       unsigned int i1, i2;
6891       char padding[200+1];
6892       char propname[200+1];
6893       int propvalue;
6894
6895       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
6896         break;
6897
6898       if (buf[0] == '\0' || buf[0] == '#')
6899         continue;
6900
6901       if (sscanf (buf, "%X..%X%[ ;]%[^ ]", &i1, &i2, padding, propname) != 4)
6902         {
6903           if (sscanf (buf, "%X%[ ;]%[^ ]", &i1, padding, propname) != 3)
6904             {
6905               fprintf (stderr, "parse error in '%s'\n",
6906                        wordbreakproperty_filename);
6907               exit (1);
6908             }
6909           i2 = i1;
6910         }
6911 #define PROP(name,value) \
6912       if (strcmp (propname, name) == 0) propvalue = value; else
6913       PROP ("CR", WBP_CR)
6914       PROP ("LF", WBP_LF)
6915       PROP ("Newline", WBP_NEWLINE)
6916       PROP ("Extend", WBP_EXTEND)
6917       PROP ("Format", WBP_FORMAT)
6918       PROP ("Katakana", WBP_KATAKANA)
6919       PROP ("ALetter", WBP_ALETTER)
6920       PROP ("MidNumLet", WBP_MIDNUMLET)
6921       PROP ("MidLetter", WBP_MIDLETTER)
6922       PROP ("MidNum", WBP_MIDNUM)
6923       PROP ("Numeric", WBP_NUMERIC)
6924       PROP ("ExtendNumLet", WBP_EXTENDNUMLET)
6925 #undef PROP
6926         {
6927           fprintf (stderr, "unknown property value '%s' in '%s'\n", propname,
6928                    wordbreakproperty_filename);
6929           exit (1);
6930         }
6931       if (!(i1 <= i2 && i2 < 0x110000))
6932         abort ();
6933
6934       for (i = i1; i <= i2; i++)
6935         unicode_org_wbp[i] = propvalue;
6936     }
6937
6938   if (ferror (stream) || fclose (stream))
6939     {
6940       fprintf (stderr, "error reading from '%s'\n", wordbreakproperty_filename);
6941       exit (1);
6942     }
6943 }
6944
6945 /* Output the word break property in a human readable format.  */
6946 static void
6947 debug_output_org_wbp (FILE *stream)
6948 {
6949   unsigned int i;
6950
6951   for (i = 0; i < 0x110000; i++)
6952     {
6953       int propvalue = unicode_org_wbp[i];
6954       if (propvalue != WBP_OTHER)
6955         {
6956           fprintf (stream, "0x%04X", i);
6957 #define PROP(name,value) \
6958           if (propvalue == value) fprintf (stream, " " name); else
6959           PROP ("CR", WBP_CR)
6960           PROP ("LF", WBP_LF)
6961           PROP ("Newline", WBP_NEWLINE)
6962           PROP ("Extend", WBP_EXTEND)
6963           PROP ("Format", WBP_FORMAT)
6964           PROP ("Katakana", WBP_KATAKANA)
6965           PROP ("ALetter", WBP_ALETTER)
6966           PROP ("MidNumLet", WBP_MIDNUMLET)
6967           PROP ("MidLetter", WBP_MIDLETTER)
6968           PROP ("MidNum", WBP_MIDNUM)
6969           PROP ("Numeric", WBP_NUMERIC)
6970           PROP ("ExtendNumLet", WBP_EXTENDNUMLET)
6971 #undef PROP
6972           fprintf (stream, " ??");
6973           fprintf (stream, "\n");
6974         }
6975     }
6976 }
6977
6978 static void
6979 debug_output_org_wbrk_tables (const char *filename)
6980 {
6981   FILE *stream;
6982
6983   stream = fopen (filename, "w");
6984   if (stream == NULL)
6985     {
6986       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6987       exit (1);
6988     }
6989
6990   debug_output_org_wbp (stream);
6991
6992   if (ferror (stream) || fclose (stream))
6993     {
6994       fprintf (stderr, "error writing to '%s'\n", filename);
6995       exit (1);
6996     }
6997 }
6998
6999 /* Construction of sparse 3-level tables.  */
7000 #define TABLE wbp_table
7001 #define ELEMENT unsigned char
7002 #define DEFAULT WBP_OTHER
7003 #define xmalloc malloc
7004 #define xrealloc realloc
7005 #include "3level.h"
7006
7007 static void
7008 output_wbp (FILE *stream)
7009 {
7010   unsigned int i;
7011   struct wbp_table t;
7012   unsigned int level1_offset, level2_offset, level3_offset;
7013
7014   t.p = 7;
7015   t.q = 9;
7016   wbp_table_init (&t);
7017
7018   for (i = 0; i < 0x110000; i++)
7019     {
7020       int attr = get_wbp (i);
7021
7022       /* Now attr should contain exactly one bit.  */
7023       if (attr == 0 || ((attr & (attr - 1)) != 0))
7024         abort ();
7025
7026       if (attr != 1 << WBP_OTHER)
7027         {
7028           unsigned int log2_attr;
7029           for (log2_attr = 0; attr > 1; attr >>= 1, log2_attr++);
7030
7031           wbp_table_add (&t, i, log2_attr);
7032         }
7033     }
7034
7035   wbp_table_finalize (&t);
7036
7037   level1_offset =
7038     5 * sizeof (uint32_t);
7039   level2_offset =
7040     5 * sizeof (uint32_t)
7041     + t.level1_size * sizeof (uint32_t);
7042   level3_offset =
7043     5 * sizeof (uint32_t)
7044     + t.level1_size * sizeof (uint32_t)
7045     + (t.level2_size << t.q) * sizeof (uint32_t);
7046
7047   for (i = 0; i < 5; i++)
7048     fprintf (stream, "#define wbrkprop_header_%d %d\n", i,
7049              ((uint32_t *) t.result)[i]);
7050   fprintf (stream, "\n");
7051   fprintf (stream, "typedef struct\n");
7052   fprintf (stream, "  {\n");
7053   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
7054   fprintf (stream, "    int level2[%zu << %d];\n", t.level2_size, t.q);
7055   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
7056   fprintf (stream, "  }\n");
7057   fprintf (stream, "wbrkprop_t;\n");
7058   fprintf (stream, "static const wbrkprop_t uniwbrkprop =\n");
7059   fprintf (stream, "{\n");
7060   fprintf (stream, "  {");
7061   if (t.level1_size > 8)
7062     fprintf (stream, "\n   ");
7063   for (i = 0; i < t.level1_size; i++)
7064     {
7065       uint32_t offset;
7066       if (i > 0 && (i % 8) == 0)
7067         fprintf (stream, "\n   ");
7068       offset = ((uint32_t *) (t.result + level1_offset))[i];
7069       if (offset == 0)
7070         fprintf (stream, " %5d", -1);
7071       else
7072         fprintf (stream, " %5zu",
7073                  (offset - level2_offset) / sizeof (uint32_t));
7074       if (i+1 < t.level1_size)
7075         fprintf (stream, ",");
7076     }
7077   if (t.level1_size > 8)
7078     fprintf (stream, "\n ");
7079   fprintf (stream, " },\n");
7080   fprintf (stream, "  {");
7081   if (t.level2_size << t.q > 8)
7082     fprintf (stream, "\n   ");
7083   for (i = 0; i < t.level2_size << t.q; i++)
7084     {
7085       uint32_t offset;
7086       if (i > 0 && (i % 8) == 0)
7087         fprintf (stream, "\n   ");
7088       offset = ((uint32_t *) (t.result + level2_offset))[i];
7089       if (offset == 0)
7090         fprintf (stream, " %5d", -1);
7091       else
7092         fprintf (stream, " %5zu",
7093                  (offset - level3_offset) / sizeof (unsigned char));
7094       if (i+1 < t.level2_size << t.q)
7095         fprintf (stream, ",");
7096     }
7097   if (t.level2_size << t.q > 8)
7098     fprintf (stream, "\n ");
7099   fprintf (stream, " },\n");
7100   fprintf (stream, "  {");
7101   if (t.level3_size << t.p > 4)
7102     fprintf (stream, "\n   ");
7103   for (i = 0; i < t.level3_size << t.p; i++)
7104     {
7105       unsigned char value = ((unsigned char *) (t.result + level3_offset))[i];
7106       const char *value_string;
7107       switch (value)
7108         {
7109 #define CASE(x) case x: value_string = #x; break;
7110           CASE(WBP_OTHER);
7111           CASE(WBP_CR);
7112           CASE(WBP_LF);
7113           CASE(WBP_NEWLINE);
7114           CASE(WBP_EXTEND);
7115           CASE(WBP_FORMAT);
7116           CASE(WBP_KATAKANA);
7117           CASE(WBP_ALETTER);
7118           CASE(WBP_MIDNUMLET);
7119           CASE(WBP_MIDLETTER);
7120           CASE(WBP_MIDNUM);
7121           CASE(WBP_NUMERIC);
7122           CASE(WBP_EXTENDNUMLET);
7123 #undef CASE
7124           default:
7125             abort ();
7126         }
7127       if (i > 0 && (i % 4) == 0)
7128         fprintf (stream, "\n   ");
7129       fprintf (stream, " %s%s", value_string,
7130                (i+1 < t.level3_size << t.p ? "," : ""));
7131     }
7132   if (t.level3_size << t.p > 4)
7133     fprintf (stream, "\n ");
7134   fprintf (stream, " }\n");
7135   fprintf (stream, "};\n");
7136 }
7137
7138 static void
7139 output_wbrk_tables (const char *filename, const char *version)
7140 {
7141   FILE *stream;
7142
7143   stream = fopen (filename, "w");
7144   if (stream == NULL)
7145     {
7146       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7147       exit (1);
7148     }
7149
7150   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7151   fprintf (stream, "/* Line breaking properties of Unicode characters.  */\n");
7152   fprintf (stream, "/* Generated automatically by gen-uni-tables for Unicode %s.  */\n",
7153            version);
7154   fprintf (stream, "\n");
7155
7156   /* Put a GPL header on it.  The gnulib module is under LGPL (although it
7157      still carries the GPL header), and it's gnulib-tool which replaces the
7158      GPL header with an LGPL header.  */
7159   fprintf (stream, "/* Copyright (C) 2000-2002, 2004, 2007-2009 Free Software Foundation, Inc.\n");
7160   fprintf (stream, "\n");
7161   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
7162   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
7163   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
7164   fprintf (stream, "   (at your option) any later version.\n");
7165   fprintf (stream, "\n");
7166   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
7167   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
7168   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
7169   fprintf (stream, "   GNU General Public License for more details.\n");
7170   fprintf (stream, "\n");
7171   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
7172   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
7173   fprintf (stream, "\n");
7174
7175   output_wbp (stream);
7176
7177   if (ferror (stream) || fclose (stream))
7178     {
7179       fprintf (stderr, "error writing to '%s'\n", filename);
7180       exit (1);
7181     }
7182 }
7183
7184 /* ========================================================================= */
7185
7186 /* Grapheme break property.
7187    Updated for Unicode TR #29 revision 17.  */
7188
7189 /* Possible values of the Grapheme_Cluster_Break property.  */
7190 enum
7191 {
7192   GBP_OTHER        = 0,
7193   GBP_CR           = 1,
7194   GBP_LF           = 2,
7195   GBP_CONTROL      = 3,
7196   GBP_EXTEND       = 4,
7197   GBP_PREPEND      = 5,
7198   GBP_SPACINGMARK  = 6,
7199   GBP_L            = 7,
7200   GBP_V            = 8,
7201   GBP_T            = 9,
7202   GBP_LV           = 10,
7203   GBP_LVT          = 11
7204 };
7205
7206 /* Construction of sparse 3-level tables.  */
7207 #define TABLE gbp_table
7208 #define ELEMENT unsigned char
7209 #define DEFAULT GBP_OTHER
7210 #define xmalloc malloc
7211 #define xrealloc realloc
7212 #include "3level.h"
7213
7214 /* The grapheme break property from the GraphemeBreakProperty.txt file.  */
7215 int unicode_org_gbp[0x110000];
7216
7217 /* Output the unit test data for the grapheme break property.  */
7218 static void
7219 output_gbp_test (const char *filename)
7220 {
7221   FILE *stream;
7222   bool need_comma;
7223   unsigned int ch;
7224
7225   stream = fopen (filename, "w");
7226   if (stream == NULL)
7227     {
7228       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7229       exit (1);
7230     }
7231
7232   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7233   fprintf (stream, "/* Test the Unicode grapheme break property functions.\n");
7234   fprintf (stream, "   Copyright (C) 2010 Free Software Foundation, Inc.\n");
7235   fprintf (stream, "\n");
7236   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
7237   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
7238   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
7239   fprintf (stream, "   (at your option) any later version.\n");
7240   fprintf (stream, "\n");
7241   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
7242   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
7243   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
7244   fprintf (stream, "   GNU General Public License for more details.\n");
7245   fprintf (stream, "\n");
7246   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
7247   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
7248   fprintf (stream, "\n");
7249
7250   need_comma = false;
7251   for (ch = 0; ch < 0x110000; ch++)
7252     {
7253       int gbp = unicode_org_gbp[ch];
7254       const char *gbp_string;
7255
7256       while (ch + 1 < 0x110000 && unicode_org_gbp[ch + 1] == gbp)
7257         ch++;
7258
7259       switch (gbp)
7260         {
7261 #define CASE(x) case x: gbp_string = #x; break;
7262       CASE (GBP_OTHER)
7263       CASE (GBP_CR)
7264       CASE (GBP_LF)
7265       CASE (GBP_CONTROL)
7266       CASE (GBP_EXTEND)
7267       CASE (GBP_PREPEND)
7268       CASE (GBP_SPACINGMARK)
7269       CASE (GBP_L)
7270       CASE (GBP_V)
7271       CASE (GBP_T)
7272       CASE (GBP_LV)
7273       CASE (GBP_LVT)
7274 #undef CASE
7275         default:
7276           abort ();
7277         }
7278
7279       if (need_comma)
7280         fprintf (stream, ",\n");
7281       fprintf (stream, "{ 0x%04X, %s }", ch + 1, gbp_string);
7282
7283       need_comma = true;
7284     }
7285   fprintf (stream, "\n");
7286
7287   if (ferror (stream) || fclose (stream))
7288     {
7289       fprintf (stderr, "error writing to '%s'\n", filename);
7290       exit (1);
7291     }
7292 }
7293
7294 /* Output the per-character grapheme break property table.  */
7295 static void
7296 output_gbp_table (const char *filename, const char *version)
7297 {
7298   FILE *stream;
7299   unsigned int ch, i;
7300   struct gbp_table t;
7301   unsigned int level1_offset, level2_offset, level3_offset;
7302
7303   stream = fopen (filename, "w");
7304   if (stream == NULL)
7305     {
7306       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7307       exit (1);
7308     }
7309
7310   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7311   fprintf (stream, "/* Grapheme break property of Unicode characters.  */\n");
7312   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
7313            version);
7314
7315   t.p = 7;
7316   t.q = 9;
7317   gbp_table_init (&t);
7318
7319   for (ch = 0; ch < 0x110000; ch++)
7320     gbp_table_add (&t, ch, unicode_org_gbp[ch]);
7321
7322   gbp_table_finalize (&t);
7323
7324   /* Offsets in t.result, in memory of this process.  */
7325   level1_offset =
7326     5 * sizeof (uint32_t);
7327   level2_offset =
7328     5 * sizeof (uint32_t)
7329     + t.level1_size * sizeof (uint32_t);
7330   level3_offset =
7331     5 * sizeof (uint32_t)
7332     + t.level1_size * sizeof (uint32_t)
7333     + (t.level2_size << t.q) * sizeof (uint32_t);
7334
7335   for (i = 0; i < 5; i++)
7336     fprintf (stream, "#define gbrkprop_header_%d %d\n", i,
7337              ((uint32_t *) t.result)[i]);
7338   fprintf (stream, "static const\n");
7339   fprintf (stream, "struct\n");
7340   fprintf (stream, "  {\n");
7341   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
7342   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
7343   fprintf (stream, "    unsigned char level3[(%zu << %d) / 2];\n",
7344            t.level3_size, t.p);
7345   fprintf (stream, "  }\n");
7346   fprintf (stream, "unigbrkprop =\n");
7347   fprintf (stream, "{\n");
7348   fprintf (stream, "  {");
7349   if (t.level1_size > 8)
7350     fprintf (stream, "\n   ");
7351   for (i = 0; i < t.level1_size; i++)
7352     {
7353       uint32_t offset;
7354       if (i > 0 && (i % 8) == 0)
7355         fprintf (stream, "\n   ");
7356       offset = ((uint32_t *) (t.result + level1_offset))[i];
7357       if (offset == 0)
7358         fprintf (stream, " %5d", -1);
7359       else
7360         fprintf (stream, " %5zu",
7361                  (offset - level2_offset) / sizeof (uint32_t));
7362       if (i+1 < t.level1_size)
7363         fprintf (stream, ",");
7364     }
7365   if (t.level1_size > 8)
7366     fprintf (stream, "\n ");
7367   fprintf (stream, " },\n");
7368   fprintf (stream, "  {");
7369   if (t.level2_size << t.q > 8)
7370     fprintf (stream, "\n   ");
7371   for (i = 0; i < t.level2_size << t.q; i++)
7372     {
7373       uint32_t offset;
7374       if (i > 0 && (i % 8) == 0)
7375         fprintf (stream, "\n   ");
7376       offset = ((uint32_t *) (t.result + level2_offset))[i];
7377       if (offset == 0)
7378         fprintf (stream, " %5d", -1);
7379       else
7380         fprintf (stream, " %5zu",
7381                  (offset - level3_offset) / sizeof (uint8_t) / 2);
7382       if (i+1 < t.level2_size << t.q)
7383         fprintf (stream, ",");
7384     }
7385   if (t.level2_size << t.q > 8)
7386     fprintf (stream, "\n ");
7387   fprintf (stream, " },\n");
7388   fprintf (stream, "  {");
7389   if (t.level3_size << t.p > 8)
7390     fprintf (stream, "\n   ");
7391   for (i = 0; i < (t.level3_size << t.p) / 2; i++)
7392     {
7393       unsigned char *p = (unsigned char *) (t.result + level3_offset);
7394       unsigned char value0 = p[i * 2];
7395       unsigned char value1 = p[i * 2 + 1];
7396       if (i > 0 && (i % 8) == 0)
7397         fprintf (stream, "\n   ");
7398       fprintf (stream, " 0x%02x%s", (value1 << 4) + value0,
7399                (i+1 < (t.level3_size << t.p) / 2 ? "," : ""));
7400     }
7401   if (t.level3_size << t.p > 8)
7402     fprintf (stream, "\n ");
7403   fprintf (stream, " }\n");
7404   fprintf (stream, "};\n");
7405
7406   if (ferror (stream) || fclose (stream))
7407     {
7408       fprintf (stderr, "error writing to '%s'\n", filename);
7409       exit (1);
7410     }
7411 }
7412
7413 /* Stores in unicode_org_gbp[] the grapheme breaking property from the
7414    GraphemeBreakProperty.txt file.  */
7415 static void
7416 fill_org_gbp (const char *graphemebreakproperty_filename)
7417 {
7418   unsigned int i;
7419   FILE *stream;
7420   int lineno = 0;
7421
7422   for (i = 0; i < 0x110000; i++)
7423     unicode_org_gbp[i] = GBP_OTHER;
7424
7425   stream = fopen (graphemebreakproperty_filename, "r");
7426   if (stream == NULL)
7427     {
7428       fprintf (stderr, "error during fopen of '%s'\n",
7429                graphemebreakproperty_filename);
7430       exit (1);
7431     }
7432
7433   for (;;)
7434     {
7435       char buf[200+1];
7436       unsigned int i1, i2;
7437       char padding[200+1];
7438       char propname[200+1];
7439       int propvalue;
7440
7441       lineno++;
7442       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
7443         break;
7444
7445       if (buf[0] == '\0' || buf[0] == '#')
7446         continue;
7447
7448       if (sscanf (buf, "%X..%X%[ ;]%[^ ]", &i1, &i2, padding, propname) != 4)
7449         {
7450           if (sscanf (buf, "%X%[ ;]%[^ ]", &i1, padding, propname) != 3)
7451             {
7452               fprintf (stderr, "parse error in '%s'\n",
7453                        graphemebreakproperty_filename);
7454               exit (1);
7455             }
7456           i2 = i1;
7457         }
7458 #define PROP(name,value) \
7459       if (strcmp (propname, name) == 0) propvalue = value; else
7460       PROP ("CR", GBP_CR)
7461       PROP ("LF", GBP_LF)
7462       PROP ("Control", GBP_CONTROL)
7463       PROP ("Extend", GBP_EXTEND)
7464       PROP ("Prepend", GBP_PREPEND)
7465       PROP ("SpacingMark", GBP_SPACINGMARK)
7466       PROP ("L", GBP_L)
7467       PROP ("V", GBP_V)
7468       PROP ("T", GBP_T)
7469       PROP ("LV", GBP_LV)
7470       PROP ("LVT", GBP_LVT)
7471 #undef PROP
7472         {
7473           fprintf (stderr, "unknown property value '%s' in %s:%d\n", propname,
7474                    graphemebreakproperty_filename, lineno);
7475           exit (1);
7476         }
7477       if (!(i1 <= i2 && i2 < 0x110000))
7478         abort ();
7479
7480       for (i = i1; i <= i2; i++)
7481         unicode_org_gbp[i] = propvalue;
7482     }
7483   if (ferror (stream) || fclose (stream))
7484     {
7485       fprintf (stderr, "error reading from '%s'\n", graphemebreakproperty_filename);
7486       exit (1);
7487     }
7488 }
7489
7490 /* ========================================================================= */
7491
7492 /* Composition and decomposition.
7493    Updated for Unicode TR #15 revision 33.  */
7494
7495 /* Maximum number of characters into which a single Unicode character can be
7496    decomposed.  */
7497 #define MAX_DECOMP_LENGTH 18
7498
7499 enum
7500 {
7501   UC_DECOMP_CANONICAL,/*            Canonical decomposition.                  */
7502   UC_DECOMP_FONT,    /*   <font>    A font variant (e.g. a blackletter form). */
7503   UC_DECOMP_NOBREAK, /* <noBreak>   A no-break version of a space or hyphen.  */
7504   UC_DECOMP_INITIAL, /* <initial>   An initial presentation form (Arabic).    */
7505   UC_DECOMP_MEDIAL,  /*  <medial>   A medial presentation form (Arabic).      */
7506   UC_DECOMP_FINAL,   /*  <final>    A final presentation form (Arabic).       */
7507   UC_DECOMP_ISOLATED,/* <isolated>  An isolated presentation form (Arabic).   */
7508   UC_DECOMP_CIRCLE,  /*  <circle>   An encircled form.                        */
7509   UC_DECOMP_SUPER,   /*  <super>    A superscript form.                       */
7510   UC_DECOMP_SUB,     /*   <sub>     A subscript form.                         */
7511   UC_DECOMP_VERTICAL,/* <vertical>  A vertical layout presentation form.      */
7512   UC_DECOMP_WIDE,    /*   <wide>    A wide (or zenkaku) compatibility character. */
7513   UC_DECOMP_NARROW,  /*  <narrow>   A narrow (or hankaku) compatibility character. */
7514   UC_DECOMP_SMALL,   /*  <small>    A small variant form (CNS compatibility). */
7515   UC_DECOMP_SQUARE,  /*  <square>   A CJK squared font variant.               */
7516   UC_DECOMP_FRACTION,/* <fraction>  A vulgar fraction form.                   */
7517   UC_DECOMP_COMPAT   /*  <compat>   Otherwise unspecified compatibility character. */
7518 };
7519
7520 /* Return the decomposition for a Unicode character (ignoring Hangul Jamo
7521    decompositions).  Return the type, or -1 for none.  */
7522 static int
7523 get_decomposition (unsigned int ch,
7524                    unsigned int *lengthp, unsigned int decomposed[MAX_DECOMP_LENGTH])
7525 {
7526   const char *decomposition = unicode_attributes[ch].decomposition;
7527
7528   if (decomposition != NULL && decomposition[0] != '\0')
7529     {
7530       int type = UC_DECOMP_CANONICAL;
7531       unsigned int length;
7532       char *endptr;
7533
7534       if (decomposition[0] == '<')
7535         {
7536           const char *rangle;
7537           size_t typelen;
7538
7539           rangle = strchr (decomposition + 1, '>');
7540           if (rangle == NULL)
7541             abort ();
7542           typelen = rangle + 1 - decomposition;
7543 #define TYPE(t1,t2) \
7544           if (typelen == (sizeof (t1) - 1) && memcmp (decomposition, t1, typelen) == 0) \
7545             type = t2; \
7546           else
7547           TYPE ("<font>", UC_DECOMP_FONT)
7548           TYPE ("<noBreak>", UC_DECOMP_NOBREAK)
7549           TYPE ("<initial>", UC_DECOMP_INITIAL)
7550           TYPE ("<medial>", UC_DECOMP_MEDIAL)
7551           TYPE ("<final>", UC_DECOMP_FINAL)
7552           TYPE ("<isolated>", UC_DECOMP_ISOLATED)
7553           TYPE ("<circle>", UC_DECOMP_CIRCLE)
7554           TYPE ("<super>", UC_DECOMP_SUPER)
7555           TYPE ("<sub>", UC_DECOMP_SUB)
7556           TYPE ("<vertical>", UC_DECOMP_VERTICAL)
7557           TYPE ("<wide>", UC_DECOMP_WIDE)
7558           TYPE ("<narrow>", UC_DECOMP_NARROW)
7559           TYPE ("<small>", UC_DECOMP_SMALL)
7560           TYPE ("<square>", UC_DECOMP_SQUARE)
7561           TYPE ("<fraction>", UC_DECOMP_FRACTION)
7562           TYPE ("<compat>", UC_DECOMP_COMPAT)
7563             {
7564               fprintf (stderr, "unknown decomposition type %*s\n", (int)typelen, decomposition);
7565               exit (1);
7566             }
7567 #undef TYPE
7568           decomposition = rangle + 1;
7569           if (decomposition[0] == ' ')
7570             decomposition++;
7571         }
7572       for (length = 0; length < MAX_DECOMP_LENGTH; length++)
7573         {
7574           decomposed[length] = strtoul (decomposition, &endptr, 16);
7575           if (endptr == decomposition)
7576             break;
7577           decomposition = endptr;
7578           if (decomposition[0] == ' ')
7579             decomposition++;
7580         }
7581       if (*decomposition != '\0')
7582         /* MAX_DECOMP_LENGTH is too small.  */
7583         abort ();
7584
7585       *lengthp = length;
7586       return type;
7587     }
7588   else
7589     return -1;
7590 }
7591
7592 /* Construction of sparse 3-level tables.  */
7593 #define TABLE decomp_table
7594 #define ELEMENT uint16_t
7595 #define DEFAULT (uint16_t)(-1)
7596 #define xmalloc malloc
7597 #define xrealloc realloc
7598 #include "3level.h"
7599
7600 static void
7601 output_decomposition (FILE *stream1, FILE *stream2)
7602 {
7603   struct decomp_table t;
7604   unsigned int level1_offset, level2_offset, level3_offset;
7605   unsigned int offset;
7606   unsigned int ch;
7607   unsigned int i;
7608
7609   t.p = 5;
7610   t.q = 5;
7611   decomp_table_init (&t);
7612
7613   fprintf (stream1, "extern const unsigned char gl_uninorm_decomp_chars_table[];\n");
7614   fprintf (stream1, "\n");
7615   fprintf (stream2, "const unsigned char gl_uninorm_decomp_chars_table[] =\n{");
7616   offset = 0;
7617
7618   for (ch = 0; ch < 0x110000; ch++)
7619     {
7620       unsigned int length;
7621       unsigned int decomposed[MAX_DECOMP_LENGTH];
7622       int type = get_decomposition (ch, &length, decomposed);
7623
7624       if (type >= 0)
7625         {
7626           if (!(offset < (1 << 15)))
7627             abort ();
7628           decomp_table_add (&t, ch, ((type == UC_DECOMP_CANONICAL ? 0 : 1) << 15) | offset);
7629
7630           /* Produce length 3-bytes entries.  */
7631           if (length == 0)
7632             /* We would need a special representation of zero-length entries.  */
7633             abort ();
7634           for (i = 0; i < length; i++)
7635             {
7636               if (offset > 0)
7637                 fprintf (stream2, ",");
7638               if ((offset % 4) == 0)
7639                 fprintf (stream2, "\n ");
7640               if (!(decomposed[i] < (1 << 18)))
7641                 abort ();
7642               fprintf (stream2, " 0x%02X, 0x%02X, 0x%02X",
7643                        (((i+1 < length ? (1 << 23) : 0)
7644                          | (i == 0 ? (type << 18) : 0)
7645                          | decomposed[i]) >> 16) & 0xff,
7646                        (decomposed[i] >> 8) & 0xff,
7647                        decomposed[i] & 0xff);
7648               offset++;
7649             }
7650         }
7651     }
7652
7653   fprintf (stream2, "\n};\n");
7654   fprintf (stream2, "\n");
7655
7656   decomp_table_finalize (&t);
7657
7658   level1_offset =
7659     5 * sizeof (uint32_t);
7660   level2_offset =
7661     5 * sizeof (uint32_t)
7662     + t.level1_size * sizeof (uint32_t);
7663   level3_offset =
7664     5 * sizeof (uint32_t)
7665     + t.level1_size * sizeof (uint32_t)
7666     + (t.level2_size << t.q) * sizeof (uint32_t);
7667
7668   for (i = 0; i < 5; i++)
7669     fprintf (stream1, "#define decomp_header_%d %d\n", i,
7670              ((uint32_t *) t.result)[i]);
7671   fprintf (stream1, "\n");
7672   fprintf (stream1, "typedef struct\n");
7673   fprintf (stream1, "  {\n");
7674   fprintf (stream1, "    int level1[%zu];\n", t.level1_size);
7675   fprintf (stream1, "    int level2[%zu << %d];\n", t.level2_size, t.q);
7676   fprintf (stream1, "    unsigned short level3[%zu << %d];\n", t.level3_size, t.p);
7677   fprintf (stream1, "  }\n");
7678   fprintf (stream1, "decomp_index_table_t;\n");
7679   fprintf (stream1, "extern const decomp_index_table_t gl_uninorm_decomp_index_table;\n");
7680   fprintf (stream2, "const decomp_index_table_t gl_uninorm_decomp_index_table =\n");
7681   fprintf (stream2, "{\n");
7682   fprintf (stream2, "  {");
7683   if (t.level1_size > 8)
7684     fprintf (stream2, "\n   ");
7685   for (i = 0; i < t.level1_size; i++)
7686     {
7687       uint32_t offset;
7688       if (i > 0 && (i % 8) == 0)
7689         fprintf (stream2, "\n   ");
7690       offset = ((uint32_t *) (t.result + level1_offset))[i];
7691       if (offset == 0)
7692         fprintf (stream2, " %5d", -1);
7693       else
7694         fprintf (stream2, " %5zu",
7695                  (offset - level2_offset) / sizeof (uint32_t));
7696       if (i+1 < t.level1_size)
7697         fprintf (stream2, ",");
7698     }
7699   if (t.level1_size > 8)
7700     fprintf (stream2, "\n ");
7701   fprintf (stream2, " },\n");
7702   fprintf (stream2, "  {");
7703   if (t.level2_size << t.q > 8)
7704     fprintf (stream2, "\n   ");
7705   for (i = 0; i < t.level2_size << t.q; i++)
7706     {
7707       uint32_t offset;
7708       if (i > 0 && (i % 8) == 0)
7709         fprintf (stream2, "\n   ");
7710       offset = ((uint32_t *) (t.result + level2_offset))[i];
7711       if (offset == 0)
7712         fprintf (stream2, " %5d", -1);
7713       else
7714         fprintf (stream2, " %5zu",
7715                  (offset - level3_offset) / sizeof (uint16_t));
7716       if (i+1 < t.level2_size << t.q)
7717         fprintf (stream2, ",");
7718     }
7719   if (t.level2_size << t.q > 8)
7720     fprintf (stream2, "\n ");
7721   fprintf (stream2, " },\n");
7722   fprintf (stream2, "  {");
7723   if (t.level3_size << t.p > 8)
7724     fprintf (stream2, "\n   ");
7725   for (i = 0; i < t.level3_size << t.p; i++)
7726     {
7727       uint16_t value = ((uint16_t *) (t.result + level3_offset))[i];
7728       if (i > 0 && (i % 8) == 0)
7729         fprintf (stream2, "\n   ");
7730       fprintf (stream2, " %5d", value == (uint16_t)(-1) ? -1 : value);
7731       if (i+1 < t.level3_size << t.p)
7732         fprintf (stream2, ",");
7733     }
7734   if (t.level3_size << t.p > 8)
7735     fprintf (stream2, "\n ");
7736   fprintf (stream2, " }\n");
7737   fprintf (stream2, "};\n");
7738 }
7739
7740 static void
7741 output_decomposition_tables (const char *filename1, const char *filename2, const char *version)
7742 {
7743   const char *filenames[2];
7744   FILE *streams[2];
7745   size_t i;
7746
7747   filenames[0] = filename1;
7748   filenames[1] = filename2;
7749
7750   for (i = 0; i < 2; i++)
7751     {
7752       streams[i] = fopen (filenames[i], "w");
7753       if (streams[i] == NULL)
7754         {
7755           fprintf (stderr, "cannot open '%s' for writing\n", filenames[i]);
7756           exit (1);
7757         }
7758     }
7759
7760   for (i = 0; i < 2; i++)
7761     {
7762       FILE *stream = streams[i];
7763
7764       fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7765       fprintf (stream, "/* Decomposition of Unicode characters.  */\n");
7766       fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
7767                version);
7768       fprintf (stream, "\n");
7769     }
7770
7771   output_decomposition (streams[0], streams[1]);
7772
7773   for (i = 0; i < 2; i++)
7774     {
7775       if (ferror (streams[i]) || fclose (streams[i]))
7776         {
7777           fprintf (stderr, "error writing to '%s'\n", filenames[i]);
7778           exit (1);
7779         }
7780     }
7781 }
7782
7783 /* The "excluded from composition" property from the CompositionExclusions.txt file.  */
7784 char unicode_composition_exclusions[0x110000];
7785
7786 static void
7787 fill_composition_exclusions (const char *compositionexclusions_filename)
7788 {
7789   FILE *stream;
7790   unsigned int i;
7791
7792   stream = fopen (compositionexclusions_filename, "r");
7793   if (stream == NULL)
7794     {
7795       fprintf (stderr, "error during fopen of '%s'\n", compositionexclusions_filename);
7796       exit (1);
7797     }
7798
7799   for (i = 0; i < 0x110000; i++)
7800     unicode_composition_exclusions[i] = 0;
7801
7802   for (;;)
7803     {
7804       char buf[200+1];
7805       unsigned int i;
7806
7807       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
7808         break;
7809
7810       if (buf[0] == '\0' || buf[0] == '#')
7811         continue;
7812
7813       if (sscanf (buf, "%X", &i) != 1)
7814         {
7815           fprintf (stderr, "parse error in '%s'\n", compositionexclusions_filename);
7816           exit (1);
7817         }
7818       if (!(i < 0x110000))
7819         abort ();
7820
7821       unicode_composition_exclusions[i] = 1;
7822     }
7823
7824   if (ferror (stream) || fclose (stream))
7825     {
7826       fprintf (stderr, "error reading from '%s'\n", compositionexclusions_filename);
7827       exit (1);
7828     }
7829 }
7830
7831 static void
7832 debug_output_composition_tables (const char *filename)
7833 {
7834   FILE *stream;
7835   unsigned int ch;
7836
7837   stream = fopen (filename, "w");
7838   if (stream == NULL)
7839     {
7840       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7841       exit (1);
7842     }
7843
7844   for (ch = 0; ch < 0x110000; ch++)
7845     {
7846       unsigned int length;
7847       unsigned int decomposed[MAX_DECOMP_LENGTH];
7848       int type = get_decomposition (ch, &length, decomposed);
7849
7850       if (type == UC_DECOMP_CANONICAL
7851           /* Consider only binary decompositions.
7852              Exclude singleton decompositions.  */
7853           && length == 2)
7854         {
7855           unsigned int code1 = decomposed[0];
7856           unsigned int code2 = decomposed[1];
7857           unsigned int combined = ch;
7858
7859           /* Exclude decompositions where the first part is not a starter,
7860              i.e. is not of canonical combining class 0.  */
7861           if (strcmp (unicode_attributes[code1].combining, "0") == 0
7862               /* Exclude characters listed in CompositionExclusions.txt.  */
7863               && !unicode_composition_exclusions[combined])
7864             {
7865               /* The combined character must now also be a starter.
7866                  Verify this.  */
7867               if (strcmp (unicode_attributes[combined].combining, "0") != 0)
7868                 abort ();
7869
7870               fprintf (stream, "0x%04X\t0x%04X\t0x%04X\t%s\n",
7871                        code1,
7872                        code2,
7873                        combined,
7874                        unicode_attributes[code2].combining);
7875             }
7876         }
7877     }
7878
7879   if (ferror (stream) || fclose (stream))
7880     {
7881       fprintf (stderr, "error writing to '%s'\n", filename);
7882       exit (1);
7883     }
7884 }
7885
7886 static void
7887 output_composition_tables (const char *filename, const char *version)
7888 {
7889   FILE *stream;
7890   unsigned int ch;
7891
7892   stream = fopen (filename, "w");
7893   if (stream == NULL)
7894     {
7895       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7896       exit (1);
7897     }
7898
7899   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7900   fprintf (stream, "/* Canonical composition of Unicode characters.  */\n");
7901   fprintf (stream, "/* Generated automatically by gen-uni-tables for Unicode %s.  */\n",
7902            version);
7903   fprintf (stream, "\n");
7904
7905   /* Put a GPL header on it.  The gnulib module is under LGPL (although it
7906      still carries the GPL header), and it's gnulib-tool which replaces the
7907      GPL header with an LGPL header.  */
7908   fprintf (stream, "/* Copyright (C) 2009 Free Software Foundation, Inc.\n");
7909   fprintf (stream, "\n");
7910   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
7911   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
7912   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
7913   fprintf (stream, "   (at your option) any later version.\n");
7914   fprintf (stream, "\n");
7915   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
7916   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
7917   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
7918   fprintf (stream, "   GNU General Public License for more details.\n");
7919   fprintf (stream, "\n");
7920   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
7921   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
7922   fprintf (stream, "\n");
7923
7924   /* The composition table is a set of mappings (code1, code2) -> combined,
7925      with 928 entries,
7926      367 values for code1 (from 0x003C to 0x30FD),
7927       54 values for code2 (from 0x0300 to 0x309A).
7928      For a fixed code1, there are from 1 to 19 possible values for code2.
7929      For a fixed code2, there are from 1 to 117 possible values for code1.
7930      This is a very sparse matrix.
7931
7932      We want an O(1) hash lookup.
7933
7934      We could implement the hash lookup by mapping (code1, code2) to a linear
7935      combination  mul1*code1 + mul2*code2, which is then used as an index into
7936      a 3-level table.  But this leads to a table of size 37 KB.
7937
7938      We use gperf to implement the hash lookup, giving it the 928 sets of
7939      4 bytes (code1, code2) as input.  gperf generates a hash table of size
7940      1527, which is quite good (60% filled).  It requires an auxiliary table
7941      lookup in a table of size 0.5 KB.  The total tables size is 11 KB.  */
7942
7943   fprintf (stream, "struct composition_rule { char codes[6]; };\n");
7944   fprintf (stream, "%%struct-type\n");
7945   fprintf (stream, "%%language=ANSI-C\n");
7946   fprintf (stream, "%%define slot-name codes\n");
7947   fprintf (stream, "%%define hash-function-name gl_uninorm_compose_hash\n");
7948   fprintf (stream, "%%define lookup-function-name gl_uninorm_compose_lookup\n");
7949   fprintf (stream, "%%compare-lengths\n");
7950   fprintf (stream, "%%compare-strncmp\n");
7951   fprintf (stream, "%%readonly-tables\n");
7952   fprintf (stream, "%%omit-struct-type\n");
7953   fprintf (stream, "%%%%\n");
7954
7955   for (ch = 0; ch < 0x110000; ch++)
7956     {
7957       unsigned int length;
7958       unsigned int decomposed[MAX_DECOMP_LENGTH];
7959       int type = get_decomposition (ch, &length, decomposed);
7960
7961       if (type == UC_DECOMP_CANONICAL
7962           /* Consider only binary decompositions.
7963              Exclude singleton decompositions.  */
7964           && length == 2)
7965         {
7966           unsigned int code1 = decomposed[0];
7967           unsigned int code2 = decomposed[1];
7968           unsigned int combined = ch;
7969
7970           /* Exclude decompositions where the first part is not a starter,
7971              i.e. is not of canonical combining class 0.  */
7972           if (strcmp (unicode_attributes[code1].combining, "0") == 0
7973               /* Exclude characters listed in CompositionExclusions.txt.  */
7974               && !unicode_composition_exclusions[combined])
7975             {
7976               /* The combined character must now also be a starter.
7977                  Verify this.  */
7978               if (strcmp (unicode_attributes[combined].combining, "0") != 0)
7979                 abort ();
7980
7981               fprintf (stream, "\"\\x%02x\\x%02x\\x%02x\\x%02x\\x%02x\\x%02x\", 0x%04x\n",
7982                        (code1 >> 16) & 0xff, (code1 >> 8) & 0xff, code1 & 0xff,
7983                        (code2 >> 16) & 0xff, (code2 >> 8) & 0xff, code2 & 0xff,
7984                        combined);
7985             }
7986         }
7987     }
7988
7989   if (ferror (stream) || fclose (stream))
7990     {
7991       fprintf (stderr, "error writing to '%s'\n", filename);
7992       exit (1);
7993     }
7994 }
7995
7996 /* ========================================================================= */
7997
7998 /* Output the test for a simple character mapping table to the given file.  */
7999
8000 static void
8001 output_simple_mapping_test (const char *filename,
8002                             const char *function_name,
8003                             unsigned int (*func) (unsigned int),
8004                             const char *version)
8005 {
8006   FILE *stream;
8007   bool need_comma;
8008   unsigned int ch;
8009
8010   stream = fopen (filename, "w");
8011   if (stream == NULL)
8012     {
8013       fprintf (stderr, "cannot open '%s' for writing\n", filename);
8014       exit (1);
8015     }
8016
8017   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
8018   fprintf (stream, "/* Test the Unicode character mapping functions.\n");
8019   fprintf (stream, "   Copyright (C) 2009 Free Software Foundation, Inc.\n");
8020   fprintf (stream, "\n");
8021   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
8022   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
8023   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
8024   fprintf (stream, "   (at your option) any later version.\n");
8025   fprintf (stream, "\n");
8026   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
8027   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
8028   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
8029   fprintf (stream, "   GNU General Public License for more details.\n");
8030   fprintf (stream, "\n");
8031   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
8032   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
8033   fprintf (stream, "\n");
8034   fprintf (stream, "/* Generated automatically by gen-case.c for Unicode %s.  */\n",
8035            version);
8036   fprintf (stream, "\n");
8037   fprintf (stream, "#include \"test-mapping-part1.h\"\n");
8038   fprintf (stream, "\n");
8039
8040   need_comma = false;
8041   for (ch = 0; ch < 0x110000; ch++)
8042     {
8043       unsigned int value = func (ch);
8044
8045       if (value != ch)
8046         {
8047           if (need_comma)
8048             fprintf (stream, ",\n");
8049           fprintf (stream, "    { 0x%04X, 0x%04X }", ch, value);
8050           need_comma = true;
8051         }
8052     }
8053   if (need_comma)
8054     fprintf (stream, "\n");
8055
8056   fprintf (stream, "\n");
8057   fprintf (stream, "#define MAP(c) %s (c)\n", function_name);
8058   fprintf (stream, "#include \"test-mapping-part2.h\"\n");
8059
8060   if (ferror (stream) || fclose (stream))
8061     {
8062       fprintf (stderr, "error writing to '%s'\n", filename);
8063       exit (1);
8064     }
8065 }
8066
8067 /* Construction of sparse 3-level tables.  */
8068 #define TABLE mapping_table
8069 #define ELEMENT int32_t
8070 #define DEFAULT 0
8071 #define xmalloc malloc
8072 #define xrealloc realloc
8073 #include "3level.h"
8074
8075 /* Output a simple character mapping table to the given file.  */
8076
8077 static void
8078 output_simple_mapping (const char *filename,
8079                        unsigned int (*func) (unsigned int),
8080                        const char *version)
8081 {
8082   FILE *stream;
8083   unsigned int ch, i;
8084   struct mapping_table t;
8085   unsigned int level1_offset, level2_offset, level3_offset;
8086
8087   stream = fopen (filename, "w");
8088   if (stream == NULL)
8089     {
8090       fprintf (stderr, "cannot open '%s' for writing\n", filename);
8091       exit (1);
8092     }
8093
8094   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
8095   fprintf (stream, "/* Simple character mapping of Unicode characters.  */\n");
8096   fprintf (stream, "/* Generated automatically by gen-case.c for Unicode %s.  */\n",
8097            version);
8098
8099   t.p = 7;
8100   t.q = 9;
8101   mapping_table_init (&t);
8102
8103   for (ch = 0; ch < 0x110000; ch++)
8104     {
8105       int value = (int) func (ch) - (int) ch;
8106
8107       mapping_table_add (&t, ch, value);
8108     }
8109
8110   mapping_table_finalize (&t);
8111
8112   /* Offsets in t.result, in memory of this process.  */
8113   level1_offset =
8114     5 * sizeof (uint32_t);
8115   level2_offset =
8116     5 * sizeof (uint32_t)
8117     + t.level1_size * sizeof (uint32_t);
8118   level3_offset =
8119     5 * sizeof (uint32_t)
8120     + t.level1_size * sizeof (uint32_t)
8121     + (t.level2_size << t.q) * sizeof (uint32_t);
8122
8123   for (i = 0; i < 5; i++)
8124     fprintf (stream, "#define mapping_header_%d %d\n", i,
8125              ((uint32_t *) t.result)[i]);
8126   fprintf (stream, "static const\n");
8127   fprintf (stream, "struct\n");
8128   fprintf (stream, "  {\n");
8129   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
8130   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
8131   fprintf (stream, "    int level3[%zu << %d];\n", t.level3_size, t.p);
8132   fprintf (stream, "  }\n");
8133   fprintf (stream, "u_mapping =\n");
8134   fprintf (stream, "{\n");
8135   fprintf (stream, "  {");
8136   if (t.level1_size > 8)
8137     fprintf (stream, "\n   ");
8138   for (i = 0; i < t.level1_size; i++)
8139     {
8140       uint32_t offset;
8141       if (i > 0 && (i % 8) == 0)
8142         fprintf (stream, "\n   ");
8143       offset = ((uint32_t *) (t.result + level1_offset))[i];
8144       if (offset == 0)
8145         fprintf (stream, " %5d", -1);
8146       else
8147         fprintf (stream, " %5zu",
8148                  (offset - level2_offset) / sizeof (uint32_t));
8149       if (i+1 < t.level1_size)
8150         fprintf (stream, ",");
8151     }
8152   if (t.level1_size > 8)
8153     fprintf (stream, "\n ");
8154   fprintf (stream, " },\n");
8155   fprintf (stream, "  {");
8156   if (t.level2_size << t.q > 8)
8157     fprintf (stream, "\n   ");
8158   for (i = 0; i < t.level2_size << t.q; i++)
8159     {
8160       uint32_t offset;
8161       if (i > 0 && (i % 8) == 0)
8162         fprintf (stream, "\n   ");
8163       offset = ((uint32_t *) (t.result + level2_offset))[i];
8164       if (offset == 0)
8165         fprintf (stream, " %5d", -1);
8166       else
8167         fprintf (stream, " %5zu",
8168                  (offset - level3_offset) / sizeof (int32_t));
8169       if (i+1 < t.level2_size << t.q)
8170         fprintf (stream, ",");
8171     }
8172   if (t.level2_size << t.q > 8)
8173     fprintf (stream, "\n ");
8174   fprintf (stream, " },\n");
8175   fprintf (stream, "  {");
8176   if (t.level3_size << t.p > 8)
8177     fprintf (stream, "\n   ");
8178   for (i = 0; i < t.level3_size << t.p; i++)
8179     {
8180       if (i > 0 && (i % 8) == 0)
8181         fprintf (stream, "\n   ");
8182       fprintf (stream, " %5d", ((int32_t *) (t.result + level3_offset))[i]);
8183       if (i+1 < t.level3_size << t.p)
8184         fprintf (stream, ",");
8185     }
8186   if (t.level3_size << t.p > 8)
8187     fprintf (stream, "\n ");
8188   fprintf (stream, " }\n");
8189   fprintf (stream, "};\n");
8190
8191   if (ferror (stream) || fclose (stream))
8192     {
8193       fprintf (stderr, "error writing to '%s'\n", filename);
8194       exit (1);
8195     }
8196 }
8197
8198 /* ========================================================================= */
8199
8200 /* A special casing context.
8201    A context is negated through x -> -x.  */
8202 enum
8203 {
8204   SCC_ALWAYS             = 0,
8205   SCC_FINAL_SIGMA,
8206   SCC_AFTER_SOFT_DOTTED,
8207   SCC_MORE_ABOVE,
8208   SCC_BEFORE_DOT,
8209   SCC_AFTER_I
8210 };
8211
8212 /* A special casing rule.  */
8213 struct special_casing_rule
8214 {
8215   unsigned int code;
8216   unsigned int lower_mapping[3];
8217   unsigned int title_mapping[3];
8218   unsigned int upper_mapping[3];
8219   unsigned int casefold_mapping[3];
8220   const char *language;
8221   int context;
8222 };
8223
8224 /* The special casing rules.  */
8225 struct special_casing_rule **casing_rules;
8226 unsigned int num_casing_rules;
8227 unsigned int allocated_casing_rules;
8228
8229 static void
8230 add_casing_rule (struct special_casing_rule *new_rule)
8231 {
8232   if (num_casing_rules == allocated_casing_rules)
8233     {
8234       allocated_casing_rules = 2 * allocated_casing_rules;
8235       if (allocated_casing_rules < 16)
8236         allocated_casing_rules = 16;
8237       casing_rules =
8238         (struct special_casing_rule **)
8239         realloc (casing_rules, allocated_casing_rules * sizeof (struct special_casing_rule *));
8240     }
8241   casing_rules[num_casing_rules++] = new_rule;
8242 }
8243
8244 /* Stores in casing_rules the special casing rules found in
8245    specialcasing_filename.  */
8246 static void
8247 fill_casing_rules (const char *specialcasing_filename)
8248 {
8249   FILE *stream;
8250
8251   stream = fopen (specialcasing_filename, "r");
8252   if (stream == NULL)
8253     {
8254       fprintf (stderr, "error during fopen of '%s'\n", specialcasing_filename);
8255       exit (1);
8256     }
8257
8258   casing_rules = NULL;
8259   num_casing_rules = 0;
8260   allocated_casing_rules = 0;
8261
8262   for (;;)
8263     {
8264       char buf[200+1];
8265       char *scanptr;
8266       char *endptr;
8267       int i;
8268
8269       unsigned int code;
8270       unsigned int lower_mapping[3];
8271       unsigned int title_mapping[3];
8272       unsigned int upper_mapping[3];
8273       char *language;
8274       int context;
8275
8276       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
8277         break;
8278
8279       if (buf[0] == '\0' || buf[0] == '#')
8280         continue;
8281
8282       /* Scan code.  */
8283       scanptr = buf;
8284       code = strtoul (scanptr, &endptr, 16);
8285       if (endptr == scanptr)
8286         {
8287           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8288           exit (1);
8289         }
8290       scanptr = endptr;
8291       if (*scanptr != ';')
8292         {
8293           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8294           exit (1);
8295         }
8296       scanptr++;
8297
8298       /* Scan lower mapping.  */
8299       for (i = 0; i < 3; i++)
8300         lower_mapping[i] = 0;
8301       for (i = 0; i < 3; i++)
8302         {
8303           while (*scanptr == ' ')
8304             scanptr++;
8305           if (*scanptr == ';')
8306             break;
8307           lower_mapping[i] = strtoul (scanptr, &endptr, 16);
8308           if (endptr == scanptr)
8309             {
8310               fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8311               exit (1);
8312             }
8313           scanptr = endptr;
8314         }
8315       if (*scanptr != ';')
8316         {
8317           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8318           exit (1);
8319         }
8320       scanptr++;
8321
8322       /* Scan title mapping.  */
8323       for (i = 0; i < 3; i++)
8324         title_mapping[i] = 0;
8325       for (i = 0; i < 3; i++)
8326         {
8327           while (*scanptr == ' ')
8328             scanptr++;
8329           if (*scanptr == ';')
8330             break;
8331           title_mapping[i] = strtoul (scanptr, &endptr, 16);
8332           if (endptr == scanptr)
8333             {
8334               fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8335               exit (1);
8336             }
8337           scanptr = endptr;
8338         }
8339       if (*scanptr != ';')
8340         {
8341           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8342           exit (1);
8343         }
8344       scanptr++;
8345
8346       /* Scan upper mapping.  */
8347       for (i = 0; i < 3; i++)
8348         upper_mapping[i] = 0;
8349       for (i = 0; i < 3; i++)
8350         {
8351           while (*scanptr == ' ')
8352             scanptr++;
8353           if (*scanptr == ';')
8354             break;
8355           upper_mapping[i] = strtoul (scanptr, &endptr, 16);
8356           if (endptr == scanptr)
8357             {
8358               fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8359               exit (1);
8360             }
8361           scanptr = endptr;
8362         }
8363       if (*scanptr != ';')
8364         {
8365           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8366           exit (1);
8367         }
8368       scanptr++;
8369
8370       /* Scan language and context.  */
8371       language = NULL;
8372       context = SCC_ALWAYS;
8373       while (*scanptr == ' ')
8374         scanptr++;
8375       if (*scanptr != '\0' && *scanptr != '#')
8376         {
8377           const char *word_begin = scanptr;
8378           const char *word_end;
8379
8380           while (*scanptr != '\0' && *scanptr != '#' && *scanptr != ';' && *scanptr != ' ')
8381             scanptr++;
8382           word_end = scanptr;
8383
8384           while (*scanptr == ' ')
8385             scanptr++;
8386
8387           if (word_end - word_begin == 2)
8388             {
8389               language = (char *) malloc ((word_end - word_begin) + 1);
8390               memcpy (language, word_begin, 2);
8391               language[word_end - word_begin] = '\0';
8392               word_begin = word_end = NULL;
8393
8394               if (*scanptr != '\0' && *scanptr != '#' &&  *scanptr != ';')
8395                 {
8396                   word_begin = scanptr;
8397                   while (*scanptr != '\0' && *scanptr != '#' && *scanptr != ';' && *scanptr != ' ')
8398                     scanptr++;
8399                   word_end = scanptr;
8400                 }
8401             }
8402
8403           if (word_end > word_begin)
8404             {
8405               bool negate = false;
8406
8407               if (word_end - word_begin >= 4 && memcmp (word_begin, "Not_", 4) == 0)
8408                 {
8409                   word_begin += 4;
8410                   negate = true;
8411                 }
8412               if (word_end - word_begin == 11 && memcmp (word_begin, "Final_Sigma", 11) == 0)
8413                 context = SCC_FINAL_SIGMA;
8414               else if (word_end - word_begin == 17 && memcmp (word_begin, "After_Soft_Dotted", 17) == 0)
8415                 context = SCC_AFTER_SOFT_DOTTED;
8416               else if (word_end - word_begin == 10 && memcmp (word_begin, "More_Above", 10) == 0)
8417                 context = SCC_MORE_ABOVE;
8418               else if (word_end - word_begin == 10 && memcmp (word_begin, "Before_Dot", 10) == 0)
8419                 context = SCC_BEFORE_DOT;
8420               else if (word_end - word_begin == 7 && memcmp (word_begin, "After_I", 7) == 0)
8421                 context = SCC_AFTER_I;
8422               else
8423                 {
8424                   fprintf (stderr, "unknown context type in '%s'\n", specialcasing_filename);
8425                   exit (1);
8426                 }
8427               if (negate)
8428                 context = - context;
8429             }
8430
8431           if (*scanptr != '\0' && *scanptr != '#' &&  *scanptr != ';')
8432             {
8433               fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8434               exit (1);
8435             }
8436         }
8437
8438       /* Store the rule.  */
8439       {
8440         struct special_casing_rule *new_rule =
8441           (struct special_casing_rule *) malloc (sizeof (struct special_casing_rule));
8442         new_rule->code = code;
8443         new_rule->language = language;
8444         new_rule->context = context;
8445         memcpy (new_rule->lower_mapping, lower_mapping, sizeof (new_rule->lower_mapping));
8446         memcpy (new_rule->title_mapping, title_mapping, sizeof (new_rule->title_mapping));
8447         memcpy (new_rule->upper_mapping, upper_mapping, sizeof (new_rule->upper_mapping));
8448
8449         add_casing_rule (new_rule);
8450       }
8451     }
8452
8453   if (ferror (stream) || fclose (stream))
8454     {
8455       fprintf (stderr, "error reading from '%s'\n", specialcasing_filename);
8456       exit (1);
8457     }
8458 }
8459
8460 /* A casefolding rule.  */
8461 struct casefold_rule
8462 {
8463   unsigned int code;
8464   unsigned int mapping[3];
8465   const char *language;
8466 };
8467
8468 /* The casefolding rules.  */
8469 struct casefold_rule **casefolding_rules;
8470 unsigned int num_casefolding_rules;
8471 unsigned int allocated_casefolding_rules;
8472
8473 /* Stores in casefolding_rules the case folding rules found in
8474    casefolding_filename.  */
8475 static void
8476 fill_casefolding_rules (const char *casefolding_filename)
8477 {
8478   FILE *stream;
8479
8480   stream = fopen (casefolding_filename, "r");
8481   if (stream == NULL)
8482     {
8483       fprintf (stderr, "error during fopen of '%s'\n", casefolding_filename);
8484       exit (1);
8485     }
8486
8487   casefolding_rules = NULL;
8488   num_casefolding_rules = 0;
8489   allocated_casefolding_rules = 0;
8490
8491   for (;;)
8492     {
8493       char buf[200+1];
8494       char *scanptr;
8495       char *endptr;
8496       int i;
8497
8498       unsigned int code;
8499       char type;
8500       unsigned int mapping[3];
8501
8502       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
8503         break;
8504
8505       if (buf[0] == '\0' || buf[0] == '#')
8506         continue;
8507
8508       /* Scan code.  */
8509       scanptr = buf;
8510       code = strtoul (scanptr, &endptr, 16);
8511       if (endptr == scanptr)
8512         {
8513           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8514           exit (1);
8515         }
8516       scanptr = endptr;
8517       if (*scanptr != ';')
8518         {
8519           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8520           exit (1);
8521         }
8522       scanptr++;
8523
8524       /* Scan type.  */
8525       while (*scanptr == ' ')
8526         scanptr++;
8527
8528       switch (*scanptr)
8529         {
8530         case 'C': case 'F': case 'S': case 'T':
8531           type = *scanptr;
8532           break;
8533         default:
8534           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8535           exit (1);
8536         }
8537       scanptr++;
8538       if (*scanptr != ';')
8539         {
8540           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8541           exit (1);
8542         }
8543       scanptr++;
8544
8545       /* Scan casefold mapping.  */
8546       for (i = 0; i < 3; i++)
8547         mapping[i] = 0;
8548       for (i = 0; i < 3; i++)
8549         {
8550           while (*scanptr == ' ')
8551             scanptr++;
8552           if (*scanptr == ';')
8553             break;
8554           mapping[i] = strtoul (scanptr, &endptr, 16);
8555           if (endptr == scanptr)
8556             {
8557               fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8558               exit (1);
8559             }
8560           scanptr = endptr;
8561         }
8562       if (*scanptr != ';')
8563         {
8564           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8565           exit (1);
8566         }
8567       scanptr++;
8568
8569       /* Ignore rules of type 'S'; we use the rules of type 'F' instead.  */
8570       if (type != 'S')
8571         {
8572           const char * const *languages;
8573           unsigned int languages_count;
8574
8575           /* Type 'T' indicates that the rule is applicable to Turkish
8576              languages only.  */
8577           if (type == 'T')
8578             {
8579               static const char * const turkish_languages[] = { "tr", "az" };
8580               languages = turkish_languages;
8581               languages_count = 2;
8582             }
8583           else
8584             {
8585               static const char * const all_languages[] = { NULL };
8586               languages = all_languages;
8587               languages_count = 1;
8588             }
8589
8590           for (i = 0; i < languages_count; i++)
8591             {
8592               /* Store a new rule.  */
8593               struct casefold_rule *new_rule =
8594                 (struct casefold_rule *) malloc (sizeof (struct casefold_rule));
8595               new_rule->code = code;
8596               memcpy (new_rule->mapping, mapping, sizeof (new_rule->mapping));
8597               new_rule->language = languages[i];
8598
8599               if (num_casefolding_rules == allocated_casefolding_rules)
8600                 {
8601                   allocated_casefolding_rules = 2 * allocated_casefolding_rules;
8602                   if (allocated_casefolding_rules < 16)
8603                     allocated_casefolding_rules = 16;
8604                   casefolding_rules =
8605                     (struct casefold_rule **)
8606                     realloc (casefolding_rules,
8607                              allocated_casefolding_rules * sizeof (struct casefold_rule *));
8608                 }
8609               casefolding_rules[num_casefolding_rules++] = new_rule;
8610             }
8611         }
8612     }
8613
8614   if (ferror (stream) || fclose (stream))
8615     {
8616       fprintf (stderr, "error reading from '%s'\n", casefolding_filename);
8617       exit (1);
8618     }
8619 }
8620
8621 /* Casefold mapping, when it maps to a single character.  */
8622 unsigned int unicode_casefold[0x110000];
8623
8624 static unsigned int
8625 to_casefold (unsigned int ch)
8626 {
8627   return unicode_casefold[ch];
8628 }
8629
8630 /* Redistribute the casefolding_rules:
8631    - Rules that map to a single character, language independently, are stored
8632      in unicode_casefold.
8633    - Other rules are merged into casing_rules.  */
8634 static void
8635 redistribute_casefolding_rules (void)
8636 {
8637   unsigned int ch, i, j;
8638
8639   /* Fill unicode_casefold[].  */
8640   for (ch = 0; ch < 0x110000; ch++)
8641     unicode_casefold[ch] = ch;
8642   for (i = 0; i < num_casefolding_rules; i++)
8643     {
8644       struct casefold_rule *cfrule = casefolding_rules[i];
8645
8646       if (cfrule->language == NULL && cfrule->mapping[1] == 0)
8647         {
8648           ch = cfrule->code;
8649           if (!(ch < 0x110000))
8650             abort ();
8651           unicode_casefold[ch] = cfrule->mapping[0];
8652         }
8653     }
8654
8655   /* Extend the special casing rules by filling in their casefold_mapping[]
8656      field.  */
8657   for (j = 0; j < num_casing_rules; j++)
8658     {
8659       struct special_casing_rule *rule = casing_rules[j];
8660       unsigned int k;
8661
8662       rule->casefold_mapping[0] = to_casefold (rule->code);
8663       for (k = 1; k < 3; k++)
8664         rule->casefold_mapping[k] = 0;
8665     }
8666
8667   /* Now merge the other casefolding rules into casing_rules.  */
8668   for (i = 0; i < num_casefolding_rules; i++)
8669     {
8670       struct casefold_rule *cfrule = casefolding_rules[i];
8671
8672       if (!(cfrule->language == NULL && cfrule->mapping[1] == 0))
8673         {
8674           /* Find a rule that applies to the same code, same language, and it
8675              has context SCC_ALWAYS.  At the same time, update all rules that
8676              have the same code and same or more specific language.  */
8677           struct special_casing_rule *found_rule = NULL;
8678
8679           for (j = 0; j < num_casing_rules; j++)
8680             {
8681               struct special_casing_rule *rule = casing_rules[j];
8682
8683               if (rule->code == cfrule->code
8684                   && (cfrule->language == NULL
8685                       || (rule->language != NULL
8686                           && strcmp (rule->language, cfrule->language) == 0)))
8687                 {
8688                   memcpy (rule->casefold_mapping, cfrule->mapping,
8689                           sizeof (rule->casefold_mapping));
8690
8691                   if ((cfrule->language == NULL
8692                        ? rule->language == NULL
8693                        : rule->language != NULL
8694                          && strcmp (rule->language, cfrule->language) == 0)
8695                       && rule->context == SCC_ALWAYS)
8696                     {
8697                       /* Found it.  */
8698                       found_rule = rule;
8699                     }
8700                 }
8701             }
8702
8703           if (found_rule == NULL)
8704             {
8705               /* Create a new rule.  */
8706               struct special_casing_rule *new_rule =
8707                 (struct special_casing_rule *) malloc (sizeof (struct special_casing_rule));
8708
8709               /* Try to find a rule that applies to the same code, no language
8710                  restriction, and with context SCC_ALWAYS.  */
8711               for (j = 0; j < num_casing_rules; j++)
8712                 {
8713                   struct special_casing_rule *rule = casing_rules[j];
8714
8715                   if (rule->code == cfrule->code
8716                       && rule->context == SCC_ALWAYS
8717                       && rule->language == NULL)
8718                     {
8719                       /* Found it.  */
8720                       found_rule = rule;
8721                       break;
8722                     }
8723                 }
8724
8725               new_rule->code = cfrule->code;
8726               new_rule->language = cfrule->language;
8727               new_rule->context = SCC_ALWAYS;
8728               if (found_rule != NULL)
8729                 {
8730                   memcpy (new_rule->lower_mapping, found_rule->lower_mapping,
8731                           sizeof (new_rule->lower_mapping));
8732                   memcpy (new_rule->title_mapping, found_rule->title_mapping,
8733                           sizeof (new_rule->title_mapping));
8734                   memcpy (new_rule->upper_mapping, found_rule->upper_mapping,
8735                           sizeof (new_rule->upper_mapping));
8736                 }
8737               else
8738                 {
8739                   unsigned int k;
8740
8741                   new_rule->lower_mapping[0] = to_lower (cfrule->code);
8742                   for (k = 1; k < 3; k++)
8743                     new_rule->lower_mapping[k] = 0;
8744                   new_rule->title_mapping[0] = to_title (cfrule->code);
8745                   for (k = 1; k < 3; k++)
8746                     new_rule->title_mapping[k] = 0;
8747                   new_rule->upper_mapping[0] = to_upper (cfrule->code);
8748                   for (k = 1; k < 3; k++)
8749                     new_rule->upper_mapping[k] = 0;
8750                 }
8751               memcpy (new_rule->casefold_mapping, cfrule->mapping,
8752                       sizeof (new_rule->casefold_mapping));
8753
8754               add_casing_rule (new_rule);
8755             }
8756         }
8757     }
8758 }
8759
8760 static int
8761 compare_casing_rules (const void *a, const void *b)
8762 {
8763   struct special_casing_rule *a_rule = *(struct special_casing_rule **) a;
8764   struct special_casing_rule *b_rule = *(struct special_casing_rule **) b;
8765   unsigned int a_code = a_rule->code;
8766   unsigned int b_code = b_rule->code;
8767
8768   if (a_code < b_code)
8769     return -1;
8770   if (a_code > b_code)
8771     return 1;
8772
8773   /* Sort the more specific rules before the more general ones.  */
8774   return (- ((a_rule->language != NULL ? 1 : 0) + (a_rule->context != SCC_ALWAYS ? 1 : 0))
8775           + ((b_rule->language != NULL ? 1 : 0) + (b_rule->context != SCC_ALWAYS ? 1 : 0)));
8776 }
8777
8778 static void
8779 sort_casing_rules (void)
8780 {
8781   /* Sort the rules 1. by code, 2. by specificity.  */
8782   if (num_casing_rules > 1)
8783     qsort (casing_rules, num_casing_rules, sizeof (struct special_casing_rule *),
8784            compare_casing_rules);
8785 }
8786
8787 /* Output the special casing rules.  */
8788 static void
8789 output_casing_rules (const char *filename, const char *version)
8790 {
8791   FILE *stream;
8792   unsigned int i, j;
8793   unsigned int minor;
8794
8795   stream = fopen (filename, "w");
8796   if (stream == NULL)
8797     {
8798       fprintf (stderr, "cannot open '%s' for writing\n", filename);
8799       exit (1);
8800     }
8801
8802   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
8803   fprintf (stream, "/* Special casing rules of Unicode characters.  */\n");
8804   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
8805            version);
8806   fprintf (stream, "struct special_casing_rule { char code[3]; };\n");
8807   fprintf (stream, "%%struct-type\n");
8808   fprintf (stream, "%%language=ANSI-C\n");
8809   fprintf (stream, "%%define slot-name code\n");
8810   fprintf (stream, "%%define hash-function-name gl_unicase_special_hash\n");
8811   fprintf (stream, "%%define lookup-function-name gl_unicase_special_lookup\n");
8812   fprintf (stream, "%%compare-lengths\n");
8813   fprintf (stream, "%%compare-strncmp\n");
8814   fprintf (stream, "%%readonly-tables\n");
8815   fprintf (stream, "%%omit-struct-type\n");
8816   fprintf (stream, "%%%%\n");
8817
8818   minor = 0;
8819   for (i = 0; i < num_casing_rules; i++)
8820     {
8821       struct special_casing_rule *rule = casing_rules[i];
8822       int context;
8823
8824       if (i > 0 && rule->code == casing_rules[i - 1]->code)
8825         minor += 1;
8826       else
8827         minor = 0;
8828
8829       if (!(rule->code < 0x10000))
8830         {
8831           fprintf (stderr, "special rule #%u: code %u out of range\n", i, rule->code);
8832           exit (1);
8833         }
8834
8835       fprintf (stream, "\"\\x%02x\\x%02x\\x%02x\", ",
8836                (rule->code >> 8) & 0xff, rule->code & 0xff, minor);
8837
8838       fprintf (stream, "%d, ",
8839                i + 1 < num_casing_rules && casing_rules[i + 1]->code == rule->code ? 1 : 0);
8840
8841       context = rule->context;
8842       if (context < 0)
8843         {
8844           fprintf (stream, "-");
8845           context = - context;
8846         }
8847       else
8848         fprintf (stream, " ");
8849       switch (context)
8850         {
8851         case SCC_ALWAYS:
8852           fprintf (stream, "SCC_ALWAYS           ");
8853           break;
8854         case SCC_FINAL_SIGMA:
8855           fprintf (stream, "SCC_FINAL_SIGMA      ");
8856           break;
8857         case SCC_AFTER_SOFT_DOTTED:
8858           fprintf (stream, "SCC_AFTER_SOFT_DOTTED");
8859           break;
8860         case SCC_MORE_ABOVE:
8861           fprintf (stream, "SCC_MORE_ABOVE       ");
8862           break;
8863         case SCC_BEFORE_DOT:
8864           fprintf (stream, "SCC_BEFORE_DOT       ");
8865           break;
8866         case SCC_AFTER_I:
8867           fprintf (stream, "SCC_AFTER_I          ");
8868           break;
8869         default:
8870           abort ();
8871         }
8872       fprintf (stream, ", ");
8873
8874       if (rule->language != NULL)
8875         {
8876           if (strlen (rule->language) != 2)
8877             abort ();
8878           fprintf (stream, "{  '%c',  '%c' }, ", rule->language[0], rule->language[1]);
8879         }
8880       else
8881         fprintf (stream, "{ '\\0', '\\0' }, ");
8882
8883       fprintf (stream, "{ ");
8884       for (j = 0; j < 3; j++)
8885         {
8886           if (j > 0)
8887             fprintf (stream, ", ");
8888           if (!(rule->upper_mapping[j] < 0x10000))
8889             {
8890               fprintf (stderr, "special rule #%u: upper mapping of code %u out of range\n", i, rule->code);
8891               exit (1);
8892             }
8893           if (rule->upper_mapping[j] != 0)
8894             fprintf (stream, "0x%04X", rule->upper_mapping[j]);
8895           else
8896             fprintf (stream, "     0");
8897         }
8898       fprintf (stream, " }, { ");
8899       for (j = 0; j < 3; j++)
8900         {
8901           if (j > 0)
8902             fprintf (stream, ", ");
8903           if (!(rule->lower_mapping[j] < 0x10000))
8904             {
8905               fprintf (stderr, "special rule #%u: lower mapping of code %u out of range\n", i, rule->code);
8906               exit (1);
8907             }
8908           if (rule->lower_mapping[j] != 0)
8909             fprintf (stream, "0x%04X", rule->lower_mapping[j]);
8910           else
8911             fprintf (stream, "     0");
8912         }
8913       fprintf (stream, " }, { ");
8914       for (j = 0; j < 3; j++)
8915         {
8916           if (j > 0)
8917             fprintf (stream, ", ");
8918           if (!(rule->title_mapping[j] < 0x10000))
8919             {
8920               fprintf (stderr, "special rule #%u: title mapping of code %u out of range\n", i, rule->code);
8921               exit (1);
8922             }
8923           if (rule->title_mapping[j] != 0)
8924             fprintf (stream, "0x%04X", rule->title_mapping[j]);
8925           else
8926             fprintf (stream, "     0");
8927         }
8928       fprintf (stream, " }, { ");
8929       for (j = 0; j < 3; j++)
8930         {
8931           if (j > 0)
8932             fprintf (stream, ", ");
8933           if (!(rule->casefold_mapping[j] < 0x10000))
8934             {
8935               fprintf (stderr, "special rule #%u: casefold mapping of code %u out of range\n", i, rule->code);
8936               exit (1);
8937             }
8938           if (rule->casefold_mapping[j] != 0)
8939             fprintf (stream, "0x%04X", rule->casefold_mapping[j]);
8940           else
8941             fprintf (stream, "     0");
8942         }
8943       fprintf (stream, " }\n");
8944     }
8945
8946   if (ferror (stream) || fclose (stream))
8947     {
8948       fprintf (stderr, "error writing to '%s'\n", filename);
8949       exit (1);
8950     }
8951 }
8952
8953 /* ========================================================================= */
8954
8955 /* Quoting the Unicode standard:
8956      Definition: A character is defined to be "cased" if it has the Lowercase
8957      or Uppercase property or has a General_Category value of
8958      Titlecase_Letter.  */
8959 static bool
8960 is_cased (unsigned int ch)
8961 {
8962   return (is_property_lowercase (ch)
8963           || is_property_uppercase (ch)
8964           || is_category_Lt (ch));
8965 }
8966
8967 /* Quoting the Unicode standard:
8968      Definition: A character is defined to be "case-ignorable" if it has the
8969      value MidLetter {or the value MidNumLet} for the Word_Break property or
8970      its General_Category is one of Nonspacing_Mark (Mn), Enclosing_Mark (Me),
8971      Format (Cf), Modifier_Letter (Lm), or Modifier_Symbol (Sk).
8972    The text marked in braces was added in Unicode 5.1.0, see
8973    <http://www.unicode.org/versions/Unicode5.1.0/> section "Update of
8974    Definition of case-ignorable".   */
8975 /* Since this predicate is only used for the "Before C" and "After C"
8976    conditions of FINAL_SIGMA, we exclude the "cased" characters here.
8977    This simplifies the evaluation of the regular expressions
8978      \p{cased} (\p{case-ignorable})* C
8979    and
8980      C (\p{case-ignorable})* \p{cased}
8981  */
8982 static bool
8983 is_case_ignorable (unsigned int ch)
8984 {
8985   return (unicode_org_wbp[ch] == WBP_MIDLETTER
8986           || unicode_org_wbp[ch] == WBP_MIDNUMLET
8987           || is_category_Mn (ch)
8988           || is_category_Me (ch)
8989           || is_category_Cf (ch)
8990           || is_category_Lm (ch)
8991           || is_category_Sk (ch))
8992          && !is_cased (ch);
8993 }
8994
8995 /* ------------------------------------------------------------------------- */
8996
8997 /* Output all case related properties.  */
8998 static void
8999 output_casing_properties (const char *version)
9000 {
9001 #define PROPERTY(FN,P) \
9002   debug_output_predicate ("unicase/" #FN ".txt", is_ ## P); \
9003   output_predicate_test ("../tests/unicase/test-" #FN ".c", is_ ## P, "uc_is_" #P " (c)"); \
9004   output_predicate ("unicase/" #FN ".h", is_ ## P, "u_casing_property_" #P, "Casing Properties", version);
9005   PROPERTY(cased, cased)
9006   PROPERTY(ignorable, case_ignorable)
9007 #undef PROPERTY
9008 }
9009
9010 /* ========================================================================= */
9011
9012 int
9013 main (int argc, char * argv[])
9014 {
9015   const char *unicodedata_filename;
9016   const char *proplist_filename;
9017   const char *derivedproplist_filename;
9018   const char *scripts_filename;
9019   const char *blocks_filename;
9020   const char *proplist30_filename;
9021   const char *eastasianwidth_filename;
9022   const char *linebreak_filename;
9023   const char *wordbreakproperty_filename;
9024   const char *graphemebreakproperty_filename;
9025   const char *compositionexclusions_filename;
9026   const char *specialcasing_filename;
9027   const char *casefolding_filename;
9028   const char *version;
9029
9030   if (argc != 15)
9031     {
9032       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 GraphemeBreakProperty.txt CompositionExclusions.txt SpecialCasing.txt CaseFolding.txt version\n",
9033                argv[0]);
9034       exit (1);
9035     }
9036
9037   unicodedata_filename = argv[1];
9038   proplist_filename = argv[2];
9039   derivedproplist_filename = argv[3];
9040   scripts_filename = argv[4];
9041   blocks_filename = argv[5];
9042   proplist30_filename = argv[6];
9043   eastasianwidth_filename = argv[7];
9044   linebreak_filename = argv[8];
9045   wordbreakproperty_filename = argv[9];
9046   graphemebreakproperty_filename = argv[10];
9047   compositionexclusions_filename = argv[11];
9048   specialcasing_filename = argv[12];
9049   casefolding_filename = argv[13];
9050   version = argv[14];
9051
9052   fill_attributes (unicodedata_filename);
9053   clear_properties ();
9054   fill_properties (proplist_filename);
9055   fill_properties (derivedproplist_filename);
9056   fill_properties30 (proplist30_filename);
9057   fill_scripts (scripts_filename);
9058   fill_blocks (blocks_filename);
9059   fill_width (eastasianwidth_filename);
9060   fill_org_lbp (linebreak_filename);
9061   fill_org_wbp (wordbreakproperty_filename);
9062   fill_org_gbp (graphemebreakproperty_filename);
9063   fill_composition_exclusions (compositionexclusions_filename);
9064   fill_casing_rules (specialcasing_filename);
9065   fill_casefolding_rules (casefolding_filename);
9066   redistribute_casefolding_rules ();
9067   sort_casing_rules ();
9068
9069   output_categories (version);
9070   output_category ("unictype/categ_of.h", version);
9071   output_combclass ("unictype/combining.h", version);
9072   output_bidi_category ("unictype/bidi_of.h", version);
9073   output_decimal_digit_test ("../tests/unictype/test-decdigit.h", version);
9074   output_decimal_digit ("unictype/decdigit.h", version);
9075   output_digit_test ("../tests/unictype/test-digit.h", version);
9076   output_digit ("unictype/digit.h", version);
9077   output_numeric_test ("../tests/unictype/test-numeric.h", version);
9078   output_numeric ("unictype/numeric.h", version);
9079   output_mirror ("unictype/mirror.h", version);
9080   output_properties (version);
9081   output_scripts (version);
9082   output_scripts_byname (version);
9083   output_blocks (version);
9084   output_ident_properties (version);
9085   output_nonspacing_property ("uniwidth/width.c.part");
9086   output_width_property_test ("../tests/uniwidth/test-uc_width2.sh.part");
9087   output_old_ctype (version);
9088
9089   debug_output_lbrk_tables ("unilbrk/lbrkprop.txt");
9090   debug_output_org_lbrk_tables ("unilbrk/lbrkprop_org.txt");
9091   output_lbrk_tables ("unilbrk/lbrkprop1.h", "unilbrk/lbrkprop2.h", version);
9092
9093   debug_output_wbrk_tables ("uniwbrk/wbrkprop.txt");
9094   debug_output_org_wbrk_tables ("uniwbrk/wbrkprop_org.txt");
9095   output_wbrk_tables ("uniwbrk/wbrkprop.h", version);
9096
9097   output_gbp_test ("../tests/unigbrk/test-uc-gbrk-prop.h");
9098   output_gbp_table ("unigbrk/gbrkprop.h", version);
9099
9100   output_decomposition_tables ("uninorm/decomposition-table1.h", "uninorm/decomposition-table2.h", version);
9101   debug_output_composition_tables ("uninorm/composition.txt");
9102   output_composition_tables ("uninorm/composition-table.gperf", version);
9103
9104   output_simple_mapping_test ("../tests/unicase/test-uc_toupper.c", "uc_toupper", to_upper, version);
9105   output_simple_mapping_test ("../tests/unicase/test-uc_tolower.c", "uc_tolower", to_lower, version);
9106   output_simple_mapping_test ("../tests/unicase/test-uc_totitle.c", "uc_totitle", to_title, version);
9107   output_simple_mapping ("unicase/toupper.h", to_upper, version);
9108   output_simple_mapping ("unicase/tolower.h", to_lower, version);
9109   output_simple_mapping ("unicase/totitle.h", to_title, version);
9110   output_simple_mapping ("unicase/tocasefold.h", to_casefold, version);
9111   output_casing_rules ("unicase/special-casing-table.gperf", version);
9112   output_casing_properties (version);
9113
9114   return 0;
9115 }
9116
9117 /*
9118  * For Emacs M-x compile
9119  * Local Variables:
9120  * compile-command: "
9121    gcc -O -Wall gen-uni-tables.c -Iunictype -o gen-uni-tables && \
9122    ./gen-uni-tables \
9123         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/UnicodeData.txt \
9124         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/PropList.txt \
9125         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/DerivedCoreProperties.txt \
9126         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/Scripts.txt \
9127         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/Blocks.txt \
9128         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/3.0.1/PropList-3.0.1.txt \
9129         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/EastAsianWidth.txt \
9130         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/LineBreak.txt \
9131         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/auxiliary/WordBreakProperty.txt \
9132         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/auxiliary/GraphemeBreakProperty.txt \
9133         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/CompositionExclusions.txt \
9134         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/SpecialCasing.txt \
9135         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/6.0.0/ucd/CaseFolding.txt \
9136         6.0.0 \
9137    && diff unilbrk/lbrkprop_org.txt unilbrk/lbrkprop.txt \
9138    && diff uniwbrk/wbrkprop_org.txt uniwbrk/wbrkprop.txt
9139    "
9140  * End:
9141  */