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