Update to Unicode 5.2.0.
[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                       5.2.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 { const char *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, "%%%%\n");
3955   for (s = 0; s < numscripts; s++)
3956     fprintf (stream, "%s, %u\n", scripts[s], s);
3957
3958   if (ferror (stream) || fclose (stream))
3959     {
3960       fprintf (stderr, "error writing to '%s'\n", filename);
3961       exit (1);
3962     }
3963 }
3964
3965 /* ========================================================================= */
3966
3967 /* Blocks.  */
3968
3969 typedef struct { unsigned int start; unsigned int end; const char *name; }
3970   block_t;
3971 static block_t blocks[256];
3972 static unsigned int numblocks;
3973
3974 static void
3975 fill_blocks (const char *blocks_filename)
3976 {
3977   FILE *stream;
3978
3979   stream = fopen (blocks_filename, "r");
3980   if (stream == NULL)
3981     {
3982       fprintf (stderr, "error during fopen of '%s'\n", blocks_filename);
3983       exit (1);
3984     }
3985
3986   for (;;)
3987     {
3988       char buf[200+1];
3989       unsigned int i1, i2;
3990       char padding[200+1];
3991       char blockname[200+1];
3992
3993       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
3994         break;
3995
3996       if (buf[0] == '\0' || buf[0] == '#')
3997         continue;
3998
3999       if (sscanf (buf, "%X..%X%[ ;]%[^\r]", &i1, &i2, padding, blockname) != 4)
4000         {
4001           fprintf (stderr, "parse error in '%s'\n", blocks_filename);
4002           exit (1);
4003         }
4004       blocks[numblocks].start = i1;
4005       blocks[numblocks].end = i2;
4006       blocks[numblocks].name = strdup (blockname);
4007       /* It must be sorted.  */
4008       if (numblocks > 0 && !(blocks[numblocks-1].end < blocks[numblocks].start))
4009         abort ();
4010       numblocks++;
4011       if (numblocks == 256)
4012         abort ();
4013     }
4014
4015   if (ferror (stream) || fclose (stream))
4016     {
4017       fprintf (stderr, "error reading from '%s'\n", blocks_filename);
4018       exit (1);
4019     }
4020 }
4021
4022 /* Return the smallest block index among the blocks for characters >= ch.  */
4023 static unsigned int
4024 block_first_index (unsigned int ch)
4025 {
4026   /* Binary search.  */
4027   unsigned int lo = 0;
4028   unsigned int hi = numblocks;
4029   /* Invariants:
4030      All blocks[i], i < lo, have blocks[i].end < ch,
4031      all blocks[i], i >= hi, have blocks[i].end >= ch.  */
4032   while (lo < hi)
4033     {
4034       unsigned int mid = (lo + hi) / 2; /* >= lo, < hi */
4035       if (blocks[mid].end < ch)
4036         lo = mid + 1;
4037       else
4038         hi = mid;
4039     }
4040   return hi;
4041 }
4042
4043 /* Return the largest block index among the blocks for characters <= ch,
4044    plus 1.  */
4045 static unsigned int
4046 block_last_index (unsigned int ch)
4047 {
4048   /* Binary search.  */
4049   unsigned int lo = 0;
4050   unsigned int hi = numblocks;
4051   /* Invariants:
4052      All blocks[i], i < lo, have blocks[i].start <= ch,
4053      all blocks[i], i >= hi, have blocks[i].start > ch.  */
4054   while (lo < hi)
4055     {
4056       unsigned int mid = (lo + hi) / 2; /* >= lo, < hi */
4057       if (blocks[mid].start <= ch)
4058         lo = mid + 1;
4059       else
4060         hi = mid;
4061     }
4062   return hi;
4063 }
4064
4065 static void
4066 output_blocks (const char *version)
4067 {
4068   const char *filename = "unictype/blocks.h";
4069   const unsigned int shift = 8; /* bits to shift away for array access */
4070   const unsigned int threshold = 0x30000; /* cut-off table here to save space */
4071   FILE *stream;
4072   unsigned int i;
4073   unsigned int i1;
4074
4075   stream = fopen (filename, "w");
4076   if (stream == NULL)
4077     {
4078       fprintf (stderr, "cannot open '%s' for writing\n", filename);
4079       exit (1);
4080     }
4081
4082   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
4083   fprintf (stream, "/* Unicode blocks.  */\n");
4084   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
4085            version);
4086
4087   fprintf (stream, "static const uc_block_t blocks[] =\n");
4088   fprintf (stream, "{\n");
4089   for (i = 0; i < numblocks; i++)
4090     {
4091       fprintf (stream, "  { 0x%04X, 0x%04X, \"%s\" }", blocks[i].start,
4092                blocks[i].end, blocks[i].name);
4093       if (i+1 < numblocks)
4094         fprintf (stream, ",");
4095       fprintf (stream, "\n");
4096     }
4097   fprintf (stream, "};\n");
4098   fprintf (stream, "#define blocks_level1_shift %d\n", shift);
4099   fprintf (stream, "#define blocks_level1_threshold 0x%04X\n", threshold);
4100   fprintf (stream, "static const uint8_t blocks_level1[%d * 2] =\n",
4101            threshold >> shift);
4102   fprintf (stream, "{\n");
4103   for (i1 = 0; i1 < (threshold >> shift); i1++)
4104     {
4105       unsigned int first_index = block_first_index (i1 << shift);
4106       unsigned int last_index = block_last_index (((i1 + 1) << shift) - 1);
4107       fprintf (stream, "  %3d, %3d", first_index, last_index);
4108       if (i1+1 < (threshold >> shift))
4109         fprintf (stream, ",");
4110       fprintf (stream, "\n");
4111     }
4112   fprintf (stream, "};\n");
4113   fprintf (stream, "#define blocks_upper_first_index %d\n",
4114            block_first_index (threshold));
4115   fprintf (stream, "#define blocks_upper_last_index %d\n",
4116            block_last_index (0x10FFFF));
4117
4118   if (ferror (stream) || fclose (stream))
4119     {
4120       fprintf (stderr, "error writing to '%s'\n", filename);
4121       exit (1);
4122     }
4123 }
4124
4125 /* ========================================================================= */
4126
4127 /* C and Java syntax.  */
4128
4129 enum
4130 {
4131   UC_IDENTIFIER_START,    /* valid as first or subsequent character */
4132   UC_IDENTIFIER_VALID,    /* valid as subsequent character only */
4133   UC_IDENTIFIER_INVALID,  /* not valid */
4134   UC_IDENTIFIER_IGNORABLE /* ignorable (Java only) */
4135 };
4136
4137 /* ISO C 99 section 6.4.(3).  */
4138 static bool
4139 is_c_whitespace (unsigned int ch)
4140 {
4141   return (ch == ' ' /* space */
4142           || ch == '\t' /* horizontal tab */
4143           || ch == '\n' || ch == '\r' /* new-line */
4144           || ch == '\v' /* vertical tab */
4145           || ch == '\f'); /* form-feed */
4146 }
4147
4148 /* ISO C 99 section 6.4.2.1 and appendix D.  */
4149 static int
4150 c_ident_category (unsigned int ch)
4151 {
4152   /* Section 6.4.2.1.  */
4153   if (ch >= '0' && ch <= '9')
4154     return UC_IDENTIFIER_VALID;
4155   if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || ch == '_')
4156     return UC_IDENTIFIER_START;
4157   /* Appendix D.  */
4158   if (0
4159       /* Latin */
4160       || (ch == 0x00AA)
4161       || (ch == 0x00BA)
4162       || (ch >= 0x00C0 && ch <= 0x00D6)
4163       || (ch >= 0x00D8 && ch <= 0x00F6)
4164       || (ch >= 0x00F8 && ch <= 0x01F5)
4165       || (ch >= 0x01FA && ch <= 0x0217)
4166       || (ch >= 0x0250 && ch <= 0x02A8)
4167       || (ch >= 0x1E00 && ch <= 0x1E9B)
4168       || (ch >= 0x1EA0 && ch <= 0x1EF9)
4169       || (ch == 0x207F)
4170       /* Greek */
4171       || (ch == 0x0386)
4172       || (ch >= 0x0388 && ch <= 0x038A)
4173       || (ch == 0x038C)
4174       || (ch >= 0x038E && ch <= 0x03A1)
4175       || (ch >= 0x03A3 && ch <= 0x03CE)
4176       || (ch >= 0x03D0 && ch <= 0x03D6)
4177       || (ch == 0x03DA)
4178       || (ch == 0x03DC)
4179       || (ch == 0x03DE)
4180       || (ch == 0x03E0)
4181       || (ch >= 0x03E2 && ch <= 0x03F3)
4182       || (ch >= 0x1F00 && ch <= 0x1F15)
4183       || (ch >= 0x1F18 && ch <= 0x1F1D)
4184       || (ch >= 0x1F20 && ch <= 0x1F45)
4185       || (ch >= 0x1F48 && ch <= 0x1F4D)
4186       || (ch >= 0x1F50 && ch <= 0x1F57)
4187       || (ch == 0x1F59)
4188       || (ch == 0x1F5B)
4189       || (ch == 0x1F5D)
4190       || (ch >= 0x1F5F && ch <= 0x1F7D)
4191       || (ch >= 0x1F80 && ch <= 0x1FB4)
4192       || (ch >= 0x1FB6 && ch <= 0x1FBC)
4193       || (ch >= 0x1FC2 && ch <= 0x1FC4)
4194       || (ch >= 0x1FC6 && ch <= 0x1FCC)
4195       || (ch >= 0x1FD0 && ch <= 0x1FD3)
4196       || (ch >= 0x1FD6 && ch <= 0x1FDB)
4197       || (ch >= 0x1FE0 && ch <= 0x1FEC)
4198       || (ch >= 0x1FF2 && ch <= 0x1FF4)
4199       || (ch >= 0x1FF6 && ch <= 0x1FFC)
4200       /* Cyrillic */
4201       || (ch >= 0x0401 && ch <= 0x040C)
4202       || (ch >= 0x040E && ch <= 0x044F)
4203       || (ch >= 0x0451 && ch <= 0x045C)
4204       || (ch >= 0x045E && ch <= 0x0481)
4205       || (ch >= 0x0490 && ch <= 0x04C4)
4206       || (ch >= 0x04C7 && ch <= 0x04C8)
4207       || (ch >= 0x04CB && ch <= 0x04CC)
4208       || (ch >= 0x04D0 && ch <= 0x04EB)
4209       || (ch >= 0x04EE && ch <= 0x04F5)
4210       || (ch >= 0x04F8 && ch <= 0x04F9)
4211       /* Armenian */
4212       || (ch >= 0x0531 && ch <= 0x0556)
4213       || (ch >= 0x0561 && ch <= 0x0587)
4214       /* Hebrew */
4215       || (ch >= 0x05B0 && ch <= 0x05B9)
4216       || (ch >= 0x05BB && ch <= 0x05BD)
4217       || (ch == 0x05BF)
4218       || (ch >= 0x05C1 && ch <= 0x05C2)
4219       || (ch >= 0x05D0 && ch <= 0x05EA)
4220       || (ch >= 0x05F0 && ch <= 0x05F2)
4221       /* Arabic */
4222       || (ch >= 0x0621 && ch <= 0x063A)
4223       || (ch >= 0x0640 && ch <= 0x0652)
4224       || (ch >= 0x0670 && ch <= 0x06B7)
4225       || (ch >= 0x06BA && ch <= 0x06BE)
4226       || (ch >= 0x06C0 && ch <= 0x06CE)
4227       || (ch >= 0x06D0 && ch <= 0x06DC)
4228       || (ch >= 0x06E5 && ch <= 0x06E8)
4229       || (ch >= 0x06EA && ch <= 0x06ED)
4230       /* Devanagari */
4231       || (ch >= 0x0901 && ch <= 0x0903)
4232       || (ch >= 0x0905 && ch <= 0x0939)
4233       || (ch >= 0x093E && ch <= 0x094D)
4234       || (ch >= 0x0950 && ch <= 0x0952)
4235       || (ch >= 0x0958 && ch <= 0x0963)
4236       /* Bengali */
4237       || (ch >= 0x0981 && ch <= 0x0983)
4238       || (ch >= 0x0985 && ch <= 0x098C)
4239       || (ch >= 0x098F && ch <= 0x0990)
4240       || (ch >= 0x0993 && ch <= 0x09A8)
4241       || (ch >= 0x09AA && ch <= 0x09B0)
4242       || (ch == 0x09B2)
4243       || (ch >= 0x09B6 && ch <= 0x09B9)
4244       || (ch >= 0x09BE && ch <= 0x09C4)
4245       || (ch >= 0x09C7 && ch <= 0x09C8)
4246       || (ch >= 0x09CB && ch <= 0x09CD)
4247       || (ch >= 0x09DC && ch <= 0x09DD)
4248       || (ch >= 0x09DF && ch <= 0x09E3)
4249       || (ch >= 0x09F0 && ch <= 0x09F1)
4250       /* Gurmukhi */
4251       || (ch == 0x0A02)
4252       || (ch >= 0x0A05 && ch <= 0x0A0A)
4253       || (ch >= 0x0A0F && ch <= 0x0A10)
4254       || (ch >= 0x0A13 && ch <= 0x0A28)
4255       || (ch >= 0x0A2A && ch <= 0x0A30)
4256       || (ch >= 0x0A32 && ch <= 0x0A33)
4257       || (ch >= 0x0A35 && ch <= 0x0A36)
4258       || (ch >= 0x0A38 && ch <= 0x0A39)
4259       || (ch >= 0x0A3E && ch <= 0x0A42)
4260       || (ch >= 0x0A47 && ch <= 0x0A48)
4261       || (ch >= 0x0A4B && ch <= 0x0A4D)
4262       || (ch >= 0x0A59 && ch <= 0x0A5C)
4263       || (ch == 0x0A5E)
4264       || (ch == 0x0A74)
4265       /* Gujarati */
4266       || (ch >= 0x0A81 && ch <= 0x0A83)
4267       || (ch >= 0x0A85 && ch <= 0x0A8B)
4268       || (ch == 0x0A8D)
4269       || (ch >= 0x0A8F && ch <= 0x0A91)
4270       || (ch >= 0x0A93 && ch <= 0x0AA8)
4271       || (ch >= 0x0AAA && ch <= 0x0AB0)
4272       || (ch >= 0x0AB2 && ch <= 0x0AB3)
4273       || (ch >= 0x0AB5 && ch <= 0x0AB9)
4274       || (ch >= 0x0ABD && ch <= 0x0AC5)
4275       || (ch >= 0x0AC7 && ch <= 0x0AC9)
4276       || (ch >= 0x0ACB && ch <= 0x0ACD)
4277       || (ch == 0x0AD0)
4278       || (ch == 0x0AE0)
4279       /* Oriya */
4280       || (ch >= 0x0B01 && ch <= 0x0B03)
4281       || (ch >= 0x0B05 && ch <= 0x0B0C)
4282       || (ch >= 0x0B0F && ch <= 0x0B10)
4283       || (ch >= 0x0B13 && ch <= 0x0B28)
4284       || (ch >= 0x0B2A && ch <= 0x0B30)
4285       || (ch >= 0x0B32 && ch <= 0x0B33)
4286       || (ch >= 0x0B36 && ch <= 0x0B39)
4287       || (ch >= 0x0B3E && ch <= 0x0B43)
4288       || (ch >= 0x0B47 && ch <= 0x0B48)
4289       || (ch >= 0x0B4B && ch <= 0x0B4D)
4290       || (ch >= 0x0B5C && ch <= 0x0B5D)
4291       || (ch >= 0x0B5F && ch <= 0x0B61)
4292       /* Tamil */
4293       || (ch >= 0x0B82 && ch <= 0x0B83)
4294       || (ch >= 0x0B85 && ch <= 0x0B8A)
4295       || (ch >= 0x0B8E && ch <= 0x0B90)
4296       || (ch >= 0x0B92 && ch <= 0x0B95)
4297       || (ch >= 0x0B99 && ch <= 0x0B9A)
4298       || (ch == 0x0B9C)
4299       || (ch >= 0x0B9E && ch <= 0x0B9F)
4300       || (ch >= 0x0BA3 && ch <= 0x0BA4)
4301       || (ch >= 0x0BA8 && ch <= 0x0BAA)
4302       || (ch >= 0x0BAE && ch <= 0x0BB5)
4303       || (ch >= 0x0BB7 && ch <= 0x0BB9)
4304       || (ch >= 0x0BBE && ch <= 0x0BC2)
4305       || (ch >= 0x0BC6 && ch <= 0x0BC8)
4306       || (ch >= 0x0BCA && ch <= 0x0BCD)
4307       /* Telugu */
4308       || (ch >= 0x0C01 && ch <= 0x0C03)
4309       || (ch >= 0x0C05 && ch <= 0x0C0C)
4310       || (ch >= 0x0C0E && ch <= 0x0C10)
4311       || (ch >= 0x0C12 && ch <= 0x0C28)
4312       || (ch >= 0x0C2A && ch <= 0x0C33)
4313       || (ch >= 0x0C35 && ch <= 0x0C39)
4314       || (ch >= 0x0C3E && ch <= 0x0C44)
4315       || (ch >= 0x0C46 && ch <= 0x0C48)
4316       || (ch >= 0x0C4A && ch <= 0x0C4D)
4317       || (ch >= 0x0C60 && ch <= 0x0C61)
4318       /* Kannada */
4319       || (ch >= 0x0C82 && ch <= 0x0C83)
4320       || (ch >= 0x0C85 && ch <= 0x0C8C)
4321       || (ch >= 0x0C8E && ch <= 0x0C90)
4322       || (ch >= 0x0C92 && ch <= 0x0CA8)
4323       || (ch >= 0x0CAA && ch <= 0x0CB3)
4324       || (ch >= 0x0CB5 && ch <= 0x0CB9)
4325       || (ch >= 0x0CBE && ch <= 0x0CC4)
4326       || (ch >= 0x0CC6 && ch <= 0x0CC8)
4327       || (ch >= 0x0CCA && ch <= 0x0CCD)
4328       || (ch == 0x0CDE)
4329       || (ch >= 0x0CE0 && ch <= 0x0CE1)
4330       /* Malayalam */
4331       || (ch >= 0x0D02 && ch <= 0x0D03)
4332       || (ch >= 0x0D05 && ch <= 0x0D0C)
4333       || (ch >= 0x0D0E && ch <= 0x0D10)
4334       || (ch >= 0x0D12 && ch <= 0x0D28)
4335       || (ch >= 0x0D2A && ch <= 0x0D39)
4336       || (ch >= 0x0D3E && ch <= 0x0D43)
4337       || (ch >= 0x0D46 && ch <= 0x0D48)
4338       || (ch >= 0x0D4A && ch <= 0x0D4D)
4339       || (ch >= 0x0D60 && ch <= 0x0D61)
4340       /* Thai */
4341       || (ch >= 0x0E01 && ch <= 0x0E3A)
4342       || (ch >= 0x0E40 && ch <= 0x0E5B)
4343       /* Lao */
4344       || (ch >= 0x0E81 && ch <= 0x0E82)
4345       || (ch == 0x0E84)
4346       || (ch >= 0x0E87 && ch <= 0x0E88)
4347       || (ch == 0x0E8A)
4348       || (ch == 0x0E8D)
4349       || (ch >= 0x0E94 && ch <= 0x0E97)
4350       || (ch >= 0x0E99 && ch <= 0x0E9F)
4351       || (ch >= 0x0EA1 && ch <= 0x0EA3)
4352       || (ch == 0x0EA5)
4353       || (ch == 0x0EA7)
4354       || (ch >= 0x0EAA && ch <= 0x0EAB)
4355       || (ch >= 0x0EAD && ch <= 0x0EAE)
4356       || (ch >= 0x0EB0 && ch <= 0x0EB9)
4357       || (ch >= 0x0EBB && ch <= 0x0EBD)
4358       || (ch >= 0x0EC0 && ch <= 0x0EC4)
4359       || (ch == 0x0EC6)
4360       || (ch >= 0x0EC8 && ch <= 0x0ECD)
4361       || (ch >= 0x0EDC && ch <= 0x0EDD)
4362       /* Tibetan */
4363       || (ch == 0x0F00)
4364       || (ch >= 0x0F18 && ch <= 0x0F19)
4365       || (ch == 0x0F35)
4366       || (ch == 0x0F37)
4367       || (ch == 0x0F39)
4368       || (ch >= 0x0F3E && ch <= 0x0F47)
4369       || (ch >= 0x0F49 && ch <= 0x0F69)
4370       || (ch >= 0x0F71 && ch <= 0x0F84)
4371       || (ch >= 0x0F86 && ch <= 0x0F8B)
4372       || (ch >= 0x0F90 && ch <= 0x0F95)
4373       || (ch == 0x0F97)
4374       || (ch >= 0x0F99 && ch <= 0x0FAD)
4375       || (ch >= 0x0FB1 && ch <= 0x0FB7)
4376       || (ch == 0x0FB9)
4377       /* Georgian */
4378       || (ch >= 0x10A0 && ch <= 0x10C5)
4379       || (ch >= 0x10D0 && ch <= 0x10F6)
4380       /* Hiragana */
4381       || (ch >= 0x3041 && ch <= 0x3093)
4382       || (ch >= 0x309B && ch <= 0x309C)
4383       /* Katakana */
4384       || (ch >= 0x30A1 && ch <= 0x30F6)
4385       || (ch >= 0x30FB && ch <= 0x30FC)
4386       /* Bopomofo */
4387       || (ch >= 0x3105 && ch <= 0x312C)
4388       /* CJK Unified Ideographs */
4389       || (ch >= 0x4E00 && ch <= 0x9FA5)
4390       /* Hangul */
4391       || (ch >= 0xAC00 && ch <= 0xD7A3)
4392       /* Digits */
4393       || (ch >= 0x0660 && ch <= 0x0669)
4394       || (ch >= 0x06F0 && ch <= 0x06F9)
4395       || (ch >= 0x0966 && ch <= 0x096F)
4396       || (ch >= 0x09E6 && ch <= 0x09EF)
4397       || (ch >= 0x0A66 && ch <= 0x0A6F)
4398       || (ch >= 0x0AE6 && ch <= 0x0AEF)
4399       || (ch >= 0x0B66 && ch <= 0x0B6F)
4400       || (ch >= 0x0BE7 && ch <= 0x0BEF)
4401       || (ch >= 0x0C66 && ch <= 0x0C6F)
4402       || (ch >= 0x0CE6 && ch <= 0x0CEF)
4403       || (ch >= 0x0D66 && ch <= 0x0D6F)
4404       || (ch >= 0x0E50 && ch <= 0x0E59)
4405       || (ch >= 0x0ED0 && ch <= 0x0ED9)
4406       || (ch >= 0x0F20 && ch <= 0x0F33)
4407       /* Special characters */
4408       || (ch == 0x00B5)
4409       || (ch == 0x00B7)
4410       || (ch >= 0x02B0 && ch <= 0x02B8)
4411       || (ch == 0x02BB)
4412       || (ch >= 0x02BD && ch <= 0x02C1)
4413       || (ch >= 0x02D0 && ch <= 0x02D1)
4414       || (ch >= 0x02E0 && ch <= 0x02E4)
4415       || (ch == 0x037A)
4416       || (ch == 0x0559)
4417       || (ch == 0x093D)
4418       || (ch == 0x0B3D)
4419       || (ch == 0x1FBE)
4420       || (ch >= 0x203F && ch <= 0x2040)
4421       || (ch == 0x2102)
4422       || (ch == 0x2107)
4423       || (ch >= 0x210A && ch <= 0x2113)
4424       || (ch == 0x2115)
4425       || (ch >= 0x2118 && ch <= 0x211D)
4426       || (ch == 0x2124)
4427       || (ch == 0x2126)
4428       || (ch == 0x2128)
4429       || (ch >= 0x212A && ch <= 0x2131)
4430       || (ch >= 0x2133 && ch <= 0x2138)
4431       || (ch >= 0x2160 && ch <= 0x2182)
4432       || (ch >= 0x3005 && ch <= 0x3007)
4433       || (ch >= 0x3021 && ch <= 0x3029)
4434      )
4435     return UC_IDENTIFIER_START;
4436   return UC_IDENTIFIER_INVALID;
4437 }
4438
4439 /* The Java Language Specification, 3rd edition, Â§3.6.
4440    http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#95710  */
4441 static bool
4442 is_java_whitespace (unsigned int ch)
4443 {
4444   return (ch == ' ' || ch == '\t' || ch == '\f'
4445           || ch == '\n' || ch == '\r');
4446 }
4447
4448 /* The Java Language Specification, 3rd edition, Â§3.8.
4449    http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#40625
4450    and Character.isJavaIdentifierStart and Character.isJavaIdentifierPart  */
4451 static int
4452 java_ident_category (unsigned int ch)
4453 {
4454   /* FIXME: Check this against Sun's JDK implementation.  */
4455   if (is_category_L (ch) /* = Character.isLetter(ch) */
4456       || is_category_Nl (ch) /* = Character.getType(ch)==LETTER_NUMBER */
4457       || is_category_Sc (ch) /* currency symbol */
4458       || is_category_Pc (ch) /* connector punctuation */
4459      )
4460     return UC_IDENTIFIER_START;
4461   if (is_category_Nd (ch) /* digit */
4462       || is_category_Mc (ch) /* combining mark */
4463       || is_category_Mn (ch) /* non-spacing mark */
4464      )
4465     return UC_IDENTIFIER_VALID;
4466   if ((ch >= 0x0000 && ch <= 0x0008)
4467       || (ch >= 0x000E && ch <= 0x001B)
4468       || (ch >= 0x007F && ch <= 0x009F)
4469       || is_category_Cf (ch) /* = Character.getType(ch)==FORMAT */
4470      )
4471     return UC_IDENTIFIER_IGNORABLE;
4472   return UC_IDENTIFIER_INVALID;
4473 }
4474
4475 /* Construction of sparse 3-level tables.  */
4476 #define TABLE identsyntax_table
4477 #define ELEMENT uint8_t
4478 #define DEFAULT UC_IDENTIFIER_INVALID
4479 #define xmalloc malloc
4480 #define xrealloc realloc
4481 #include "3level.h"
4482
4483 /* Output an identifier syntax categorization in a three-level bitmap.  */
4484 static void
4485 output_ident_category (const char *filename, int (*predicate) (unsigned int), const char *name, const char *version)
4486 {
4487   FILE *stream;
4488   unsigned int ch, i;
4489   struct identsyntax_table t;
4490   unsigned int level1_offset, level2_offset, level3_offset;
4491
4492   stream = fopen (filename, "w");
4493   if (stream == NULL)
4494     {
4495       fprintf (stderr, "cannot open '%s' for writing\n", filename);
4496       exit (1);
4497     }
4498
4499   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
4500   fprintf (stream, "/* Language syntax properties of Unicode characters.  */\n");
4501   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
4502            version);
4503
4504   t.p = 7; /* or 8 */
4505   t.q = 5; /* or 4 */
4506   identsyntax_table_init (&t);
4507
4508   for (ch = 0; ch < 0x110000; ch++)
4509     {
4510       int syntaxcode = predicate (ch);
4511       if (syntaxcode != UC_IDENTIFIER_INVALID)
4512         identsyntax_table_add (&t, ch, syntaxcode);
4513     }
4514
4515   identsyntax_table_finalize (&t);
4516
4517   /* Offsets in t.result, in memory of this process.  */
4518   level1_offset =
4519     5 * sizeof (uint32_t);
4520   level2_offset =
4521     5 * sizeof (uint32_t)
4522     + t.level1_size * sizeof (uint32_t);
4523   level3_offset =
4524     5 * sizeof (uint32_t)
4525     + t.level1_size * sizeof (uint32_t)
4526     + (t.level2_size << t.q) * sizeof (uint32_t);
4527
4528   for (i = 0; i < 5; i++)
4529     fprintf (stream, "#define identsyntax_header_%d %d\n", i,
4530              ((uint32_t *) t.result)[i]);
4531   fprintf (stream, "static const\n");
4532   fprintf (stream, "struct\n");
4533   fprintf (stream, "  {\n");
4534   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
4535   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
4536   fprintf (stream, "    unsigned short level3[%zu * %d];\n", t.level3_size,
4537            (1 << t.p) * 2 / 16);
4538   fprintf (stream, "  }\n");
4539   fprintf (stream, "%s =\n", name);
4540   fprintf (stream, "{\n");
4541   fprintf (stream, "  {");
4542   if (t.level1_size > 8)
4543     fprintf (stream, "\n   ");
4544   for (i = 0; i < t.level1_size; i++)
4545     {
4546       uint32_t offset;
4547       if (i > 0 && (i % 8) == 0)
4548         fprintf (stream, "\n   ");
4549       offset = ((uint32_t *) (t.result + level1_offset))[i];
4550       if (offset == 0)
4551         fprintf (stream, " %5d", -1);
4552       else
4553         fprintf (stream, " %5zu",
4554                  (offset - level2_offset) / sizeof (uint32_t));
4555       if (i+1 < t.level1_size)
4556         fprintf (stream, ",");
4557     }
4558   if (t.level1_size > 8)
4559     fprintf (stream, "\n ");
4560   fprintf (stream, " },\n");
4561   fprintf (stream, "  {");
4562   if (t.level2_size << t.q > 8)
4563     fprintf (stream, "\n   ");
4564   for (i = 0; i < t.level2_size << t.q; i++)
4565     {
4566       uint32_t offset;
4567       if (i > 0 && (i % 8) == 0)
4568         fprintf (stream, "\n   ");
4569       offset = ((uint32_t *) (t.result + level2_offset))[i];
4570       if (offset == 0)
4571         fprintf (stream, " %5d", -1);
4572       else
4573         fprintf (stream, " %5zu",
4574                  (offset - level3_offset) / sizeof (uint8_t));
4575       if (i+1 < t.level2_size << t.q)
4576         fprintf (stream, ",");
4577     }
4578   if (t.level2_size << t.q > 8)
4579     fprintf (stream, "\n ");
4580   fprintf (stream, " },\n");
4581   /* Pack the level3 array.  Each entry needs 2 bits only.  */
4582   fprintf (stream, "  {");
4583   if ((t.level3_size << t.p) * 2 / 16 > 8)
4584     fprintf (stream, "\n   ");
4585   for (i = 0; i < (t.level3_size << t.p) * 2 / 16; i++)
4586     {
4587       if (i > 0 && (i % 8) == 0)
4588         fprintf (stream, "\n   ");
4589       fprintf (stream, " 0x%04x",
4590                (((uint8_t *) (t.result + level3_offset))[8 * i] << 0)
4591                | (((uint8_t *) (t.result + level3_offset))[8 * i + 1] << 2)
4592                | (((uint8_t *) (t.result + level3_offset))[8 * i + 2] << 4)
4593                | (((uint8_t *) (t.result + level3_offset))[8 * i + 3] << 6)
4594                | (((uint8_t *) (t.result + level3_offset))[8 * i + 4] << 8)
4595                | (((uint8_t *) (t.result + level3_offset))[8 * i + 5] << 10)
4596                | (((uint8_t *) (t.result + level3_offset))[8 * i + 6] << 12)
4597                | (((uint8_t *) (t.result + level3_offset))[8 * i + 7] << 14));
4598       if (i+1 < (t.level3_size << t.p) * 2 / 16)
4599         fprintf (stream, ",");
4600     }
4601   if ((t.level3_size << t.p) * 2 / 16 > 8)
4602     fprintf (stream, "\n ");
4603   fprintf (stream, " }\n");
4604   fprintf (stream, "};\n");
4605
4606   if (ferror (stream) || fclose (stream))
4607     {
4608       fprintf (stderr, "error writing to '%s'\n", filename);
4609       exit (1);
4610     }
4611 }
4612
4613 static void
4614 output_ident_properties (const char *version)
4615 {
4616 #define PROPERTY(P) \
4617   debug_output_predicate ("unictype/sy_" #P ".txt", is_ ## P); \
4618   output_predicate_test ("../tests/unictype/test-sy_" #P ".c", is_ ## P, "uc_is_" #P " (c)"); \
4619   output_predicate ("unictype/sy_" #P ".h", is_ ## P, "u_" #P, "Language syntax properties", version);
4620   PROPERTY(c_whitespace)
4621   PROPERTY(java_whitespace)
4622 #undef PROPERTY
4623
4624   output_ident_category ("unictype/sy_c_ident.h", c_ident_category, "u_c_ident", version);
4625   output_ident_category ("unictype/sy_java_ident.h", java_ident_category, "u_java_ident", version);
4626 }
4627
4628 /* ========================================================================= */
4629
4630 /* Like ISO C <ctype.h> and <wctype.h>.  Compatible to glibc's
4631    glibc/localedata/locales/i18n file, generated by
4632    glibc/localedata/gen-unicode-ctype.c.  */
4633
4634 /* Character mappings.  */
4635
4636 static unsigned int
4637 to_upper (unsigned int ch)
4638 {
4639   if (unicode_attributes[ch].name != NULL
4640       && unicode_attributes[ch].upper != NONE)
4641     return unicode_attributes[ch].upper;
4642   else
4643     return ch;
4644 }
4645
4646 static unsigned int
4647 to_lower (unsigned int ch)
4648 {
4649   if (unicode_attributes[ch].name != NULL
4650       && unicode_attributes[ch].lower != NONE)
4651     return unicode_attributes[ch].lower;
4652   else
4653     return ch;
4654 }
4655
4656 static unsigned int
4657 to_title (unsigned int ch)
4658 {
4659   if (unicode_attributes[ch].name != NULL
4660       && unicode_attributes[ch].title != NONE)
4661     return unicode_attributes[ch].title;
4662   else
4663     return ch;
4664 }
4665
4666 /* Character class properties.  */
4667
4668 static bool
4669 is_upper (unsigned int ch)
4670 {
4671   return (to_lower (ch) != ch);
4672 }
4673
4674 static bool
4675 is_lower (unsigned int ch)
4676 {
4677   return (to_upper (ch) != ch)
4678          /* <U00DF> is lowercase, but without simple to_upper mapping.  */
4679          || (ch == 0x00DF);
4680 }
4681
4682 static bool
4683 is_alpha (unsigned int ch)
4684 {
4685   return (unicode_attributes[ch].name != NULL
4686           && ((unicode_attributes[ch].category[0] == 'L'
4687                /* Theppitak Karoonboonyanan <thep@links.nectec.or.th> says
4688                   <U0E2F>, <U0E46> should belong to is_punct.  */
4689                && (ch != 0x0E2F) && (ch != 0x0E46))
4690               /* Theppitak Karoonboonyanan <thep@links.nectec.or.th> says
4691                  <U0E31>, <U0E34>..<U0E3A>, <U0E47>..<U0E4E> are is_alpha.  */
4692               || (ch == 0x0E31)
4693               || (ch >= 0x0E34 && ch <= 0x0E3A)
4694               || (ch >= 0x0E47 && ch <= 0x0E4E)
4695               /* Avoid warning for <U0345>.  */
4696               || (ch == 0x0345)
4697               /* Avoid warnings for <U2160>..<U217F>.  */
4698               || (unicode_attributes[ch].category[0] == 'N'
4699                   && unicode_attributes[ch].category[1] == 'l')
4700               /* Avoid warnings for <U24B6>..<U24E9>.  */
4701               || (unicode_attributes[ch].category[0] == 'S'
4702                   && unicode_attributes[ch].category[1] == 'o'
4703                   && strstr (unicode_attributes[ch].name, " LETTER ")
4704                      != NULL)
4705               /* Consider all the non-ASCII digits as alphabetic.
4706                  ISO C 99 forbids us to have them in category "digit",
4707                  but we want iswalnum to return true on them.  */
4708               || (unicode_attributes[ch].category[0] == 'N'
4709                   && unicode_attributes[ch].category[1] == 'd'
4710                   && !(ch >= 0x0030 && ch <= 0x0039))));
4711 }
4712
4713 static bool
4714 is_digit (unsigned int ch)
4715 {
4716 #if 0
4717   return (unicode_attributes[ch].name != NULL
4718           && unicode_attributes[ch].category[0] == 'N'
4719           && unicode_attributes[ch].category[1] == 'd');
4720   /* Note: U+0BE7..U+0BEF and U+1369..U+1371 are digit systems without
4721      a zero.  Must add <0> in front of them by hand.  */
4722 #else
4723   /* SUSV2 gives us some freedom for the "digit" category, but ISO C 99
4724      takes it away:
4725      7.25.2.1.5:
4726         The iswdigit function tests for any wide character that corresponds
4727         to a decimal-digit character (as defined in 5.2.1).
4728      5.2.1:
4729         the 10 decimal digits 0 1 2 3 4 5 6 7 8 9
4730    */
4731   return (ch >= 0x0030 && ch <= 0x0039);
4732 #endif
4733 }
4734
4735 static bool
4736 is_outdigit (unsigned int ch)
4737 {
4738   return (ch >= 0x0030 && ch <= 0x0039);
4739 }
4740
4741 static bool
4742 is_alnum (unsigned int ch)
4743 {
4744   return is_alpha (ch) || is_digit (ch);
4745 }
4746
4747 static bool
4748 is_blank (unsigned int ch)
4749 {
4750   return (ch == 0x0009 /* '\t' */
4751           /* Category Zs without mention of "<noBreak>" */
4752           || (unicode_attributes[ch].name != NULL
4753               && unicode_attributes[ch].category[0] == 'Z'
4754               && unicode_attributes[ch].category[1] == 's'
4755               && !strstr (unicode_attributes[ch].decomposition, "<noBreak>")));
4756 }
4757
4758 static bool
4759 is_space (unsigned int ch)
4760 {
4761   /* Don't make U+00A0 a space. Non-breaking space means that all programs
4762      should treat it like a punctuation character, not like a space. */
4763   return (ch == 0x0020 /* ' ' */
4764           || ch == 0x000C /* '\f' */
4765           || ch == 0x000A /* '\n' */
4766           || ch == 0x000D /* '\r' */
4767           || ch == 0x0009 /* '\t' */
4768           || ch == 0x000B /* '\v' */
4769           /* Categories Zl, Zp, and Zs without mention of "<noBreak>" */
4770           || (unicode_attributes[ch].name != NULL
4771               && unicode_attributes[ch].category[0] == 'Z'
4772               && (unicode_attributes[ch].category[1] == 'l'
4773                   || unicode_attributes[ch].category[1] == 'p'
4774                   || (unicode_attributes[ch].category[1] == 's'
4775                       && !strstr (unicode_attributes[ch].decomposition,
4776                                   "<noBreak>")))));
4777 }
4778
4779 static bool
4780 is_cntrl (unsigned int ch)
4781 {
4782   return (unicode_attributes[ch].name != NULL
4783           && (strcmp (unicode_attributes[ch].name, "<control>") == 0
4784               /* Categories Zl and Zp */
4785               || (unicode_attributes[ch].category[0] == 'Z'
4786                   && (unicode_attributes[ch].category[1] == 'l'
4787                       || unicode_attributes[ch].category[1] == 'p'))));
4788 }
4789
4790 static bool
4791 is_xdigit (unsigned int ch)
4792 {
4793 #if 0
4794   return is_digit (ch)
4795          || (ch >= 0x0041 && ch <= 0x0046)
4796          || (ch >= 0x0061 && ch <= 0x0066);
4797 #else
4798   /* SUSV2 gives us some freedom for the "xdigit" category, but ISO C 99
4799      takes it away:
4800      7.25.2.1.12:
4801         The iswxdigit function tests for any wide character that corresponds
4802         to a hexadecimal-digit character (as defined in 6.4.4.1).
4803      6.4.4.1:
4804         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
4805    */
4806   return (ch >= 0x0030 && ch <= 0x0039)
4807          || (ch >= 0x0041 && ch <= 0x0046)
4808          || (ch >= 0x0061 && ch <= 0x0066);
4809 #endif
4810 }
4811
4812 static bool
4813 is_graph (unsigned int ch)
4814 {
4815   return (unicode_attributes[ch].name != NULL
4816           && strcmp (unicode_attributes[ch].name, "<control>")
4817           && !is_space (ch));
4818 }
4819
4820 static bool
4821 is_print (unsigned int ch)
4822 {
4823   return (unicode_attributes[ch].name != NULL
4824           && strcmp (unicode_attributes[ch].name, "<control>")
4825           /* Categories Zl and Zp */
4826           && !(unicode_attributes[ch].name != NULL
4827                && unicode_attributes[ch].category[0] == 'Z'
4828                && (unicode_attributes[ch].category[1] == 'l'
4829                    || unicode_attributes[ch].category[1] == 'p')));
4830 }
4831
4832 static bool
4833 is_punct (unsigned int ch)
4834 {
4835 #if 0
4836   return (unicode_attributes[ch].name != NULL
4837           && unicode_attributes[ch].category[0] == 'P');
4838 #else
4839   /* The traditional POSIX definition of punctuation is every graphic,
4840      non-alphanumeric character.  */
4841   return (is_graph (ch) && !is_alpha (ch) && !is_digit (ch));
4842 #endif
4843 }
4844
4845 /* Output all properties.  */
4846 static void
4847 output_old_ctype (const char *version)
4848 {
4849 #define PROPERTY(P) \
4850   debug_output_predicate ("unictype/ctype_" #P ".txt", is_ ## P); \
4851   output_predicate_test ("../tests/unictype/test-ctype_" #P ".c", is_ ## P, "uc_is_" #P " (c)"); \
4852   output_predicate ("unictype/ctype_" #P ".h", is_ ## P, "u_is_" #P, "ISO C <ctype.h> like properties", version);
4853   PROPERTY(alnum)
4854   PROPERTY(alpha)
4855   PROPERTY(cntrl)
4856   PROPERTY(digit)
4857   PROPERTY(graph)
4858   PROPERTY(lower)
4859   PROPERTY(print)
4860   PROPERTY(punct)
4861   PROPERTY(space)
4862   PROPERTY(upper)
4863   PROPERTY(xdigit)
4864   PROPERTY(blank)
4865 #undef PROPERTY
4866 }
4867
4868 #if 0
4869
4870 static bool
4871 is_combining (unsigned int ch)
4872 {
4873   /* Up to Unicode 3.0.1 we took the Combining property from the PropList.txt
4874      file. In 3.0.1 it was identical to the union of the general categories
4875      "Mn", "Mc", "Me". In Unicode 3.1 this property has been dropped from the
4876      PropList.txt file, so we take the latter definition.  */
4877   return (unicode_attributes[ch].name != NULL
4878           && unicode_attributes[ch].category[0] == 'M'
4879           && (unicode_attributes[ch].category[1] == 'n'
4880               || unicode_attributes[ch].category[1] == 'c'
4881               || unicode_attributes[ch].category[1] == 'e'));
4882 }
4883
4884 static bool
4885 is_combining_level3 (unsigned int ch)
4886 {
4887   return is_combining (ch)
4888          && !(unicode_attributes[ch].combining[0] != '\0'
4889               && unicode_attributes[ch].combining[0] != '0'
4890               && strtoul (unicode_attributes[ch].combining, NULL, 10) >= 200);
4891 }
4892
4893 /* Return the UCS symbol string for a Unicode character.  */
4894 static const char *
4895 ucs_symbol (unsigned int i)
4896 {
4897   static char buf[11+1];
4898
4899   sprintf (buf, (i < 0x10000 ? "<U%04X>" : "<U%08X>"), i);
4900   return buf;
4901 }
4902
4903 /* Return the UCS symbol range string for a Unicode characters interval.  */
4904 static const char *
4905 ucs_symbol_range (unsigned int low, unsigned int high)
4906 {
4907   static char buf[24+1];
4908
4909   strcpy (buf, ucs_symbol (low));
4910   strcat (buf, "..");
4911   strcat (buf, ucs_symbol (high));
4912   return buf;
4913 }
4914
4915 /* Output a character class (= property) table.  */
4916
4917 static void
4918 output_charclass (FILE *stream, const char *classname,
4919                   bool (*func) (unsigned int))
4920 {
4921   char table[0x110000];
4922   unsigned int i;
4923   bool need_semicolon;
4924   const int max_column = 75;
4925   int column;
4926
4927   for (i = 0; i < 0x110000; i++)
4928     table[i] = (int) func (i);
4929
4930   fprintf (stream, "%s ", classname);
4931   need_semicolon = false;
4932   column = 1000;
4933   for (i = 0; i < 0x110000; )
4934     {
4935       if (!table[i])
4936         i++;
4937       else
4938         {
4939           unsigned int low, high;
4940           char buf[25];
4941
4942           low = i;
4943           do
4944             i++;
4945           while (i < 0x110000 && table[i]);
4946           high = i - 1;
4947
4948           if (low == high)
4949             strcpy (buf, ucs_symbol (low));
4950           else
4951             strcpy (buf, ucs_symbol_range (low, high));
4952
4953           if (need_semicolon)
4954             {
4955               fprintf (stream, ";");
4956               column++;
4957             }
4958
4959           if (column + strlen (buf) > max_column)
4960             {
4961               fprintf (stream, "/\n   ");
4962               column = 3;
4963             }
4964
4965           fprintf (stream, "%s", buf);
4966           column += strlen (buf);
4967           need_semicolon = true;
4968         }
4969     }
4970   fprintf (stream, "\n");
4971 }
4972
4973 /* Output a character mapping table.  */
4974
4975 static void
4976 output_charmap (FILE *stream, const char *mapname,
4977                 unsigned int (*func) (unsigned int))
4978 {
4979   char table[0x110000];
4980   unsigned int i;
4981   bool need_semicolon;
4982   const int max_column = 75;
4983   int column;
4984
4985   for (i = 0; i < 0x110000; i++)
4986     table[i] = (func (i) != i);
4987
4988   fprintf (stream, "%s ", mapname);
4989   need_semicolon = false;
4990   column = 1000;
4991   for (i = 0; i < 0x110000; i++)
4992     if (table[i])
4993       {
4994         char buf[25+1];
4995
4996         strcpy (buf, "(");
4997         strcat (buf, ucs_symbol (i));
4998         strcat (buf, ",");
4999         strcat (buf, ucs_symbol (func (i)));
5000         strcat (buf, ")");
5001
5002         if (need_semicolon)
5003           {
5004             fprintf (stream, ";");
5005             column++;
5006           }
5007
5008         if (column + strlen (buf) > max_column)
5009           {
5010             fprintf (stream, "/\n   ");
5011             column = 3;
5012           }
5013
5014         fprintf (stream, "%s", buf);
5015         column += strlen (buf);
5016         need_semicolon = true;
5017       }
5018   fprintf (stream, "\n");
5019 }
5020
5021 /* Output the width table.  */
5022
5023 static void
5024 output_widthmap (FILE *stream)
5025 {
5026 }
5027
5028 /* Output the tables to the given file.  */
5029
5030 static void
5031 output_tables (const char *filename, const char *version)
5032 {
5033   FILE *stream;
5034   unsigned int ch;
5035
5036   stream = fopen (filename, "w");
5037   if (stream == NULL)
5038     {
5039       fprintf (stderr, "cannot open '%s' for writing\n", filename);
5040       exit (1);
5041     }
5042
5043   fprintf (stream, "escape_char /\n");
5044   fprintf (stream, "comment_char %%\n");
5045   fprintf (stream, "\n");
5046   fprintf (stream, "%% Generated automatically by gen-unicode-ctype for Unicode %s.\n",
5047            version);
5048   fprintf (stream, "\n");
5049
5050   fprintf (stream, "LC_IDENTIFICATION\n");
5051   fprintf (stream, "title     \"Unicode %s FDCC-set\"\n", version);
5052   fprintf (stream, "source    \"UnicodeData.txt, PropList.txt\"\n");
5053   fprintf (stream, "address   \"\"\n");
5054   fprintf (stream, "contact   \"\"\n");
5055   fprintf (stream, "email     \"bug-glibc@gnu.org\"\n");
5056   fprintf (stream, "tel       \"\"\n");
5057   fprintf (stream, "fax       \"\"\n");
5058   fprintf (stream, "language  \"\"\n");
5059   fprintf (stream, "territory \"Earth\"\n");
5060   fprintf (stream, "revision  \"%s\"\n", version);
5061   {
5062     time_t now;
5063     char date[11];
5064     now = time (NULL);
5065     strftime (date, sizeof (date), "%Y-%m-%d", gmtime (&now));
5066     fprintf (stream, "date      \"%s\"\n", date);
5067   }
5068   fprintf (stream, "category  \"unicode:2001\";LC_CTYPE\n");
5069   fprintf (stream, "END LC_IDENTIFICATION\n");
5070   fprintf (stream, "\n");
5071
5072   /* Verifications. */
5073   for (ch = 0; ch < 0x110000; ch++)
5074     {
5075       /* toupper restriction: "Only characters specified for the keywords
5076          lower and upper shall be specified.  */
5077       if (to_upper (ch) != ch && !(is_lower (ch) || is_upper (ch)))
5078         fprintf (stderr,
5079                  "%s is not upper|lower but toupper(0x%04X) = 0x%04X\n",
5080                  ucs_symbol (ch), ch, to_upper (ch));
5081
5082       /* tolower restriction: "Only characters specified for the keywords
5083          lower and upper shall be specified.  */
5084       if (to_lower (ch) != ch && !(is_lower (ch) || is_upper (ch)))
5085         fprintf (stderr,
5086                  "%s is not upper|lower but tolower(0x%04X) = 0x%04X\n",
5087                  ucs_symbol (ch), ch, to_lower (ch));
5088
5089       /* alpha restriction: "Characters classified as either upper or lower
5090          shall automatically belong to this class.  */
5091       if ((is_lower (ch) || is_upper (ch)) && !is_alpha (ch))
5092         fprintf (stderr, "%s is upper|lower but not alpha\n", ucs_symbol (ch));
5093
5094       /* alpha restriction: "No character specified for the keywords cntrl,
5095          digit, punct or space shall be specified."  */
5096       if (is_alpha (ch) && is_cntrl (ch))
5097         fprintf (stderr, "%s is alpha and cntrl\n", ucs_symbol (ch));
5098       if (is_alpha (ch) && is_digit (ch))
5099         fprintf (stderr, "%s is alpha and digit\n", ucs_symbol (ch));
5100       if (is_alpha (ch) && is_punct (ch))
5101         fprintf (stderr, "%s is alpha and punct\n", ucs_symbol (ch));
5102       if (is_alpha (ch) && is_space (ch))
5103         fprintf (stderr, "%s is alpha and space\n", ucs_symbol (ch));
5104
5105       /* space restriction: "No character specified for the keywords upper,
5106          lower, alpha, digit, graph or xdigit shall be specified."
5107          upper, lower, alpha already checked above.  */
5108       if (is_space (ch) && is_digit (ch))
5109         fprintf (stderr, "%s is space and digit\n", ucs_symbol (ch));
5110       if (is_space (ch) && is_graph (ch))
5111         fprintf (stderr, "%s is space and graph\n", ucs_symbol (ch));
5112       if (is_space (ch) && is_xdigit (ch))
5113         fprintf (stderr, "%s is space and xdigit\n", ucs_symbol (ch));
5114
5115       /* cntrl restriction: "No character specified for the keywords upper,
5116          lower, alpha, digit, punct, graph, print or xdigit shall be
5117          specified."  upper, lower, alpha already checked above.  */
5118       if (is_cntrl (ch) && is_digit (ch))
5119         fprintf (stderr, "%s is cntrl and digit\n", ucs_symbol (ch));
5120       if (is_cntrl (ch) && is_punct (ch))
5121         fprintf (stderr, "%s is cntrl and punct\n", ucs_symbol (ch));
5122       if (is_cntrl (ch) && is_graph (ch))
5123         fprintf (stderr, "%s is cntrl and graph\n", ucs_symbol (ch));
5124       if (is_cntrl (ch) && is_print (ch))
5125         fprintf (stderr, "%s is cntrl and print\n", ucs_symbol (ch));
5126       if (is_cntrl (ch) && is_xdigit (ch))
5127         fprintf (stderr, "%s is cntrl and xdigit\n", ucs_symbol (ch));
5128
5129       /* punct restriction: "No character specified for the keywords upper,
5130          lower, alpha, digit, cntrl, xdigit or as the <space> character shall
5131          be specified."  upper, lower, alpha, cntrl already checked above.  */
5132       if (is_punct (ch) && is_digit (ch))
5133         fprintf (stderr, "%s is punct and digit\n", ucs_symbol (ch));
5134       if (is_punct (ch) && is_xdigit (ch))
5135         fprintf (stderr, "%s is punct and xdigit\n", ucs_symbol (ch));
5136       if (is_punct (ch) && (ch == 0x0020))
5137         fprintf (stderr, "%s is punct\n", ucs_symbol (ch));
5138
5139       /* graph restriction: "No character specified for the keyword cntrl
5140          shall be specified."  Already checked above.  */
5141
5142       /* print restriction: "No character specified for the keyword cntrl
5143          shall be specified."  Already checked above.  */
5144
5145       /* graph - print relation: differ only in the <space> character.
5146          How is this possible if there are more than one space character?!
5147          I think susv2/xbd/locale.html should speak of "space characters",
5148          not "space character".  */
5149       if (is_print (ch) && !(is_graph (ch) || /* ch == 0x0020 */ is_space (ch)))
5150         fprintf (stderr,
5151                  "%s is print but not graph|<space>\n", ucs_symbol (ch));
5152       if (!is_print (ch) && (is_graph (ch) || ch == 0x0020))
5153         fprintf (stderr,
5154                  "%s is graph|<space> but not print\n", ucs_symbol (ch));
5155     }
5156
5157   fprintf (stream, "LC_CTYPE\n");
5158   output_charclass (stream, "upper", is_upper);
5159   output_charclass (stream, "lower", is_lower);
5160   output_charclass (stream, "alpha", is_alpha);
5161   output_charclass (stream, "digit", is_digit);
5162   output_charclass (stream, "outdigit", is_outdigit);
5163   output_charclass (stream, "blank", is_blank);
5164   output_charclass (stream, "space", is_space);
5165   output_charclass (stream, "cntrl", is_cntrl);
5166   output_charclass (stream, "punct", is_punct);
5167   output_charclass (stream, "xdigit", is_xdigit);
5168   output_charclass (stream, "graph", is_graph);
5169   output_charclass (stream, "print", is_print);
5170   output_charclass (stream, "class \"combining\";", is_combining);
5171   output_charclass (stream, "class \"combining_level3\";", is_combining_level3);
5172   output_charmap (stream, "toupper", to_upper);
5173   output_charmap (stream, "tolower", to_lower);
5174   output_charmap (stream, "map \"totitle\";", to_title);
5175   output_widthmap (stream);
5176   fprintf (stream, "END LC_CTYPE\n");
5177
5178   if (ferror (stream) || fclose (stream))
5179     {
5180       fprintf (stderr, "error writing to '%s'\n", filename);
5181       exit (1);
5182     }
5183 }
5184
5185 #endif
5186
5187 /* ========================================================================= */
5188
5189 /* The width property from the EastAsianWidth.txt file.
5190    Each is NULL (unassigned) or "N", "A", "H", "W", "F", "Na".  */
5191 const char * unicode_width[0x110000];
5192
5193 /* Stores in unicode_width[] the width property from the EastAsianWidth.txt
5194    file.  */
5195 static void
5196 fill_width (const char *width_filename)
5197 {
5198   unsigned int i, j;
5199   FILE *stream;
5200   char field0[FIELDLEN];
5201   char field1[FIELDLEN];
5202   char field2[FIELDLEN];
5203   int lineno = 0;
5204
5205   for (i = 0; i < 0x110000; i++)
5206     unicode_width[i] = (unicode_attributes[i].name != NULL ? "N" : NULL);
5207
5208   stream = fopen (width_filename, "r");
5209   if (stream == NULL)
5210     {
5211       fprintf (stderr, "error during fopen of '%s'\n", width_filename);
5212       exit (1);
5213     }
5214
5215   for (;;)
5216     {
5217       int n;
5218       int c;
5219
5220       lineno++;
5221       c = getc (stream);
5222       if (c == EOF)
5223         break;
5224       if (c == '#')
5225         {
5226           do c = getc (stream); while (c != EOF && c != '\n');
5227           continue;
5228         }
5229       ungetc (c, stream);
5230       n = getfield (stream, field0, ';');
5231       n += getfield (stream, field1, ' ');
5232       n += getfield (stream, field2, '\n');
5233       if (n == 0)
5234         break;
5235       if (n != 3)
5236         {
5237           fprintf (stderr, "short line in '%s':%d\n", width_filename, lineno);
5238           exit (1);
5239         }
5240       i = strtoul (field0, NULL, 16);
5241       if (strstr (field0, "..") != NULL)
5242         {
5243           /* Deal with a range.  */
5244           j = strtoul (strstr (field0, "..") + 2, NULL, 16);
5245           for (; i <= j; i++)
5246             unicode_width[i] = strdup (field1);
5247         }
5248       else
5249         {
5250           /* Single character line.  */
5251           unicode_width[i] = strdup (field1);
5252         }
5253     }
5254   if (ferror (stream) || fclose (stream))
5255     {
5256       fprintf (stderr, "error reading from '%s'\n", width_filename);
5257       exit (1);
5258     }
5259 }
5260
5261 /* ========================================================================= */
5262
5263 /* Non-spacing attribute and width.  */
5264
5265 /* The non-spacing attribute table consists of:
5266    - Non-spacing characters; generated from PropList.txt or
5267      "grep '^[^;]*;[^;]*;[^;]*;[^;]*;NSM;' UnicodeData.txt"
5268    - Format control characters; generated from
5269      "grep '^[^;]*;[^;]*;Cf;' UnicodeData.txt"
5270    - Zero width characters; generated from
5271      "grep '^[^;]*;ZERO WIDTH ' UnicodeData.txt"
5272  */
5273
5274 static bool
5275 is_nonspacing (unsigned int ch)
5276 {
5277   return (unicode_attributes[ch].name != NULL
5278           && (get_bidi_category (ch) == UC_BIDI_NSM
5279               || is_category_Cc (ch) || is_category_Cf (ch)
5280               || strncmp (unicode_attributes[ch].name, "ZERO WIDTH ", 11) == 0));
5281 }
5282
5283 static void
5284 output_nonspacing_property (const char *filename)
5285 {
5286   FILE *stream;
5287   int ind[0x110000 / 0x200];
5288   unsigned int i;
5289   unsigned int i_max;
5290   int next_ind;
5291
5292   stream = fopen (filename, "w");
5293   if (stream == NULL)
5294     {
5295       fprintf (stderr, "cannot open '%s' for writing\n", filename);
5296       exit (1);
5297     }
5298
5299   next_ind = 0;
5300   for (i = 0; i < 0x110000 / 0x200; i++)
5301     {
5302       bool nontrivial = false;
5303       unsigned int ch;
5304
5305       if (i != 0xe0000 / 0x200) /* The 0xe0000 block is handled by code.  */
5306         for (ch = i * 0x200; ch < (i + 1) * 0x200; ch++)
5307           if (is_nonspacing (ch))
5308             {
5309               nontrivial = true;
5310               break;
5311             }
5312       if (nontrivial)
5313         ind[i] = next_ind++;
5314       else
5315         ind[i] = -1;
5316     }
5317
5318   fprintf (stream, "static const unsigned char nonspacing_table_data[%d*64] = {\n",
5319            next_ind);
5320   i_max = 0;
5321   for (i = 0; i < 0x110000 / 0x200; i++)
5322     {
5323       bool nontrivial = (ind[i] >= 0);
5324
5325       if (nontrivial)
5326         {
5327           unsigned int j;
5328
5329           fprintf (stream, "  /* 0x%04x-0x%04x */\n", i * 0x200, (i + 1) * 0x200 - 1);
5330           for (j = 0; j < 8; j++)
5331             {
5332               unsigned int k;
5333
5334               fprintf (stream, " ");
5335               for (k = 0; k < 8; k++)
5336                 {
5337                   unsigned int l;
5338                   unsigned char bits = 0;
5339
5340                   for (l = 0; l < 8; l++)
5341                     {
5342                       unsigned int ch = i * 0x200 + j * 0x40 + k * 8 + l;
5343
5344                       if (is_nonspacing (ch))
5345                         bits |= 1 << l;
5346                     }
5347                   fprintf (stream, " 0x%02x%c", bits,
5348                            ind[i] + 1 == next_ind && j == 8 - 1 && k == 8 - 1 ? ' ' : ',');
5349                 }
5350               fprintf (stream, " /* 0x%04x-0x%04x */\n",
5351                        i * 0x200 + j * 0x40, i * 0x200 + (j + 1) * 0x40 - 1);
5352             }
5353           i_max = i;
5354         }
5355     }
5356   fprintf (stream, "};\n");
5357
5358   i_max = ((i_max + 8 - 1) / 8) * 8;
5359   fprintf (stream, "static const signed char nonspacing_table_ind[%u] = {\n",
5360            i_max);
5361   {
5362     unsigned int j;
5363
5364     for (j = 0; j < i_max / 8; j++)
5365       {
5366         unsigned int k;
5367
5368         fprintf (stream, " ");
5369         for (k = 0; k < 8; k++)
5370           {
5371             i = j * 8 + k;
5372             fprintf (stream, " %2d%c", ind[i],
5373                      j == i_max / 8 - 1 && k == 8 - 1 ? ' ' : ',');
5374           }
5375         fprintf (stream, " /* 0x%04x-0x%04x */\n",
5376                  j * 8 * 0x200, (j + 1) * 8 * 0x200 - 1);
5377       }
5378   }
5379   fprintf (stream, "};\n");
5380
5381   if (ferror (stream) || fclose (stream))
5382     {
5383       fprintf (stderr, "error writing to '%s'\n", filename);
5384       exit (1);
5385     }
5386 }
5387
5388 /* Returns the width of ch as one of 0, '0', '1', '2', 'A'.  */
5389 static char
5390 symbolic_width (unsigned int ch)
5391 {
5392   /* Test for unassigned character.  */
5393   if (is_property_unassigned_code_value (ch))
5394     {
5395       /* Unicode TR#11 section "Unassigned and Private-Use Characters".  */
5396       if (ch >= 0xE000 && ch <= 0xF8FF) /* Private Use */
5397         return 'A';
5398       if ((ch >= 0x4E00 && ch <= 0x9FFF) /* CJK Unified Ideographs block */
5399           || (ch >= 0x3400 && ch <= 0x4DBF) /* CJK Unified Ideographs Extension A block */
5400           || (ch >= 0xF900 && ch <= 0xFAFF) /* CJK Compatibility Ideographs block */
5401           || (ch >= 0x20000 && ch <= 0x2FFFD) /* Supplementary Ideographic Plane */
5402           || (ch >= 0x30000 && ch <= 0x3FFFD) /* Tertiary Ideographic Plane */)
5403         return '2';
5404       return 0;
5405     }
5406   else
5407     {
5408       /* Test for non-spacing or control character.  */
5409       if (is_category_Cc (ch) && ch < 0x00A0)
5410         return 0;
5411       if (is_nonspacing (ch))
5412         return '0';
5413       /* Test for double-width character.  */
5414       if (unicode_width[ch] != NULL
5415           && (strcmp (unicode_width[ch], "W") == 0
5416               || strcmp (unicode_width[ch], "F") == 0))
5417         return '2';
5418       /* Test for half-width character.  */
5419       if (unicode_width[ch] != NULL
5420           && strcmp (unicode_width[ch], "H") == 0)
5421         return '1';
5422     }
5423   /* In ancient CJK encodings, Cyrillic and most other characters are
5424      double-width as well.  */
5425   if (ch >= 0x00A1 && ch < 0x10000)
5426     return 'A';
5427   return '1';
5428 }
5429
5430 static void
5431 output_width_property_test (const char *filename)
5432 {
5433   FILE *stream;
5434   unsigned int interval_start, interval_end, ch;
5435   char interval_value;
5436
5437   stream = fopen (filename, "w");
5438   if (stream == NULL)
5439     {
5440       fprintf (stderr, "cannot open '%s' for writing\n", filename);
5441       exit (1);
5442     }
5443
5444   interval_value = 0;
5445   interval_start = interval_end = 0; /* avoid GCC warning */
5446   for (ch = 0; ch < 0x110000; ch++)
5447     {
5448       char value = symbolic_width (ch);
5449       if (value != 0) /* skip Cc control characters and unassigned characters */
5450         {
5451           if (value == interval_value)
5452             /* Extend the interval.  */
5453             interval_end = ch;
5454           else
5455             {
5456               /* Terminate the interval.  */
5457               if (interval_value != 0)
5458                 {
5459                   if (interval_end == interval_start)
5460                     fprintf (stream, "%04X\t\t%c\n", interval_start, interval_value);
5461                   else
5462                     fprintf (stream, "%04X..%04X\t%c\n", interval_start, interval_end, interval_value);
5463                 }
5464               /* Start a new interval.  */
5465               interval_start = interval_end = ch;
5466               interval_value = value;
5467             }
5468         }
5469     }
5470   /* Terminate the last interval.  */
5471   if (interval_value != 0)
5472     {
5473       if (interval_end == interval_start)
5474         fprintf (stream, "%04X\t\t%c\n", interval_start, interval_value);
5475       else
5476         fprintf (stream, "%04X..%04X\t%c\n", interval_start, interval_end, interval_value);
5477     }
5478
5479   if (ferror (stream) || fclose (stream))
5480     {
5481       fprintf (stderr, "error writing to '%s'\n", filename);
5482       exit (1);
5483     }
5484 }
5485
5486 /* ========================================================================= */
5487
5488 /* Line breaking classification.
5489    Updated for Unicode TR #14 revision 24.  */
5490
5491 enum
5492 {
5493   /* Values >= 25 are resolved at run time. */
5494   LBP_BK = 25, /* mandatory break */
5495 /*LBP_CR,         carriage return - not used here because it's a DOSism */
5496 /*LBP_LF,         line feed - not used here because it's a DOSism */
5497   LBP_CM = 26, /* attached characters and combining marks */
5498 /*LBP_NL,         next line - not used here because it's equivalent to LBP_BK */
5499 /*LBP_SG,         surrogates - not used here because they are not characters */
5500   LBP_WJ =  0, /* word joiner */
5501   LBP_ZW = 27, /* zero width space */
5502   LBP_GL =  1, /* non-breaking (glue) */
5503   LBP_SP = 28, /* space */
5504   LBP_B2 =  2, /* break opportunity before and after */
5505   LBP_BA =  3, /* break opportunity after */
5506   LBP_BB =  4, /* break opportunity before */
5507   LBP_HY =  5, /* hyphen */
5508   LBP_CB = 29, /* contingent break opportunity */
5509   LBP_CL =  6, /* closing punctuation */
5510   LBP_CP =  7, /* closing parenthesis */
5511   LBP_EX =  8, /* exclamation/interrogation */
5512   LBP_IN =  9, /* inseparable */
5513   LBP_NS = 10, /* non starter */
5514   LBP_OP = 11, /* opening punctuation */
5515   LBP_QU = 12, /* ambiguous quotation */
5516   LBP_IS = 13, /* infix separator (numeric) */
5517   LBP_NU = 14, /* numeric */
5518   LBP_PO = 15, /* postfix (numeric) */
5519   LBP_PR = 16, /* prefix (numeric) */
5520   LBP_SY = 17, /* symbols allowing breaks */
5521   LBP_AI = 30, /* ambiguous (alphabetic or ideograph) */
5522   LBP_AL = 18, /* ordinary alphabetic and symbol characters */
5523   LBP_H2 = 19, /* Hangul LV syllable */
5524   LBP_H3 = 20, /* Hangul LVT syllable */
5525   LBP_ID = 21, /* ideographic */
5526   LBP_JL = 22, /* Hangul L Jamo */
5527   LBP_JV = 23, /* Hangul V Jamo */
5528   LBP_JT = 24, /* Hangul T Jamo */
5529   LBP_SA = 31, /* complex context (South East Asian) */
5530   LBP_XX = 32  /* unknown */
5531 };
5532
5533 /* Returns the line breaking classification for ch, as a bit mask.  */
5534 static int64_t
5535 get_lbp (unsigned int ch)
5536 {
5537   int64_t attr = 0;
5538
5539   if (unicode_attributes[ch].name != NULL)
5540     {
5541       /* mandatory break */
5542       if (ch == 0x000A || ch == 0x000D || ch == 0x0085 /* newline */
5543           || ch == 0x000C /* form feed */
5544           || ch == 0x000B /* line tabulation */
5545           || ch == 0x2028 /* LINE SEPARATOR */
5546           || ch == 0x2029 /* PARAGRAPH SEPARATOR */)
5547         attr |= (int64_t) 1 << LBP_BK;
5548
5549       if (ch == 0x2060 /* WORD JOINER */
5550           || ch == 0xFEFF /* ZERO WIDTH NO-BREAK SPACE */)
5551         attr |= (int64_t) 1 << LBP_WJ;
5552
5553       /* zero width space */
5554       if (ch == 0x200B /* ZERO WIDTH SPACE */)
5555         attr |= (int64_t) 1 << LBP_ZW;
5556
5557       /* non-breaking (glue) */
5558       if (ch == 0x00A0 /* NO-BREAK SPACE */
5559           || ch == 0x202F /* NARROW NO-BREAK SPACE */
5560           || ch == 0x180E /* MONGOLIAN VOWEL SEPARATOR */
5561           || ch == 0x034F /* COMBINING GRAPHEME JOINER */
5562           || ch == 0x2007 /* FIGURE SPACE */
5563           || ch == 0x2011 /* NON-BREAKING HYPHEN */
5564           || ch == 0x0F08 /* TIBETAN MARK SBRUL SHAD */
5565           || ch == 0x0F0C /* TIBETAN MARK DELIMITER TSHEG BSTAR */
5566           || ch == 0x0F12 /* TIBETAN MARK RGYA GRAM SHAD */
5567           || (ch >= 0x035C && ch <= 0x0362) /* COMBINING DOUBLE ... */)
5568         attr |= (int64_t) 1 << LBP_GL;
5569
5570       /* space */
5571       if (ch == 0x0020 /* SPACE */)
5572         attr |= (int64_t) 1 << LBP_SP;
5573
5574       /* break opportunity before and after */
5575       if (ch == 0x2014 /* EM DASH */)
5576         attr |= (int64_t) 1 << LBP_B2;
5577
5578       /* break opportunity after */
5579       if (/* Breaking Spaces */
5580           ch == 0x1680 /* OGHAM SPACE MARK */
5581           || ch == 0x2000 /* EN QUAD */
5582           || ch == 0x2001 /* EM QUAD */
5583           || ch == 0x2002 /* EN SPACE */
5584           || ch == 0x2003 /* EM SPACE */
5585           || ch == 0x2004 /* THREE-PER-EM SPACE */
5586           || ch == 0x2005 /* FOUR-PER-EM SPACE */
5587           || ch == 0x2006 /* SIX-PER-EM SPACE */
5588           || ch == 0x2008 /* PUNCTUATION SPACE */
5589           || ch == 0x2009 /* THIN SPACE */
5590           || ch == 0x200A /* HAIR SPACE */
5591           || ch == 0x205F /* MEDIUM MATHEMATICAL SPACE */
5592           /* Tabs */
5593           || ch == 0x0009 /* tab */
5594           /* Conditional Hyphens */
5595           || ch == 0x00AD /* SOFT HYPHEN */
5596           /* Breaking Hyphens */
5597           || ch == 0x058A /* ARMENIAN HYPHEN */
5598           || ch == 0x1400 /* CANADIAN SYLLABICS HYPHEN */
5599           || ch == 0x2010 /* HYPHEN */
5600           || ch == 0x2012 /* FIGURE DASH */
5601           || ch == 0x2013 /* EN DASH */
5602           /* Visible Word Dividers */
5603           || ch == 0x05BE /* HEBREW PUNCTUATION MAQAF */
5604           || ch == 0x0F0B /* TIBETAN MARK INTERSYLLABIC TSHEG */
5605           || ch == 0x1361 /* ETHIOPIC WORDSPACE */
5606           || ch == 0x17D8 /* KHMER SIGN BEYYAL */
5607           || ch == 0x17DA /* KHMER SIGN KOOMUUT */
5608           || ch == 0x2027 /* HYPHENATION POINT */
5609           || ch == 0x007C /* VERTICAL LINE */
5610           /* Historic Word Separators */
5611           || ch == 0x16EB /* RUNIC SINGLE PUNCTUATION */
5612           || ch == 0x16EC /* RUNIC MULTIPLE PUNCTUATION */
5613           || ch == 0x16ED /* RUNIC CROSS PUNCTUATION */
5614           || ch == 0x2056 /* THREE DOT PUNCTUATION */
5615           || ch == 0x2058 /* FOUR DOT PUNCTUATION */
5616           || ch == 0x2059 /* FIVE DOT PUNCTUATION */
5617           || ch == 0x205A /* TWO DOT PUNCTUATION */
5618           || ch == 0x205B /* FOUR DOT MARK */
5619           || ch == 0x205D /* TRICOLON */
5620           || ch == 0x205E /* VERTICAL FOUR DOTS */
5621           || ch == 0x2E19 /* PALM BRANCH */
5622           || ch == 0x2E2A /* TWO DOTS OVER ONE DOT PUNCTUATION */
5623           || ch == 0x2E2B /* ONE DOT OVER TWO DOTS PUNCTUATION */
5624           || ch == 0x2E2C /* SQUARED FOUR DOT PUNCTUATION */
5625           || ch == 0x2E2D /* FIVE DOT PUNCTUATION */
5626           || ch == 0x2E30 /* RING POINT */
5627           || ch == 0x2E31 /* WORD SEPARATOR MIDDLE DOT */
5628           || ch == 0x10100 /* AEGEAN WORD SEPARATOR LINE */
5629           || ch == 0x10101 /* AEGEAN WORD SEPARATOR DOT */
5630           || ch == 0x10102 /* AEGEAN CHECK MARK */
5631           || ch == 0x1039F /* UGARITIC WORD DIVIDER */
5632           || ch == 0x103D0 /* OLD PERSIAN WORD DIVIDER */
5633           || ch == 0x1091F /* PHOENICIAN WORD SEPARATOR */
5634           || ch == 0x12470 /* CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER */
5635           /* Dandas */
5636           || ch == 0x0964 /* DEVANAGARI DANDA */
5637           || ch == 0x0965 /* DEVANAGARI DOUBLE DANDA */
5638           || ch == 0x0E5A /* THAI CHARACTER ANGKHANKHU */
5639           || ch == 0x0E5B /* THAI CHARACTER KHOMUT */
5640           || ch == 0x104A /* MYANMAR SIGN LITTLE SECTION */
5641           || ch == 0x104B /* MYANMAR SIGN SECTION */
5642           || ch == 0x1735 /* PHILIPPINE SINGLE PUNCTUATION */
5643           || ch == 0x1736 /* PHILIPPINE DOUBLE PUNCTUATION */
5644           || ch == 0x17D4 /* KHMER SIGN KHAN */
5645           || ch == 0x17D5 /* KHMER SIGN BARIYOOSAN */
5646           || ch == 0x1B5E /* BALINESE CARIK SIKI */
5647           || ch == 0x1B5F /* BALINESE CARIK PAREREN */
5648           || ch == 0xA8CE /* SAURASHTRA DANDA */
5649           || ch == 0xA8CF /* SAURASHTRA DOUBLE DANDA */
5650           || ch == 0xAA5D /* CHAM PUNCTUATION DANDA */
5651           || ch == 0xAA5E /* CHAM PUNCTUATION DOUBLE DANDA */
5652           || ch == 0xAA5F /* CHAM PUNCTUATION TRIPLE DANDA */
5653           || ch == 0x10A56 /* KHAROSHTHI PUNCTUATION DANDA */
5654           || ch == 0x10A57 /* KHAROSHTHI PUNCTUATION DOUBLE DANDA */
5655           /* Tibetan */
5656           || ch == 0x0F34 /* TIBETAN MARK BSDUS RTAGS */
5657           || ch == 0x0F7F /* TIBETAN SIGN RNAM BCAD */
5658           || ch == 0x0F85 /* TIBETAN MARK PALUTA */
5659           || ch == 0x0FBE /* TIBETAN KU RU KHA */
5660           || ch == 0x0FBF /* TIBETAN KU RU KHA BZHI MIG CAN */
5661           || ch == 0x0FD2 /* TIBETAN MARK NYIS TSHEG */
5662           /* Other Terminating Punctuation */
5663           || ch == 0x1804 /* MONGOLIAN COLON */
5664           || ch == 0x1805 /* MONGOLIAN FOUR DOTS */
5665           || ch == 0x1B5A /* BALINESE PANTI */
5666           || ch == 0x1B5B /* BALINESE PAMADA */
5667           || ch == 0x1B5D /* BALINESE CARIK PAMUNGKAH */
5668           || ch == 0x1B60 /* BALINESE PAMENENG */
5669           || ch == 0x1C3B /* LEPCHA PUNCTUATION TA-ROL */
5670           || ch == 0x1C3C /* LEPCHA PUNCTUATION NYET THYOOM TA-ROL */
5671           || ch == 0x1C3D /* LEPCHA PUNCTUATION CER-WA */
5672           || ch == 0x1C3E /* LEPCHA PUNCTUATION TSHOOK CER-WA */
5673           || ch == 0x1C3F /* LEPCHA PUNCTUATION TSHOOK */
5674           || ch == 0x1C7E /* OL CHIKI PUNCTUATION MUCAAD */
5675           || ch == 0x1C7F /* OL CHIKI PUNCTUATION DOUBLE MUCAAD */
5676           || ch == 0x2CFA /* COPTIC OLD NUBIAN DIRECT QUESTION MARK */
5677           || ch == 0x2CFB /* COPTIC OLD NUBIAN INDIRECT QUESTION MARK */
5678           || ch == 0x2CFC /* COPTIC OLD NUBIAN VERSE DIVIDER */
5679           || ch == 0x2CFF /* COPTIC MORPHOLOGICAL DIVIDER */
5680           || (ch >= 0x2E0E && ch <= 0x2E15) /* EDITORIAL CORONIS .. UPWARDS ANCORA */
5681           || ch == 0x2E17 /* DOUBLE OBLIQUE HYPHEN */
5682           || ch == 0xA60D /* VAI COMMA */
5683           || ch == 0xA60F /* VAI QUESTION MARK */
5684           || ch == 0xA92E /* KAYAH LI SIGN CWI */
5685           || ch == 0xA92F /* KAYAH LI SIGN SHYA */
5686           || ch == 0x10A50 /* KHAROSHTHI PUNCTUATION DOT */
5687           || ch == 0x10A51 /* KHAROSHTHI PUNCTUATION SMALL CIRCLE */
5688           || ch == 0x10A52 /* KHAROSHTHI PUNCTUATION CIRCLE */
5689           || ch == 0x10A53 /* KHAROSHTHI PUNCTUATION CRESCENT BAR */
5690           || ch == 0x10A54 /* KHAROSHTHI PUNCTUATION MANGALAM */
5691           || ch == 0x10A55 /* KHAROSHTHI PUNCTUATION LOTUS */
5692           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5693           || ch == 0xA4FE /* LISU PUNCTUATION COMMA */
5694           || ch == 0xA4FF /* LISU PUNCTUATION FULL STOP */
5695           || ch == 0xA6F3 /* BAMUM FULL STOP */
5696           || ch == 0xA6F4 /* BAMUM COLON */
5697           || ch == 0xA6F5 /* BAMUM COMMA */
5698           || ch == 0xA6F6 /* BAMUM SEMICOLON */
5699           || ch == 0xA6F7 /* BAMUM QUESTION MARK */
5700           || ch == 0xA9C7 /* JAVANESE PADA PANGKAT */
5701           || ch == 0xA9C8 /* JAVANESE PADA LINGSA */
5702           || ch == 0xA9C9 /* JAVANESE PADA LUNGSI */
5703           || ch == 0xABEB /* MEETEI MAYEK CHEIKHEI */
5704           || ch == 0x10857 /* IMPERIAL ARAMAIC SECTION SIGN */
5705           || ch == 0x10B39 /* AVESTAN ABBREVIATION MARK */
5706           || ch == 0x10B3A /* TINY TWO DOTS OVER ONE DOT PUNCTUATION */
5707           || ch == 0x10B3B /* SMALL TWO DOTS OVER ONE DOT PUNCTUATION */
5708           || ch == 0x10B3C /* LARGE TWO DOTS OVER ONE DOT PUNCTUATION */
5709           || ch == 0x10B3D /* LARGE ONE DOT OVER TWO DOTS PUNCTUATION */
5710           || ch == 0x10B3E /* LARGE TWO RINGS OVER ONE RING PUNCTUATION */
5711           || ch == 0x10B3F /* LARGE ONE RING OVER TWO RINGS PUNCTUATION */
5712           || ch == 0x110BE /* KAITHI SECTION MARK */
5713           || ch == 0x110BF /* KAITHI DOUBLE SECTION MARK */
5714           || ch == 0x110C0 /* KAITHI DANDA */
5715           || ch == 0x110C1 /* KAITHI DOUBLE DANDA */
5716           || ch == 0x12471 /* CUNEIFORM PUNCTUATION SIGN VERTICAL COLON */
5717           || ch == 0x12472 /* CUNEIFORM PUNCTUATION SIGN DIAGONAL COLON */
5718           || ch == 0x12473 /* CUNEIFORM PUNCTUATION SIGN DIAGONAL TRICOLON */)
5719         attr |= (int64_t) 1 << LBP_BA;
5720
5721       /* break opportunity before */
5722       if (ch == 0x00B4 /* ACUTE ACCENT */
5723           || ch == 0x1FFD /* GREEK OXIA */
5724           || ch == 0x02DF /* MODIFIER LETTER CROSS ACCENT */
5725           || ch == 0x02C8 /* MODIFIER LETTER VERTICAL LINE */
5726           || ch == 0x02CC /* MODIFIER LETTER LOW VERTICAL LINE */
5727           || ch == 0x0F01 /* TIBETAN MARK GTER YIG MGO TRUNCATED A */
5728           || ch == 0x0F02 /* TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA */
5729           || ch == 0x0F03 /* TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA */
5730           || ch == 0x0F04 /* TIBETAN MARK INITIAL YIG MGO MDUN MA */
5731           || ch == 0x0F06 /* TIBETAN MARK CARET YIG MGO PHUR SHAD MA */
5732           || ch == 0x0F07 /* TIBETAN MARK YIG MGO TSHEG SHAD MA */
5733           || ch == 0x0F09 /* TIBETAN MARK BSKUR YIG MGO */
5734           || ch == 0x0F0A /* TIBETAN MARK BKA- SHOG YIG MGO */
5735           || ch == 0x0FD0 /* TIBETAN MARK BSKA- SHOG GI MGO RGYAN */
5736           || ch == 0x0FD1 /* TIBETAN MARK MNYAM YIG GI MGO RGYAN */
5737           || ch == 0x0FD3 /* TIBETAN MARK INITIAL BRDA RNYING YIG MGO MDUN MA */
5738           || ch == 0xA874 /* PHAGS-PA SINGLE HEAD MARK */
5739           || ch == 0xA875 /* PHAGS-PA DOUBLE HEAD MARK */
5740           || ch == 0x1806 /* MONGOLIAN TODO SOFT HYPHEN */)
5741         attr |= (int64_t) 1 << LBP_BB;
5742
5743       /* hyphen */
5744       if (ch == 0x002D /* HYPHEN-MINUS */)
5745         attr |= (int64_t) 1 << LBP_HY;
5746
5747       /* contingent break opportunity */
5748       if (ch == 0xFFFC /* OBJECT REPLACEMENT CHARACTER */)
5749         attr |= (int64_t) 1 << LBP_CB;
5750
5751       /* closing parenthesis */
5752       if (ch == 0x0029 /* RIGHT PARENTHESIS */
5753           || ch == 0x005D /* RIGHT SQUARE BRACKET */)
5754         attr |= (int64_t) 1 << LBP_CP;
5755
5756       /* closing punctuation */
5757       if ((unicode_attributes[ch].category[0] == 'P'
5758            && unicode_attributes[ch].category[1] == 'e'
5759            && !(attr & ((int64_t) 1 << LBP_CP)))
5760           || ch == 0x3001 /* IDEOGRAPHIC COMMA */
5761           || ch == 0x3002 /* IDEOGRAPHIC FULL STOP */
5762           || ch == 0xFE11 /* PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC COMMA */
5763           || ch == 0xFE12 /* PRESENTATION FORM FOR VERTICAL IDEOGRAPHIC FULL STOP */
5764           || ch == 0xFE50 /* SMALL COMMA */
5765           || ch == 0xFE52 /* SMALL FULL STOP */
5766           || ch == 0xFF0C /* FULLWIDTH COMMA */
5767           || ch == 0xFF0E /* FULLWIDTH FULL STOP */
5768           || ch == 0xFF61 /* HALFWIDTH IDEOGRAPHIC FULL STOP */
5769           || ch == 0xFF64 /* HALFWIDTH IDEOGRAPHIC COMMA */
5770           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5771           || ch == 0x1325B /* EGYPTIAN HIEROGLYPH O006D */
5772           || ch == 0x1325C /* EGYPTIAN HIEROGLYPH O006E */
5773           || ch == 0x1325D /* EGYPTIAN HIEROGLYPH O006F */
5774           || ch == 0x13282 /* EGYPTIAN HIEROGLYPH O033A */
5775           || ch == 0x13287 /* EGYPTIAN HIEROGLYPH O036B */
5776           || ch == 0x13289 /* EGYPTIAN HIEROGLYPH O036D */
5777           || ch == 0x1337A /* EGYPTIAN HIEROGLYPH V011B */
5778           || ch == 0x1337B /* EGYPTIAN HIEROGLYPH V011C */)
5779         attr |= (int64_t) 1 << LBP_CL;
5780
5781       /* exclamation/interrogation */
5782       if (ch == 0x0021 /* EXCLAMATION MARK */
5783           || ch == 0x003F /* QUESTION MARK */
5784           || ch == 0x05C6 /* HEBREW PUNCTUATION NUN HAFUKHA */
5785           || ch == 0x061B /* ARABIC SEMICOLON */
5786           || ch == 0x061E /* ARABIC TRIPLE DOT PUNCTUATION MARK */
5787           || ch == 0x061F /* ARABIC QUESTION MARK */
5788           || ch == 0x06D4 /* ARABIC FULL STOP */
5789           || ch == 0x07F9 /* NKO EXCLAMATION MARK */
5790           || ch == 0x0F0D /* TIBETAN MARK SHAD */
5791           || ch == 0x0F0E /* TIBETAN MARK NYIS SHAD */
5792           || ch == 0x0F0F /* TIBETAN MARK TSHEG SHAD */
5793           || ch == 0x0F10 /* TIBETAN MARK NYIS TSHEG SHAD */
5794           || ch == 0x0F11 /* TIBETAN MARK RIN CHEN SPUNGS SHAD */
5795           || ch == 0x0F14 /* TIBETAN MARK GTER TSHEG */
5796           || ch == 0x1802 /* MONGOLIAN COMMA */
5797           || ch == 0x1803 /* MONGOLIAN FULL STOP */
5798           || ch == 0x1808 /* MONGOLIAN MANCHU COMMA */
5799           || ch == 0x1809 /* MONGOLIAN MANCHU FULL STOP */
5800           || ch == 0x1944 /* LIMBU EXCLAMATION MARK */
5801           || ch == 0x1945 /* LIMBU QUESTION MARK */
5802           || ch == 0x2762 /* HEAVY EXCLAMATION MARK ORNAMENT */
5803           || ch == 0x2763 /* HEAVY HEART EXCLAMATION MARK ORNAMENT */
5804           || ch == 0x2CF9 /* COPTIC OLD NUBIAN FULL STOP */
5805           || ch == 0x2CFE /* COPTIC FULL STOP */
5806           || ch == 0x2E2E /* REVERSED QUESTION MARK */
5807           || ch == 0xA60E /* VAI FULL STOP */
5808           || ch == 0xA876 /* PHAGS-PA MARK SHAD */
5809           || ch == 0xA877 /* PHAGS-PA MARK DOUBLE SHAD */
5810           || ch == 0xFE15 /* PRESENTATION FORM FOR VERTICAL EXCLAMATION MARK */
5811           || ch == 0xFE16 /* PRESENTATION FORM FOR VERTICAL QUESTION MARK */
5812           || ch == 0xFE56 /* SMALL QUESTION MARK */
5813           || ch == 0xFE57 /* SMALL EXCLAMATION MARK */
5814           || ch == 0xFF01 /* FULLWIDTH EXCLAMATION MARK */
5815           || ch == 0xFF1F /* FULLWIDTH QUESTION MARK */)
5816         attr |= (int64_t) 1 << LBP_EX;
5817
5818       /* inseparable */
5819       if (ch == 0x2024 /* ONE DOT LEADER */
5820           || ch == 0x2025 /* TWO DOT LEADER */
5821           || ch == 0x2026 /* HORIZONTAL ELLIPSIS */
5822           || ch == 0xFE19 /* PRESENTATION FORM FOR VERTICAL HORIZONTAL ELLIPSIS */)
5823         attr |= (int64_t) 1 << LBP_IN;
5824
5825       /* non starter */
5826       if (ch == 0x17D6 /* KHMER SIGN CAMNUC PII KUUH */
5827           || ch == 0x203C /* DOUBLE EXCLAMATION MARK */
5828           || ch == 0x203D /* INTERROBANG */
5829           || ch == 0x2047 /* DOUBLE QUESTION MARK */
5830           || ch == 0x2048 /* QUESTION EXCLAMATION MARK */
5831           || ch == 0x2049 /* EXCLAMATION QUESTION MARK */
5832           || ch == 0x3005 /* IDEOGRAPHIC ITERATION MARK */
5833           || ch == 0x301C /* WAVE DASH */
5834           || ch == 0x303C /* MASU MARK */
5835           || ch == 0x303B /* VERTICAL IDEOGRAPHIC ITERATION MARK */
5836           || ch == 0x309B /* KATAKANA-HIRAGANA VOICED SOUND MARK */
5837           || ch == 0x309C /* KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */
5838           || ch == 0x309D /* HIRAGANA ITERATION MARK */
5839           || ch == 0x309E /* HIRAGANA VOICED ITERATION MARK */
5840           || ch == 0x30A0 /* KATAKANA-HIRAGANA DOUBLE HYPHEN */
5841           || ch == 0x30FB /* KATAKANA MIDDLE DOT */
5842           || ch == 0x30FC /* KATAKANA-HIRAGANA PROLONGED SOUND MARK */
5843           || ch == 0x30FD /* KATAKANA ITERATION MARK */
5844           || ch == 0x30FE /* KATAKANA VOICED ITERATION MARK */
5845           || ch == 0xA015 /* YI SYLLABLE WU */
5846           || ch == 0xFE54 /* SMALL SEMICOLON */
5847           || ch == 0xFE55 /* SMALL COLON */
5848           || ch == 0xFF1A /* FULLWIDTH COLON */
5849           || ch == 0xFF1B /* FULLWIDTH SEMICOLON */
5850           || ch == 0xFF65 /* HALFWIDTH KATAKANA MIDDLE DOT */
5851           || ch == 0xFF70 /* HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK */
5852           || ch == 0xFF9E /* HALFWIDTH KATAKANA VOICED SOUND MARK */
5853           || ch == 0xFF9F /* HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK */
5854           || strstr (unicode_attributes[ch].name, "HIRAGANA LETTER SMALL ") != NULL
5855           || strstr (unicode_attributes[ch].name, "KATAKANA LETTER SMALL ") != NULL)
5856         attr |= (int64_t) 1 << LBP_NS;
5857
5858       /* opening punctuation */
5859       if ((unicode_attributes[ch].category[0] == 'P'
5860            && unicode_attributes[ch].category[1] == 's')
5861           || ch == 0x00A1 /* INVERTED EXCLAMATION MARK */
5862           || ch == 0x00BF /* INVERTED QUESTION MARK */
5863           || ch == 0x2E18 /* INVERTED INTERROBANG */
5864           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5865           || ch == 0x13258 /* EGYPTIAN HIEROGLYPH O006A */
5866           || ch == 0x13259 /* EGYPTIAN HIEROGLYPH O006B */
5867           || ch == 0x1325A /* EGYPTIAN HIEROGLYPH O006C */
5868           || ch == 0x13286 /* EGYPTIAN HIEROGLYPH O036A */
5869           || ch == 0x13288 /* EGYPTIAN HIEROGLYPH O036C */
5870           || ch == 0x13379 /* EGYPTIAN HIEROGLYPH V011A */)
5871         attr |= (int64_t) 1 << LBP_OP;
5872
5873       /* ambiguous quotation */
5874       if ((unicode_attributes[ch].category[0] == 'P'
5875            && (unicode_attributes[ch].category[1] == 'f'
5876                || unicode_attributes[ch].category[1] == 'i'))
5877           || ch == 0x0022 /* QUOTATION MARK */
5878           || ch == 0x0027 /* APOSTROPHE */
5879           || ch == 0x275B /* HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT */
5880           || ch == 0x275C /* HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT */
5881           || ch == 0x275D /* HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT */
5882           || ch == 0x275E /* HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT */
5883           || ch == 0x2E00 /* RIGHT ANGLE SUBSTITUTION MARKER */
5884           || ch == 0x2E01 /* RIGHT ANGLE DOTTED SUBSTITUTION MARKER */
5885           || ch == 0x2E06 /* RAISED INTERPOLATION MARKER */
5886           || ch == 0x2E07 /* RAISED DOTTED INTERPOLATION MARKER */
5887           || ch == 0x2E08 /* DOTTED TRANSPOSITION MARKER */
5888           || ch == 0x2E0B /* RAISED SQUARE */)
5889         attr |= (int64_t) 1 << LBP_QU;
5890
5891       /* infix separator (numeric) */
5892       if (ch == 0x002C /* COMMA */
5893           || ch == 0x002E /* FULL STOP */
5894           || ch == 0x003A /* COLON */
5895           || ch == 0x003B /* SEMICOLON */
5896           || ch == 0x037E /* GREEK QUESTION MARK */
5897           || ch == 0x0589 /* ARMENIAN FULL STOP */
5898           || ch == 0x060C /* ARABIC COMMA */
5899           || ch == 0x060D /* ARABIC DATE SEPARATOR */
5900           || ch == 0x07F8 /* NKO COMMA */
5901           || ch == 0x2044 /* FRACTION SLASH */
5902           || ch == 0xFE10 /* PRESENTATION FORM FOR VERTICAL COMMA */
5903           || ch == 0xFE13 /* PRESENTATION FORM FOR VERTICAL COLON */
5904           || ch == 0xFE14 /* PRESENTATION FORM FOR VERTICAL SEMICOLON */)
5905         attr |= (int64_t) 1 << LBP_IS;
5906
5907       /* numeric */
5908       if ((unicode_attributes[ch].category[0] == 'N'
5909            && unicode_attributes[ch].category[1] == 'd'
5910            && strstr (unicode_attributes[ch].name, "FULLWIDTH") == NULL)
5911           || ch == 0x066B /* ARABIC DECIMAL SEPARATOR */
5912           || ch == 0x066C /* ARABIC THOUSANDS SEPARATOR */)
5913         attr |= (int64_t) 1 << LBP_NU;
5914
5915       /* postfix (numeric) */
5916       if (ch == 0x0025 /* PERCENT SIGN */
5917           || ch == 0x00A2 /* CENT SIGN */
5918           || ch == 0x00B0 /* DEGREE SIGN */
5919           || ch == 0x060B /* AFGHANI SIGN */
5920           || ch == 0x066A /* ARABIC PERCENT SIGN */
5921           || ch == 0x2030 /* PER MILLE SIGN */
5922           || ch == 0x2031 /* PER TEN THOUSAND SIGN */
5923           || ch == 0x2032 /* PRIME */
5924           || ch == 0x2033 /* DOUBLE PRIME */
5925           || ch == 0x2034 /* TRIPLE PRIME */
5926           || ch == 0x2035 /* REVERSED PRIME */
5927           || ch == 0x2036 /* REVERSED DOUBLE PRIME */
5928           || ch == 0x2037 /* REVERSED TRIPLE PRIME */
5929           || ch == 0x20A7 /* PESETA SIGN */
5930           || ch == 0x2103 /* DEGREE CELSIUS */
5931           || ch == 0x2109 /* DEGREE FAHRENHEIT */
5932           || ch == 0xFDFC /* RIAL SIGN */
5933           || ch == 0xFE6A /* SMALL PERCENT SIGN */
5934           || ch == 0xFF05 /* FULLWIDTH PERCENT SIGN */
5935           || ch == 0xFFE0 /* FULLWIDTH DIGIT ZERO */
5936           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5937           || ch == 0x0609 /* ARABIC-INDIC PER MILLE SIGN */
5938           || ch == 0x060A /* ARABIC-INDIC PER TEN THOUSAND SIGN */
5939           || ch == 0x09F2 /* BENGALI RUPEE MARK */
5940           || ch == 0x09F3 /* BENGALI RUPEE SIGN */
5941           || ch == 0x09F9 /* BENGALI CURRENCY DENOMINATOR SIXTEEN */
5942           || ch == 0x0D79 /* MALAYALAM DATE MARK */
5943           || ch == 0x20B6 /* LIVRE TOURNOIS SIGN */
5944           || ch == 0xA838 /* NORTH INDIC RUPEE MARK */)
5945         attr |= (int64_t) 1 << LBP_PO;
5946
5947       /* prefix (numeric) */
5948       if ((unicode_attributes[ch].category[0] == 'S'
5949            && unicode_attributes[ch].category[1] == 'c')
5950           || ch == 0x002B /* PLUS SIGN */
5951           || ch == 0x005C /* REVERSE SOLIDUS */
5952           || ch == 0x00B1 /* PLUS-MINUS SIGN */
5953           || ch == 0x2116 /* NUMERO SIGN */
5954           || ch == 0x2212 /* MINUS SIGN */
5955           || ch == 0x2213 /* MINUS-OR-PLUS SIGN */)
5956         if (!(attr & ((int64_t) 1 << LBP_PO)))
5957           attr |= (int64_t) 1 << LBP_PR;
5958
5959       /* symbols allowing breaks */
5960       if (ch == 0x002F /* SOLIDUS */)
5961         attr |= (int64_t) 1 << LBP_SY;
5962
5963       if (ch >= 0xAC00 && ch <= 0xD7A3 && ((ch - 0xAC00) % 28) == 0)
5964         attr |= (int64_t) 1 << LBP_H2;
5965
5966       if (ch >= 0xAC00 && ch <= 0xD7A3 && ((ch - 0xAC00) % 28) != 0)
5967         attr |= (int64_t) 1 << LBP_H3;
5968
5969       if ((ch >= 0x1100 && ch <= 0x115F) || (ch >= 0xA960 && ch <= 0xA97C))
5970         attr |= (int64_t) 1 << LBP_JL;
5971
5972       if ((ch >= 0x1160 && ch <= 0x11A7) || (ch >= 0xD7B0 && ch <= 0xD7C6))
5973         attr |= (int64_t) 1 << LBP_JV;
5974
5975       if ((ch >= 0x11A8 && ch <= 0x11FF) || (ch >= 0xD7CB && ch <= 0xD7FB))
5976         attr |= (int64_t) 1 << LBP_JT;
5977
5978       /* complex context (South East Asian) */
5979       if (((unicode_attributes[ch].category[0] == 'C'
5980             && unicode_attributes[ch].category[1] == 'f')
5981            || (unicode_attributes[ch].category[0] == 'L'
5982                && (unicode_attributes[ch].category[1] == 'm'
5983                    || unicode_attributes[ch].category[1] == 'o'))
5984            || (unicode_attributes[ch].category[0] == 'M'
5985                && (unicode_attributes[ch].category[1] == 'c'
5986                    || unicode_attributes[ch].category[1] == 'n')
5987                && ch != 0x1A7F /* TAI THAM COMBINING CRYPTOGRAMMIC DOT */)
5988            /* Extra characters for compatibility with Unicode LineBreak.txt.  */
5989            || ch == 0x109E /* MYANMAR SYMBOL SHAN ONE */
5990            || ch == 0x109F /* MYANMAR SYMBOL SHAN EXCLAMATION */
5991            || ch == 0x19DE /* NEW TAI LUE SIGN LAE */
5992            || ch == 0x19DF /* NEW TAI LUE SIGN LAEV */
5993            || (ch >= 0x1AA0 && ch <= 0x1AAD) /* TAI THAM SIGN */
5994            || (ch >= 0xAA77 && ch <= 0xAA79) /* MYANMAR SYMBOL AITON */
5995            || (ch >= 0xAADE && ch <= 0xAADF) /* TAI VIET SYMBOL */)
5996           && ((ch >= 0x0E00 && ch <= 0x0EFF) /* Thai, Lao */
5997               || (ch >= 0x1000 && ch <= 0x109F) /* Myanmar */
5998               || (ch >= 0x1780 && ch <= 0x17FF) /* Khmer */
5999               || (ch >= 0x1950 && ch <= 0x19DF) /* Tai Le, New Tai Lue */
6000               || (ch >= 0x1A20 && ch <= 0x1AAF) /* Tai Tham */
6001               || (ch >= 0xAA60 && ch <= 0xAADF) /* Myanmar Extended-A, Tai Viet */))
6002         attr |= (int64_t) 1 << LBP_SA;
6003
6004       /* attached characters and combining marks */
6005       if ((unicode_attributes[ch].category[0] == 'M'
6006            && (unicode_attributes[ch].category[1] == 'c'
6007                || unicode_attributes[ch].category[1] == 'e'
6008                || unicode_attributes[ch].category[1] == 'n'))
6009           || (unicode_attributes[ch].category[0] == 'C'
6010               && (unicode_attributes[ch].category[1] == 'c'
6011                   || unicode_attributes[ch].category[1] == 'f')
6012               && ch != 0x110BD /* KAITHI NUMBER SIGN */))
6013         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))))
6014           attr |= (int64_t) 1 << LBP_CM;
6015
6016       /* ideographic */
6017       if ((ch >= 0x2E80 && ch <= 0x2FFF) /* CJK RADICAL, KANGXI RADICAL, IDEOGRAPHIC DESCRIPTION */
6018           || ch == 0x3000 /* IDEOGRAPHIC SPACE */
6019           || (ch >= 0x3040 && ch <= 0x309F) /* HIRAGANA */
6020           || (ch >= 0x30A0 && ch <= 0x30FF) /* KATAKANA */
6021           || (ch >= 0x3400 && ch <= 0x4DBF) /* CJK Ideograph Extension A */
6022           || (ch >= 0x4E00 && ch <= 0x9FFF) /* CJK Ideograph */
6023           || (ch >= 0xF900 && ch <= 0xFAD9) /* CJK COMPATIBILITY IDEOGRAPH */
6024           || (ch >= 0xA000 && ch <= 0xA48F) /* YI SYLLABLE */
6025           || (ch >= 0xA490 && ch <= 0xA4CF) /* YI RADICAL */
6026           || ch == 0xFE62 /* SMALL PLUS SIGN */
6027           || ch == 0xFE63 /* SMALL HYPHEN-MINUS */
6028           || ch == 0xFE64 /* SMALL LESS-THAN SIGN */
6029           || ch == 0xFE65 /* SMALL GREATER-THAN SIGN */
6030           || ch == 0xFE66 /* SMALL EQUALS SIGN */
6031           || (ch >= 0xFF10 && ch <= 0xFF19) /* FULLWIDTH DIGIT */
6032           || (ch >= 0x20000 && ch <= 0x2A6D6) /* CJK Ideograph Extension B */
6033           || (ch >= 0x2F800 && ch <= 0x2FA1D) /* CJK COMPATIBILITY IDEOGRAPH */
6034           || strstr (unicode_attributes[ch].name, "FULLWIDTH LATIN ") != NULL
6035           || (ch >= 0x3000 && ch <= 0x33FF
6036               && !(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))))
6037           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
6038           || ch == 0xFE30 /* PRESENTATION FORM FOR VERTICAL TWO DOT LEADER */
6039           || ch == 0xFE31 /* PRESENTATION FORM FOR VERTICAL EM DASH */
6040           || ch == 0xFE32 /* PRESENTATION FORM FOR VERTICAL EN DASH */
6041           || ch == 0xFE33 /* PRESENTATION FORM FOR VERTICAL LOW LINE */
6042           || ch == 0xFE34 /* PRESENTATION FORM FOR VERTICAL WAVY LOW LINE */
6043           || ch == 0xFE45 /* SESAME DOT */
6044           || ch == 0xFE46 /* WHITE SESAME DOT */
6045           || ch == 0xFE49 /* DASHED OVERLINE */
6046           || ch == 0xFE4A /* CENTRELINE OVERLINE */
6047           || ch == 0xFE4B /* WAVY OVERLINE */
6048           || ch == 0xFE4C /* DOUBLE WAVY OVERLINE */
6049           || ch == 0xFE4D /* DASHED LOW LINE */
6050           || ch == 0xFE4E /* CENTRELINE LOW LINE */
6051           || ch == 0xFE4F /* WAVY LOW LINE */
6052           || ch == 0xFE51 /* SMALL IDEOGRAPHIC COMMA */
6053           || ch == 0xFE58 /* SMALL EM DASH */
6054           || ch == 0xFE5F /* SMALL NUMBER SIGN */
6055           || ch == 0xFE60 /* SMALL AMPERSAND */
6056           || ch == 0xFE61 /* SMALL ASTERISK */
6057           || ch == 0xFE68 /* SMALL REVERSE SOLIDUS */
6058           || ch == 0xFE6B /* SMALL COMMERCIAL AT */
6059           || ch == 0xFF02 /* FULLWIDTH QUOTATION MARK */
6060           || ch == 0xFF03 /* FULLWIDTH NUMBER SIGN */
6061           || ch == 0xFF06 /* FULLWIDTH AMPERSAND */
6062           || ch == 0xFF07 /* FULLWIDTH APOSTROPHE */
6063           || ch == 0xFF0A /* FULLWIDTH ASTERISK */
6064           || ch == 0xFF0B /* FULLWIDTH PLUS SIGN */
6065           || ch == 0xFF0D /* FULLWIDTH HYPHEN-MINUS */
6066           || ch == 0xFF0F /* FULLWIDTH SOLIDUS */
6067           || ch == 0xFF1C /* FULLWIDTH LESS-THAN SIGN */
6068           || ch == 0xFF1D /* FULLWIDTH EQUALS SIGN */
6069           || ch == 0xFF1E /* FULLWIDTH GREATER-THAN SIGN */
6070           || ch == 0xFF20 /* FULLWIDTH COMMERCIAL AT */
6071           || ch == 0xFF3C /* FULLWIDTH REVERSE SOLIDUS */
6072           || ch == 0xFF3E /* FULLWIDTH CIRCUMFLEX ACCENT */
6073           || ch == 0xFF3F /* FULLWIDTH LOW LINE */
6074           || ch == 0xFF40 /* FULLWIDTH GRAVE ACCENT */
6075           || ch == 0xFF5C /* FULLWIDTH VERTICAL LINE */
6076           || ch == 0xFF5E /* FULLWIDTH TILDE */
6077           || ch == 0xFFE2 /* FULLWIDTH NOT SIGN */
6078           || ch == 0xFFE3 /* FULLWIDTH MACRON */
6079           || ch == 0xFFE4 /* FULLWIDTH BROKEN BAR */
6080           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
6081           || (ch >= 0x1F200 && ch <= 0x1F248) /* Enclosed Ideographic Supplement */
6082           || (ch >= 0x2A700 && ch <= 0x2B734) /* CJK Ideograph Extension C */)
6083         if (!(attr & (((int64_t) 1 << LBP_NS) | ((int64_t) 1 << LBP_CM))))
6084           {
6085             /* ambiguous (ideograph) ? */
6086             if ((unicode_width[ch] != NULL
6087                  && unicode_width[ch][0] == 'A'
6088                  && ch >= 0x2000)
6089                 || ch == 0x24EA /* CIRCLED DIGIT ZERO */
6090                 || (ch >= 0x2780 && ch <= 0x2793) /* DINGBAT ... CIRCLED DIGIT ... */)
6091               attr |= (int64_t) 1 << LBP_AI;
6092             else
6093               attr |= (int64_t) 1 << LBP_ID;
6094           }
6095
6096       /* ordinary alphabetic and symbol characters */
6097       if ((unicode_attributes[ch].category[0] == 'L'
6098            && (unicode_attributes[ch].category[1] == 'u'
6099                || unicode_attributes[ch].category[1] == 'l'
6100                || unicode_attributes[ch].category[1] == 't'
6101                || unicode_attributes[ch].category[1] == 'm'
6102                || unicode_attributes[ch].category[1] == 'o'))
6103           || (unicode_attributes[ch].category[0] == 'S'
6104               && (unicode_attributes[ch].category[1] == 'm'
6105                   || unicode_attributes[ch].category[1] == 'k'
6106                   || unicode_attributes[ch].category[1] == 'o'))
6107           || (unicode_attributes[ch].category[0] == 'N'
6108               && (unicode_attributes[ch].category[1] == 'l'
6109                   || unicode_attributes[ch].category[1] == 'o'))
6110           || (unicode_attributes[ch].category[0] == 'P'
6111               && (unicode_attributes[ch].category[1] == 'c'
6112                   || unicode_attributes[ch].category[1] == 'd'
6113                   || unicode_attributes[ch].category[1] == 'o'))
6114           || ch == 0x0600 /* ARABIC NUMBER SIGN */
6115           || ch == 0x0601 /* ARABIC SIGN SANAH */
6116           || ch == 0x0602 /* ARABIC FOOTNOTE MARKER */
6117           || ch == 0x0603 /* ARABIC SIGN SAFHA */
6118           || ch == 0x06DD /* ARABIC END OF AYAH */
6119           || ch == 0x070F /* SYRIAC ABBREVIATION MARK */
6120           || ch == 0x2061 /* FUNCTION APPLICATION */
6121           || ch == 0x2062 /* INVISIBLE TIMES */
6122           || ch == 0x2063 /* INVISIBLE SEPARATOR */
6123           || ch == 0x2064 /* INVISIBLE PLUS */
6124           /* Extra characters for compatibility with Unicode LineBreak.txt.  */
6125           || ch == 0x110BD /* KAITHI NUMBER SIGN */)
6126         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))))
6127           {
6128             /* ambiguous (alphabetic) ? */
6129             if ((unicode_width[ch] != NULL
6130                  && unicode_width[ch][0] == 'A'
6131                  && ch >= 0x2000
6132                  /* Extra exceptions for compatibility with Unicode LineBreak.txt.  */
6133                  && ch != 0x2022 /* BULLET */
6134                  && ch != 0x203E /* OVERLINE */
6135                  && ch != 0x2126 /* OHM SIGN */
6136                  && ch != 0x2153 /* VULGAR FRACTION ONE THIRD */
6137                  && ch != 0x215C /* VULGAR FRACTION THREE EIGHTHS */
6138                  && ch != 0x215D /* VULGAR FRACTION FIVE EIGHTHS */
6139                  && ch != 0x21B8 /* NORTH WEST ARROW TO LONG BAR */
6140                  && ch != 0x21B9 /* LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR */
6141                  && ch != 0x21E7 /* UPWARDS WHITE ARROW */
6142                  && ch != 0x24FF /* NEGATIVE CIRCLED DIGIT ZERO */
6143                  && ch != 0x273D /* HEAVY TEARDROP-SPOKED ASTERISK */)
6144                 || ch == 0x00A7 /* SECTION SIGN */
6145                 || ch == 0x00A8 /* DIAERESIS */
6146                 || ch == 0x00AA /* FEMININE ORDINAL INDICATOR */
6147                 || ch == 0x00B2 /* SUPERSCRIPT TWO */
6148                 || ch == 0x00B3 /* SUPERSCRIPT THREE */
6149                 || ch == 0x00B6 /* PILCROW SIGN */
6150                 || ch == 0x00B7 /* MIDDLE DOT */
6151                 || ch == 0x00B8 /* CEDILLA */
6152                 || ch == 0x00B9 /* SUPERSCRIPT ONE */
6153                 || ch == 0x00BA /* MASCULINE ORDINAL INDICATOR */
6154                 || ch == 0x00BC /* VULGAR FRACTION ONE QUARTER */
6155                 || ch == 0x00BD /* VULGAR FRACTION ONE HALF */
6156                 || ch == 0x00BE /* VULGAR FRACTION THREE QUARTERS */
6157                 || ch == 0x00D7 /* MULTIPLICATION SIGN */
6158                 || ch == 0x00F7 /* DIVISION SIGN */
6159                 || ch == 0x02C7 /* CARON */
6160                 || ch == 0x02C9 /* MODIFIER LETTER MACRON */
6161                 || ch == 0x02CA /* MODIFIER LETTER ACUTE ACCENT */
6162                 || ch == 0x02CB /* MODIFIER LETTER GRAVE ACCENT */
6163                 || ch == 0x02CD /* MODIFIER LETTER LOW MACRON */
6164                 || ch == 0x02D0 /* MODIFIER LETTER TRIANGULAR COLON */
6165                 || ch == 0x02D8 /* BREVE */
6166                 || ch == 0x02D9 /* DOT ABOVE */
6167                 || ch == 0x02DA /* RING ABOVE */
6168                 || ch == 0x02DB /* OGONEK */
6169                 || ch == 0x02DD /* DOUBLE ACUTE ACCENT */
6170                 || ch == 0x24EA /* CIRCLED DIGIT ZERO */
6171                 || (ch >= 0x2780 && ch <= 0x2793) /* DINGBAT ... CIRCLED DIGIT ... */
6172                 /* Extra characters for compatibility with Unicode LineBreak.txt.  */
6173                 || ch == 0x2155 /* VULGAR FRACTION ONE FIFTH */
6174                 || ch == 0x2574 /* BOX DRAWINGS LIGHT LEFT */
6175                 || ch == 0x2616 /* WHITE SHOGI PIECE */
6176                 || ch == 0x2617 /* BLACK SHOGI PIECE */)
6177               attr |= (int64_t) 1 << LBP_AI;
6178             else
6179               attr |= (int64_t) 1 << LBP_AL;
6180             attr &= ~((int64_t) 1 << LBP_CM);
6181           }
6182     }
6183   else
6184     {
6185       /* Unassigned character.  */
6186       if ((ch >= 0x3400 && ch <= 0x4DBF) /* CJK Unified Ideographs Extension A */
6187           || (ch >= 0x4E00 && ch <= 0x9FFF) /* CJK Unified Ideographs */
6188           || (ch >= 0xF900 && ch <= 0xFAFF) /* CJK Compatibility Ideographs */
6189           || (ch >= 0x20000 && ch <= 0x2A6FF) /* CJK Unified Ideographs Extension B */
6190           || (ch >= 0x2A700 && ch <= 0x2F7FF) /* CJK Unified Ideographs Extension C,
6191                                                  Supplementary Ideographic Plane (Plane 2) outside of blocks */
6192           || (ch >= 0x2F800 && ch <= 0x2FFFD) /* CJK Compatibility Ideographs Supplement,
6193                                                  Supplementary Ideographic Plane (Plane 2) outside of blocks */
6194           || (ch >= 0x30000 && ch <= 0x3FFFD) /* Tertiary Ideographic Plane (Plane 3) outside of blocks */)
6195         attr |= (int64_t) 1 << LBP_ID;
6196     }
6197
6198   if (attr == 0)
6199     /* unknown */
6200     attr |= (int64_t) 1 << LBP_XX;
6201
6202   return attr;
6203 }
6204
6205 /* Output the line breaking properties in a human readable format.  */
6206 static void
6207 debug_output_lbp (FILE *stream)
6208 {
6209   unsigned int i;
6210
6211   for (i = 0; i < 0x110000; i++)
6212     {
6213       int64_t attr = get_lbp (i);
6214       if (attr != (int64_t) 1 << LBP_XX)
6215         {
6216           fprintf (stream, "0x%04X", i);
6217 #define PRINT_BIT(attr,bit) \
6218   if (attr & ((int64_t) 1 << bit)) fprintf (stream, " " #bit);
6219           PRINT_BIT(attr,LBP_BK);
6220           PRINT_BIT(attr,LBP_CM);
6221           PRINT_BIT(attr,LBP_WJ);
6222           PRINT_BIT(attr,LBP_ZW);
6223           PRINT_BIT(attr,LBP_GL);
6224           PRINT_BIT(attr,LBP_SP);
6225           PRINT_BIT(attr,LBP_B2);
6226           PRINT_BIT(attr,LBP_BA);
6227           PRINT_BIT(attr,LBP_BB);
6228           PRINT_BIT(attr,LBP_HY);
6229           PRINT_BIT(attr,LBP_CB);
6230           PRINT_BIT(attr,LBP_CL);
6231           PRINT_BIT(attr,LBP_CP);
6232           PRINT_BIT(attr,LBP_EX);
6233           PRINT_BIT(attr,LBP_IN);
6234           PRINT_BIT(attr,LBP_NS);
6235           PRINT_BIT(attr,LBP_OP);
6236           PRINT_BIT(attr,LBP_QU);
6237           PRINT_BIT(attr,LBP_IS);
6238           PRINT_BIT(attr,LBP_NU);
6239           PRINT_BIT(attr,LBP_PO);
6240           PRINT_BIT(attr,LBP_PR);
6241           PRINT_BIT(attr,LBP_SY);
6242           PRINT_BIT(attr,LBP_AI);
6243           PRINT_BIT(attr,LBP_AL);
6244           PRINT_BIT(attr,LBP_H2);
6245           PRINT_BIT(attr,LBP_H3);
6246           PRINT_BIT(attr,LBP_ID);
6247           PRINT_BIT(attr,LBP_JL);
6248           PRINT_BIT(attr,LBP_JV);
6249           PRINT_BIT(attr,LBP_JT);
6250           PRINT_BIT(attr,LBP_SA);
6251           PRINT_BIT(attr,LBP_XX);
6252 #undef PRINT_BIT
6253           fprintf (stream, "\n");
6254         }
6255     }
6256 }
6257
6258 static void
6259 debug_output_lbrk_tables (const char *filename)
6260 {
6261   FILE *stream;
6262
6263   stream = fopen (filename, "w");
6264   if (stream == NULL)
6265     {
6266       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6267       exit (1);
6268     }
6269
6270   debug_output_lbp (stream);
6271
6272   if (ferror (stream) || fclose (stream))
6273     {
6274       fprintf (stderr, "error writing to '%s'\n", filename);
6275       exit (1);
6276     }
6277 }
6278
6279 /* The line breaking property from the LineBreak.txt file.  */
6280 int unicode_org_lbp[0x110000];
6281
6282 /* Stores in unicode_org_lbp[] the line breaking property from the
6283    LineBreak.txt file.  */
6284 static void
6285 fill_org_lbp (const char *linebreak_filename)
6286 {
6287   unsigned int i, j;
6288   FILE *stream;
6289   char field0[FIELDLEN];
6290   char field1[FIELDLEN];
6291   char field2[FIELDLEN];
6292   int lineno = 0;
6293
6294   for (i = 0; i < 0x110000; i++)
6295     unicode_org_lbp[i] = LBP_XX;
6296
6297   stream = fopen (linebreak_filename, "r");
6298   if (stream == NULL)
6299     {
6300       fprintf (stderr, "error during fopen of '%s'\n", linebreak_filename);
6301       exit (1);
6302     }
6303
6304   for (;;)
6305     {
6306       int n;
6307       int c;
6308       int value;
6309
6310       lineno++;
6311       c = getc (stream);
6312       if (c == EOF)
6313         break;
6314       if (c == '#')
6315         {
6316           do c = getc (stream); while (c != EOF && c != '\n');
6317           continue;
6318         }
6319       ungetc (c, stream);
6320       n = getfield (stream, field0, ';');
6321       n += getfield (stream, field1, ' ');
6322       n += getfield (stream, field2, '\n');
6323       if (n == 0)
6324         break;
6325       if (n != 3)
6326         {
6327           fprintf (stderr, "short line in '%s':%d\n", linebreak_filename,
6328                    lineno);
6329           exit (1);
6330         }
6331 #define TRY(bit) else if (strcmp (field1, #bit + 4) == 0) value = bit;
6332       if (false) {}
6333       TRY(LBP_BK)
6334       TRY(LBP_CM)
6335       TRY(LBP_WJ)
6336       TRY(LBP_ZW)
6337       TRY(LBP_GL)
6338       TRY(LBP_SP)
6339       TRY(LBP_B2)
6340       TRY(LBP_BA)
6341       TRY(LBP_BB)
6342       TRY(LBP_HY)
6343       TRY(LBP_CB)
6344       TRY(LBP_CL)
6345       TRY(LBP_CP)
6346       TRY(LBP_EX)
6347       TRY(LBP_IN)
6348       TRY(LBP_NS)
6349       TRY(LBP_OP)
6350       TRY(LBP_QU)
6351       TRY(LBP_IS)
6352       TRY(LBP_NU)
6353       TRY(LBP_PO)
6354       TRY(LBP_PR)
6355       TRY(LBP_SY)
6356       TRY(LBP_AI)
6357       TRY(LBP_AL)
6358       TRY(LBP_H2)
6359       TRY(LBP_H3)
6360       TRY(LBP_ID)
6361       TRY(LBP_JL)
6362       TRY(LBP_JV)
6363       TRY(LBP_JT)
6364       TRY(LBP_SA)
6365       TRY(LBP_XX)
6366 #undef TRY
6367       else if (strcmp (field1, "LF") == 0) value = LBP_BK;
6368       else if (strcmp (field1, "CR") == 0) value = LBP_BK;
6369       else if (strcmp (field1, "NL") == 0) value = LBP_BK;
6370       else if (strcmp (field1, "SG") == 0) value = LBP_XX;
6371       else
6372         {
6373           fprintf (stderr, "unknown property value \"%s\" in '%s':%d\n",
6374                    field1, linebreak_filename, lineno);
6375           exit (1);
6376         }
6377       i = strtoul (field0, NULL, 16);
6378       if (strstr (field0, "..") != NULL)
6379         {
6380           /* Deal with a range.  */
6381           j = strtoul (strstr (field0, "..") + 2, NULL, 16);
6382           for (; i <= j; i++)
6383             unicode_org_lbp[i] = value;
6384         }
6385       else
6386         {
6387           /* Single character line.  */
6388           unicode_org_lbp[i] = value;
6389         }
6390     }
6391   if (ferror (stream) || fclose (stream))
6392     {
6393       fprintf (stderr, "error reading from '%s'\n", linebreak_filename);
6394       exit (1);
6395     }
6396 }
6397
6398 /* Output the line breaking properties in a human readable format.  */
6399 static void
6400 debug_output_org_lbp (FILE *stream)
6401 {
6402   unsigned int i;
6403
6404   for (i = 0; i < 0x110000; i++)
6405     {
6406       int attr = unicode_org_lbp[i];
6407       if (attr != LBP_XX)
6408         {
6409           fprintf (stream, "0x%04X", i);
6410 #define PRINT_BIT(attr,bit) \
6411   if (attr == bit) fprintf (stream, " " #bit);
6412           PRINT_BIT(attr,LBP_BK);
6413           PRINT_BIT(attr,LBP_CM);
6414           PRINT_BIT(attr,LBP_WJ);
6415           PRINT_BIT(attr,LBP_ZW);
6416           PRINT_BIT(attr,LBP_GL);
6417           PRINT_BIT(attr,LBP_SP);
6418           PRINT_BIT(attr,LBP_B2);
6419           PRINT_BIT(attr,LBP_BA);
6420           PRINT_BIT(attr,LBP_BB);
6421           PRINT_BIT(attr,LBP_HY);
6422           PRINT_BIT(attr,LBP_CB);
6423           PRINT_BIT(attr,LBP_CL);
6424           PRINT_BIT(attr,LBP_CP);
6425           PRINT_BIT(attr,LBP_EX);
6426           PRINT_BIT(attr,LBP_IN);
6427           PRINT_BIT(attr,LBP_NS);
6428           PRINT_BIT(attr,LBP_OP);
6429           PRINT_BIT(attr,LBP_QU);
6430           PRINT_BIT(attr,LBP_IS);
6431           PRINT_BIT(attr,LBP_NU);
6432           PRINT_BIT(attr,LBP_PO);
6433           PRINT_BIT(attr,LBP_PR);
6434           PRINT_BIT(attr,LBP_SY);
6435           PRINT_BIT(attr,LBP_AI);
6436           PRINT_BIT(attr,LBP_AL);
6437           PRINT_BIT(attr,LBP_H2);
6438           PRINT_BIT(attr,LBP_H3);
6439           PRINT_BIT(attr,LBP_ID);
6440           PRINT_BIT(attr,LBP_JL);
6441           PRINT_BIT(attr,LBP_JV);
6442           PRINT_BIT(attr,LBP_JT);
6443           PRINT_BIT(attr,LBP_SA);
6444           PRINT_BIT(attr,LBP_XX);
6445 #undef PRINT_BIT
6446           fprintf (stream, "\n");
6447         }
6448     }
6449 }
6450
6451 static void
6452 debug_output_org_lbrk_tables (const char *filename)
6453 {
6454   FILE *stream;
6455
6456   stream = fopen (filename, "w");
6457   if (stream == NULL)
6458     {
6459       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6460       exit (1);
6461     }
6462
6463   debug_output_org_lbp (stream);
6464
6465   if (ferror (stream) || fclose (stream))
6466     {
6467       fprintf (stderr, "error writing to '%s'\n", filename);
6468       exit (1);
6469     }
6470 }
6471
6472 /* Construction of sparse 3-level tables.  */
6473 #define TABLE lbp_table
6474 #define ELEMENT unsigned char
6475 #define DEFAULT LBP_XX
6476 #define xmalloc malloc
6477 #define xrealloc realloc
6478 #include "3level.h"
6479
6480 static void
6481 output_lbp (FILE *stream1, FILE *stream2)
6482 {
6483   unsigned int i;
6484   struct lbp_table t;
6485   unsigned int level1_offset, level2_offset, level3_offset;
6486
6487   t.p = 7;
6488   t.q = 9;
6489   lbp_table_init (&t);
6490
6491   for (i = 0; i < 0x110000; i++)
6492     {
6493       int64_t attr = get_lbp (i);
6494
6495       /* Now attr should contain exactly one bit.  */
6496       if (attr == 0 || ((attr & (attr - 1)) != 0))
6497         abort ();
6498
6499       if (attr != (int64_t) 1 << LBP_XX)
6500         {
6501           unsigned int log2_attr;
6502           for (log2_attr = 0; attr > 1; attr >>= 1, log2_attr++);
6503
6504           lbp_table_add (&t, i, log2_attr);
6505         }
6506     }
6507
6508   lbp_table_finalize (&t);
6509
6510   level1_offset =
6511     5 * sizeof (uint32_t);
6512   level2_offset =
6513     5 * sizeof (uint32_t)
6514     + t.level1_size * sizeof (uint32_t);
6515   level3_offset =
6516     5 * sizeof (uint32_t)
6517     + t.level1_size * sizeof (uint32_t)
6518     + (t.level2_size << t.q) * sizeof (uint32_t);
6519
6520   for (i = 0; i < 5; i++)
6521     fprintf (stream1, "#define lbrkprop_header_%d %d\n", i,
6522              ((uint32_t *) t.result)[i]);
6523   fprintf (stream1, "\n");
6524   fprintf (stream1, "typedef struct\n");
6525   fprintf (stream1, "  {\n");
6526   fprintf (stream1, "    int level1[%zu];\n", t.level1_size);
6527   fprintf (stream1, "    int level2[%zu << %d];\n", t.level2_size, t.q);
6528   fprintf (stream1, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
6529   fprintf (stream1, "  }\n");
6530   fprintf (stream1, "lbrkprop_t;\n");
6531   fprintf (stream1, "extern const lbrkprop_t unilbrkprop;\n");
6532
6533   fprintf (stream2, "const lbrkprop_t unilbrkprop =\n");
6534   fprintf (stream2, "{\n");
6535   fprintf (stream2, "  {");
6536   if (t.level1_size > 8)
6537     fprintf (stream2, "\n   ");
6538   for (i = 0; i < t.level1_size; i++)
6539     {
6540       uint32_t offset;
6541       if (i > 0 && (i % 8) == 0)
6542         fprintf (stream2, "\n   ");
6543       offset = ((uint32_t *) (t.result + level1_offset))[i];
6544       if (offset == 0)
6545         fprintf (stream2, " %5d", -1);
6546       else
6547         fprintf (stream2, " %5zu",
6548                  (offset - level2_offset) / sizeof (uint32_t));
6549       if (i+1 < t.level1_size)
6550         fprintf (stream2, ",");
6551     }
6552   if (t.level1_size > 8)
6553     fprintf (stream2, "\n ");
6554   fprintf (stream2, " },\n");
6555   fprintf (stream2, "  {");
6556   if (t.level2_size << t.q > 8)
6557     fprintf (stream2, "\n   ");
6558   for (i = 0; i < t.level2_size << t.q; i++)
6559     {
6560       uint32_t offset;
6561       if (i > 0 && (i % 8) == 0)
6562         fprintf (stream2, "\n   ");
6563       offset = ((uint32_t *) (t.result + level2_offset))[i];
6564       if (offset == 0)
6565         fprintf (stream2, " %5d", -1);
6566       else
6567         fprintf (stream2, " %5zu",
6568                  (offset - level3_offset) / sizeof (unsigned char));
6569       if (i+1 < t.level2_size << t.q)
6570         fprintf (stream2, ",");
6571     }
6572   if (t.level2_size << t.q > 8)
6573     fprintf (stream2, "\n ");
6574   fprintf (stream2, " },\n");
6575   fprintf (stream2, "  {");
6576   if (t.level3_size << t.p > 8)
6577     fprintf (stream2, "\n   ");
6578   for (i = 0; i < t.level3_size << t.p; i++)
6579     {
6580       unsigned char value = ((unsigned char *) (t.result + level3_offset))[i];
6581       const char *value_string;
6582       switch (value)
6583         {
6584 #define CASE(x) case x: value_string = #x; break;
6585           CASE(LBP_BK);
6586           CASE(LBP_CM);
6587           CASE(LBP_WJ);
6588           CASE(LBP_ZW);
6589           CASE(LBP_GL);
6590           CASE(LBP_SP);
6591           CASE(LBP_B2);
6592           CASE(LBP_BA);
6593           CASE(LBP_BB);
6594           CASE(LBP_HY);
6595           CASE(LBP_CB);
6596           CASE(LBP_CL);
6597           CASE(LBP_CP);
6598           CASE(LBP_EX);
6599           CASE(LBP_IN);
6600           CASE(LBP_NS);
6601           CASE(LBP_OP);
6602           CASE(LBP_QU);
6603           CASE(LBP_IS);
6604           CASE(LBP_NU);
6605           CASE(LBP_PO);
6606           CASE(LBP_PR);
6607           CASE(LBP_SY);
6608           CASE(LBP_AI);
6609           CASE(LBP_AL);
6610           CASE(LBP_H2);
6611           CASE(LBP_H3);
6612           CASE(LBP_ID);
6613           CASE(LBP_JL);
6614           CASE(LBP_JV);
6615           CASE(LBP_JT);
6616           CASE(LBP_SA);
6617           CASE(LBP_XX);
6618 #undef CASE
6619           default:
6620             abort ();
6621         }
6622       if (i > 0 && (i % 8) == 0)
6623         fprintf (stream2, "\n   ");
6624       fprintf (stream2, " %s%s", value_string,
6625                (i+1 < t.level3_size << t.p ? "," : ""));
6626     }
6627   if (t.level3_size << t.p > 8)
6628     fprintf (stream2, "\n ");
6629   fprintf (stream2, " }\n");
6630   fprintf (stream2, "};\n");
6631 }
6632
6633 static void
6634 output_lbrk_tables (const char *filename1, const char *filename2, const char *version)
6635 {
6636   const char *filenames[2];
6637   FILE *streams[2];
6638   size_t i;
6639
6640   filenames[0] = filename1;
6641   filenames[1] = filename2;
6642
6643   for (i = 0; i < 2; i++)
6644     {
6645       streams[i] = fopen (filenames[i], "w");
6646       if (streams[i] == NULL)
6647         {
6648           fprintf (stderr, "cannot open '%s' for writing\n", filenames[i]);
6649           exit (1);
6650         }
6651     }
6652
6653   for (i = 0; i < 2; i++)
6654     {
6655       FILE *stream = streams[i];
6656
6657       fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
6658       fprintf (stream, "/* Line breaking properties of Unicode characters.  */\n");
6659       fprintf (stream, "/* Generated automatically by gen-lbrk for Unicode %s.  */\n",
6660                version);
6661       fprintf (stream, "\n");
6662
6663       /* Put a GPL header on it.  The gnulib module is under LGPL (although it
6664          still carries the GPL header), and it's gnulib-tool which replaces the
6665          GPL header with an LGPL header.  */
6666       fprintf (stream, "/* Copyright (C) 2000-2002, 2004, 2008 Free Software Foundation, Inc.\n");
6667       fprintf (stream, "\n");
6668       fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
6669       fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
6670       fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
6671       fprintf (stream, "   (at your option) any later version.\n");
6672       fprintf (stream, "\n");
6673       fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
6674       fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
6675       fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
6676       fprintf (stream, "   GNU General Public License for more details.\n");
6677       fprintf (stream, "\n");
6678       fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
6679       fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
6680       fprintf (stream, "\n");
6681     }
6682
6683   output_lbp (streams[0], streams[1]);
6684
6685   for (i = 0; i < 2; i++)
6686     {
6687       if (ferror (streams[i]) || fclose (streams[i]))
6688         {
6689           fprintf (stderr, "error writing to '%s'\n", filenames[i]);
6690           exit (1);
6691         }
6692     }
6693 }
6694
6695 /* ========================================================================= */
6696
6697 /* Word break property.
6698    Updated for Unicode TR #29 revision 15.  */
6699
6700 /* Possible values of the Word_Break property.  */
6701 enum
6702 {
6703   WBP_OTHER        = 0,
6704   WBP_CR           = 11,
6705   WBP_LF           = 12,
6706   WBP_NEWLINE      = 10,
6707   WBP_EXTEND       = 8,
6708   WBP_FORMAT       = 9,
6709   WBP_KATAKANA     = 1,
6710   WBP_ALETTER      = 2,
6711   WBP_MIDNUMLET    = 3,
6712   WBP_MIDLETTER    = 4,
6713   WBP_MIDNUM       = 5,
6714   WBP_NUMERIC      = 6,
6715   WBP_EXTENDNUMLET = 7
6716 };
6717
6718 /* Returns the word breaking property for ch, as a bit mask.  */
6719 static int
6720 get_wbp (unsigned int ch)
6721 {
6722   int attr = 0;
6723
6724   if (unicode_attributes[ch].name != NULL)
6725     {
6726       if (ch == 0x000D)
6727         attr |= 1 << WBP_CR;
6728
6729       if (ch == 0x000A)
6730         attr |= 1 << WBP_LF;
6731
6732       if (ch == 0x000B || ch == 0x000C
6733           || ch == 0x0085
6734           || ch == 0x2028 || ch == 0x2029)
6735         attr |= 1 << WBP_NEWLINE;
6736
6737       if (((unicode_properties[ch] >> PROP_GRAPHEME_EXTEND) & 1) != 0
6738           || (unicode_attributes[ch].category != NULL
6739               && strcmp (unicode_attributes[ch].category, "Mc") == 0))
6740         attr |= 1 << WBP_EXTEND;
6741
6742       if (unicode_attributes[ch].category != NULL
6743           && strcmp (unicode_attributes[ch].category, "Cf") == 0
6744           && ch != 0x200B && ch != 0x200C && ch != 0x200D)
6745         attr |= 1 << WBP_FORMAT;
6746
6747       if ((unicode_scripts[ch] < numscripts
6748            && strcmp (scripts[unicode_scripts[ch]], "Katakana") == 0)
6749           || (ch >= 0x3031 && ch <= 0x3035)
6750           || ch == 0x309B || ch == 0x309C || ch == 0x30A0 || ch == 0x30FC
6751           || ch == 0xFF70)
6752         attr |= 1 << WBP_KATAKANA;
6753
6754       if ((((unicode_properties[ch] >> PROP_ALPHABETIC) & 1) != 0
6755            || ch == 0x05F3)
6756           && ((unicode_properties[ch] >> PROP_IDEOGRAPHIC) & 1) == 0
6757           && (attr & (1 << WBP_KATAKANA)) == 0
6758           && ((get_lbp (ch) >> LBP_SA) & 1) == 0
6759           && !(unicode_scripts[ch] < numscripts
6760                && strcmp (scripts[unicode_scripts[ch]], "Hiragana") == 0)
6761           && (attr & (1 << WBP_EXTEND)) == 0)
6762         attr |= 1 << WBP_ALETTER;
6763
6764       if (is_WBP_MIDNUMLET (ch))
6765         attr |= 1 << WBP_MIDNUMLET;
6766
6767       if (is_WBP_MIDLETTER (ch))
6768         attr |= 1 << WBP_MIDLETTER;
6769
6770       if ((((get_lbp (ch) >> LBP_IS) & 1) != 0
6771            || ch == 0x066C || ch == 0xFE50 || ch == 0xFE54 || ch == 0xFF0C
6772            || ch == 0xFF1B)
6773           && ch != 0x003A && ch != 0xFE13 && ch != 0x002E)
6774         attr |= 1 << WBP_MIDNUM;
6775
6776       if (((get_lbp (ch) >> LBP_NU) & 1) != 0
6777           && ch != 0x066C)
6778         attr |= 1 << WBP_NUMERIC;
6779
6780       if (unicode_attributes[ch].category != NULL
6781           && strcmp (unicode_attributes[ch].category, "Pc") == 0)
6782         attr |= 1 << WBP_EXTENDNUMLET;
6783     }
6784
6785   if (attr == 0)
6786     /* other */
6787     attr |= 1 << WBP_OTHER;
6788
6789   return attr;
6790 }
6791
6792 /* Output the word break property in a human readable format.  */
6793 static void
6794 debug_output_wbp (FILE *stream)
6795 {
6796   unsigned int i;
6797
6798   for (i = 0; i < 0x110000; i++)
6799     {
6800       int attr = get_wbp (i);
6801       if (attr != 1 << WBP_OTHER)
6802         {
6803           fprintf (stream, "0x%04X", i);
6804           if (attr & (1 << WBP_CR))
6805             fprintf (stream, " CR");
6806           if (attr & (1 << WBP_LF))
6807             fprintf (stream, " LF");
6808           if (attr & (1 << WBP_NEWLINE))
6809             fprintf (stream, " Newline");
6810           if (attr & (1 << WBP_EXTEND))
6811             fprintf (stream, " Extend");
6812           if (attr & (1 << WBP_FORMAT))
6813             fprintf (stream, " Format");
6814           if (attr & (1 << WBP_KATAKANA))
6815             fprintf (stream, " Katakana");
6816           if (attr & (1 << WBP_ALETTER))
6817             fprintf (stream, " ALetter");
6818           if (attr & (1 << WBP_MIDNUMLET))
6819             fprintf (stream, " MidNumLet");
6820           if (attr & (1 << WBP_MIDLETTER))
6821             fprintf (stream, " MidLetter");
6822           if (attr & (1 << WBP_MIDNUM))
6823             fprintf (stream, " MidNum");
6824           if (attr & (1 << WBP_NUMERIC))
6825             fprintf (stream, " Numeric");
6826           if (attr & (1 << WBP_EXTENDNUMLET))
6827             fprintf (stream, " ExtendNumLet");
6828           fprintf (stream, "\n");
6829         }
6830     }
6831 }
6832
6833 static void
6834 debug_output_wbrk_tables (const char *filename)
6835 {
6836   FILE *stream;
6837
6838   stream = fopen (filename, "w");
6839   if (stream == NULL)
6840     {
6841       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6842       exit (1);
6843     }
6844
6845   debug_output_wbp (stream);
6846
6847   if (ferror (stream) || fclose (stream))
6848     {
6849       fprintf (stderr, "error writing to '%s'\n", filename);
6850       exit (1);
6851     }
6852 }
6853
6854 /* The word break property from the WordBreakProperty.txt file.  */
6855 int unicode_org_wbp[0x110000];
6856
6857 /* Stores in unicode_org_wbp[] the word break property from the
6858    WordBreakProperty.txt file.  */
6859 static void
6860 fill_org_wbp (const char *wordbreakproperty_filename)
6861 {
6862   unsigned int i;
6863   FILE *stream;
6864
6865   for (i = 0; i < 0x110000; i++)
6866     unicode_org_wbp[i] = WBP_OTHER;
6867
6868   stream = fopen (wordbreakproperty_filename, "r");
6869   if (stream == NULL)
6870     {
6871       fprintf (stderr, "error during fopen of '%s'\n", wordbreakproperty_filename);
6872       exit (1);
6873     }
6874
6875   for (;;)
6876     {
6877       char buf[200+1];
6878       unsigned int i1, i2;
6879       char padding[200+1];
6880       char propname[200+1];
6881       int propvalue;
6882
6883       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
6884         break;
6885
6886       if (buf[0] == '\0' || buf[0] == '#')
6887         continue;
6888
6889       if (sscanf (buf, "%X..%X%[ ;]%[^ ]", &i1, &i2, padding, propname) != 4)
6890         {
6891           if (sscanf (buf, "%X%[ ;]%[^ ]", &i1, padding, propname) != 3)
6892             {
6893               fprintf (stderr, "parse error in '%s'\n",
6894                        wordbreakproperty_filename);
6895               exit (1);
6896             }
6897           i2 = i1;
6898         }
6899 #define PROP(name,value) \
6900       if (strcmp (propname, name) == 0) propvalue = value; else
6901       PROP ("CR", WBP_CR)
6902       PROP ("LF", WBP_LF)
6903       PROP ("Newline", WBP_NEWLINE)
6904       PROP ("Extend", WBP_EXTEND)
6905       PROP ("Format", WBP_FORMAT)
6906       PROP ("Katakana", WBP_KATAKANA)
6907       PROP ("ALetter", WBP_ALETTER)
6908       PROP ("MidNumLet", WBP_MIDNUMLET)
6909       PROP ("MidLetter", WBP_MIDLETTER)
6910       PROP ("MidNum", WBP_MIDNUM)
6911       PROP ("Numeric", WBP_NUMERIC)
6912       PROP ("ExtendNumLet", WBP_EXTENDNUMLET)
6913 #undef PROP
6914         {
6915           fprintf (stderr, "unknown property value '%s' in '%s'\n", propname,
6916                    wordbreakproperty_filename);
6917           exit (1);
6918         }
6919       if (!(i1 <= i2 && i2 < 0x110000))
6920         abort ();
6921
6922       for (i = i1; i <= i2; i++)
6923         unicode_org_wbp[i] = propvalue;
6924     }
6925
6926   if (ferror (stream) || fclose (stream))
6927     {
6928       fprintf (stderr, "error reading from '%s'\n", wordbreakproperty_filename);
6929       exit (1);
6930     }
6931 }
6932
6933 /* Output the word break property in a human readable format.  */
6934 static void
6935 debug_output_org_wbp (FILE *stream)
6936 {
6937   unsigned int i;
6938
6939   for (i = 0; i < 0x110000; i++)
6940     {
6941       int propvalue = unicode_org_wbp[i];
6942       if (propvalue != WBP_OTHER)
6943         {
6944           fprintf (stream, "0x%04X", i);
6945 #define PROP(name,value) \
6946           if (propvalue == value) fprintf (stream, " " name); else
6947           PROP ("CR", WBP_CR)
6948           PROP ("LF", WBP_LF)
6949           PROP ("Newline", WBP_NEWLINE)
6950           PROP ("Extend", WBP_EXTEND)
6951           PROP ("Format", WBP_FORMAT)
6952           PROP ("Katakana", WBP_KATAKANA)
6953           PROP ("ALetter", WBP_ALETTER)
6954           PROP ("MidNumLet", WBP_MIDNUMLET)
6955           PROP ("MidLetter", WBP_MIDLETTER)
6956           PROP ("MidNum", WBP_MIDNUM)
6957           PROP ("Numeric", WBP_NUMERIC)
6958           PROP ("ExtendNumLet", WBP_EXTENDNUMLET)
6959 #undef PROP
6960           fprintf (stream, " ??");
6961           fprintf (stream, "\n");
6962         }
6963     }
6964 }
6965
6966 static void
6967 debug_output_org_wbrk_tables (const char *filename)
6968 {
6969   FILE *stream;
6970
6971   stream = fopen (filename, "w");
6972   if (stream == NULL)
6973     {
6974       fprintf (stderr, "cannot open '%s' for writing\n", filename);
6975       exit (1);
6976     }
6977
6978   debug_output_org_wbp (stream);
6979
6980   if (ferror (stream) || fclose (stream))
6981     {
6982       fprintf (stderr, "error writing to '%s'\n", filename);
6983       exit (1);
6984     }
6985 }
6986
6987 /* Construction of sparse 3-level tables.  */
6988 #define TABLE wbp_table
6989 #define ELEMENT unsigned char
6990 #define DEFAULT WBP_OTHER
6991 #define xmalloc malloc
6992 #define xrealloc realloc
6993 #include "3level.h"
6994
6995 static void
6996 output_wbp (FILE *stream)
6997 {
6998   unsigned int i;
6999   struct wbp_table t;
7000   unsigned int level1_offset, level2_offset, level3_offset;
7001
7002   t.p = 7;
7003   t.q = 9;
7004   wbp_table_init (&t);
7005
7006   for (i = 0; i < 0x110000; i++)
7007     {
7008       int attr = get_wbp (i);
7009
7010       /* Now attr should contain exactly one bit.  */
7011       if (attr == 0 || ((attr & (attr - 1)) != 0))
7012         abort ();
7013
7014       if (attr != 1 << WBP_OTHER)
7015         {
7016           unsigned int log2_attr;
7017           for (log2_attr = 0; attr > 1; attr >>= 1, log2_attr++);
7018
7019           wbp_table_add (&t, i, log2_attr);
7020         }
7021     }
7022
7023   wbp_table_finalize (&t);
7024
7025   level1_offset =
7026     5 * sizeof (uint32_t);
7027   level2_offset =
7028     5 * sizeof (uint32_t)
7029     + t.level1_size * sizeof (uint32_t);
7030   level3_offset =
7031     5 * sizeof (uint32_t)
7032     + t.level1_size * sizeof (uint32_t)
7033     + (t.level2_size << t.q) * sizeof (uint32_t);
7034
7035   for (i = 0; i < 5; i++)
7036     fprintf (stream, "#define wbrkprop_header_%d %d\n", i,
7037              ((uint32_t *) t.result)[i]);
7038   fprintf (stream, "\n");
7039   fprintf (stream, "typedef struct\n");
7040   fprintf (stream, "  {\n");
7041   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
7042   fprintf (stream, "    int level2[%zu << %d];\n", t.level2_size, t.q);
7043   fprintf (stream, "    unsigned char level3[%zu << %d];\n", t.level3_size, t.p);
7044   fprintf (stream, "  }\n");
7045   fprintf (stream, "wbrkprop_t;\n");
7046   fprintf (stream, "static const wbrkprop_t uniwbrkprop =\n");
7047   fprintf (stream, "{\n");
7048   fprintf (stream, "  {");
7049   if (t.level1_size > 8)
7050     fprintf (stream, "\n   ");
7051   for (i = 0; i < t.level1_size; i++)
7052     {
7053       uint32_t offset;
7054       if (i > 0 && (i % 8) == 0)
7055         fprintf (stream, "\n   ");
7056       offset = ((uint32_t *) (t.result + level1_offset))[i];
7057       if (offset == 0)
7058         fprintf (stream, " %5d", -1);
7059       else
7060         fprintf (stream, " %5zu",
7061                  (offset - level2_offset) / sizeof (uint32_t));
7062       if (i+1 < t.level1_size)
7063         fprintf (stream, ",");
7064     }
7065   if (t.level1_size > 8)
7066     fprintf (stream, "\n ");
7067   fprintf (stream, " },\n");
7068   fprintf (stream, "  {");
7069   if (t.level2_size << t.q > 8)
7070     fprintf (stream, "\n   ");
7071   for (i = 0; i < t.level2_size << t.q; i++)
7072     {
7073       uint32_t offset;
7074       if (i > 0 && (i % 8) == 0)
7075         fprintf (stream, "\n   ");
7076       offset = ((uint32_t *) (t.result + level2_offset))[i];
7077       if (offset == 0)
7078         fprintf (stream, " %5d", -1);
7079       else
7080         fprintf (stream, " %5zu",
7081                  (offset - level3_offset) / sizeof (unsigned char));
7082       if (i+1 < t.level2_size << t.q)
7083         fprintf (stream, ",");
7084     }
7085   if (t.level2_size << t.q > 8)
7086     fprintf (stream, "\n ");
7087   fprintf (stream, " },\n");
7088   fprintf (stream, "  {");
7089   if (t.level3_size << t.p > 4)
7090     fprintf (stream, "\n   ");
7091   for (i = 0; i < t.level3_size << t.p; i++)
7092     {
7093       unsigned char value = ((unsigned char *) (t.result + level3_offset))[i];
7094       const char *value_string;
7095       switch (value)
7096         {
7097 #define CASE(x) case x: value_string = #x; break;
7098           CASE(WBP_OTHER);
7099           CASE(WBP_CR);
7100           CASE(WBP_LF);
7101           CASE(WBP_NEWLINE);
7102           CASE(WBP_EXTEND);
7103           CASE(WBP_FORMAT);
7104           CASE(WBP_KATAKANA);
7105           CASE(WBP_ALETTER);
7106           CASE(WBP_MIDNUMLET);
7107           CASE(WBP_MIDLETTER);
7108           CASE(WBP_MIDNUM);
7109           CASE(WBP_NUMERIC);
7110           CASE(WBP_EXTENDNUMLET);
7111 #undef CASE
7112           default:
7113             abort ();
7114         }
7115       if (i > 0 && (i % 4) == 0)
7116         fprintf (stream, "\n   ");
7117       fprintf (stream, " %s%s", value_string,
7118                (i+1 < t.level3_size << t.p ? "," : ""));
7119     }
7120   if (t.level3_size << t.p > 4)
7121     fprintf (stream, "\n ");
7122   fprintf (stream, " }\n");
7123   fprintf (stream, "};\n");
7124 }
7125
7126 static void
7127 output_wbrk_tables (const char *filename, const char *version)
7128 {
7129   FILE *stream;
7130
7131   stream = fopen (filename, "w");
7132   if (stream == NULL)
7133     {
7134       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7135       exit (1);
7136     }
7137
7138   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7139   fprintf (stream, "/* Line breaking properties of Unicode characters.  */\n");
7140   fprintf (stream, "/* Generated automatically by gen-uni-tables for Unicode %s.  */\n",
7141            version);
7142   fprintf (stream, "\n");
7143
7144   /* Put a GPL header on it.  The gnulib module is under LGPL (although it
7145      still carries the GPL header), and it's gnulib-tool which replaces the
7146      GPL header with an LGPL header.  */
7147   fprintf (stream, "/* Copyright (C) 2000-2002, 2004, 2007-2009 Free Software Foundation, Inc.\n");
7148   fprintf (stream, "\n");
7149   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
7150   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
7151   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
7152   fprintf (stream, "   (at your option) any later version.\n");
7153   fprintf (stream, "\n");
7154   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
7155   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
7156   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
7157   fprintf (stream, "   GNU General Public License for more details.\n");
7158   fprintf (stream, "\n");
7159   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
7160   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
7161   fprintf (stream, "\n");
7162
7163   output_wbp (stream);
7164
7165   if (ferror (stream) || fclose (stream))
7166     {
7167       fprintf (stderr, "error writing to '%s'\n", filename);
7168       exit (1);
7169     }
7170 }
7171
7172 /* ========================================================================= */
7173
7174 /* Grapheme break property.
7175    Updated for Unicode TR #29 revision 15.  */
7176
7177 /* Possible values of the Grapheme_Cluster_Break property.  */
7178 enum
7179 {
7180   GBP_OTHER        = 0,
7181   GBP_CR           = 1,
7182   GBP_LF           = 2,
7183   GBP_CONTROL      = 3,
7184   GBP_EXTEND       = 4,
7185   GBP_PREPEND      = 5,
7186   GBP_SPACINGMARK  = 6,
7187   GBP_L            = 7,
7188   GBP_V            = 8,
7189   GBP_T            = 9,
7190   GBP_LV           = 10,
7191   GBP_LVT          = 11
7192 };
7193
7194 /* Construction of sparse 3-level tables.  */
7195 #define TABLE gbp_table
7196 #define ELEMENT unsigned char
7197 #define DEFAULT GBP_OTHER
7198 #define xmalloc malloc
7199 #define xrealloc realloc
7200 #include "3level.h"
7201
7202 /* The grapheme break property from the GraphemeBreakProperty.txt file.  */
7203 int unicode_org_gbp[0x110000];
7204
7205 /* Output the unit test data for the grapheme break property.  */
7206 static void
7207 output_gbp_test (const char *filename)
7208 {
7209   FILE *stream;
7210   bool need_comma;
7211   unsigned int ch;
7212
7213   stream = fopen (filename, "w");
7214   if (stream == NULL)
7215     {
7216       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7217       exit (1);
7218     }
7219
7220   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7221   fprintf (stream, "/* Test the Unicode grapheme break property functions.\n");
7222   fprintf (stream, "   Copyright (C) 2010 Free Software Foundation, Inc.\n");
7223   fprintf (stream, "\n");
7224   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
7225   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
7226   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
7227   fprintf (stream, "   (at your option) any later version.\n");
7228   fprintf (stream, "\n");
7229   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
7230   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
7231   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
7232   fprintf (stream, "   GNU General Public License for more details.\n");
7233   fprintf (stream, "\n");
7234   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
7235   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
7236   fprintf (stream, "\n");
7237
7238   need_comma = false;
7239   for (ch = 0; ch < 0x110000; ch++)
7240     {
7241       int gbp = unicode_org_gbp[ch];
7242       const char *gbp_string;
7243
7244       while (ch + 1 < 0x110000 && unicode_org_gbp[ch + 1] == gbp)
7245         ch++;
7246
7247       switch (gbp)
7248         {
7249 #define CASE(x) case x: gbp_string = #x; break;
7250       CASE (GBP_OTHER)
7251       CASE (GBP_CR)
7252       CASE (GBP_LF)
7253       CASE (GBP_CONTROL)
7254       CASE (GBP_EXTEND)
7255       CASE (GBP_PREPEND)
7256       CASE (GBP_SPACINGMARK)
7257       CASE (GBP_L)
7258       CASE (GBP_V)
7259       CASE (GBP_T)
7260       CASE (GBP_LV)
7261       CASE (GBP_LVT)
7262 #undef CASE
7263         default:
7264           abort ();
7265         }
7266
7267       if (need_comma)
7268         fprintf (stream, ",\n");
7269       fprintf (stream, "{ 0x%04X, %s }", ch + 1, gbp_string);
7270
7271       need_comma = true;
7272     }
7273   fprintf (stream, "\n");
7274
7275   if (ferror (stream) || fclose (stream))
7276     {
7277       fprintf (stderr, "error writing to '%s'\n", filename);
7278       exit (1);
7279     }
7280 }
7281
7282 /* Output the per-character grapheme break property table.  */
7283 static void
7284 output_gbp_table (const char *filename, const char *version)
7285 {
7286   FILE *stream;
7287   unsigned int ch, i;
7288   struct gbp_table t;
7289   unsigned int level1_offset, level2_offset, level3_offset;
7290
7291   stream = fopen (filename, "w");
7292   if (stream == NULL)
7293     {
7294       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7295       exit (1);
7296     }
7297
7298   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7299   fprintf (stream, "/* Grapheme break property of Unicode characters.  */\n");
7300   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
7301            version);
7302
7303   t.p = 7;
7304   t.q = 9;
7305   gbp_table_init (&t);
7306
7307   for (ch = 0; ch < 0x110000; ch++)
7308     gbp_table_add (&t, ch, unicode_org_gbp[ch]);
7309
7310   gbp_table_finalize (&t);
7311
7312   /* Offsets in t.result, in memory of this process.  */
7313   level1_offset =
7314     5 * sizeof (uint32_t);
7315   level2_offset =
7316     5 * sizeof (uint32_t)
7317     + t.level1_size * sizeof (uint32_t);
7318   level3_offset =
7319     5 * sizeof (uint32_t)
7320     + t.level1_size * sizeof (uint32_t)
7321     + (t.level2_size << t.q) * sizeof (uint32_t);
7322
7323   for (i = 0; i < 5; i++)
7324     fprintf (stream, "#define gbrkprop_header_%d %d\n", i,
7325              ((uint32_t *) t.result)[i]);
7326   fprintf (stream, "static const\n");
7327   fprintf (stream, "struct\n");
7328   fprintf (stream, "  {\n");
7329   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
7330   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
7331   fprintf (stream, "    unsigned char level3[(%zu << %d) / 2];\n",
7332            t.level3_size, t.p);
7333   fprintf (stream, "  }\n");
7334   fprintf (stream, "unigbrkprop =\n");
7335   fprintf (stream, "{\n");
7336   fprintf (stream, "  {");
7337   if (t.level1_size > 8)
7338     fprintf (stream, "\n   ");
7339   for (i = 0; i < t.level1_size; i++)
7340     {
7341       uint32_t offset;
7342       if (i > 0 && (i % 8) == 0)
7343         fprintf (stream, "\n   ");
7344       offset = ((uint32_t *) (t.result + level1_offset))[i];
7345       if (offset == 0)
7346         fprintf (stream, " %5d", -1);
7347       else
7348         fprintf (stream, " %5zu",
7349                  (offset - level2_offset) / sizeof (uint32_t));
7350       if (i+1 < t.level1_size)
7351         fprintf (stream, ",");
7352     }
7353   if (t.level1_size > 8)
7354     fprintf (stream, "\n ");
7355   fprintf (stream, " },\n");
7356   fprintf (stream, "  {");
7357   if (t.level2_size << t.q > 8)
7358     fprintf (stream, "\n   ");
7359   for (i = 0; i < t.level2_size << t.q; i++)
7360     {
7361       uint32_t offset;
7362       if (i > 0 && (i % 8) == 0)
7363         fprintf (stream, "\n   ");
7364       offset = ((uint32_t *) (t.result + level2_offset))[i];
7365       if (offset == 0)
7366         fprintf (stream, " %5d", -1);
7367       else
7368         fprintf (stream, " %5zu",
7369                  (offset - level3_offset) / sizeof (uint8_t) / 2);
7370       if (i+1 < t.level2_size << t.q)
7371         fprintf (stream, ",");
7372     }
7373   if (t.level2_size << t.q > 8)
7374     fprintf (stream, "\n ");
7375   fprintf (stream, " },\n");
7376   fprintf (stream, "  {");
7377   if (t.level3_size << t.p > 8)
7378     fprintf (stream, "\n   ");
7379   for (i = 0; i < (t.level3_size << t.p) / 2; i++)
7380     {
7381       unsigned char *p = (unsigned char *) (t.result + level3_offset);
7382       unsigned char value0 = p[i * 2];
7383       unsigned char value1 = p[i * 2 + 1];
7384       if (i > 0 && (i % 8) == 0)
7385         fprintf (stream, "\n   ");
7386       fprintf (stream, " 0x%02x%s", (value1 << 4) + value0,
7387                (i+1 < (t.level3_size << t.p) / 2 ? "," : ""));
7388     }
7389   if (t.level3_size << t.p > 8)
7390     fprintf (stream, "\n ");
7391   fprintf (stream, " }\n");
7392   fprintf (stream, "};\n");
7393
7394   if (ferror (stream) || fclose (stream))
7395     {
7396       fprintf (stderr, "error writing to '%s'\n", filename);
7397       exit (1);
7398     }
7399 }
7400
7401 /* Stores in unicode_org_gbp[] the grapheme breaking property from the
7402    GraphemeBreakProperty.txt file.  */
7403 static void
7404 fill_org_gbp (const char *graphemebreakproperty_filename)
7405 {
7406   unsigned int i;
7407   FILE *stream;
7408   int lineno = 0;
7409
7410   for (i = 0; i < 0x110000; i++)
7411     unicode_org_gbp[i] = GBP_OTHER;
7412
7413   stream = fopen (graphemebreakproperty_filename, "r");
7414   if (stream == NULL)
7415     {
7416       fprintf (stderr, "error during fopen of '%s'\n",
7417                graphemebreakproperty_filename);
7418       exit (1);
7419     }
7420
7421   for (;;)
7422     {
7423       char buf[200+1];
7424       unsigned int i1, i2;
7425       char padding[200+1];
7426       char propname[200+1];
7427       int propvalue;
7428
7429       lineno++;
7430       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
7431         break;
7432
7433       if (buf[0] == '\0' || buf[0] == '#')
7434         continue;
7435
7436       if (sscanf (buf, "%X..%X%[ ;]%[^ ]", &i1, &i2, padding, propname) != 4)
7437         {
7438           if (sscanf (buf, "%X%[ ;]%[^ ]", &i1, padding, propname) != 3)
7439             {
7440               fprintf (stderr, "parse error in '%s'\n",
7441                        graphemebreakproperty_filename);
7442               exit (1);
7443             }
7444           i2 = i1;
7445         }
7446 #define PROP(name,value) \
7447       if (strcmp (propname, name) == 0) propvalue = value; else
7448       PROP ("CR", GBP_CR)
7449       PROP ("LF", GBP_LF)
7450       PROP ("Control", GBP_CONTROL)
7451       PROP ("Extend", GBP_EXTEND)
7452       PROP ("Prepend", GBP_PREPEND)
7453       PROP ("SpacingMark", GBP_SPACINGMARK)
7454       PROP ("L", GBP_L)
7455       PROP ("V", GBP_V)
7456       PROP ("T", GBP_T)
7457       PROP ("LV", GBP_LV)
7458       PROP ("LVT", GBP_LVT)
7459 #undef PROP
7460         {
7461           fprintf (stderr, "unknown property value '%s' in %s:%d\n", propname,
7462                    graphemebreakproperty_filename, lineno);
7463           exit (1);
7464         }
7465       if (!(i1 <= i2 && i2 < 0x110000))
7466         abort ();
7467
7468       for (i = i1; i <= i2; i++)
7469         unicode_org_gbp[i] = propvalue;
7470     }
7471   if (ferror (stream) || fclose (stream))
7472     {
7473       fprintf (stderr, "error reading from '%s'\n", graphemebreakproperty_filename);
7474       exit (1);
7475     }
7476 }
7477
7478 /* ========================================================================= */
7479
7480 /* Composition and decomposition.
7481    Updated for Unicode TR #15 revision 31.  */
7482
7483 /* Maximum number of characters into which a single Unicode character can be
7484    decomposed.  */
7485 #define MAX_DECOMP_LENGTH 18
7486
7487 enum
7488 {
7489   UC_DECOMP_CANONICAL,/*            Canonical decomposition.                  */
7490   UC_DECOMP_FONT,    /*   <font>    A font variant (e.g. a blackletter form). */
7491   UC_DECOMP_NOBREAK, /* <noBreak>   A no-break version of a space or hyphen.  */
7492   UC_DECOMP_INITIAL, /* <initial>   An initial presentation form (Arabic).    */
7493   UC_DECOMP_MEDIAL,  /*  <medial>   A medial presentation form (Arabic).      */
7494   UC_DECOMP_FINAL,   /*  <final>    A final presentation form (Arabic).       */
7495   UC_DECOMP_ISOLATED,/* <isolated>  An isolated presentation form (Arabic).   */
7496   UC_DECOMP_CIRCLE,  /*  <circle>   An encircled form.                        */
7497   UC_DECOMP_SUPER,   /*  <super>    A superscript form.                       */
7498   UC_DECOMP_SUB,     /*   <sub>     A subscript form.                         */
7499   UC_DECOMP_VERTICAL,/* <vertical>  A vertical layout presentation form.      */
7500   UC_DECOMP_WIDE,    /*   <wide>    A wide (or zenkaku) compatibility character. */
7501   UC_DECOMP_NARROW,  /*  <narrow>   A narrow (or hankaku) compatibility character. */
7502   UC_DECOMP_SMALL,   /*  <small>    A small variant form (CNS compatibility). */
7503   UC_DECOMP_SQUARE,  /*  <square>   A CJK squared font variant.               */
7504   UC_DECOMP_FRACTION,/* <fraction>  A vulgar fraction form.                   */
7505   UC_DECOMP_COMPAT   /*  <compat>   Otherwise unspecified compatibility character. */
7506 };
7507
7508 /* Return the decomposition for a Unicode character (ignoring Hangul Jamo
7509    decompositions).  Return the type, or -1 for none.  */
7510 static int
7511 get_decomposition (unsigned int ch,
7512                    unsigned int *lengthp, unsigned int decomposed[MAX_DECOMP_LENGTH])
7513 {
7514   const char *decomposition = unicode_attributes[ch].decomposition;
7515
7516   if (decomposition != NULL && decomposition[0] != '\0')
7517     {
7518       int type = UC_DECOMP_CANONICAL;
7519       unsigned int length;
7520       char *endptr;
7521
7522       if (decomposition[0] == '<')
7523         {
7524           const char *rangle;
7525           size_t typelen;
7526
7527           rangle = strchr (decomposition + 1, '>');
7528           if (rangle == NULL)
7529             abort ();
7530           typelen = rangle + 1 - decomposition;
7531 #define TYPE(t1,t2) \
7532           if (typelen == (sizeof (t1) - 1) && memcmp (decomposition, t1, typelen) == 0) \
7533             type = t2; \
7534           else
7535           TYPE ("<font>", UC_DECOMP_FONT)
7536           TYPE ("<noBreak>", UC_DECOMP_NOBREAK)
7537           TYPE ("<initial>", UC_DECOMP_INITIAL)
7538           TYPE ("<medial>", UC_DECOMP_MEDIAL)
7539           TYPE ("<final>", UC_DECOMP_FINAL)
7540           TYPE ("<isolated>", UC_DECOMP_ISOLATED)
7541           TYPE ("<circle>", UC_DECOMP_CIRCLE)
7542           TYPE ("<super>", UC_DECOMP_SUPER)
7543           TYPE ("<sub>", UC_DECOMP_SUB)
7544           TYPE ("<vertical>", UC_DECOMP_VERTICAL)
7545           TYPE ("<wide>", UC_DECOMP_WIDE)
7546           TYPE ("<narrow>", UC_DECOMP_NARROW)
7547           TYPE ("<small>", UC_DECOMP_SMALL)
7548           TYPE ("<square>", UC_DECOMP_SQUARE)
7549           TYPE ("<fraction>", UC_DECOMP_FRACTION)
7550           TYPE ("<compat>", UC_DECOMP_COMPAT)
7551             {
7552               fprintf (stderr, "unknown decomposition type %*s\n", (int)typelen, decomposition);
7553               exit (1);
7554             }
7555 #undef TYPE
7556           decomposition = rangle + 1;
7557           if (decomposition[0] == ' ')
7558             decomposition++;
7559         }
7560       for (length = 0; length < MAX_DECOMP_LENGTH; length++)
7561         {
7562           decomposed[length] = strtoul (decomposition, &endptr, 16);
7563           if (endptr == decomposition)
7564             break;
7565           decomposition = endptr;
7566           if (decomposition[0] == ' ')
7567             decomposition++;
7568         }
7569       if (*decomposition != '\0')
7570         /* MAX_DECOMP_LENGTH is too small.  */
7571         abort ();
7572
7573       *lengthp = length;
7574       return type;
7575     }
7576   else
7577     return -1;
7578 }
7579
7580 /* Construction of sparse 3-level tables.  */
7581 #define TABLE decomp_table
7582 #define ELEMENT uint16_t
7583 #define DEFAULT (uint16_t)(-1)
7584 #define xmalloc malloc
7585 #define xrealloc realloc
7586 #include "3level.h"
7587
7588 static void
7589 output_decomposition (FILE *stream1, FILE *stream2)
7590 {
7591   struct decomp_table t;
7592   unsigned int level1_offset, level2_offset, level3_offset;
7593   unsigned int offset;
7594   unsigned int ch;
7595   unsigned int i;
7596
7597   t.p = 5;
7598   t.q = 5;
7599   decomp_table_init (&t);
7600
7601   fprintf (stream1, "extern const unsigned char gl_uninorm_decomp_chars_table[];\n");
7602   fprintf (stream1, "\n");
7603   fprintf (stream2, "const unsigned char gl_uninorm_decomp_chars_table[] =\n{");
7604   offset = 0;
7605
7606   for (ch = 0; ch < 0x110000; ch++)
7607     {
7608       unsigned int length;
7609       unsigned int decomposed[MAX_DECOMP_LENGTH];
7610       int type = get_decomposition (ch, &length, decomposed);
7611
7612       if (type >= 0)
7613         {
7614           if (!(offset < (1 << 15)))
7615             abort ();
7616           decomp_table_add (&t, ch, ((type == UC_DECOMP_CANONICAL ? 0 : 1) << 15) | offset);
7617
7618           /* Produce length 3-bytes entries.  */
7619           if (length == 0)
7620             /* We would need a special representation of zero-length entries.  */
7621             abort ();
7622           for (i = 0; i < length; i++)
7623             {
7624               if (offset > 0)
7625                 fprintf (stream2, ",");
7626               if ((offset % 4) == 0)
7627                 fprintf (stream2, "\n ");
7628               if (!(decomposed[i] < (1 << 18)))
7629                 abort ();
7630               fprintf (stream2, " 0x%02X, 0x%02X, 0x%02X",
7631                        (((i+1 < length ? (1 << 23) : 0)
7632                          | (i == 0 ? (type << 18) : 0)
7633                          | decomposed[i]) >> 16) & 0xff,
7634                        (decomposed[i] >> 8) & 0xff,
7635                        decomposed[i] & 0xff);
7636               offset++;
7637             }
7638         }
7639     }
7640
7641   fprintf (stream2, "\n};\n");
7642   fprintf (stream2, "\n");
7643
7644   decomp_table_finalize (&t);
7645
7646   level1_offset =
7647     5 * sizeof (uint32_t);
7648   level2_offset =
7649     5 * sizeof (uint32_t)
7650     + t.level1_size * sizeof (uint32_t);
7651   level3_offset =
7652     5 * sizeof (uint32_t)
7653     + t.level1_size * sizeof (uint32_t)
7654     + (t.level2_size << t.q) * sizeof (uint32_t);
7655
7656   for (i = 0; i < 5; i++)
7657     fprintf (stream1, "#define decomp_header_%d %d\n", i,
7658              ((uint32_t *) t.result)[i]);
7659   fprintf (stream1, "\n");
7660   fprintf (stream1, "typedef struct\n");
7661   fprintf (stream1, "  {\n");
7662   fprintf (stream1, "    int level1[%zu];\n", t.level1_size);
7663   fprintf (stream1, "    int level2[%zu << %d];\n", t.level2_size, t.q);
7664   fprintf (stream1, "    unsigned short level3[%zu << %d];\n", t.level3_size, t.p);
7665   fprintf (stream1, "  }\n");
7666   fprintf (stream1, "decomp_index_table_t;\n");
7667   fprintf (stream1, "extern const decomp_index_table_t gl_uninorm_decomp_index_table;\n");
7668   fprintf (stream2, "const decomp_index_table_t gl_uninorm_decomp_index_table =\n");
7669   fprintf (stream2, "{\n");
7670   fprintf (stream2, "  {");
7671   if (t.level1_size > 8)
7672     fprintf (stream2, "\n   ");
7673   for (i = 0; i < t.level1_size; i++)
7674     {
7675       uint32_t offset;
7676       if (i > 0 && (i % 8) == 0)
7677         fprintf (stream2, "\n   ");
7678       offset = ((uint32_t *) (t.result + level1_offset))[i];
7679       if (offset == 0)
7680         fprintf (stream2, " %5d", -1);
7681       else
7682         fprintf (stream2, " %5zu",
7683                  (offset - level2_offset) / sizeof (uint32_t));
7684       if (i+1 < t.level1_size)
7685         fprintf (stream2, ",");
7686     }
7687   if (t.level1_size > 8)
7688     fprintf (stream2, "\n ");
7689   fprintf (stream2, " },\n");
7690   fprintf (stream2, "  {");
7691   if (t.level2_size << t.q > 8)
7692     fprintf (stream2, "\n   ");
7693   for (i = 0; i < t.level2_size << t.q; i++)
7694     {
7695       uint32_t offset;
7696       if (i > 0 && (i % 8) == 0)
7697         fprintf (stream2, "\n   ");
7698       offset = ((uint32_t *) (t.result + level2_offset))[i];
7699       if (offset == 0)
7700         fprintf (stream2, " %5d", -1);
7701       else
7702         fprintf (stream2, " %5zu",
7703                  (offset - level3_offset) / sizeof (uint16_t));
7704       if (i+1 < t.level2_size << t.q)
7705         fprintf (stream2, ",");
7706     }
7707   if (t.level2_size << t.q > 8)
7708     fprintf (stream2, "\n ");
7709   fprintf (stream2, " },\n");
7710   fprintf (stream2, "  {");
7711   if (t.level3_size << t.p > 8)
7712     fprintf (stream2, "\n   ");
7713   for (i = 0; i < t.level3_size << t.p; i++)
7714     {
7715       uint16_t value = ((uint16_t *) (t.result + level3_offset))[i];
7716       if (i > 0 && (i % 8) == 0)
7717         fprintf (stream2, "\n   ");
7718       fprintf (stream2, " %5d", value == (uint16_t)(-1) ? -1 : value);
7719       if (i+1 < t.level3_size << t.p)
7720         fprintf (stream2, ",");
7721     }
7722   if (t.level3_size << t.p > 8)
7723     fprintf (stream2, "\n ");
7724   fprintf (stream2, " }\n");
7725   fprintf (stream2, "};\n");
7726 }
7727
7728 static void
7729 output_decomposition_tables (const char *filename1, const char *filename2, const char *version)
7730 {
7731   const char *filenames[2];
7732   FILE *streams[2];
7733   size_t i;
7734
7735   filenames[0] = filename1;
7736   filenames[1] = filename2;
7737
7738   for (i = 0; i < 2; i++)
7739     {
7740       streams[i] = fopen (filenames[i], "w");
7741       if (streams[i] == NULL)
7742         {
7743           fprintf (stderr, "cannot open '%s' for writing\n", filenames[i]);
7744           exit (1);
7745         }
7746     }
7747
7748   for (i = 0; i < 2; i++)
7749     {
7750       FILE *stream = streams[i];
7751
7752       fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7753       fprintf (stream, "/* Decomposition of Unicode characters.  */\n");
7754       fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
7755                version);
7756       fprintf (stream, "\n");
7757     }
7758
7759   output_decomposition (streams[0], streams[1]);
7760
7761   for (i = 0; i < 2; i++)
7762     {
7763       if (ferror (streams[i]) || fclose (streams[i]))
7764         {
7765           fprintf (stderr, "error writing to '%s'\n", filenames[i]);
7766           exit (1);
7767         }
7768     }
7769 }
7770
7771 /* The "excluded from composition" property from the CompositionExclusions.txt file.  */
7772 char unicode_composition_exclusions[0x110000];
7773
7774 static void
7775 fill_composition_exclusions (const char *compositionexclusions_filename)
7776 {
7777   FILE *stream;
7778   unsigned int i;
7779
7780   stream = fopen (compositionexclusions_filename, "r");
7781   if (stream == NULL)
7782     {
7783       fprintf (stderr, "error during fopen of '%s'\n", compositionexclusions_filename);
7784       exit (1);
7785     }
7786
7787   for (i = 0; i < 0x110000; i++)
7788     unicode_composition_exclusions[i] = 0;
7789
7790   for (;;)
7791     {
7792       char buf[200+1];
7793       unsigned int i;
7794
7795       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
7796         break;
7797
7798       if (buf[0] == '\0' || buf[0] == '#')
7799         continue;
7800
7801       if (sscanf (buf, "%X", &i) != 1)
7802         {
7803           fprintf (stderr, "parse error in '%s'\n", compositionexclusions_filename);
7804           exit (1);
7805         }
7806       if (!(i < 0x110000))
7807         abort ();
7808
7809       unicode_composition_exclusions[i] = 1;
7810     }
7811
7812   if (ferror (stream) || fclose (stream))
7813     {
7814       fprintf (stderr, "error reading from '%s'\n", compositionexclusions_filename);
7815       exit (1);
7816     }
7817 }
7818
7819 static void
7820 debug_output_composition_tables (const char *filename)
7821 {
7822   FILE *stream;
7823   unsigned int ch;
7824
7825   stream = fopen (filename, "w");
7826   if (stream == NULL)
7827     {
7828       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7829       exit (1);
7830     }
7831
7832   for (ch = 0; ch < 0x110000; ch++)
7833     {
7834       unsigned int length;
7835       unsigned int decomposed[MAX_DECOMP_LENGTH];
7836       int type = get_decomposition (ch, &length, decomposed);
7837
7838       if (type == UC_DECOMP_CANONICAL
7839           /* Consider only binary decompositions.
7840              Exclude singleton decompositions.  */
7841           && length == 2)
7842         {
7843           unsigned int code1 = decomposed[0];
7844           unsigned int code2 = decomposed[1];
7845           unsigned int combined = ch;
7846
7847           /* Exclude decompositions where the first part is not a starter,
7848              i.e. is not of canonical combining class 0.  */
7849           if (strcmp (unicode_attributes[code1].combining, "0") == 0
7850               /* Exclude characters listed in CompositionExclusions.txt.  */
7851               && !unicode_composition_exclusions[combined])
7852             {
7853               /* The combined character must now also be a starter.
7854                  Verify this.  */
7855               if (strcmp (unicode_attributes[combined].combining, "0") != 0)
7856                 abort ();
7857
7858               fprintf (stream, "0x%04X\t0x%04X\t0x%04X\t%s\n",
7859                        code1,
7860                        code2,
7861                        combined,
7862                        unicode_attributes[code2].combining);
7863             }
7864         }
7865     }
7866
7867   if (ferror (stream) || fclose (stream))
7868     {
7869       fprintf (stderr, "error writing to '%s'\n", filename);
7870       exit (1);
7871     }
7872 }
7873
7874 static void
7875 output_composition_tables (const char *filename, const char *version)
7876 {
7877   FILE *stream;
7878   unsigned int ch;
7879
7880   stream = fopen (filename, "w");
7881   if (stream == NULL)
7882     {
7883       fprintf (stderr, "cannot open '%s' for writing\n", filename);
7884       exit (1);
7885     }
7886
7887   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
7888   fprintf (stream, "/* Canonical composition of Unicode characters.  */\n");
7889   fprintf (stream, "/* Generated automatically by gen-uni-tables for Unicode %s.  */\n",
7890            version);
7891   fprintf (stream, "\n");
7892
7893   /* Put a GPL header on it.  The gnulib module is under LGPL (although it
7894      still carries the GPL header), and it's gnulib-tool which replaces the
7895      GPL header with an LGPL header.  */
7896   fprintf (stream, "/* Copyright (C) 2009 Free Software Foundation, Inc.\n");
7897   fprintf (stream, "\n");
7898   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
7899   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
7900   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
7901   fprintf (stream, "   (at your option) any later version.\n");
7902   fprintf (stream, "\n");
7903   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
7904   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
7905   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
7906   fprintf (stream, "   GNU General Public License for more details.\n");
7907   fprintf (stream, "\n");
7908   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
7909   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
7910   fprintf (stream, "\n");
7911
7912   /* The composition table is a set of mappings (code1, code2) -> combined,
7913      with 928 entries,
7914      367 values for code1 (from 0x003C to 0x30FD),
7915       54 values for code2 (from 0x0300 to 0x309A).
7916      For a fixed code1, there are from 1 to 19 possible values for code2.
7917      For a fixed code2, there are from 1 to 117 possible values for code1.
7918      This is a very sparse matrix.
7919
7920      We want an O(1) hash lookup.
7921
7922      We could implement the hash lookup by mapping (code1, code2) to a linear
7923      combination  mul1*code1 + mul2*code2, which is then used as an index into
7924      a 3-level table.  But this leads to a table of size 37 KB.
7925
7926      We use gperf to implement the hash lookup, giving it the 928 sets of
7927      4 bytes (code1, code2) as input.  gperf generates a hash table of size
7928      1527, which is quite good (60% filled).  It requires an auxiliary table
7929      lookup in a table of size 0.5 KB.  The total tables size is 11 KB.  */
7930
7931   fprintf (stream, "struct composition_rule { char codes[6]; };\n");
7932   fprintf (stream, "%%struct-type\n");
7933   fprintf (stream, "%%language=ANSI-C\n");
7934   fprintf (stream, "%%define slot-name codes\n");
7935   fprintf (stream, "%%define hash-function-name gl_uninorm_compose_hash\n");
7936   fprintf (stream, "%%define lookup-function-name gl_uninorm_compose_lookup\n");
7937   fprintf (stream, "%%compare-lengths\n");
7938   fprintf (stream, "%%compare-strncmp\n");
7939   fprintf (stream, "%%readonly-tables\n");
7940   fprintf (stream, "%%omit-struct-type\n");
7941   fprintf (stream, "%%%%\n");
7942
7943   for (ch = 0; ch < 0x110000; ch++)
7944     {
7945       unsigned int length;
7946       unsigned int decomposed[MAX_DECOMP_LENGTH];
7947       int type = get_decomposition (ch, &length, decomposed);
7948
7949       if (type == UC_DECOMP_CANONICAL
7950           /* Consider only binary decompositions.
7951              Exclude singleton decompositions.  */
7952           && length == 2)
7953         {
7954           unsigned int code1 = decomposed[0];
7955           unsigned int code2 = decomposed[1];
7956           unsigned int combined = ch;
7957
7958           /* Exclude decompositions where the first part is not a starter,
7959              i.e. is not of canonical combining class 0.  */
7960           if (strcmp (unicode_attributes[code1].combining, "0") == 0
7961               /* Exclude characters listed in CompositionExclusions.txt.  */
7962               && !unicode_composition_exclusions[combined])
7963             {
7964               /* The combined character must now also be a starter.
7965                  Verify this.  */
7966               if (strcmp (unicode_attributes[combined].combining, "0") != 0)
7967                 abort ();
7968
7969               fprintf (stream, "\"\\x%02x\\x%02x\\x%02x\\x%02x\\x%02x\\x%02x\", 0x%04x\n",
7970                        (code1 >> 16) & 0xff, (code1 >> 8) & 0xff, code1 & 0xff,
7971                        (code2 >> 16) & 0xff, (code2 >> 8) & 0xff, code2 & 0xff,
7972                        combined);
7973             }
7974         }
7975     }
7976
7977   if (ferror (stream) || fclose (stream))
7978     {
7979       fprintf (stderr, "error writing to '%s'\n", filename);
7980       exit (1);
7981     }
7982 }
7983
7984 /* ========================================================================= */
7985
7986 /* Output the test for a simple character mapping table to the given file.  */
7987
7988 static void
7989 output_simple_mapping_test (const char *filename,
7990                             const char *function_name,
7991                             unsigned int (*func) (unsigned int),
7992                             const char *version)
7993 {
7994   FILE *stream;
7995   bool need_comma;
7996   unsigned int ch;
7997
7998   stream = fopen (filename, "w");
7999   if (stream == NULL)
8000     {
8001       fprintf (stderr, "cannot open '%s' for writing\n", filename);
8002       exit (1);
8003     }
8004
8005   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
8006   fprintf (stream, "/* Test the Unicode character mapping functions.\n");
8007   fprintf (stream, "   Copyright (C) 2009 Free Software Foundation, Inc.\n");
8008   fprintf (stream, "\n");
8009   fprintf (stream, "   This program is free software: you can redistribute it and/or modify\n");
8010   fprintf (stream, "   it under the terms of the GNU General Public License as published by\n");
8011   fprintf (stream, "   the Free Software Foundation; either version 3 of the License, or\n");
8012   fprintf (stream, "   (at your option) any later version.\n");
8013   fprintf (stream, "\n");
8014   fprintf (stream, "   This program is distributed in the hope that it will be useful,\n");
8015   fprintf (stream, "   but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
8016   fprintf (stream, "   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
8017   fprintf (stream, "   GNU General Public License for more details.\n");
8018   fprintf (stream, "\n");
8019   fprintf (stream, "   You should have received a copy of the GNU General Public License\n");
8020   fprintf (stream, "   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */\n");
8021   fprintf (stream, "\n");
8022   fprintf (stream, "/* Generated automatically by gen-case.c for Unicode %s.  */\n",
8023            version);
8024   fprintf (stream, "\n");
8025   fprintf (stream, "#include \"test-mapping-part1.h\"\n");
8026   fprintf (stream, "\n");
8027
8028   need_comma = false;
8029   for (ch = 0; ch < 0x110000; ch++)
8030     {
8031       unsigned int value = func (ch);
8032
8033       if (value != ch)
8034         {
8035           if (need_comma)
8036             fprintf (stream, ",\n");
8037           fprintf (stream, "    { 0x%04X, 0x%04X }", ch, value);
8038           need_comma = true;
8039         }
8040     }
8041   if (need_comma)
8042     fprintf (stream, "\n");
8043
8044   fprintf (stream, "\n");
8045   fprintf (stream, "#define MAP(c) %s (c)\n", function_name);
8046   fprintf (stream, "#include \"test-mapping-part2.h\"\n");
8047
8048   if (ferror (stream) || fclose (stream))
8049     {
8050       fprintf (stderr, "error writing to '%s'\n", filename);
8051       exit (1);
8052     }
8053 }
8054
8055 /* Construction of sparse 3-level tables.  */
8056 #define TABLE mapping_table
8057 #define ELEMENT int32_t
8058 #define DEFAULT 0
8059 #define xmalloc malloc
8060 #define xrealloc realloc
8061 #include "3level.h"
8062
8063 /* Output a simple character mapping table to the given file.  */
8064
8065 static void
8066 output_simple_mapping (const char *filename,
8067                        unsigned int (*func) (unsigned int),
8068                        const char *version)
8069 {
8070   FILE *stream;
8071   unsigned int ch, i;
8072   struct mapping_table t;
8073   unsigned int level1_offset, level2_offset, level3_offset;
8074
8075   stream = fopen (filename, "w");
8076   if (stream == NULL)
8077     {
8078       fprintf (stderr, "cannot open '%s' for writing\n", filename);
8079       exit (1);
8080     }
8081
8082   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
8083   fprintf (stream, "/* Simple character mapping of Unicode characters.  */\n");
8084   fprintf (stream, "/* Generated automatically by gen-case.c for Unicode %s.  */\n",
8085            version);
8086
8087   t.p = 7;
8088   t.q = 9;
8089   mapping_table_init (&t);
8090
8091   for (ch = 0; ch < 0x110000; ch++)
8092     {
8093       int value = (int) func (ch) - (int) ch;
8094
8095       mapping_table_add (&t, ch, value);
8096     }
8097
8098   mapping_table_finalize (&t);
8099
8100   /* Offsets in t.result, in memory of this process.  */
8101   level1_offset =
8102     5 * sizeof (uint32_t);
8103   level2_offset =
8104     5 * sizeof (uint32_t)
8105     + t.level1_size * sizeof (uint32_t);
8106   level3_offset =
8107     5 * sizeof (uint32_t)
8108     + t.level1_size * sizeof (uint32_t)
8109     + (t.level2_size << t.q) * sizeof (uint32_t);
8110
8111   for (i = 0; i < 5; i++)
8112     fprintf (stream, "#define mapping_header_%d %d\n", i,
8113              ((uint32_t *) t.result)[i]);
8114   fprintf (stream, "static const\n");
8115   fprintf (stream, "struct\n");
8116   fprintf (stream, "  {\n");
8117   fprintf (stream, "    int level1[%zu];\n", t.level1_size);
8118   fprintf (stream, "    short level2[%zu << %d];\n", t.level2_size, t.q);
8119   fprintf (stream, "    int level3[%zu << %d];\n", t.level3_size, t.p);
8120   fprintf (stream, "  }\n");
8121   fprintf (stream, "u_mapping =\n");
8122   fprintf (stream, "{\n");
8123   fprintf (stream, "  {");
8124   if (t.level1_size > 8)
8125     fprintf (stream, "\n   ");
8126   for (i = 0; i < t.level1_size; i++)
8127     {
8128       uint32_t offset;
8129       if (i > 0 && (i % 8) == 0)
8130         fprintf (stream, "\n   ");
8131       offset = ((uint32_t *) (t.result + level1_offset))[i];
8132       if (offset == 0)
8133         fprintf (stream, " %5d", -1);
8134       else
8135         fprintf (stream, " %5zu",
8136                  (offset - level2_offset) / sizeof (uint32_t));
8137       if (i+1 < t.level1_size)
8138         fprintf (stream, ",");
8139     }
8140   if (t.level1_size > 8)
8141     fprintf (stream, "\n ");
8142   fprintf (stream, " },\n");
8143   fprintf (stream, "  {");
8144   if (t.level2_size << t.q > 8)
8145     fprintf (stream, "\n   ");
8146   for (i = 0; i < t.level2_size << t.q; i++)
8147     {
8148       uint32_t offset;
8149       if (i > 0 && (i % 8) == 0)
8150         fprintf (stream, "\n   ");
8151       offset = ((uint32_t *) (t.result + level2_offset))[i];
8152       if (offset == 0)
8153         fprintf (stream, " %5d", -1);
8154       else
8155         fprintf (stream, " %5zu",
8156                  (offset - level3_offset) / sizeof (int32_t));
8157       if (i+1 < t.level2_size << t.q)
8158         fprintf (stream, ",");
8159     }
8160   if (t.level2_size << t.q > 8)
8161     fprintf (stream, "\n ");
8162   fprintf (stream, " },\n");
8163   fprintf (stream, "  {");
8164   if (t.level3_size << t.p > 8)
8165     fprintf (stream, "\n   ");
8166   for (i = 0; i < t.level3_size << t.p; i++)
8167     {
8168       if (i > 0 && (i % 8) == 0)
8169         fprintf (stream, "\n   ");
8170       fprintf (stream, " %5d", ((int32_t *) (t.result + level3_offset))[i]);
8171       if (i+1 < t.level3_size << t.p)
8172         fprintf (stream, ",");
8173     }
8174   if (t.level3_size << t.p > 8)
8175     fprintf (stream, "\n ");
8176   fprintf (stream, " }\n");
8177   fprintf (stream, "};\n");
8178
8179   if (ferror (stream) || fclose (stream))
8180     {
8181       fprintf (stderr, "error writing to '%s'\n", filename);
8182       exit (1);
8183     }
8184 }
8185
8186 /* ========================================================================= */
8187
8188 /* A special casing context.
8189    A context is negated through x -> -x.  */
8190 enum
8191 {
8192   SCC_ALWAYS             = 0,
8193   SCC_FINAL_SIGMA,
8194   SCC_AFTER_SOFT_DOTTED,
8195   SCC_MORE_ABOVE,
8196   SCC_BEFORE_DOT,
8197   SCC_AFTER_I
8198 };
8199
8200 /* A special casing rule.  */
8201 struct special_casing_rule
8202 {
8203   unsigned int code;
8204   unsigned int lower_mapping[3];
8205   unsigned int title_mapping[3];
8206   unsigned int upper_mapping[3];
8207   unsigned int casefold_mapping[3];
8208   const char *language;
8209   int context;
8210 };
8211
8212 /* The special casing rules.  */
8213 struct special_casing_rule **casing_rules;
8214 unsigned int num_casing_rules;
8215 unsigned int allocated_casing_rules;
8216
8217 static void
8218 add_casing_rule (struct special_casing_rule *new_rule)
8219 {
8220   if (num_casing_rules == allocated_casing_rules)
8221     {
8222       allocated_casing_rules = 2 * allocated_casing_rules;
8223       if (allocated_casing_rules < 16)
8224         allocated_casing_rules = 16;
8225       casing_rules =
8226         (struct special_casing_rule **)
8227         realloc (casing_rules, allocated_casing_rules * sizeof (struct special_casing_rule *));
8228     }
8229   casing_rules[num_casing_rules++] = new_rule;
8230 }
8231
8232 /* Stores in casing_rules the special casing rules found in
8233    specialcasing_filename.  */
8234 static void
8235 fill_casing_rules (const char *specialcasing_filename)
8236 {
8237   FILE *stream;
8238
8239   stream = fopen (specialcasing_filename, "r");
8240   if (stream == NULL)
8241     {
8242       fprintf (stderr, "error during fopen of '%s'\n", specialcasing_filename);
8243       exit (1);
8244     }
8245
8246   casing_rules = NULL;
8247   num_casing_rules = 0;
8248   allocated_casing_rules = 0;
8249
8250   for (;;)
8251     {
8252       char buf[200+1];
8253       char *scanptr;
8254       char *endptr;
8255       int i;
8256
8257       unsigned int code;
8258       unsigned int lower_mapping[3];
8259       unsigned int title_mapping[3];
8260       unsigned int upper_mapping[3];
8261       char *language;
8262       int context;
8263
8264       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
8265         break;
8266
8267       if (buf[0] == '\0' || buf[0] == '#')
8268         continue;
8269
8270       /* Scan code.  */
8271       scanptr = buf;
8272       code = strtoul (scanptr, &endptr, 16);
8273       if (endptr == scanptr)
8274         {
8275           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8276           exit (1);
8277         }
8278       scanptr = endptr;
8279       if (*scanptr != ';')
8280         {
8281           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8282           exit (1);
8283         }
8284       scanptr++;
8285
8286       /* Scan lower mapping.  */
8287       for (i = 0; i < 3; i++)
8288         lower_mapping[i] = 0;
8289       for (i = 0; i < 3; i++)
8290         {
8291           while (*scanptr == ' ')
8292             scanptr++;
8293           if (*scanptr == ';')
8294             break;
8295           lower_mapping[i] = strtoul (scanptr, &endptr, 16);
8296           if (endptr == scanptr)
8297             {
8298               fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8299               exit (1);
8300             }
8301           scanptr = endptr;
8302         }
8303       if (*scanptr != ';')
8304         {
8305           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8306           exit (1);
8307         }
8308       scanptr++;
8309
8310       /* Scan title mapping.  */
8311       for (i = 0; i < 3; i++)
8312         title_mapping[i] = 0;
8313       for (i = 0; i < 3; i++)
8314         {
8315           while (*scanptr == ' ')
8316             scanptr++;
8317           if (*scanptr == ';')
8318             break;
8319           title_mapping[i] = strtoul (scanptr, &endptr, 16);
8320           if (endptr == scanptr)
8321             {
8322               fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8323               exit (1);
8324             }
8325           scanptr = endptr;
8326         }
8327       if (*scanptr != ';')
8328         {
8329           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8330           exit (1);
8331         }
8332       scanptr++;
8333
8334       /* Scan upper mapping.  */
8335       for (i = 0; i < 3; i++)
8336         upper_mapping[i] = 0;
8337       for (i = 0; i < 3; i++)
8338         {
8339           while (*scanptr == ' ')
8340             scanptr++;
8341           if (*scanptr == ';')
8342             break;
8343           upper_mapping[i] = strtoul (scanptr, &endptr, 16);
8344           if (endptr == scanptr)
8345             {
8346               fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8347               exit (1);
8348             }
8349           scanptr = endptr;
8350         }
8351       if (*scanptr != ';')
8352         {
8353           fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8354           exit (1);
8355         }
8356       scanptr++;
8357
8358       /* Scan language and context.  */
8359       language = NULL;
8360       context = SCC_ALWAYS;
8361       while (*scanptr == ' ')
8362         scanptr++;
8363       if (*scanptr != '\0' && *scanptr != '#')
8364         {
8365           const char *word_begin = scanptr;
8366           const char *word_end;
8367
8368           while (*scanptr != '\0' && *scanptr != '#' && *scanptr != ';' && *scanptr != ' ')
8369             scanptr++;
8370           word_end = scanptr;
8371
8372           while (*scanptr == ' ')
8373             scanptr++;
8374
8375           if (word_end - word_begin == 2)
8376             {
8377               language = (char *) malloc ((word_end - word_begin) + 1);
8378               memcpy (language, word_begin, 2);
8379               language[word_end - word_begin] = '\0';
8380               word_begin = word_end = NULL;
8381
8382               if (*scanptr != '\0' && *scanptr != '#' &&  *scanptr != ';')
8383                 {
8384                   word_begin = scanptr;
8385                   while (*scanptr != '\0' && *scanptr != '#' && *scanptr != ';' && *scanptr != ' ')
8386                     scanptr++;
8387                   word_end = scanptr;
8388                 }
8389             }
8390
8391           if (word_end > word_begin)
8392             {
8393               bool negate = false;
8394
8395               if (word_end - word_begin >= 4 && memcmp (word_begin, "Not_", 4) == 0)
8396                 {
8397                   word_begin += 4;
8398                   negate = true;
8399                 }
8400               if (word_end - word_begin == 11 && memcmp (word_begin, "Final_Sigma", 11) == 0)
8401                 context = SCC_FINAL_SIGMA;
8402               else if (word_end - word_begin == 17 && memcmp (word_begin, "After_Soft_Dotted", 17) == 0)
8403                 context = SCC_AFTER_SOFT_DOTTED;
8404               else if (word_end - word_begin == 10 && memcmp (word_begin, "More_Above", 10) == 0)
8405                 context = SCC_MORE_ABOVE;
8406               else if (word_end - word_begin == 10 && memcmp (word_begin, "Before_Dot", 10) == 0)
8407                 context = SCC_BEFORE_DOT;
8408               else if (word_end - word_begin == 7 && memcmp (word_begin, "After_I", 7) == 0)
8409                 context = SCC_AFTER_I;
8410               else
8411                 {
8412                   fprintf (stderr, "unknown context type in '%s'\n", specialcasing_filename);
8413                   exit (1);
8414                 }
8415               if (negate)
8416                 context = - context;
8417             }
8418
8419           if (*scanptr != '\0' && *scanptr != '#' &&  *scanptr != ';')
8420             {
8421               fprintf (stderr, "parse error in '%s'\n", specialcasing_filename);
8422               exit (1);
8423             }
8424         }
8425
8426       /* Store the rule.  */
8427       {
8428         struct special_casing_rule *new_rule =
8429           (struct special_casing_rule *) malloc (sizeof (struct special_casing_rule));
8430         new_rule->code = code;
8431         new_rule->language = language;
8432         new_rule->context = context;
8433         memcpy (new_rule->lower_mapping, lower_mapping, sizeof (new_rule->lower_mapping));
8434         memcpy (new_rule->title_mapping, title_mapping, sizeof (new_rule->title_mapping));
8435         memcpy (new_rule->upper_mapping, upper_mapping, sizeof (new_rule->upper_mapping));
8436
8437         add_casing_rule (new_rule);
8438       }
8439     }
8440
8441   if (ferror (stream) || fclose (stream))
8442     {
8443       fprintf (stderr, "error reading from '%s'\n", specialcasing_filename);
8444       exit (1);
8445     }
8446 }
8447
8448 /* A casefolding rule.  */
8449 struct casefold_rule
8450 {
8451   unsigned int code;
8452   unsigned int mapping[3];
8453   const char *language;
8454 };
8455
8456 /* The casefolding rules.  */
8457 struct casefold_rule **casefolding_rules;
8458 unsigned int num_casefolding_rules;
8459 unsigned int allocated_casefolding_rules;
8460
8461 /* Stores in casefolding_rules the case folding rules found in
8462    casefolding_filename.  */
8463 static void
8464 fill_casefolding_rules (const char *casefolding_filename)
8465 {
8466   FILE *stream;
8467
8468   stream = fopen (casefolding_filename, "r");
8469   if (stream == NULL)
8470     {
8471       fprintf (stderr, "error during fopen of '%s'\n", casefolding_filename);
8472       exit (1);
8473     }
8474
8475   casefolding_rules = NULL;
8476   num_casefolding_rules = 0;
8477   allocated_casefolding_rules = 0;
8478
8479   for (;;)
8480     {
8481       char buf[200+1];
8482       char *scanptr;
8483       char *endptr;
8484       int i;
8485
8486       unsigned int code;
8487       char type;
8488       unsigned int mapping[3];
8489
8490       if (fscanf (stream, "%200[^\n]\n", buf) < 1)
8491         break;
8492
8493       if (buf[0] == '\0' || buf[0] == '#')
8494         continue;
8495
8496       /* Scan code.  */
8497       scanptr = buf;
8498       code = strtoul (scanptr, &endptr, 16);
8499       if (endptr == scanptr)
8500         {
8501           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8502           exit (1);
8503         }
8504       scanptr = endptr;
8505       if (*scanptr != ';')
8506         {
8507           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8508           exit (1);
8509         }
8510       scanptr++;
8511
8512       /* Scan type.  */
8513       while (*scanptr == ' ')
8514         scanptr++;
8515
8516       switch (*scanptr)
8517         {
8518         case 'C': case 'F': case 'S': case 'T':
8519           type = *scanptr;
8520           break;
8521         default:
8522           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8523           exit (1);
8524         }
8525       scanptr++;
8526       if (*scanptr != ';')
8527         {
8528           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8529           exit (1);
8530         }
8531       scanptr++;
8532
8533       /* Scan casefold mapping.  */
8534       for (i = 0; i < 3; i++)
8535         mapping[i] = 0;
8536       for (i = 0; i < 3; i++)
8537         {
8538           while (*scanptr == ' ')
8539             scanptr++;
8540           if (*scanptr == ';')
8541             break;
8542           mapping[i] = strtoul (scanptr, &endptr, 16);
8543           if (endptr == scanptr)
8544             {
8545               fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8546               exit (1);
8547             }
8548           scanptr = endptr;
8549         }
8550       if (*scanptr != ';')
8551         {
8552           fprintf (stderr, "parse error in '%s'\n", casefolding_filename);
8553           exit (1);
8554         }
8555       scanptr++;
8556
8557       /* Ignore rules of type 'S'; we use the rules of type 'F' instead.  */
8558       if (type != 'S')
8559         {
8560           const char * const *languages;
8561           unsigned int languages_count;
8562
8563           /* Type 'T' indicates that the rule is applicable to Turkish
8564              languages only.  */
8565           if (type == 'T')
8566             {
8567               static const char * const turkish_languages[] = { "tr", "az" };
8568               languages = turkish_languages;
8569               languages_count = 2;
8570             }
8571           else
8572             {
8573               static const char * const all_languages[] = { NULL };
8574               languages = all_languages;
8575               languages_count = 1;
8576             }
8577
8578           for (i = 0; i < languages_count; i++)
8579             {
8580               /* Store a new rule.  */
8581               struct casefold_rule *new_rule =
8582                 (struct casefold_rule *) malloc (sizeof (struct casefold_rule));
8583               new_rule->code = code;
8584               memcpy (new_rule->mapping, mapping, sizeof (new_rule->mapping));
8585               new_rule->language = languages[i];
8586
8587               if (num_casefolding_rules == allocated_casefolding_rules)
8588                 {
8589                   allocated_casefolding_rules = 2 * allocated_casefolding_rules;
8590                   if (allocated_casefolding_rules < 16)
8591                     allocated_casefolding_rules = 16;
8592                   casefolding_rules =
8593                     (struct casefold_rule **)
8594                     realloc (casefolding_rules,
8595                              allocated_casefolding_rules * sizeof (struct casefold_rule *));
8596                 }
8597               casefolding_rules[num_casefolding_rules++] = new_rule;
8598             }
8599         }
8600     }
8601
8602   if (ferror (stream) || fclose (stream))
8603     {
8604       fprintf (stderr, "error reading from '%s'\n", casefolding_filename);
8605       exit (1);
8606     }
8607 }
8608
8609 /* Casefold mapping, when it maps to a single character.  */
8610 unsigned int unicode_casefold[0x110000];
8611
8612 static unsigned int
8613 to_casefold (unsigned int ch)
8614 {
8615   return unicode_casefold[ch];
8616 }
8617
8618 /* Redistribute the casefolding_rules:
8619    - Rules that map to a single character, language independently, are stored
8620      in unicode_casefold.
8621    - Other rules are merged into casing_rules.  */
8622 static void
8623 redistribute_casefolding_rules (void)
8624 {
8625   unsigned int ch, i, j;
8626
8627   /* Fill unicode_casefold[].  */
8628   for (ch = 0; ch < 0x110000; ch++)
8629     unicode_casefold[ch] = ch;
8630   for (i = 0; i < num_casefolding_rules; i++)
8631     {
8632       struct casefold_rule *cfrule = casefolding_rules[i];
8633
8634       if (cfrule->language == NULL && cfrule->mapping[1] == 0)
8635         {
8636           ch = cfrule->code;
8637           if (!(ch < 0x110000))
8638             abort ();
8639           unicode_casefold[ch] = cfrule->mapping[0];
8640         }
8641     }
8642
8643   /* Extend the special casing rules by filling in their casefold_mapping[]
8644      field.  */
8645   for (j = 0; j < num_casing_rules; j++)
8646     {
8647       struct special_casing_rule *rule = casing_rules[j];
8648       unsigned int k;
8649
8650       rule->casefold_mapping[0] = to_casefold (rule->code);
8651       for (k = 1; k < 3; k++)
8652         rule->casefold_mapping[k] = 0;
8653     }
8654
8655   /* Now merge the other casefolding rules into casing_rules.  */
8656   for (i = 0; i < num_casefolding_rules; i++)
8657     {
8658       struct casefold_rule *cfrule = casefolding_rules[i];
8659
8660       if (!(cfrule->language == NULL && cfrule->mapping[1] == 0))
8661         {
8662           /* Find a rule that applies to the same code, same language, and it
8663              has context SCC_ALWAYS.  At the same time, update all rules that
8664              have the same code and same or more specific language.  */
8665           struct special_casing_rule *found_rule = NULL;
8666
8667           for (j = 0; j < num_casing_rules; j++)
8668             {
8669               struct special_casing_rule *rule = casing_rules[j];
8670
8671               if (rule->code == cfrule->code
8672                   && (cfrule->language == NULL
8673                       || (rule->language != NULL
8674                           && strcmp (rule->language, cfrule->language) == 0)))
8675                 {
8676                   memcpy (rule->casefold_mapping, cfrule->mapping,
8677                           sizeof (rule->casefold_mapping));
8678
8679                   if ((cfrule->language == NULL
8680                        ? rule->language == NULL
8681                        : rule->language != NULL
8682                          && strcmp (rule->language, cfrule->language) == 0)
8683                       && rule->context == SCC_ALWAYS)
8684                     {
8685                       /* Found it.  */
8686                       found_rule = rule;
8687                     }
8688                 }
8689             }
8690
8691           if (found_rule == NULL)
8692             {
8693               /* Create a new rule.  */
8694               struct special_casing_rule *new_rule =
8695                 (struct special_casing_rule *) malloc (sizeof (struct special_casing_rule));
8696
8697               /* Try to find a rule that applies to the same code, no language
8698                  restriction, and with context SCC_ALWAYS.  */
8699               for (j = 0; j < num_casing_rules; j++)
8700                 {
8701                   struct special_casing_rule *rule = casing_rules[j];
8702
8703                   if (rule->code == cfrule->code
8704                       && rule->context == SCC_ALWAYS
8705                       && rule->language == NULL)
8706                     {
8707                       /* Found it.  */
8708                       found_rule = rule;
8709                       break;
8710                     }
8711                 }
8712
8713               new_rule->code = cfrule->code;
8714               new_rule->language = cfrule->language;
8715               new_rule->context = SCC_ALWAYS;
8716               if (found_rule != NULL)
8717                 {
8718                   memcpy (new_rule->lower_mapping, found_rule->lower_mapping,
8719                           sizeof (new_rule->lower_mapping));
8720                   memcpy (new_rule->title_mapping, found_rule->title_mapping,
8721                           sizeof (new_rule->title_mapping));
8722                   memcpy (new_rule->upper_mapping, found_rule->upper_mapping,
8723                           sizeof (new_rule->upper_mapping));
8724                 }
8725               else
8726                 {
8727                   unsigned int k;
8728
8729                   new_rule->lower_mapping[0] = to_lower (cfrule->code);
8730                   for (k = 1; k < 3; k++)
8731                     new_rule->lower_mapping[k] = 0;
8732                   new_rule->title_mapping[0] = to_title (cfrule->code);
8733                   for (k = 1; k < 3; k++)
8734                     new_rule->title_mapping[k] = 0;
8735                   new_rule->upper_mapping[0] = to_upper (cfrule->code);
8736                   for (k = 1; k < 3; k++)
8737                     new_rule->upper_mapping[k] = 0;
8738                 }
8739               memcpy (new_rule->casefold_mapping, cfrule->mapping,
8740                       sizeof (new_rule->casefold_mapping));
8741
8742               add_casing_rule (new_rule);
8743             }
8744         }
8745     }
8746 }
8747
8748 static int
8749 compare_casing_rules (const void *a, const void *b)
8750 {
8751   struct special_casing_rule *a_rule = *(struct special_casing_rule **) a;
8752   struct special_casing_rule *b_rule = *(struct special_casing_rule **) b;
8753   unsigned int a_code = a_rule->code;
8754   unsigned int b_code = b_rule->code;
8755
8756   if (a_code < b_code)
8757     return -1;
8758   if (a_code > b_code)
8759     return 1;
8760
8761   /* Sort the more specific rules before the more general ones.  */
8762   return (- ((a_rule->language != NULL ? 1 : 0) + (a_rule->context != SCC_ALWAYS ? 1 : 0))
8763           + ((b_rule->language != NULL ? 1 : 0) + (b_rule->context != SCC_ALWAYS ? 1 : 0)));
8764 }
8765
8766 static void
8767 sort_casing_rules (void)
8768 {
8769   /* Sort the rules 1. by code, 2. by specificity.  */
8770   if (num_casing_rules > 1)
8771     qsort (casing_rules, num_casing_rules, sizeof (struct special_casing_rule *),
8772            compare_casing_rules);
8773 }
8774
8775 /* Output the special casing rules.  */
8776 static void
8777 output_casing_rules (const char *filename, const char *version)
8778 {
8779   FILE *stream;
8780   unsigned int i, j;
8781   unsigned int minor;
8782
8783   stream = fopen (filename, "w");
8784   if (stream == NULL)
8785     {
8786       fprintf (stderr, "cannot open '%s' for writing\n", filename);
8787       exit (1);
8788     }
8789
8790   fprintf (stream, "/* DO NOT EDIT! GENERATED AUTOMATICALLY! */\n");
8791   fprintf (stream, "/* Special casing rules of Unicode characters.  */\n");
8792   fprintf (stream, "/* Generated automatically by gen-uni-tables.c for Unicode %s.  */\n",
8793            version);
8794   fprintf (stream, "struct special_casing_rule { char code[3]; };\n");
8795   fprintf (stream, "%%struct-type\n");
8796   fprintf (stream, "%%language=ANSI-C\n");
8797   fprintf (stream, "%%define slot-name code\n");
8798   fprintf (stream, "%%define hash-function-name gl_unicase_special_hash\n");
8799   fprintf (stream, "%%define lookup-function-name gl_unicase_special_lookup\n");
8800   fprintf (stream, "%%compare-lengths\n");
8801   fprintf (stream, "%%compare-strncmp\n");
8802   fprintf (stream, "%%readonly-tables\n");
8803   fprintf (stream, "%%omit-struct-type\n");
8804   fprintf (stream, "%%%%\n");
8805
8806   minor = 0;
8807   for (i = 0; i < num_casing_rules; i++)
8808     {
8809       struct special_casing_rule *rule = casing_rules[i];
8810       int context;
8811
8812       if (i > 0 && rule->code == casing_rules[i - 1]->code)
8813         minor += 1;
8814       else
8815         minor = 0;
8816
8817       if (!(rule->code < 0x10000))
8818         {
8819           fprintf (stderr, "special rule #%u: code %u out of range\n", i, rule->code);
8820           exit (1);
8821         }
8822
8823       fprintf (stream, "\"\\x%02x\\x%02x\\x%02x\", ",
8824                (rule->code >> 8) & 0xff, rule->code & 0xff, minor);
8825
8826       fprintf (stream, "%d, ",
8827                i + 1 < num_casing_rules && casing_rules[i + 1]->code == rule->code ? 1 : 0);
8828
8829       context = rule->context;
8830       if (context < 0)
8831         {
8832           fprintf (stream, "-");
8833           context = - context;
8834         }
8835       else
8836         fprintf (stream, " ");
8837       switch (context)
8838         {
8839         case SCC_ALWAYS:
8840           fprintf (stream, "SCC_ALWAYS           ");
8841           break;
8842         case SCC_FINAL_SIGMA:
8843           fprintf (stream, "SCC_FINAL_SIGMA      ");
8844           break;
8845         case SCC_AFTER_SOFT_DOTTED:
8846           fprintf (stream, "SCC_AFTER_SOFT_DOTTED");
8847           break;
8848         case SCC_MORE_ABOVE:
8849           fprintf (stream, "SCC_MORE_ABOVE       ");
8850           break;
8851         case SCC_BEFORE_DOT:
8852           fprintf (stream, "SCC_BEFORE_DOT       ");
8853           break;
8854         case SCC_AFTER_I:
8855           fprintf (stream, "SCC_AFTER_I          ");
8856           break;
8857         default:
8858           abort ();
8859         }
8860       fprintf (stream, ", ");
8861
8862       if (rule->language != NULL)
8863         {
8864           if (strlen (rule->language) != 2)
8865             abort ();
8866           fprintf (stream, "{  '%c',  '%c' }, ", rule->language[0], rule->language[1]);
8867         }
8868       else
8869         fprintf (stream, "{ '\\0', '\\0' }, ");
8870
8871       fprintf (stream, "{ ");
8872       for (j = 0; j < 3; j++)
8873         {
8874           if (j > 0)
8875             fprintf (stream, ", ");
8876           if (!(rule->upper_mapping[j] < 0x10000))
8877             {
8878               fprintf (stderr, "special rule #%u: upper mapping of code %u out of range\n", i, rule->code);
8879               exit (1);
8880             }
8881           if (rule->upper_mapping[j] != 0)
8882             fprintf (stream, "0x%04X", rule->upper_mapping[j]);
8883           else
8884             fprintf (stream, "     0");
8885         }
8886       fprintf (stream, " }, { ");
8887       for (j = 0; j < 3; j++)
8888         {
8889           if (j > 0)
8890             fprintf (stream, ", ");
8891           if (!(rule->lower_mapping[j] < 0x10000))
8892             {
8893               fprintf (stderr, "special rule #%u: lower mapping of code %u out of range\n", i, rule->code);
8894               exit (1);
8895             }
8896           if (rule->lower_mapping[j] != 0)
8897             fprintf (stream, "0x%04X", rule->lower_mapping[j]);
8898           else
8899             fprintf (stream, "     0");
8900         }
8901       fprintf (stream, " }, { ");
8902       for (j = 0; j < 3; j++)
8903         {
8904           if (j > 0)
8905             fprintf (stream, ", ");
8906           if (!(rule->title_mapping[j] < 0x10000))
8907             {
8908               fprintf (stderr, "special rule #%u: title mapping of code %u out of range\n", i, rule->code);
8909               exit (1);
8910             }
8911           if (rule->title_mapping[j] != 0)
8912             fprintf (stream, "0x%04X", rule->title_mapping[j]);
8913           else
8914             fprintf (stream, "     0");
8915         }
8916       fprintf (stream, " }, { ");
8917       for (j = 0; j < 3; j++)
8918         {
8919           if (j > 0)
8920             fprintf (stream, ", ");
8921           if (!(rule->casefold_mapping[j] < 0x10000))
8922             {
8923               fprintf (stderr, "special rule #%u: casefold mapping of code %u out of range\n", i, rule->code);
8924               exit (1);
8925             }
8926           if (rule->casefold_mapping[j] != 0)
8927             fprintf (stream, "0x%04X", rule->casefold_mapping[j]);
8928           else
8929             fprintf (stream, "     0");
8930         }
8931       fprintf (stream, " }\n");
8932     }
8933
8934   if (ferror (stream) || fclose (stream))
8935     {
8936       fprintf (stderr, "error writing to '%s'\n", filename);
8937       exit (1);
8938     }
8939 }
8940
8941 /* ========================================================================= */
8942
8943 /* Quoting the Unicode standard:
8944      Definition: A character is defined to be "cased" if it has the Lowercase
8945      or Uppercase property or has a General_Category value of
8946      Titlecase_Letter.  */
8947 static bool
8948 is_cased (unsigned int ch)
8949 {
8950   return (is_property_lowercase (ch)
8951           || is_property_uppercase (ch)
8952           || is_category_Lt (ch));
8953 }
8954
8955 /* Quoting the Unicode standard:
8956      Definition: A character is defined to be "case-ignorable" if it has the
8957      value MidLetter {or the value MidNumLet} for the Word_Break property or
8958      its General_Category is one of Nonspacing_Mark (Mn), Enclosing_Mark (Me),
8959      Format (Cf), Modifier_Letter (Lm), or Modifier_Symbol (Sk).
8960    The text marked in braces was added in Unicode 5.1.0, see
8961    <http://www.unicode.org/versions/Unicode5.1.0/> section "Update of
8962    Definition of case-ignorable".   */
8963 /* Since this predicate is only used for the "Before C" and "After C"
8964    conditions of FINAL_SIGMA, we exclude the "cased" characters here.
8965    This simplifies the evaluation of the regular expressions
8966      \p{cased} (\p{case-ignorable})* C
8967    and
8968      C (\p{case-ignorable})* \p{cased}
8969  */
8970 static bool
8971 is_case_ignorable (unsigned int ch)
8972 {
8973   return (unicode_org_wbp[ch] == WBP_MIDLETTER
8974           || unicode_org_wbp[ch] == WBP_MIDNUMLET
8975           || is_category_Mn (ch)
8976           || is_category_Me (ch)
8977           || is_category_Cf (ch)
8978           || is_category_Lm (ch)
8979           || is_category_Sk (ch))
8980          && !is_cased (ch);
8981 }
8982
8983 /* ------------------------------------------------------------------------- */
8984
8985 /* Output all case related properties.  */
8986 static void
8987 output_casing_properties (const char *version)
8988 {
8989 #define PROPERTY(FN,P) \
8990   debug_output_predicate ("unicase/" #FN ".txt", is_ ## P); \
8991   output_predicate_test ("../tests/unicase/test-" #FN ".c", is_ ## P, "uc_is_" #P " (c)"); \
8992   output_predicate ("unicase/" #FN ".h", is_ ## P, "u_casing_property_" #P, "Casing Properties", version);
8993   PROPERTY(cased, cased)
8994   PROPERTY(ignorable, case_ignorable)
8995 #undef PROPERTY
8996 }
8997
8998 /* ========================================================================= */
8999
9000 int
9001 main (int argc, char * argv[])
9002 {
9003   const char *unicodedata_filename;
9004   const char *proplist_filename;
9005   const char *derivedproplist_filename;
9006   const char *scripts_filename;
9007   const char *blocks_filename;
9008   const char *proplist30_filename;
9009   const char *eastasianwidth_filename;
9010   const char *linebreak_filename;
9011   const char *wordbreakproperty_filename;
9012   const char *graphemebreakproperty_filename;
9013   const char *compositionexclusions_filename;
9014   const char *specialcasing_filename;
9015   const char *casefolding_filename;
9016   const char *version;
9017
9018   if (argc != 15)
9019     {
9020       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",
9021                argv[0]);
9022       exit (1);
9023     }
9024
9025   unicodedata_filename = argv[1];
9026   proplist_filename = argv[2];
9027   derivedproplist_filename = argv[3];
9028   scripts_filename = argv[4];
9029   blocks_filename = argv[5];
9030   proplist30_filename = argv[6];
9031   eastasianwidth_filename = argv[7];
9032   linebreak_filename = argv[8];
9033   wordbreakproperty_filename = argv[9];
9034   graphemebreakproperty_filename = argv[10];
9035   compositionexclusions_filename = argv[11];
9036   specialcasing_filename = argv[12];
9037   casefolding_filename = argv[13];
9038   version = argv[14];
9039
9040   fill_attributes (unicodedata_filename);
9041   clear_properties ();
9042   fill_properties (proplist_filename);
9043   fill_properties (derivedproplist_filename);
9044   fill_properties30 (proplist30_filename);
9045   fill_scripts (scripts_filename);
9046   fill_blocks (blocks_filename);
9047   fill_width (eastasianwidth_filename);
9048   fill_org_lbp (linebreak_filename);
9049   fill_org_wbp (wordbreakproperty_filename);
9050   fill_org_gbp (graphemebreakproperty_filename);
9051   fill_composition_exclusions (compositionexclusions_filename);
9052   fill_casing_rules (specialcasing_filename);
9053   fill_casefolding_rules (casefolding_filename);
9054   redistribute_casefolding_rules ();
9055   sort_casing_rules ();
9056
9057   output_categories (version);
9058   output_category ("unictype/categ_of.h", version);
9059   output_combclass ("unictype/combining.h", version);
9060   output_bidi_category ("unictype/bidi_of.h", version);
9061   output_decimal_digit_test ("../tests/unictype/test-decdigit.h", version);
9062   output_decimal_digit ("unictype/decdigit.h", version);
9063   output_digit_test ("../tests/unictype/test-digit.h", version);
9064   output_digit ("unictype/digit.h", version);
9065   output_numeric_test ("../tests/unictype/test-numeric.h", version);
9066   output_numeric ("unictype/numeric.h", version);
9067   output_mirror ("unictype/mirror.h", version);
9068   output_properties (version);
9069   output_scripts (version);
9070   output_scripts_byname (version);
9071   output_blocks (version);
9072   output_ident_properties (version);
9073   output_nonspacing_property ("uniwidth/width.c.part");
9074   output_width_property_test ("../tests/uniwidth/test-uc_width2.sh.part");
9075   output_old_ctype (version);
9076
9077   debug_output_lbrk_tables ("unilbrk/lbrkprop.txt");
9078   debug_output_org_lbrk_tables ("unilbrk/lbrkprop_org.txt");
9079   output_lbrk_tables ("unilbrk/lbrkprop1.h", "unilbrk/lbrkprop2.h", version);
9080
9081   debug_output_wbrk_tables ("uniwbrk/wbrkprop.txt");
9082   debug_output_org_wbrk_tables ("uniwbrk/wbrkprop_org.txt");
9083   output_wbrk_tables ("uniwbrk/wbrkprop.h", version);
9084
9085   output_gbp_test ("../tests/unigbrk/test-uc-gbrk-prop.h");
9086   output_gbp_table ("unigbrk/gbrkprop.h", version);
9087
9088   output_decomposition_tables ("uninorm/decomposition-table1.h", "uninorm/decomposition-table2.h", version);
9089   debug_output_composition_tables ("uninorm/composition.txt");
9090   output_composition_tables ("uninorm/composition-table.gperf", version);
9091
9092   output_simple_mapping_test ("../tests/unicase/test-uc_toupper.c", "uc_toupper", to_upper, version);
9093   output_simple_mapping_test ("../tests/unicase/test-uc_tolower.c", "uc_tolower", to_lower, version);
9094   output_simple_mapping_test ("../tests/unicase/test-uc_totitle.c", "uc_totitle", to_title, version);
9095   output_simple_mapping ("unicase/toupper.h", to_upper, version);
9096   output_simple_mapping ("unicase/tolower.h", to_lower, version);
9097   output_simple_mapping ("unicase/totitle.h", to_title, version);
9098   output_simple_mapping ("unicase/tocasefold.h", to_casefold, version);
9099   output_casing_rules ("unicase/special-casing-table.gperf", version);
9100   output_casing_properties (version);
9101
9102   return 0;
9103 }
9104
9105 /*
9106  * For Emacs M-x compile
9107  * Local Variables:
9108  * compile-command: "
9109    gcc -O -Wall gen-uni-tables.c -Iunictype -o gen-uni-tables && \
9110    ./gen-uni-tables \
9111         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/UnicodeData.txt \
9112         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/PropList.txt \
9113         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/DerivedCoreProperties.txt \
9114         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/Scripts.txt \
9115         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/Blocks.txt \
9116         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/3.0.1/PropList-3.0.1.txt \
9117         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/EastAsianWidth.txt \
9118         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/LineBreak.txt \
9119         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/auxiliary/WordBreakProperty.txt \
9120         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/auxiliary/GraphemeBreakProperty.txt \
9121         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/CompositionExclusions.txt \
9122         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/SpecialCasing.txt \
9123         /gfs/petix/Volumes/ExtData/www-archive/software/i18n/unicode/ftp.unicode.org/ArchiveVersions/5.2.0/ucd/CaseFolding.txt \
9124         5.2.0 \
9125    && diff unilbrk/lbrkprop_org.txt unilbrk/lbrkprop.txt \
9126    && diff uniwbrk/wbrkprop_org.txt uniwbrk/wbrkprop.txt
9127    "
9128  * End:
9129  */