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