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