quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

unicode_gen.c (105279B)


      1 /*
      2  * Generation of Unicode tables
      3  *
      4  * Copyright (c) 2017-2018 Fabrice Bellard
      5  * Copyright (c) 2017-2018 Charlie Gordon
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     23  * THE SOFTWARE.
     24  */
     25 #include <stdlib.h>
     26 #include <stdio.h>
     27 #include <stdarg.h>
     28 #include <inttypes.h>
     29 #include <string.h>
     30 #include <assert.h>
     31 #include <ctype.h>
     32 #include <time.h>
     33 
     34 #include "cutils.h"
     35 
     36 uint32_t total_tables;
     37 uint32_t total_table_bytes;
     38 uint32_t total_index;
     39 uint32_t total_index_bytes;
     40 
     41 /* define it to be able to test unicode.c */
     42 //#define USE_TEST
     43 /* profile tests */
     44 //#define PROFILE
     45 
     46 //#define DUMP_CASE_CONV_TABLE
     47 //#define DUMP_TABLE_SIZE
     48 //#define DUMP_CC_TABLE
     49 //#define DUMP_DECOMP_TABLE
     50 //#define DUMP_CASE_FOLDING_SPECIAL_CASES
     51 
     52 /* Ideas:
     53    - Generalize run length encoding + index for all tables
     54    - remove redundant tables for ID_start, ID_continue, Case_Ignorable, Cased
     55 
     56    Case conversion:
     57    - use a single entry for consecutive U/LF runs
     58    - allow EXT runs of length > 1
     59 
     60    Decomposition:
     61    - Greek lower case (+1f10/1f10) ?
     62    - allow holes in B runs
     63    - suppress more upper / lower case redundancy
     64 */
     65 
     66 #ifdef USE_TEST
     67 #include "libunicode.c"
     68 #endif
     69 
     70 #define CHARCODE_MAX 0x10ffff
     71 #define CC_LEN_MAX 3
     72 
     73 void *mallocz(size_t size)
     74 {
     75     void *ptr;
     76     ptr = malloc(size);
     77     memset(ptr, 0, size);
     78     return ptr;
     79 }
     80 
     81 const char *get_field(const char *p, int n)
     82 {
     83     int i;
     84     for(i = 0; i < n; i++) {
     85         while (*p != ';' && *p != '\0')
     86             p++;
     87         if (*p == '\0')
     88             return NULL;
     89         p++;
     90     }
     91     return p;
     92 }
     93 
     94 const char *get_field_buf(char *buf, size_t buf_size, const char *p, int n)
     95 {
     96     char *q;
     97     p = get_field(p, n);
     98     q = buf;
     99     while (*p != ';' && *p != '\0') {
    100         if ((q - buf) < buf_size - 1)
    101             *q++ = *p;
    102         p++;
    103     }
    104     *q = '\0';
    105     return buf;
    106 }
    107 
    108 void add_char(int **pbuf, int *psize, int *plen, int c)
    109 {
    110     int len, size, *buf;
    111     buf = *pbuf;
    112     size = *psize;
    113     len = *plen;
    114     if (len >= size) {
    115         size = *psize;
    116         size = max_int(len + 1, size * 3 / 2);
    117         buf = realloc(buf, sizeof(buf[0]) * size);
    118         *pbuf = buf;
    119         *psize = size;
    120     }
    121     buf[len++] = c;
    122     *plen = len;
    123 }
    124 
    125 int *get_field_str(int *plen, const char *str, int n)
    126 {
    127     const char *p;
    128     int *buf, len, size;
    129     p = get_field(str, n);
    130     if (!p) {
    131         *plen = 0;
    132         return NULL;
    133     }
    134     len = 0;
    135     size = 0;
    136     buf = NULL;
    137     for(;;) {
    138         while (isspace(*p))
    139             p++;
    140         if (!isxdigit(*p))
    141             break;
    142         add_char(&buf, &size, &len, strtoul(p, (char **)&p, 16));
    143     }
    144     *plen = len;
    145     return buf;
    146 }
    147 
    148 char *get_line(char *buf, int buf_size, FILE *f)
    149 {
    150     int len;
    151     if (!fgets(buf, buf_size, f))
    152         return NULL;
    153     len = strlen(buf);
    154     if (len > 0 && buf[len - 1] == '\n')
    155         buf[len - 1] = '\0';
    156     return buf;
    157 }
    158 
    159 typedef struct REString {
    160     struct REString *next;
    161     uint32_t hash;
    162     uint32_t len;
    163     uint32_t flags;
    164     uint32_t buf[];
    165 } REString;
    166 
    167 typedef struct {
    168     uint32_t n_strings;
    169     uint32_t hash_size;
    170     int hash_bits;
    171     REString **hash_table;
    172 } REStringList;
    173 
    174 static uint32_t re_string_hash(int len, const uint32_t *buf)
    175 {
    176     int i;
    177     uint32_t h;
    178     h = 1;
    179     for(i = 0; i < len; i++)
    180         h = h * 263 + buf[i];
    181     return h * 0x61C88647;
    182 }
    183 
    184 static void re_string_list_init(REStringList *s)
    185 {
    186     s->n_strings = 0;
    187     s->hash_size = 0;
    188     s->hash_bits = 0;
    189     s->hash_table = NULL;
    190 }
    191 
    192 static  __maybe_unused void re_string_list_free(REStringList *s)
    193 {
    194     REString *p, *p_next;
    195     int i;
    196     for(i = 0; i < s->hash_size; i++) {
    197         for(p = s->hash_table[i]; p != NULL; p = p_next) {
    198             p_next = p->next;
    199             free(p);
    200         }
    201     }
    202     free(s->hash_table);
    203 }
    204 
    205 static void lre_print_char(int c, BOOL is_range)
    206 {
    207     if (c == '\'' || c == '\\' ||
    208         (is_range && (c == '-' || c == ']'))) {
    209         printf("\\%c", c);
    210     } else if (c >= ' ' && c <= 126) {
    211         printf("%c", c);
    212     } else {
    213         printf("\\u{%04x}", c);
    214     }
    215 }
    216 
    217 static __maybe_unused void re_string_list_dump(const char *str, const REStringList *s)
    218 {
    219     REString *p;
    220     int i, j, k;
    221 
    222     printf("%s:\n", str);
    223     
    224     j = 0;
    225     for(i = 0; i < s->hash_size; i++) {
    226         for(p = s->hash_table[i]; p != NULL; p = p->next) {
    227             printf("  %d/%d: '", j, s->n_strings);
    228             for(k = 0; k < p->len; k++) {
    229                 lre_print_char(p->buf[k], FALSE);
    230             }
    231             printf("'\n");
    232             j++;
    233         }
    234     }
    235 }
    236 
    237 static REString *re_string_find2(REStringList *s, int len, const uint32_t *buf,
    238                                  uint32_t h0, BOOL add_flag)
    239 {
    240     uint32_t h = 0; /* avoid warning */
    241     REString *p;
    242     if (s->n_strings != 0) {
    243         h = h0 >> (32 - s->hash_bits);
    244         for(p = s->hash_table[h]; p != NULL; p = p->next) {
    245             if (p->hash == h0 && p->len == len &&
    246                 !memcmp(p->buf, buf, len * sizeof(buf[0]))) {
    247                 return p;
    248             }
    249         }
    250     }
    251     /* not found */
    252     if (!add_flag)
    253         return NULL;
    254     /* increase the size of the hash table if needed */
    255     if (unlikely((s->n_strings + 1) > s->hash_size)) {
    256         REString **new_hash_table, *p_next;
    257         int new_hash_bits, i;
    258         uint32_t new_hash_size;
    259         new_hash_bits = max_int(s->hash_bits + 1, 4);
    260         new_hash_size = 1 << new_hash_bits;
    261         new_hash_table = malloc(sizeof(new_hash_table[0]) * new_hash_size);
    262         if (!new_hash_table)
    263             return NULL;
    264         memset(new_hash_table, 0, sizeof(new_hash_table[0]) * new_hash_size);
    265         for(i = 0; i < s->hash_size; i++) {
    266             for(p = s->hash_table[i]; p != NULL; p = p_next) {
    267                 p_next = p->next;
    268                 h = p->hash >> (32 - new_hash_bits);
    269                 p->next = new_hash_table[h];
    270                 new_hash_table[h] = p;
    271             }
    272         }
    273         free(s->hash_table);
    274         s->hash_bits = new_hash_bits;
    275         s->hash_size = new_hash_size;
    276         s->hash_table = new_hash_table;
    277         h = h0 >> (32 - s->hash_bits);
    278     }
    279 
    280     p = malloc(sizeof(REString) + len * sizeof(buf[0]));
    281     if (!p)
    282         return NULL;
    283     p->next = s->hash_table[h];
    284     s->hash_table[h] = p;
    285     s->n_strings++;
    286     p->hash = h0;
    287     p->len = len;
    288     p->flags = 0;
    289     memcpy(p->buf, buf, sizeof(buf[0]) * len);
    290     return p;
    291 }
    292 
    293 static REString *re_string_find(REStringList *s, int len, const uint32_t *buf,
    294                                 BOOL add_flag)
    295 {
    296     uint32_t h0;
    297     h0 = re_string_hash(len, buf);
    298     return re_string_find2(s, len, buf, h0, add_flag);
    299 }
    300 
    301 static void re_string_add(REStringList *s, int len, const uint32_t *buf)
    302 {
    303     re_string_find(s, len, buf, TRUE);
    304 }
    305 
    306 #define UNICODE_GENERAL_CATEGORY
    307 
    308 typedef enum {
    309 #define DEF(id, str) GCAT_ ## id,
    310 #include "unicode_gen_def.h"
    311 #undef DEF
    312     GCAT_COUNT,
    313 } UnicodeGCEnum1;
    314 
    315 static const char *unicode_gc_name[] = {
    316 #define DEF(id, str) #id,
    317 #include "unicode_gen_def.h"
    318 #undef DEF
    319 };
    320 
    321 static const char *unicode_gc_short_name[] = {
    322 #define DEF(id, str) str,
    323 #include "unicode_gen_def.h"
    324 #undef DEF
    325 };
    326 
    327 #undef UNICODE_GENERAL_CATEGORY
    328 
    329 #define UNICODE_SCRIPT
    330 
    331 typedef enum {
    332 #define DEF(id, str) SCRIPT_ ## id,
    333 #include "unicode_gen_def.h"
    334 #undef DEF
    335     SCRIPT_COUNT,
    336 } UnicodeScriptEnum1;
    337 
    338 static const char *unicode_script_name[] = {
    339 #define DEF(id, str) #id,
    340 #include "unicode_gen_def.h"
    341 #undef DEF
    342 };
    343 
    344 const char *unicode_script_short_name[] = {
    345 #define DEF(id, str) str,
    346 #include "unicode_gen_def.h"
    347 #undef DEF
    348 };
    349 
    350 #undef UNICODE_SCRIPT
    351 
    352 #define UNICODE_PROP_LIST
    353 
    354 typedef enum {
    355 #define DEF(id, str) PROP_ ## id,
    356 #include "unicode_gen_def.h"
    357 #undef DEF
    358     PROP_COUNT,
    359 } UnicodePropEnum1;
    360 
    361 static const char *unicode_prop_name[] = {
    362 #define DEF(id, str) #id,
    363 #include "unicode_gen_def.h"
    364 #undef DEF
    365 };
    366 
    367 static const char *unicode_prop_short_name[] = {
    368 #define DEF(id, str) str,
    369 #include "unicode_gen_def.h"
    370 #undef DEF
    371 };
    372 
    373 #undef UNICODE_PROP_LIST
    374 
    375 #define UNICODE_SEQUENCE_PROP_LIST
    376 
    377 typedef enum {
    378 #define DEF(id) SEQUENCE_PROP_ ## id,
    379 #include "unicode_gen_def.h"
    380 #undef DEF
    381     SEQUENCE_PROP_COUNT,
    382 } UnicodeSequencePropEnum1;
    383 
    384 static const char *unicode_sequence_prop_name[] = {
    385 #define DEF(id) #id,
    386 #include "unicode_gen_def.h"
    387 #undef DEF
    388 };
    389 
    390 #undef UNICODE_SEQUENCE_PROP_LIST
    391 
    392 typedef struct {
    393     /* case conv */
    394     uint8_t u_len;
    395     uint8_t l_len;
    396     uint8_t f_len;
    397     int u_data[CC_LEN_MAX]; /* to upper case */
    398     int l_data[CC_LEN_MAX]; /* to lower case */
    399     int f_data[CC_LEN_MAX]; /* to case folding */
    400 
    401     uint8_t combining_class;
    402     uint8_t is_compat:1;
    403     uint8_t is_excluded:1;
    404     uint8_t general_category;
    405     uint8_t script;
    406     uint8_t script_ext_len;
    407     uint8_t *script_ext;
    408     uint32_t prop_bitmap_tab[3];
    409     /* decomposition */
    410     int decomp_len;
    411     int *decomp_data;
    412 } CCInfo;
    413 
    414 typedef struct {
    415     int count;
    416     int size;
    417     int *tab;
    418 } UnicodeSequenceProperties;
    419 
    420 CCInfo *unicode_db;
    421 REStringList rgi_emoji_zwj_sequence;
    422 DynBuf rgi_emoji_tag_sequence;
    423 
    424 int find_name(const char **tab, int tab_len, const char *name)
    425 {
    426     int i, len, name_len;
    427     const char *p, *r;
    428 
    429     name_len = strlen(name);
    430     for(i = 0; i < tab_len; i++) {
    431         p = tab[i];
    432         for(;;) {
    433             r = strchr(p, ',');
    434             if (!r)
    435                 len = strlen(p);
    436             else
    437                 len = r - p;
    438             if (len == name_len && memcmp(p, name, len) == 0)
    439                 return i;
    440             if (!r)
    441                 break;
    442             p = r + 1;
    443         }
    444     }
    445     return -1;
    446 }
    447 
    448 static BOOL get_prop(uint32_t c, int prop_idx)
    449 {
    450     return (unicode_db[c].prop_bitmap_tab[prop_idx >> 5] >> (prop_idx & 0x1f)) & 1;
    451 }
    452 
    453 static void set_prop(uint32_t c, int prop_idx, int val)
    454 {
    455     uint32_t mask;
    456     mask = 1U << (prop_idx & 0x1f);
    457     if (val)
    458         unicode_db[c].prop_bitmap_tab[prop_idx >> 5] |= mask;
    459     else
    460         unicode_db[c].prop_bitmap_tab[prop_idx >> 5]  &= ~mask;
    461 }
    462 
    463 void parse_unicode_data(const char *filename)
    464 {
    465     FILE *f;
    466     char line[1024];
    467     char buf1[256];
    468     const char *p;
    469     int code, lc, uc, last_code;
    470     CCInfo *ci, *tab = unicode_db;
    471 
    472     f = fopen(filename, "rb");
    473     if (!f) {
    474         perror(filename);
    475         exit(1);
    476     }
    477 
    478     last_code = 0;
    479     for(;;) {
    480         if (!get_line(line, sizeof(line), f))
    481             break;
    482         p = line;
    483         while (isspace(*p))
    484             p++;
    485         if (*p == '#')
    486             continue;
    487 
    488         p = get_field(line, 0);
    489         if (!p)
    490             continue;
    491         code = strtoul(p, NULL, 16);
    492         lc = 0;
    493         uc = 0;
    494 
    495         p = get_field(line, 12);
    496         if (p && *p != ';') {
    497             uc = strtoul(p, NULL, 16);
    498         }
    499 
    500         p = get_field(line, 13);
    501         if (p && *p != ';') {
    502             lc = strtoul(p, NULL, 16);
    503         }
    504         ci = &tab[code];
    505         if (uc > 0 || lc > 0) {
    506             assert(code <= CHARCODE_MAX);
    507             if (uc > 0) {
    508                 assert(ci->u_len == 0);
    509                 ci->u_len = 1;
    510                 ci->u_data[0] = uc;
    511             }
    512             if (lc > 0) {
    513                 assert(ci->l_len == 0);
    514                 ci->l_len = 1;
    515                 ci->l_data[0] = lc;
    516             }
    517         }
    518 
    519         {
    520             int i;
    521             get_field_buf(buf1, sizeof(buf1), line, 2);
    522             i = find_name(unicode_gc_name, countof(unicode_gc_name), buf1);
    523             if (i < 0) {
    524                 fprintf(stderr, "General category '%s' not found\n",
    525                         buf1);
    526                 exit(1);
    527             }
    528             ci->general_category = i;
    529         }
    530 
    531         p = get_field(line, 3);
    532         if (p && *p != ';' && *p != '\0') {
    533             int cc;
    534             cc = strtoul(p, NULL, 0);
    535             if (cc != 0) {
    536                 assert(code <= CHARCODE_MAX);
    537                 ci->combining_class = cc;
    538                 //                printf("%05x: %d\n", code, ci->combining_class);
    539             }
    540         }
    541 
    542         p = get_field(line, 5);
    543         if (p && *p != ';' && *p != '\0') {
    544             int size;
    545             assert(code <= CHARCODE_MAX);
    546             ci->is_compat = 0;
    547             if (*p == '<') {
    548                 while (*p != '\0' && *p != '>')
    549                     p++;
    550                 if (*p == '>')
    551                     p++;
    552                 ci->is_compat = 1;
    553             }
    554             size = 0;
    555             for(;;) {
    556                 while (isspace(*p))
    557                     p++;
    558                 if (!isxdigit(*p))
    559                     break;
    560                 add_char(&ci->decomp_data, &size, &ci->decomp_len, strtoul(p, (char **)&p, 16));
    561             }
    562 #if 0
    563             {
    564                 int i;
    565                 static int count, d_count;
    566 
    567                 printf("%05x: %c", code, ci->is_compat ? 'C': ' ');
    568                 for(i = 0; i < ci->decomp_len; i++)
    569                     printf(" %05x", ci->decomp_data[i]);
    570                 printf("\n");
    571                 count++;
    572                 d_count += ci->decomp_len;
    573                 //                printf("%d %d\n", count, d_count);
    574             }
    575 #endif
    576         }
    577 
    578         p = get_field(line, 9);
    579         if (p && *p == 'Y') {
    580             set_prop(code, PROP_Bidi_Mirrored, 1);
    581         }
    582 
    583         /* handle ranges */
    584         get_field_buf(buf1, sizeof(buf1), line, 1);
    585         if (strstr(buf1, " Last>")) {
    586             int i;
    587             //            printf("range: 0x%x-%0x\n", last_code, code);
    588             assert(ci->decomp_len == 0);
    589             assert(ci->script_ext_len == 0);
    590             for(i = last_code + 1; i < code; i++) {
    591                 unicode_db[i] = *ci;
    592             }
    593         }
    594         last_code = code;
    595     }
    596 
    597     fclose(f);
    598 }
    599 
    600 void parse_special_casing(CCInfo *tab, const char *filename)
    601 {
    602     FILE *f;
    603     char line[1024];
    604     const char *p;
    605     int code;
    606     CCInfo *ci;
    607 
    608     f = fopen(filename, "rb");
    609     if (!f) {
    610         perror(filename);
    611         exit(1);
    612     }
    613 
    614     for(;;) {
    615         if (!get_line(line, sizeof(line), f))
    616             break;
    617         p = line;
    618         while (isspace(*p))
    619             p++;
    620         if (*p == '#')
    621             continue;
    622 
    623         p = get_field(line, 0);
    624         if (!p)
    625             continue;
    626         code = strtoul(p, NULL, 16);
    627         assert(code <= CHARCODE_MAX);
    628         ci = &tab[code];
    629 
    630         p = get_field(line, 4);
    631         if (p) {
    632             /* locale dependent casing */
    633             while (isspace(*p))
    634                 p++;
    635             if (*p != '#' && *p != '\0')
    636                 continue;
    637         }
    638 
    639 
    640         p = get_field(line, 1);
    641         if (p && *p != ';') {
    642             ci->l_len = 0;
    643             for(;;) {
    644                 while (isspace(*p))
    645                     p++;
    646                 if (*p == ';')
    647                     break;
    648                 assert(ci->l_len < CC_LEN_MAX);
    649                 ci->l_data[ci->l_len++] = strtoul(p, (char **)&p, 16);
    650             }
    651 
    652             if (ci->l_len == 1 && ci->l_data[0] == code)
    653                 ci->l_len = 0;
    654         }
    655 
    656         p = get_field(line, 3);
    657         if (p && *p != ';') {
    658             ci->u_len = 0;
    659             for(;;) {
    660                 while (isspace(*p))
    661                     p++;
    662                 if (*p == ';')
    663                     break;
    664                 assert(ci->u_len < CC_LEN_MAX);
    665                 ci->u_data[ci->u_len++] = strtoul(p, (char **)&p, 16);
    666             }
    667 
    668             if (ci->u_len == 1 && ci->u_data[0] == code)
    669                 ci->u_len = 0;
    670         }
    671     }
    672 
    673     fclose(f);
    674 }
    675 
    676 void parse_case_folding(CCInfo *tab, const char *filename)
    677 {
    678     FILE *f;
    679     char line[1024];
    680     const char *p;
    681     int code, status;
    682     CCInfo *ci;
    683 
    684     f = fopen(filename, "rb");
    685     if (!f) {
    686         perror(filename);
    687         exit(1);
    688     }
    689 
    690     for(;;) {
    691         if (!get_line(line, sizeof(line), f))
    692             break;
    693         p = line;
    694         while (isspace(*p))
    695             p++;
    696         if (*p == '#')
    697             continue;
    698 
    699         p = get_field(line, 0);
    700         if (!p)
    701             continue;
    702         code = strtoul(p, NULL, 16);
    703         assert(code <= CHARCODE_MAX);
    704         ci = &tab[code];
    705 
    706         p = get_field(line, 1);
    707         if (!p)
    708             continue;
    709         /* locale dependent casing */
    710         while (isspace(*p))
    711             p++;
    712         status = *p;
    713         if (status != 'C' && status != 'S' && status != 'F')
    714             continue;
    715 
    716         p = get_field(line, 2);
    717         assert(p != NULL);
    718         if (status == 'S') {
    719             /* we always select the simple case folding and assume it
    720              * comes after the full case folding case */
    721             assert(ci->f_len >= 2);
    722             ci->f_len = 0;
    723         } else {
    724             assert(ci->f_len == 0);
    725         }
    726         for(;;) {
    727             while (isspace(*p))
    728                 p++;
    729             if (*p == ';')
    730                 break;
    731             assert(ci->l_len < CC_LEN_MAX);
    732             ci->f_data[ci->f_len++] = strtoul(p, (char **)&p, 16);
    733         }
    734     }
    735 
    736     fclose(f);
    737 }
    738 
    739 void parse_composition_exclusions(const char *filename)
    740 {
    741     FILE *f;
    742     char line[4096], *p;
    743     uint32_t c0;
    744 
    745     f = fopen(filename, "rb");
    746     if (!f) {
    747         perror(filename);
    748         exit(1);
    749     }
    750 
    751     for(;;) {
    752         if (!get_line(line, sizeof(line), f))
    753             break;
    754         p = line;
    755         while (isspace(*p))
    756             p++;
    757         if (*p == '#' || *p == '@' || *p == '\0')
    758             continue;
    759         c0 = strtoul(p, (char **)&p, 16);
    760         assert(c0 > 0 && c0 <= CHARCODE_MAX);
    761         unicode_db[c0].is_excluded = TRUE;
    762     }
    763     fclose(f);
    764 }
    765 
    766 void parse_derived_core_properties(const char *filename)
    767 {
    768     FILE *f;
    769     char line[4096], *p, buf[256], *q;
    770     uint32_t c0, c1, c;
    771     int i;
    772 
    773     f = fopen(filename, "rb");
    774     if (!f) {
    775         perror(filename);
    776         exit(1);
    777     }
    778 
    779     for(;;) {
    780         if (!get_line(line, sizeof(line), f))
    781             break;
    782         p = line;
    783         while (isspace(*p))
    784             p++;
    785         if (*p == '#' || *p == '@' || *p == '\0')
    786             continue;
    787         c0 = strtoul(p, (char **)&p, 16);
    788         if (*p == '.' && p[1] == '.') {
    789             p += 2;
    790             c1 = strtoul(p, (char **)&p, 16);
    791         } else {
    792             c1 = c0;
    793         }
    794         assert(c1 <= CHARCODE_MAX);
    795         p += strspn(p, " \t");
    796         if (*p == ';') {
    797             p++;
    798             p += strspn(p, " \t");
    799             q = buf;
    800             while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t' && *p != ';') {
    801                 if ((q - buf) < sizeof(buf) - 1)
    802                     *q++ = *p;
    803                 p++;
    804             }
    805             *q = '\0';
    806             i = find_name(unicode_prop_name,
    807                           countof(unicode_prop_name), buf);
    808             if (i < 0) {
    809                 if (!strcmp(buf, "Grapheme_Link"))
    810                     goto next;
    811                 fprintf(stderr, "Property not found: %s\n", buf);
    812                 exit(1);
    813             }
    814             for(c = c0; c <= c1; c++) {
    815                 set_prop(c, i, 1);
    816             }
    817 next: ;
    818         }
    819     }
    820     fclose(f);
    821 }
    822 
    823 void parse_derived_norm_properties(const char *filename)
    824 {
    825     FILE *f;
    826     char line[4096], *p, buf[256], *q;
    827     uint32_t c0, c1, c;
    828 
    829     f = fopen(filename, "rb");
    830     if (!f) {
    831         perror(filename);
    832         exit(1);
    833     }
    834 
    835     for(;;) {
    836         if (!get_line(line, sizeof(line), f))
    837             break;
    838         p = line;
    839         while (isspace(*p))
    840             p++;
    841         if (*p == '#' || *p == '@' || *p == '\0')
    842             continue;
    843         c0 = strtoul(p, (char **)&p, 16);
    844         if (*p == '.' && p[1] == '.') {
    845             p += 2;
    846             c1 = strtoul(p, (char **)&p, 16);
    847         } else {
    848             c1 = c0;
    849         }
    850         assert(c1 <= CHARCODE_MAX);
    851         p += strspn(p, " \t");
    852         if (*p == ';') {
    853             p++;
    854             p += strspn(p, " \t");
    855             q = buf;
    856             while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') {
    857                 if ((q - buf) < sizeof(buf) - 1)
    858                     *q++ = *p;
    859                 p++;
    860             }
    861             *q = '\0';
    862             if (!strcmp(buf, "Changes_When_NFKC_Casefolded")) {
    863                 for(c = c0; c <= c1; c++) {
    864                     set_prop(c, PROP_Changes_When_NFKC_Casefolded, 1);
    865                 }
    866             }
    867         }
    868     }
    869     fclose(f);
    870 }
    871 
    872 void parse_prop_list(const char *filename)
    873 {
    874     FILE *f;
    875     char line[4096], *p, buf[256], *q;
    876     uint32_t c0, c1, c;
    877     int i;
    878 
    879     f = fopen(filename, "rb");
    880     if (!f) {
    881         perror(filename);
    882         exit(1);
    883     }
    884 
    885     for(;;) {
    886         if (!get_line(line, sizeof(line), f))
    887             break;
    888         p = line;
    889         while (isspace(*p))
    890             p++;
    891         if (*p == '#' || *p == '@' || *p == '\0')
    892             continue;
    893         c0 = strtoul(p, (char **)&p, 16);
    894         if (*p == '.' && p[1] == '.') {
    895             p += 2;
    896             c1 = strtoul(p, (char **)&p, 16);
    897         } else {
    898             c1 = c0;
    899         }
    900         assert(c1 <= CHARCODE_MAX);
    901         p += strspn(p, " \t");
    902         if (*p == ';') {
    903             p++;
    904             p += strspn(p, " \t");
    905             q = buf;
    906             while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') {
    907                 if ((q - buf) < sizeof(buf) - 1)
    908                     *q++ = *p;
    909                 p++;
    910             }
    911             *q = '\0';
    912             i = find_name(unicode_prop_name,
    913                           countof(unicode_prop_name), buf);
    914             if (i < 0) {
    915                 fprintf(stderr, "Property not found: %s\n", buf);
    916                 exit(1);
    917             }
    918             for(c = c0; c <= c1; c++) {
    919                 set_prop(c, i, 1);
    920             }
    921         }
    922     }
    923     fclose(f);
    924 }
    925 
    926 #define SEQ_MAX_LEN 16
    927 
    928 static BOOL is_emoji_modifier(uint32_t c)
    929 {
    930     return (c >= 0x1f3fb && c <= 0x1f3ff);
    931 }
    932 
    933 static void add_sequence_prop(int idx, int seq_len, int *seq)
    934 {
    935     int i;
    936     
    937     assert(idx < SEQUENCE_PROP_COUNT);
    938     switch(idx) {
    939     case SEQUENCE_PROP_Basic_Emoji:
    940         /* convert to 2 properties lists */
    941         if (seq_len == 1) {
    942             set_prop(seq[0], PROP_Basic_Emoji1, 1);
    943         } else if (seq_len == 2 && seq[1] == 0xfe0f) {
    944             set_prop(seq[0], PROP_Basic_Emoji2, 1);
    945         } else {
    946             abort();
    947         }
    948         break;
    949     case SEQUENCE_PROP_RGI_Emoji_Modifier_Sequence:
    950         assert(seq_len == 2);
    951         assert(is_emoji_modifier(seq[1]));
    952         assert(get_prop(seq[0], PROP_Emoji_Modifier_Base));
    953         set_prop(seq[0], PROP_RGI_Emoji_Modifier_Sequence, 1);
    954         break;
    955     case SEQUENCE_PROP_RGI_Emoji_Flag_Sequence:
    956         {
    957             int code;
    958             assert(seq_len == 2);
    959             assert(seq[0] >= 0x1F1E6 && seq[0] <= 0x1F1FF);
    960             assert(seq[1] >= 0x1F1E6 && seq[1] <= 0x1F1FF);
    961             code = (seq[0] - 0x1F1E6) * 26 + (seq[1] - 0x1F1E6);
    962             /* XXX: would be more compact with a simple bitmap -> 676 bits */
    963             set_prop(code, PROP_RGI_Emoji_Flag_Sequence, 1);
    964         }
    965         break;
    966     case SEQUENCE_PROP_RGI_Emoji_ZWJ_Sequence:
    967         re_string_add(&rgi_emoji_zwj_sequence, seq_len, (uint32_t *)seq);
    968         break;
    969     case SEQUENCE_PROP_RGI_Emoji_Tag_Sequence:
    970         {
    971             assert(seq_len >= 3);
    972             assert(seq[0] == 0x1F3F4);
    973             assert(seq[seq_len - 1] == 0xE007F);
    974             for(i = 1; i < seq_len - 1; i++) {
    975                 assert(seq[i] >= 0xe0001 && seq[i] <= 0xe007e);
    976                 dbuf_putc(&rgi_emoji_tag_sequence, seq[i] - 0xe0000);
    977             }
    978             dbuf_putc(&rgi_emoji_tag_sequence, 0);
    979         }
    980         break;
    981     case SEQUENCE_PROP_Emoji_Keycap_Sequence:
    982         assert(seq_len == 3);
    983         assert(seq[1] == 0xfe0f);
    984         assert(seq[2] == 0x20e3);
    985         set_prop(seq[0], PROP_Emoji_Keycap_Sequence, 1);
    986         break;
    987     default:
    988         assert(0);
    989     }
    990 }
    991 
    992 void parse_sequence_prop_list(const char *filename)
    993 {
    994     FILE *f;
    995     char line[4096], *p, buf[256], *q, *p_start;
    996     uint32_t c0, c1, c;
    997     int idx, seq_len;
    998     int seq[SEQ_MAX_LEN];
    999     
   1000     f = fopen(filename, "rb");
   1001     if (!f) {
   1002         perror(filename);
   1003         exit(1);
   1004     }
   1005 
   1006     for(;;) {
   1007         if (!get_line(line, sizeof(line), f))
   1008             break;
   1009         p = line;
   1010         while (isspace(*p))
   1011             p++;
   1012         if (*p == '#' || *p == '@' || *p == '\0')
   1013             continue;
   1014         p_start = p;
   1015 
   1016         /* find the sequence property name */
   1017         p = strchr(p, ';');
   1018         if (!p)
   1019             continue;
   1020         p++;
   1021         p += strspn(p, " \t");
   1022         q = buf;
   1023         while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t' && *p != ';') {
   1024             if ((q - buf) < sizeof(buf) - 1)
   1025                 *q++ = *p;
   1026             p++;
   1027         }
   1028         *q = '\0';
   1029         idx = find_name(unicode_sequence_prop_name,
   1030                       countof(unicode_sequence_prop_name), buf);
   1031         if (idx < 0) {
   1032             fprintf(stderr, "Property not found: %s\n", buf);
   1033             exit(1);
   1034         }
   1035         
   1036         p = p_start;
   1037         c0 = strtoul(p, (char **)&p, 16);
   1038         assert(c0 <= CHARCODE_MAX);
   1039         
   1040         if (*p == '.' && p[1] == '.') {
   1041             p += 2;
   1042             c1 = strtoul(p, (char **)&p, 16);
   1043             assert(c1 <= CHARCODE_MAX);
   1044             for(c = c0; c <= c1; c++) {
   1045                 seq[0] = c;
   1046                 add_sequence_prop(idx, 1, seq);
   1047             }
   1048         } else {
   1049             seq_len = 0;
   1050             seq[seq_len++] = c0;
   1051             for(;;) {
   1052                 while (isspace(*p))
   1053                     p++;
   1054                 if (*p == ';' || *p == '\0')
   1055                     break;
   1056                 c0 = strtoul(p, (char **)&p, 16);
   1057                 assert(c0 <= CHARCODE_MAX);
   1058                 assert(seq_len < countof(seq));
   1059                 seq[seq_len++] = c0;
   1060             }
   1061             add_sequence_prop(idx, seq_len, seq);
   1062         }
   1063     }
   1064     fclose(f);
   1065 }
   1066 
   1067 void parse_scripts(const char *filename)
   1068 {
   1069     FILE *f;
   1070     char line[4096], *p, buf[256], *q;
   1071     uint32_t c0, c1, c;
   1072     int i;
   1073 
   1074     f = fopen(filename, "rb");
   1075     if (!f) {
   1076         perror(filename);
   1077         exit(1);
   1078     }
   1079 
   1080     for(;;) {
   1081         if (!get_line(line, sizeof(line), f))
   1082             break;
   1083         p = line;
   1084         while (isspace(*p))
   1085             p++;
   1086         if (*p == '#' || *p == '@' || *p == '\0')
   1087             continue;
   1088         c0 = strtoul(p, (char **)&p, 16);
   1089         if (*p == '.' && p[1] == '.') {
   1090             p += 2;
   1091             c1 = strtoul(p, (char **)&p, 16);
   1092         } else {
   1093             c1 = c0;
   1094         }
   1095         assert(c1 <= CHARCODE_MAX);
   1096         p += strspn(p, " \t");
   1097         if (*p == ';') {
   1098             p++;
   1099             p += strspn(p, " \t");
   1100             q = buf;
   1101             while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') {
   1102                 if ((q - buf) < sizeof(buf) - 1)
   1103                     *q++ = *p;
   1104                 p++;
   1105             }
   1106             *q = '\0';
   1107             i = find_name(unicode_script_name,
   1108                           countof(unicode_script_name), buf);
   1109             if (i < 0) {
   1110                 fprintf(stderr, "Unknown script: '%s'\n", buf);
   1111                 exit(1);
   1112             }
   1113             for(c = c0; c <= c1; c++)
   1114                 unicode_db[c].script = i;
   1115         }
   1116     }
   1117     fclose(f);
   1118 }
   1119 
   1120 void parse_script_extensions(const char *filename)
   1121 {
   1122     FILE *f;
   1123     char line[4096], *p, buf[256], *q;
   1124     uint32_t c0, c1, c;
   1125     int i;
   1126     uint8_t script_ext[255];
   1127     int script_ext_len;
   1128 
   1129     f = fopen(filename, "rb");
   1130     if (!f) {
   1131         perror(filename);
   1132         exit(1);
   1133     }
   1134 
   1135     for(;;) {
   1136         if (!get_line(line, sizeof(line), f))
   1137             break;
   1138         p = line;
   1139         while (isspace(*p))
   1140             p++;
   1141         if (*p == '#' || *p == '@' || *p == '\0')
   1142             continue;
   1143         c0 = strtoul(p, (char **)&p, 16);
   1144         if (*p == '.' && p[1] == '.') {
   1145             p += 2;
   1146             c1 = strtoul(p, (char **)&p, 16);
   1147         } else {
   1148             c1 = c0;
   1149         }
   1150         assert(c1 <= CHARCODE_MAX);
   1151         p += strspn(p, " \t");
   1152         script_ext_len = 0;
   1153         if (*p == ';') {
   1154             p++;
   1155             for(;;) {
   1156                 p += strspn(p, " \t");
   1157                 q = buf;
   1158                 while (*p != '\0' && *p != ' ' && *p != '#' && *p != '\t') {
   1159                     if ((q - buf) < sizeof(buf) - 1)
   1160                         *q++ = *p;
   1161                     p++;
   1162                 }
   1163                 *q = '\0';
   1164                 if (buf[0] == '\0')
   1165                     break;
   1166                 i = find_name(unicode_script_short_name,
   1167                               countof(unicode_script_short_name), buf);
   1168                 if (i < 0) {
   1169                     fprintf(stderr, "Script not found: %s\n", buf);
   1170                     exit(1);
   1171                 }
   1172                 assert(script_ext_len < sizeof(script_ext));
   1173                 script_ext[script_ext_len++] = i;
   1174             }
   1175             for(c = c0; c <= c1; c++) {
   1176                 CCInfo *ci = &unicode_db[c];
   1177                 ci->script_ext_len = script_ext_len;
   1178                 ci->script_ext = malloc(sizeof(ci->script_ext[0]) * script_ext_len);
   1179                 for(i = 0; i < script_ext_len; i++)
   1180                     ci->script_ext[i] = script_ext[i];
   1181             }
   1182         }
   1183     }
   1184     fclose(f);
   1185 }
   1186 
   1187 void dump_cc_info(CCInfo *ci, int i)
   1188 {
   1189     int j;
   1190     printf("%05x:", i);
   1191     if (ci->u_len != 0) {
   1192         printf(" U:");
   1193         for(j = 0; j < ci->u_len; j++)
   1194             printf(" %05x", ci->u_data[j]);
   1195     }
   1196     if (ci->l_len != 0) {
   1197         printf(" L:");
   1198         for(j = 0; j < ci->l_len; j++)
   1199             printf(" %05x", ci->l_data[j]);
   1200     }
   1201     if (ci->f_len != 0) {
   1202         printf(" F:");
   1203         for(j = 0; j < ci->f_len; j++)
   1204             printf(" %05x", ci->f_data[j]);
   1205     }
   1206     printf("\n");
   1207 }
   1208 
   1209 void dump_unicode_data(CCInfo *tab)
   1210 {
   1211     int i;
   1212     CCInfo *ci;
   1213     for(i = 0; i <= CHARCODE_MAX; i++) {
   1214         ci = &tab[i];
   1215         if (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0) {
   1216             dump_cc_info(ci, i);
   1217         }
   1218     }
   1219 }
   1220 
   1221 BOOL is_complicated_case(const CCInfo *ci)
   1222 {
   1223     return (ci->u_len > 1 || ci->l_len > 1 ||
   1224             (ci->u_len > 0 && ci->l_len > 0) ||
   1225             (ci->f_len != ci->l_len) ||
   1226             (memcmp(ci->f_data, ci->l_data, ci->f_len * sizeof(ci->f_data[0])) != 0));
   1227 }
   1228 
   1229 #ifndef USE_TEST
   1230 enum {
   1231     RUN_TYPE_U,
   1232     RUN_TYPE_L,
   1233     RUN_TYPE_UF,
   1234     RUN_TYPE_LF,
   1235     RUN_TYPE_UL,
   1236     RUN_TYPE_LSU,
   1237     RUN_TYPE_U2L_399_EXT2,
   1238     RUN_TYPE_UF_D20,
   1239     RUN_TYPE_UF_D1_EXT,
   1240     RUN_TYPE_U_EXT,
   1241     RUN_TYPE_LF_EXT,
   1242     RUN_TYPE_UF_EXT2,
   1243     RUN_TYPE_LF_EXT2,
   1244     RUN_TYPE_UF_EXT3,
   1245 };
   1246 #endif
   1247 
   1248 const char *run_type_str[] = {
   1249     "U",
   1250     "L",
   1251     "UF",
   1252     "LF",
   1253     "UL",
   1254     "LSU",
   1255     "U2L_399_EXT2",
   1256     "UF_D20",
   1257     "UF_D1_EXT",
   1258     "U_EXT",
   1259     "LF_EXT",
   1260     "UF_EXT2",
   1261     "LF_EXT2",
   1262     "UF_EXT3",
   1263 };
   1264 
   1265 typedef struct {
   1266     int code;
   1267     int len;
   1268     int type;
   1269     int data;
   1270     int ext_len;
   1271     int ext_data[3];
   1272     int data_index; /* 'data' coming from the table */
   1273 } TableEntry;
   1274 
   1275 static int simple_to_lower(CCInfo *tab, int c)
   1276 {
   1277     if (tab[c].l_len != 1)
   1278         return c;
   1279     return tab[c].l_data[0];
   1280 }
   1281 
   1282 /* code (17), len (7), type (4) */
   1283 
   1284 void find_run_type(TableEntry *te, CCInfo *tab, int code)
   1285 {
   1286     int is_lower, len;
   1287     CCInfo *ci, *ci1, *ci2;
   1288 
   1289     ci = &tab[code];
   1290     ci1 = &tab[code + 1];
   1291     ci2 = &tab[code + 2];
   1292     te->code = code;
   1293 
   1294     if (ci->l_len == 1 && ci->l_data[0] == code + 2 &&
   1295         ci->f_len == 1 && ci->f_data[0] == ci->l_data[0] &&
   1296         ci->u_len == 0 &&
   1297 
   1298         ci1->l_len == 1 && ci1->l_data[0] == code + 2 &&
   1299         ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0] &&
   1300         ci1->u_len == 1 && ci1->u_data[0] == code &&
   1301 
   1302         ci2->l_len == 0 &&
   1303         ci2->f_len == 0 &&
   1304         ci2->u_len == 1 && ci2->u_data[0] == code) {
   1305         te->len = 3;
   1306         te->data = 0;
   1307         te->type = RUN_TYPE_LSU;
   1308         return;
   1309     }
   1310 
   1311     if (is_complicated_case(ci)) {
   1312         len = 1;
   1313         while (code + len <= CHARCODE_MAX) {
   1314             ci1 = &tab[code + len];
   1315             if (ci1->u_len != 1 ||
   1316                 ci1->u_data[0] != ci->u_data[0] + len ||
   1317                 ci1->l_len != 0 ||
   1318                 ci1->f_len != 1 || ci1->f_data[0] != ci1->u_data[0])
   1319                 break;
   1320             len++;
   1321         }
   1322         if (len > 1) {
   1323             te->len = len;
   1324             te->type = RUN_TYPE_UF;
   1325             te->data = ci->u_data[0];
   1326             return;
   1327         }
   1328 
   1329         if (ci->l_len == 0 &&
   1330             ci->u_len == 2 && ci->u_data[1] == 0x399 &&
   1331             ci->f_len == 2 && ci->f_data[1] == 0x3B9 &&
   1332             ci->f_data[0] == simple_to_lower(tab, ci->u_data[0])) {
   1333             len = 1;
   1334             while (code + len <= CHARCODE_MAX) {
   1335                 ci1 = &tab[code + len];
   1336                 if (!(ci1->u_len == 2 &&
   1337                       ci1->u_data[1] == ci->u_data[1] &&
   1338                       ci1->u_data[0] == ci->u_data[0] + len &&
   1339                       ci1->f_len == 2 &&
   1340                       ci1->f_data[1] == ci->f_data[1] &&
   1341                       ci1->f_data[0] == ci->f_data[0] + len &&
   1342                       ci1->l_len == 0))
   1343                     break;
   1344                 len++;
   1345             }
   1346             te->len = len;
   1347             te->type = RUN_TYPE_UF_EXT2;
   1348             te->ext_data[0] = ci->u_data[0];
   1349             te->ext_data[1] = ci->u_data[1];
   1350             te->ext_len = 2;
   1351             return;
   1352         }
   1353 
   1354         if (ci->u_len == 2 && ci->u_data[1] == 0x399 &&
   1355             ci->l_len == 1 &&
   1356             ci->f_len == 1 && ci->f_data[0] == ci->l_data[0]) {
   1357             len = 1;
   1358             while (code + len <= CHARCODE_MAX) {
   1359                 ci1 = &tab[code + len];
   1360                 if (!(ci1->u_len == 2 &&
   1361                       ci1->u_data[1] == 0x399 &&
   1362                       ci1->u_data[0] == ci->u_data[0] + len &&
   1363                       ci1->l_len == 1 &&
   1364                       ci1->l_data[0] == ci->l_data[0] + len &&
   1365                       ci1->f_len == 1 && ci1->f_data[0] == ci1->l_data[0]))
   1366                     break;
   1367                 len++;
   1368             }
   1369             te->len = len;
   1370             te->type = RUN_TYPE_U2L_399_EXT2;
   1371             te->ext_data[0] = ci->u_data[0];
   1372             te->ext_data[1] = ci->l_data[0];
   1373             te->ext_len = 2;
   1374             return;
   1375         }
   1376 
   1377         if (ci->l_len == 1 && ci->u_len == 0 && ci->f_len == 0) {
   1378             len = 1;
   1379             while (code + len <= CHARCODE_MAX) {
   1380                 ci1 = &tab[code + len];
   1381                 if (!(ci1->l_len == 1 &&
   1382                       ci1->l_data[0] == ci->l_data[0] + len &&
   1383                       ci1->u_len == 0 && ci1->f_len == 0))
   1384                     break;
   1385                 len++;
   1386             }
   1387             te->len = len;
   1388             te->type = RUN_TYPE_L;
   1389             te->data = ci->l_data[0];
   1390             return;
   1391         }
   1392 
   1393         if (ci->l_len == 0 &&
   1394             ci->u_len == 1 &&
   1395             ci->u_data[0] < 0x1000 &&
   1396             ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 0x20) {
   1397             te->len = 1;
   1398             te->type = RUN_TYPE_UF_D20;
   1399             te->data = ci->u_data[0];
   1400         } else if (ci->l_len == 0 &&
   1401                    ci->u_len == 1 &&
   1402                    ci->f_len == 1 && ci->f_data[0] == ci->u_data[0] + 1) {
   1403             te->len = 1;
   1404             te->type = RUN_TYPE_UF_D1_EXT;
   1405             te->ext_data[0] = ci->u_data[0];
   1406             te->ext_len = 1;
   1407         } else if (ci->l_len == 2 && ci->u_len == 0 && ci->f_len == 2 &&
   1408                    ci->l_data[0] == ci->f_data[0] &&
   1409                    ci->l_data[1] == ci->f_data[1]) {
   1410             te->len = 1;
   1411             te->type = RUN_TYPE_LF_EXT2;
   1412             te->ext_data[0] = ci->l_data[0];
   1413             te->ext_data[1] = ci->l_data[1];
   1414             te->ext_len = 2;
   1415         } else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 2 &&
   1416                    ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) &&
   1417                    ci->f_data[1] == simple_to_lower(tab, ci->u_data[1])) {
   1418             te->len = 1;
   1419             te->type = RUN_TYPE_UF_EXT2;
   1420             te->ext_data[0] = ci->u_data[0];
   1421             te->ext_data[1] = ci->u_data[1];
   1422             te->ext_len = 2;
   1423         } else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 3 &&
   1424                    ci->f_data[0] == simple_to_lower(tab, ci->u_data[0]) &&
   1425                    ci->f_data[1] == simple_to_lower(tab, ci->u_data[1]) &&
   1426                    ci->f_data[2] == simple_to_lower(tab, ci->u_data[2])) {
   1427             te->len = 1;
   1428             te->type = RUN_TYPE_UF_EXT3;
   1429             te->ext_data[0] = ci->u_data[0];
   1430             te->ext_data[1] = ci->u_data[1];
   1431             te->ext_data[2] = ci->u_data[2];
   1432             te->ext_len = 3;
   1433         } else if (ci->u_len == 2 && ci->l_len == 0 && ci->f_len == 1) {
   1434             // U+FB05 LATIN SMALL LIGATURE LONG S T
   1435             assert(code == 0xFB05);
   1436             te->len = 1;
   1437             te->type = RUN_TYPE_UF_EXT2;
   1438             te->ext_data[0] = ci->u_data[0];
   1439             te->ext_data[1] = ci->u_data[1];
   1440             te->ext_len = 2;
   1441         } else if (ci->u_len == 3 && ci->l_len == 0 && ci->f_len == 1) {
   1442             // U+1FD3 GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA or
   1443             // U+1FE3 GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
   1444             assert(code == 0x1FD3 || code == 0x1FE3);
   1445             te->len = 1;
   1446             te->type = RUN_TYPE_UF_EXT3;
   1447             te->ext_data[0] = ci->u_data[0];
   1448             te->ext_data[1] = ci->u_data[1];
   1449             te->ext_data[2] = ci->u_data[2];
   1450             te->ext_len = 3;
   1451         } else {
   1452             printf("unsupported encoding case:\n");
   1453             dump_cc_info(ci, code);
   1454             abort();
   1455         }
   1456     } else {
   1457         /* look for a run of identical conversions */
   1458         len = 0;
   1459         for(;;) {
   1460             if (code >= CHARCODE_MAX || len >= 126)
   1461                 break;
   1462             ci = &tab[code + len];
   1463             ci1 = &tab[code + len + 1];
   1464             if (is_complicated_case(ci) || is_complicated_case(ci1)) {
   1465                 break;
   1466             }
   1467             if (ci->l_len != 1 || ci->l_data[0] != code + len + 1)
   1468                 break;
   1469             if (ci1->u_len != 1 || ci1->u_data[0] != code + len)
   1470                 break;
   1471             len += 2;
   1472         }
   1473         if (len > 0) {
   1474             te->len = len;
   1475             te->type = RUN_TYPE_UL;
   1476             te->data = 0;
   1477             return;
   1478         }
   1479 
   1480         ci = &tab[code];
   1481         is_lower = ci->l_len > 0;
   1482         len = 1;
   1483         while (code + len <= CHARCODE_MAX) {
   1484             ci1 = &tab[code + len];
   1485             if (is_complicated_case(ci1))
   1486                 break;
   1487             if (is_lower) {
   1488                 if (ci1->l_len != 1 ||
   1489                     ci1->l_data[0] != ci->l_data[0] + len)
   1490                     break;
   1491             } else {
   1492                 if (ci1->u_len != 1 ||
   1493                     ci1->u_data[0] != ci->u_data[0] + len)
   1494                     break;
   1495             }
   1496             len++;
   1497         }
   1498         te->len = len;
   1499         if (is_lower) {
   1500             te->type = RUN_TYPE_LF;
   1501             te->data = ci->l_data[0];
   1502         } else {
   1503             te->type = RUN_TYPE_U;
   1504             te->data = ci->u_data[0];
   1505         }
   1506     }
   1507 }
   1508 
   1509 TableEntry conv_table[1000];
   1510 int conv_table_len;
   1511 int ext_data[1000];
   1512 int ext_data_len;
   1513 
   1514 void dump_case_conv_table1(void)
   1515 {
   1516     int i, j;
   1517     const TableEntry *te;
   1518 
   1519     for(i = 0; i < conv_table_len; i++) {
   1520         te = &conv_table[i];
   1521         printf("%05x %02x %-10s %05x",
   1522                te->code, te->len, run_type_str[te->type], te->data);
   1523         for(j = 0; j < te->ext_len; j++) {
   1524             printf(" %05x", te->ext_data[j]);
   1525         }
   1526         printf("\n");
   1527     }
   1528     printf("table_len=%d ext_len=%d\n", conv_table_len, ext_data_len);
   1529 }
   1530 
   1531 int find_data_index(const TableEntry *conv_table, int len, int data)
   1532 {
   1533     int i;
   1534     const TableEntry *te;
   1535     for(i = 0; i < len; i++) {
   1536         te = &conv_table[i];
   1537         if (te->code == data)
   1538             return i;
   1539     }
   1540     return -1;
   1541 }
   1542 
   1543 int find_ext_data_index(int data)
   1544 {
   1545     int i;
   1546     for(i = 0; i < ext_data_len; i++) {
   1547         if (ext_data[i] == data)
   1548             return i;
   1549     }
   1550     assert(ext_data_len < countof(ext_data));
   1551     ext_data[ext_data_len++] = data;
   1552     return ext_data_len - 1;
   1553 }
   1554 
   1555 void build_conv_table(CCInfo *tab)
   1556 {
   1557     int code, i, j;
   1558     CCInfo *ci;
   1559     TableEntry *te;
   1560 
   1561     te = conv_table;
   1562     for(code = 0; code <= CHARCODE_MAX; code++) {
   1563         ci = &tab[code];
   1564         if (ci->u_len == 0 && ci->l_len == 0 && ci->f_len == 0)
   1565             continue;
   1566         assert(te - conv_table < countof(conv_table));
   1567         find_run_type(te, tab, code);
   1568 #if 0
   1569         if (te->type == RUN_TYPE_TODO) {
   1570             printf("TODO: ");
   1571             dump_cc_info(ci, code);
   1572         }
   1573 #endif
   1574         assert(te->len <= 127);
   1575         code += te->len - 1;
   1576         te++;
   1577     }
   1578     conv_table_len = te - conv_table;
   1579 
   1580     /* find the data index */
   1581     for(i = 0; i < conv_table_len; i++) {
   1582         int data_index;
   1583         te = &conv_table[i];
   1584 
   1585         switch(te->type) {
   1586         case RUN_TYPE_U:
   1587         case RUN_TYPE_L:
   1588         case RUN_TYPE_UF:
   1589         case RUN_TYPE_LF:
   1590             data_index = find_data_index(conv_table, conv_table_len, te->data);
   1591             if (data_index < 0) {
   1592                 switch(te->type) {
   1593                 case RUN_TYPE_U:
   1594                     te->type = RUN_TYPE_U_EXT;
   1595                     te->ext_len = 1;
   1596                     te->ext_data[0] = te->data;
   1597                     break;
   1598                 case RUN_TYPE_LF:
   1599                     te->type = RUN_TYPE_LF_EXT;
   1600                     te->ext_len = 1;
   1601                     te->ext_data[0] = te->data;
   1602                     break;
   1603                 default:
   1604                     printf("%05x: index not found\n", te->code);
   1605                     exit(1);
   1606                 }
   1607             } else {
   1608                 te->data_index = data_index;
   1609             }
   1610             break;
   1611         case RUN_TYPE_UF_D20:
   1612             te->data_index = te->data;
   1613             break;
   1614         }
   1615     }
   1616 
   1617     /* find the data index for ext_data */
   1618     for(i = 0; i < conv_table_len; i++) {
   1619         te = &conv_table[i];
   1620         if (te->type == RUN_TYPE_UF_EXT3) {
   1621             int p, v;
   1622             v = 0;
   1623             for(j = 0; j < 3; j++) {
   1624                 p = find_ext_data_index(te->ext_data[j]);
   1625                 assert(p < 16);
   1626                 v = (v << 4) | p;
   1627             }
   1628             te->data_index = v;
   1629         }
   1630     }
   1631 
   1632     for(i = 0; i < conv_table_len; i++) {
   1633         te = &conv_table[i];
   1634         if (te->type == RUN_TYPE_LF_EXT2 ||
   1635             te->type == RUN_TYPE_UF_EXT2 ||
   1636             te->type == RUN_TYPE_U2L_399_EXT2) {
   1637             int p, v;
   1638             v = 0;
   1639             for(j = 0; j < 2; j++) {
   1640                 p = find_ext_data_index(te->ext_data[j]);
   1641                 assert(p < 64);
   1642                 v = (v << 6) | p;
   1643             }
   1644             te->data_index = v;
   1645         }
   1646     }
   1647 
   1648     for(i = 0; i < conv_table_len; i++) {
   1649         te = &conv_table[i];
   1650         if (te->type == RUN_TYPE_UF_D1_EXT ||
   1651             te->type == RUN_TYPE_U_EXT ||
   1652             te->type == RUN_TYPE_LF_EXT) {
   1653             te->data_index = find_ext_data_index(te->ext_data[0]);
   1654         }
   1655     }
   1656 #ifdef DUMP_CASE_CONV_TABLE
   1657     dump_case_conv_table1();
   1658 #endif
   1659 }
   1660 
   1661 void dump_case_conv_table(FILE *f)
   1662 {
   1663     int i;
   1664     uint32_t v;
   1665     const TableEntry *te;
   1666 
   1667     total_tables++;
   1668     total_table_bytes += conv_table_len * sizeof(uint32_t);
   1669     fprintf(f, "static const uint32_t case_conv_table1[%d] = {", conv_table_len);
   1670     for(i = 0; i < conv_table_len; i++) {
   1671         if (i % 4 == 0)
   1672             fprintf(f, "\n   ");
   1673         te = &conv_table[i];
   1674         v = te->code << (32 - 17);
   1675         v |= te->len << (32 - 17 - 7);
   1676         v |= te->type << (32 - 17 - 7 - 4);
   1677         v |= te->data_index >> 8;
   1678         fprintf(f, " 0x%08x,", v);
   1679     }
   1680     fprintf(f, "\n};\n\n");
   1681 
   1682     total_tables++;
   1683     total_table_bytes += conv_table_len;
   1684     fprintf(f, "static const uint8_t case_conv_table2[%d] = {", conv_table_len);
   1685     for(i = 0; i < conv_table_len; i++) {
   1686         if (i % 8 == 0)
   1687             fprintf(f, "\n   ");
   1688         te = &conv_table[i];
   1689         fprintf(f, " 0x%02x,", te->data_index & 0xff);
   1690     }
   1691     fprintf(f, "\n};\n\n");
   1692 
   1693     total_tables++;
   1694     total_table_bytes += ext_data_len * sizeof(uint16_t);
   1695     fprintf(f, "static const uint16_t case_conv_ext[%d] = {", ext_data_len);
   1696     for(i = 0; i < ext_data_len; i++) {
   1697         if (i % 8 == 0)
   1698             fprintf(f, "\n   ");
   1699         fprintf(f, " 0x%04x,", ext_data[i]);
   1700     }
   1701     fprintf(f, "\n};\n\n");
   1702 }
   1703 
   1704 
   1705 static CCInfo *global_tab;
   1706 
   1707 static int sp_cc_cmp(const void *p1, const void *p2)
   1708 {
   1709     CCInfo *c1 = &global_tab[*(const int *)p1];
   1710     CCInfo *c2 = &global_tab[*(const int *)p2];
   1711     if (c1->f_len < c2->f_len) {
   1712         return -1;
   1713     } else if (c2->f_len < c1->f_len) {
   1714         return 1;
   1715     } else {
   1716         return memcmp(c1->f_data, c2->f_data, sizeof(c1->f_data[0]) * c1->f_len);
   1717     }
   1718 }
   1719 
   1720 /* dump the case special cases (multi character results which are
   1721    identical and need specific handling in lre_canonicalize() */
   1722 void dump_case_folding_special_cases(CCInfo *tab)
   1723 {
   1724     int i, len, j;
   1725     int *perm;
   1726 
   1727     perm = malloc(sizeof(perm[0]) * (CHARCODE_MAX + 1));
   1728     for(i = 0; i <= CHARCODE_MAX; i++)
   1729         perm[i] = i;
   1730     global_tab = tab;
   1731     qsort(perm, CHARCODE_MAX + 1, sizeof(perm[0]), sp_cc_cmp);
   1732     for(i = 0; i <= CHARCODE_MAX;) {
   1733         if (tab[perm[i]].f_len <= 1) {
   1734             i++;
   1735         } else {
   1736             len = 1;
   1737             while ((i + len) <= CHARCODE_MAX && !sp_cc_cmp(&perm[i], &perm[i + len]))
   1738                 len++;
   1739 
   1740             if (len > 1) {
   1741                 for(j = i; j < i + len; j++)
   1742                     dump_cc_info(&tab[perm[j]], perm[j]);
   1743             }
   1744             i += len;
   1745         }
   1746     }
   1747     free(perm);
   1748     global_tab = NULL;
   1749 }
   1750 
   1751 
   1752 int tabcmp(const int *tab1, const int *tab2, int n)
   1753 {
   1754     int i;
   1755     for(i = 0; i < n; i++) {
   1756         if (tab1[i] != tab2[i])
   1757             return -1;
   1758     }
   1759     return 0;
   1760 }
   1761 
   1762 void dump_str(const char *str, const int *buf, int len)
   1763 {
   1764     int i;
   1765     printf("%s=", str);
   1766     for(i = 0; i < len; i++)
   1767         printf(" %05x", buf[i]);
   1768     printf("\n");
   1769 }
   1770 
   1771 void compute_internal_props(void)
   1772 {
   1773     int i;
   1774     BOOL has_ul;
   1775 
   1776     for(i = 0; i <= CHARCODE_MAX; i++) {
   1777         CCInfo *ci = &unicode_db[i];
   1778         has_ul = (ci->u_len != 0 || ci->l_len != 0 || ci->f_len != 0);
   1779         if (has_ul) {
   1780             assert(get_prop(i, PROP_Cased));
   1781         } else {
   1782             set_prop(i, PROP_Cased1, get_prop(i, PROP_Cased));
   1783         }
   1784         set_prop(i, PROP_ID_Continue1,
   1785                  get_prop(i, PROP_ID_Continue) & (get_prop(i, PROP_ID_Start) ^ 1));
   1786         set_prop(i, PROP_XID_Start1,
   1787                  get_prop(i, PROP_ID_Start) ^ get_prop(i, PROP_XID_Start));
   1788         set_prop(i, PROP_XID_Continue1,
   1789                  get_prop(i, PROP_ID_Continue) ^ get_prop(i, PROP_XID_Continue));
   1790         set_prop(i, PROP_Changes_When_Titlecased1,
   1791                  get_prop(i, PROP_Changes_When_Titlecased) ^ (ci->u_len != 0));
   1792         set_prop(i, PROP_Changes_When_Casefolded1,
   1793                  get_prop(i, PROP_Changes_When_Casefolded) ^ (ci->f_len != 0));
   1794         /* XXX: reduce table size (438 bytes) */
   1795         set_prop(i, PROP_Changes_When_NFKC_Casefolded1,
   1796                  get_prop(i, PROP_Changes_When_NFKC_Casefolded) ^ (ci->f_len != 0));
   1797 #if 0
   1798         /* TEST */
   1799 #define M(x) (1U << GCAT_ ## x)
   1800         {
   1801             int b;
   1802             b = ((M(Mn) | M(Cf) | M(Lm) | M(Sk)) >>
   1803                  unicode_db[i].general_category) & 1;
   1804             set_prop(i, PROP_Cased1,
   1805                      get_prop(i, PROP_Case_Ignorable) ^ b);
   1806         }
   1807 #undef M
   1808 #endif
   1809     }
   1810 }
   1811 
   1812 void dump_byte_table(FILE *f, const char *cname, const uint8_t *tab, int len)
   1813 {
   1814     int i;
   1815 
   1816     total_tables++;
   1817     total_table_bytes += len;
   1818     fprintf(f, "static const uint8_t %s[%d] = {", cname, len);
   1819     for(i = 0; i < len; i++) {
   1820         if (i % 8 == 0)
   1821             fprintf(f, "\n   ");
   1822         fprintf(f, " 0x%02x,", tab[i]);
   1823     }
   1824     fprintf(f, "\n};\n\n");
   1825 }
   1826 
   1827 void dump_index_table(FILE *f, const char *cname, const uint8_t *tab, int len)
   1828 {
   1829     int i, code, offset;
   1830 
   1831     total_index++;
   1832     total_index_bytes += len;
   1833     fprintf(f, "static const uint8_t %s[%d] = {\n", cname, len);
   1834     for(i = 0; i < len; i += 3) {
   1835         code = tab[i] + (tab[i+1] << 8) + ((tab[i+2] & 0x1f) << 16);
   1836         offset = ((i / 3) + 1) * 32 + (tab[i+2] >> 5);
   1837         fprintf(f, "    0x%02x, 0x%02x, 0x%02x,", tab[i], tab[i+1], tab[i+2]);
   1838         fprintf(f, "  // %6.5X at %d%s\n", code, offset,
   1839                 i == len - 3 ? " (upper bound)" : "");
   1840     }
   1841     fprintf(f, "};\n\n");
   1842 }
   1843 
   1844 #define PROP_BLOCK_LEN 32
   1845 
   1846 void build_prop_table(FILE *f, const char *name, int prop_index, BOOL add_index)
   1847 {
   1848     int i, j, n, v, offset, code;
   1849     DynBuf dbuf_s, *dbuf = &dbuf_s;
   1850     DynBuf dbuf1_s, *dbuf1 = &dbuf1_s;
   1851     DynBuf dbuf2_s, *dbuf2 = &dbuf2_s;
   1852     const uint32_t *buf;
   1853     int buf_len, block_end_pos, bit;
   1854     char cname[128];
   1855 
   1856     dbuf_init(dbuf1);
   1857 
   1858     for(i = 0; i <= CHARCODE_MAX;) {
   1859         v = get_prop(i, prop_index);
   1860         j = i + 1;
   1861         while (j <= CHARCODE_MAX && get_prop(j, prop_index) == v) {
   1862             j++;
   1863         }
   1864         n = j - i;
   1865         if (j == (CHARCODE_MAX + 1) && v == 0)
   1866             break; /* no need to encode last zero run */
   1867         //printf("%05x: %d %d\n", i, n, v);
   1868         dbuf_put_u32(dbuf1, n - 1);
   1869         i += n;
   1870     }
   1871 
   1872     dbuf_init(dbuf);
   1873     dbuf_init(dbuf2);
   1874     buf = (uint32_t *)dbuf1->buf;
   1875     buf_len = dbuf1->size / sizeof(buf[0]);
   1876 
   1877     /* the first value is assumed to be 0 */
   1878     assert(get_prop(0, prop_index) == 0);
   1879 
   1880     block_end_pos = PROP_BLOCK_LEN;
   1881     i = 0;
   1882     code = 0;
   1883     bit = 0;
   1884     while (i < buf_len) {
   1885         if (add_index && dbuf->size >= block_end_pos && bit == 0) {
   1886             offset = (dbuf->size - block_end_pos);
   1887             /* XXX: offset could be larger in case of runs of small
   1888                lengths. Could add code to change the encoding to
   1889                prevent it at the expense of one byte loss */
   1890             assert(offset <= 7);
   1891             v = code | (offset << 21);
   1892             dbuf_putc(dbuf2, v);
   1893             dbuf_putc(dbuf2, v >> 8);
   1894             dbuf_putc(dbuf2, v >> 16);
   1895             block_end_pos += PROP_BLOCK_LEN;
   1896         }
   1897 
   1898         /* Compressed byte encoding:
   1899            00..3F: 2 packed lengths: 3-bit + 3-bit
   1900            40..5F: 5-bits plus extra byte for length
   1901            60..7F: 5-bits plus 2 extra bytes for length
   1902            80..FF: 7-bit length
   1903            lengths must be incremented to get character count
   1904            Ranges alternate between false and true return value.
   1905          */
   1906         v = buf[i];
   1907         code += v + 1;
   1908         bit ^= 1;
   1909         if (v < 8 && (i + 1) < buf_len && buf[i + 1] < 8) {
   1910             code += buf[i + 1] + 1;
   1911             bit ^= 1;
   1912             dbuf_putc(dbuf, (v << 3) | buf[i + 1]);
   1913             i += 2;
   1914         } else if (v < 128) {
   1915             dbuf_putc(dbuf, 0x80 + v);
   1916             i++;
   1917         } else if (v < (1 << 13)) {
   1918             dbuf_putc(dbuf, 0x40 + (v >> 8));
   1919             dbuf_putc(dbuf, v);
   1920             i++;
   1921         } else {
   1922             assert(v < (1 << 21));
   1923             dbuf_putc(dbuf, 0x60 + (v >> 16));
   1924             dbuf_putc(dbuf, v >> 8);
   1925             dbuf_putc(dbuf, v);
   1926             i++;
   1927         }
   1928     }
   1929 
   1930     if (add_index) {
   1931         /* last index entry */
   1932         v = code;
   1933         dbuf_putc(dbuf2, v);
   1934         dbuf_putc(dbuf2, v >> 8);
   1935         dbuf_putc(dbuf2, v >> 16);
   1936     }
   1937 
   1938 #ifdef DUMP_TABLE_SIZE
   1939     printf("prop %s: length=%d bytes\n", unicode_prop_name[prop_index],
   1940            (int)(dbuf->size + dbuf2->size));
   1941 #endif
   1942     snprintf(cname, sizeof(cname), "unicode_prop_%s_table", unicode_prop_name[prop_index]);
   1943     dump_byte_table(f, cname, dbuf->buf, dbuf->size);
   1944     if (add_index) {
   1945         snprintf(cname, sizeof(cname), "unicode_prop_%s_index", unicode_prop_name[prop_index]);
   1946         dump_index_table(f, cname, dbuf2->buf, dbuf2->size);
   1947     }
   1948 
   1949     dbuf_free(dbuf);
   1950     dbuf_free(dbuf1);
   1951     dbuf_free(dbuf2);
   1952 }
   1953 
   1954 void build_flags_tables(FILE *f)
   1955 {
   1956     build_prop_table(f, "Cased1", PROP_Cased1, TRUE);
   1957     build_prop_table(f, "Case_Ignorable", PROP_Case_Ignorable, TRUE);
   1958     build_prop_table(f, "ID_Start", PROP_ID_Start, TRUE);
   1959     build_prop_table(f, "ID_Continue1", PROP_ID_Continue1, TRUE);
   1960 }
   1961 
   1962 void dump_name_table(FILE *f, const char *cname, const char **tab_name, int len,
   1963                      const char **tab_short_name)
   1964 {
   1965     int i, w, maxw;
   1966 
   1967     maxw = 0;
   1968     for(i = 0; i < len; i++) {
   1969         w = strlen(tab_name[i]);
   1970         if (tab_short_name && tab_short_name[i][0] != '\0') {
   1971             w += 1 + strlen(tab_short_name[i]);
   1972         }
   1973         if (maxw < w)
   1974             maxw = w;
   1975     }
   1976 
   1977     /* generate a sequence of strings terminated by an empty string */
   1978     fprintf(f, "static const char %s[] =\n", cname);
   1979     for(i = 0; i < len; i++) {
   1980         fprintf(f, "    \"");
   1981         w = fprintf(f, "%s", tab_name[i]);
   1982         if (tab_short_name && tab_short_name[i][0] != '\0') {
   1983             w += fprintf(f, ",%s", tab_short_name[i]);
   1984         }
   1985         fprintf(f, "\"%*s\"\\0\"\n", 1 + maxw - w, "");
   1986     }
   1987     fprintf(f, ";\n\n");
   1988 }
   1989 
   1990 void build_general_category_table(FILE *f)
   1991 {
   1992     int i, v, j, n, n1;
   1993     DynBuf dbuf_s, *dbuf = &dbuf_s;
   1994 #ifdef DUMP_TABLE_SIZE
   1995     int cw_count, cw_len_count[4], cw_start;
   1996 #endif
   1997 
   1998     fprintf(f, "typedef enum {\n");
   1999     for(i = 0; i < GCAT_COUNT; i++)
   2000         fprintf(f, "    UNICODE_GC_%s,\n", unicode_gc_name[i]);
   2001     fprintf(f, "    UNICODE_GC_COUNT,\n");
   2002     fprintf(f, "} UnicodeGCEnum;\n\n");
   2003 
   2004     dump_name_table(f, "unicode_gc_name_table",
   2005                     unicode_gc_name, GCAT_COUNT,
   2006                     unicode_gc_short_name);
   2007 
   2008 
   2009     dbuf_init(dbuf);
   2010 #ifdef DUMP_TABLE_SIZE
   2011     cw_count = 0;
   2012     for(i = 0; i < 4; i++)
   2013         cw_len_count[i] = 0;
   2014 #endif
   2015     for(i = 0; i <= CHARCODE_MAX;) {
   2016         v = unicode_db[i].general_category;
   2017         j = i + 1;
   2018         while (j <= CHARCODE_MAX && unicode_db[j].general_category == v)
   2019             j++;
   2020         n = j - i;
   2021         /* compress Lu/Ll runs */
   2022         if (v == GCAT_Lu) {
   2023             n1 = 1;
   2024             while ((i + n1) <= CHARCODE_MAX && unicode_db[i + n1].general_category == (v + (n1 & 1))) {
   2025                 n1++;
   2026             }
   2027             if (n1 > n) {
   2028                 v = 31;
   2029                 n = n1;
   2030             }
   2031         }
   2032         //        printf("%05x %05x %d\n", i, n, v);
   2033         n--;
   2034 #ifdef DUMP_TABLE_SIZE
   2035         cw_count++;
   2036         cw_start = dbuf->size;
   2037 #endif
   2038         if (n < 7) {
   2039             dbuf_putc(dbuf, (n << 5) | v);
   2040         } else if (n < 7 + 128) {
   2041             n1 = n - 7;
   2042             assert(n1 < 128);
   2043             dbuf_putc(dbuf, (0xf << 5) | v);
   2044             dbuf_putc(dbuf, n1);
   2045         } else if (n < 7 + 128 + (1 << 14)) {
   2046             n1 = n - (7 + 128);
   2047             assert(n1 < (1 << 14));
   2048             dbuf_putc(dbuf, (0xf << 5) | v);
   2049             dbuf_putc(dbuf, (n1 >> 8) + 128);
   2050             dbuf_putc(dbuf, n1);
   2051         } else {
   2052             n1 = n - (7 + 128 + (1 << 14));
   2053             assert(n1 < (1 << 22));
   2054             dbuf_putc(dbuf, (0xf << 5) | v);
   2055             dbuf_putc(dbuf, (n1 >> 16) + 128 + 64);
   2056             dbuf_putc(dbuf, n1 >> 8);
   2057             dbuf_putc(dbuf, n1);
   2058         }
   2059 #ifdef DUMP_TABLE_SIZE
   2060         cw_len_count[dbuf->size - cw_start - 1]++;
   2061 #endif
   2062         i += n + 1;
   2063     }
   2064 #ifdef DUMP_TABLE_SIZE
   2065     printf("general category: %d entries [", cw_count);
   2066     for(i = 0; i < 4; i++)
   2067         printf(" %d", cw_len_count[i]);
   2068     printf(" ], length=%d bytes\n", (int)dbuf->size);
   2069 #endif
   2070 
   2071     dump_byte_table(f, "unicode_gc_table", dbuf->buf, dbuf->size);
   2072 
   2073     dbuf_free(dbuf);
   2074 }
   2075 
   2076 void build_script_table(FILE *f)
   2077 {
   2078     int i, v, j, n, n1, type;
   2079     DynBuf dbuf_s, *dbuf = &dbuf_s;
   2080 #ifdef DUMP_TABLE_SIZE
   2081     int cw_count, cw_len_count[4], cw_start;
   2082 #endif
   2083 
   2084     fprintf(f, "typedef enum {\n");
   2085     for(i = 0; i < SCRIPT_COUNT; i++)
   2086         fprintf(f, "    UNICODE_SCRIPT_%s,\n", unicode_script_name[i]);
   2087     fprintf(f, "    UNICODE_SCRIPT_COUNT,\n");
   2088     fprintf(f, "} UnicodeScriptEnum;\n\n");
   2089 
   2090     dump_name_table(f, "unicode_script_name_table",
   2091                     unicode_script_name, SCRIPT_COUNT,
   2092                     unicode_script_short_name);
   2093 
   2094     dbuf_init(dbuf);
   2095 #ifdef DUMP_TABLE_SIZE
   2096     cw_count = 0;
   2097     for(i = 0; i < 4; i++)
   2098         cw_len_count[i] = 0;
   2099 #endif
   2100     for(i = 0; i <= CHARCODE_MAX;) {
   2101         v = unicode_db[i].script;
   2102         j = i + 1;
   2103         while (j <= CHARCODE_MAX && unicode_db[j].script == v)
   2104             j++;
   2105         n = j - i;
   2106         if (v == 0 && j == (CHARCODE_MAX + 1))
   2107             break;
   2108         //        printf("%05x %05x %d\n", i, n, v);
   2109         n--;
   2110 #ifdef DUMP_TABLE_SIZE
   2111         cw_count++;
   2112         cw_start = dbuf->size;
   2113 #endif
   2114         if (v == 0)
   2115             type = 0;
   2116         else
   2117             type = 1;
   2118         if (n < 96) {
   2119             dbuf_putc(dbuf, n | (type << 7));
   2120         } else if (n < 96 + (1 << 12)) {
   2121             n1 = n - 96;
   2122             assert(n1 < (1 << 12));
   2123             dbuf_putc(dbuf, ((n1 >> 8) + 96) | (type << 7));
   2124             dbuf_putc(dbuf, n1);
   2125         } else {
   2126             n1 = n - (96 + (1 << 12));
   2127             assert(n1 < (1 << 20));
   2128             dbuf_putc(dbuf, ((n1 >> 16) + 112) | (type << 7));
   2129             dbuf_putc(dbuf, n1 >> 8);
   2130             dbuf_putc(dbuf, n1);
   2131         }
   2132         if (type != 0)
   2133             dbuf_putc(dbuf, v);
   2134 
   2135 #ifdef DUMP_TABLE_SIZE
   2136         cw_len_count[dbuf->size - cw_start - 1]++;
   2137 #endif
   2138         i += n + 1;
   2139     }
   2140 #ifdef DUMP_TABLE_SIZE
   2141     printf("script: %d entries [", cw_count);
   2142     for(i = 0; i < 4; i++)
   2143         printf(" %d", cw_len_count[i]);
   2144     printf(" ], length=%d bytes\n", (int)dbuf->size);
   2145 #endif
   2146 
   2147     dump_byte_table(f, "unicode_script_table", dbuf->buf, dbuf->size);
   2148 
   2149     dbuf_free(dbuf);
   2150 }
   2151 
   2152 void build_script_ext_table(FILE *f)
   2153 {
   2154     int i, j, n, n1, script_ext_len;
   2155     DynBuf dbuf_s, *dbuf = &dbuf_s;
   2156 #if defined(DUMP_TABLE_SIZE)
   2157     int cw_count = 0;
   2158 #endif
   2159 
   2160     dbuf_init(dbuf);
   2161     for(i = 0; i <= CHARCODE_MAX;) {
   2162         script_ext_len = unicode_db[i].script_ext_len;
   2163         j = i + 1;
   2164         while (j <= CHARCODE_MAX &&
   2165                unicode_db[j].script_ext_len == script_ext_len &&
   2166                !memcmp(unicode_db[j].script_ext, unicode_db[i].script_ext,
   2167                        script_ext_len)) {
   2168             j++;
   2169         }
   2170         n = j - i;
   2171 #if defined(DUMP_TABLE_SIZE)
   2172         cw_count++;
   2173 #endif
   2174         n--;
   2175         if (n < 128) {
   2176             dbuf_putc(dbuf, n);
   2177         } else if (n < 128 + (1 << 14)) {
   2178             n1 = n - 128;
   2179             assert(n1 < (1 << 14));
   2180             dbuf_putc(dbuf, (n1 >> 8) + 128);
   2181             dbuf_putc(dbuf, n1);
   2182         } else {
   2183             n1 = n - (128 + (1 << 14));
   2184             assert(n1 < (1 << 22));
   2185             dbuf_putc(dbuf, (n1 >> 16) + 128 + 64);
   2186             dbuf_putc(dbuf, n1 >> 8);
   2187             dbuf_putc(dbuf, n1);
   2188         }
   2189         dbuf_putc(dbuf, script_ext_len);
   2190         for(j = 0; j < script_ext_len; j++)
   2191             dbuf_putc(dbuf, unicode_db[i].script_ext[j]);
   2192         i += n + 1;
   2193     }
   2194 #ifdef DUMP_TABLE_SIZE
   2195     printf("script_ext: %d entries", cw_count);
   2196     printf(", length=%d bytes\n", (int)dbuf->size);
   2197 #endif
   2198 
   2199     dump_byte_table(f, "unicode_script_ext_table", dbuf->buf, dbuf->size);
   2200 
   2201     dbuf_free(dbuf);
   2202 }
   2203 
   2204 /* the following properties are synthetized so no table is necessary */
   2205 #define PROP_TABLE_COUNT PROP_ASCII
   2206 
   2207 void build_prop_list_table(FILE *f)
   2208 {
   2209     int i;
   2210 
   2211     for(i = 0; i < PROP_TABLE_COUNT; i++) {
   2212         if (i == PROP_ID_Start ||
   2213             i == PROP_Case_Ignorable ||
   2214             i == PROP_ID_Continue1) {
   2215             /* already generated */
   2216         } else {
   2217             build_prop_table(f, unicode_prop_name[i], i, FALSE);
   2218         }
   2219     }
   2220 
   2221     fprintf(f, "typedef enum {\n");
   2222     for(i = 0; i < PROP_COUNT; i++)
   2223         fprintf(f, "    UNICODE_PROP_%s,\n", unicode_prop_name[i]);
   2224     fprintf(f, "    UNICODE_PROP_COUNT,\n");
   2225     fprintf(f, "} UnicodePropertyEnum;\n\n");
   2226 
   2227     i = PROP_ASCII_Hex_Digit;
   2228     dump_name_table(f, "unicode_prop_name_table",
   2229                     unicode_prop_name + i, PROP_XID_Start - i + 1,
   2230                     unicode_prop_short_name + i);
   2231 
   2232     fprintf(f, "static const uint8_t * const unicode_prop_table[] = {\n");
   2233     for(i = 0; i < PROP_TABLE_COUNT; i++) {
   2234         fprintf(f, "    unicode_prop_%s_table,\n", unicode_prop_name[i]);
   2235     }
   2236     fprintf(f, "};\n\n");
   2237 
   2238     fprintf(f, "static const uint16_t unicode_prop_len_table[] = {\n");
   2239     for(i = 0; i < PROP_TABLE_COUNT; i++) {
   2240         fprintf(f, "    countof(unicode_prop_%s_table),\n", unicode_prop_name[i]);
   2241     }
   2242     fprintf(f, "};\n\n");
   2243 }
   2244 
   2245 static BOOL is_emoji_hair_color(uint32_t c)
   2246 {
   2247     return (c >= 0x1F9B0 && c <= 0x1F9B3);
   2248 }
   2249 
   2250 #define EMOJI_MOD_NONE   0
   2251 #define EMOJI_MOD_TYPE1  1
   2252 #define EMOJI_MOD_TYPE2  2
   2253 #define EMOJI_MOD_TYPE2D 3
   2254 
   2255 static BOOL mark_zwj_string(REStringList *sl, uint32_t *buf, int len, int mod_type, int *mod_pos,
   2256                             int hc_pos, BOOL mark_flag)
   2257 {
   2258     REString *p;
   2259     int i, n_mod, i0, i1, hc_count, j;
   2260 
   2261 #if 0
   2262     if (mark_flag)
   2263         printf("mod_type=%d\n", mod_type);
   2264 #endif
   2265     
   2266     switch(mod_type) {
   2267     case EMOJI_MOD_NONE:
   2268         n_mod = 1;
   2269         break;
   2270     case EMOJI_MOD_TYPE1:
   2271         n_mod = 5;
   2272         break;
   2273     case EMOJI_MOD_TYPE2:
   2274         n_mod = 25;
   2275         break;
   2276     case EMOJI_MOD_TYPE2D:
   2277         n_mod = 20;
   2278         break;
   2279     default:
   2280         assert(0);
   2281     }
   2282     if (hc_pos >= 0)
   2283         hc_count = 4;
   2284     else
   2285         hc_count = 1;
   2286     /* check that all the related strings are present */
   2287     for(j = 0; j < hc_count; j++) {
   2288         for(i = 0; i < n_mod; i++) {
   2289             switch(mod_type) {
   2290             case EMOJI_MOD_NONE:
   2291                 break;
   2292             case EMOJI_MOD_TYPE1:
   2293                 buf[mod_pos[0]] = 0x1f3fb + i;
   2294                 break;
   2295             case EMOJI_MOD_TYPE2:
   2296             case EMOJI_MOD_TYPE2D:
   2297                 i0 = i / 5;
   2298                 i1 = i % 5;
   2299                 /* avoid identical values */
   2300                 if (mod_type == EMOJI_MOD_TYPE2D && i0 >= i1)
   2301                     i0++;
   2302                 buf[mod_pos[0]] = 0x1f3fb + i0;
   2303                 buf[mod_pos[1]] = 0x1f3fb + i1;
   2304                 break;
   2305             default:
   2306                 assert(0);
   2307             }
   2308 
   2309             if (hc_pos >= 0)
   2310                 buf[hc_pos] = 0x1F9B0 + j;
   2311             
   2312             p = re_string_find(sl, len, buf, FALSE);
   2313             if (!p)
   2314                 return FALSE;
   2315             if (mark_flag)
   2316                 p->flags |= 1;
   2317         }
   2318     }
   2319     return TRUE;
   2320 }
   2321 
   2322 static void zwj_encode_string(DynBuf *dbuf, const uint32_t *buf, int len, int mod_type, int *mod_pos,
   2323                               int hc_pos)
   2324 {
   2325     int i, j;
   2326     int c, code;
   2327     uint32_t buf1[SEQ_MAX_LEN];
   2328     
   2329     j = 0;
   2330     for(i = 0; i < len;) {
   2331         c = buf[i++];
   2332         if (c >= 0x2000 && c <= 0x2fff) {
   2333             code = c - 0x2000;
   2334         } else if (c >= 0x1f000 && c <= 0x1ffff) {
   2335             code = c - 0x1f000 + 0x1000;
   2336         } else {
   2337             assert(0);
   2338         }
   2339         if (i < len && is_emoji_modifier(buf[i])) {
   2340             /* modifier */
   2341             code |= (mod_type << 13);
   2342             i++;
   2343         }
   2344         if (i < len && buf[i] == 0xfe0f) {
   2345             /* presentation selector present */
   2346             code |= 0x8000;
   2347             i++;
   2348         }
   2349         if (i < len) {
   2350             /* zero width join */
   2351             assert(buf[i] == 0x200d);
   2352             i++;
   2353         }
   2354         buf1[j++] = code;
   2355     }
   2356     dbuf_putc(dbuf, j);
   2357     for(i = 0; i < j; i++) {
   2358         dbuf_putc(dbuf, buf1[i]);
   2359         dbuf_putc(dbuf, buf1[i] >> 8);
   2360     }
   2361 }
   2362 
   2363 static void build_rgi_emoji_zwj_sequence(FILE *f, REStringList *sl)
   2364 {
   2365     int mod_pos[2], mod_count, hair_color_pos, j, h;
   2366     REString *p;
   2367     uint32_t buf[SEQ_MAX_LEN];
   2368     DynBuf dbuf;
   2369 
   2370 #if 0
   2371     {
   2372         for(h = 0; h < sl->hash_size; h++) {
   2373             for(p = sl->hash_table[h]; p != NULL; p = p->next) {
   2374                 for(j = 0; j < p->len; j++)
   2375                     printf(" %04x", p->buf[j]);
   2376                 printf("\n");
   2377             }
   2378         }
   2379         exit(0);
   2380     }
   2381 #endif
   2382     //    printf("rgi_emoji_zwj_sequence: n=%d\n", sl->n_strings);
   2383 
   2384     dbuf_init(&dbuf);
   2385     
   2386     /* avoid duplicating strings with emoji modifiers or hair colors */
   2387     for(h = 0; h < sl->hash_size; h++) {
   2388         for(p = sl->hash_table[h]; p != NULL; p = p->next) {
   2389             if (p->flags) /* already examined */
   2390                 continue;
   2391             mod_count = 0;
   2392             hair_color_pos = -1;
   2393             for(j = 0; j < p->len; j++) {
   2394                 if (is_emoji_modifier(p->buf[j])) {
   2395                     assert(mod_count < 2);
   2396                     mod_pos[mod_count++] = j;
   2397                 } else if (is_emoji_hair_color(p->buf[j])) {
   2398                     hair_color_pos = j;
   2399                 }
   2400                 buf[j] = p->buf[j];
   2401             }
   2402             
   2403             if (mod_count != 0 || hair_color_pos >= 0) {
   2404                 int mod_type;
   2405                 if (mod_count == 0)
   2406                     mod_type = EMOJI_MOD_NONE;
   2407                 else if (mod_count == 1)
   2408                     mod_type = EMOJI_MOD_TYPE1;
   2409                 else
   2410                     mod_type = EMOJI_MOD_TYPE2;
   2411                 
   2412                 if (mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, FALSE)) {
   2413                     mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, TRUE);
   2414                 } else if (mod_type == EMOJI_MOD_TYPE2) {
   2415                     mod_type = EMOJI_MOD_TYPE2D;
   2416                     if (mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, FALSE)) {
   2417                         mark_zwj_string(sl, buf, p->len, mod_type, mod_pos, hair_color_pos, TRUE);
   2418                     } else {
   2419                         dump_str("not_found", (int *)p->buf, p->len);
   2420                         goto keep;
   2421                     }
   2422                 }
   2423                 if (hair_color_pos >= 0)
   2424                     buf[hair_color_pos] = 0x1f9b0;
   2425                 /* encode the string */
   2426                 zwj_encode_string(&dbuf, buf, p->len, mod_type, mod_pos, hair_color_pos);
   2427             } else {
   2428             keep:
   2429                 zwj_encode_string(&dbuf, buf, p->len, EMOJI_MOD_NONE, NULL, -1);
   2430             }
   2431         }
   2432     }
   2433     
   2434     /* Encode */
   2435     dump_byte_table(f, "unicode_rgi_emoji_zwj_sequence", dbuf.buf, dbuf.size);
   2436 
   2437     dbuf_free(&dbuf);
   2438 }
   2439 
   2440 void build_sequence_prop_list_table(FILE *f)
   2441 {
   2442     int i;
   2443     fprintf(f, "typedef enum {\n");
   2444     for(i = 0; i < SEQUENCE_PROP_COUNT; i++)
   2445         fprintf(f, "    UNICODE_SEQUENCE_PROP_%s,\n", unicode_sequence_prop_name[i]);
   2446     fprintf(f, "    UNICODE_SEQUENCE_PROP_COUNT,\n");
   2447     fprintf(f, "} UnicodeSequencePropertyEnum;\n\n");
   2448 
   2449     dump_name_table(f, "unicode_sequence_prop_name_table",
   2450                     unicode_sequence_prop_name, SEQUENCE_PROP_COUNT, NULL);
   2451 
   2452     dump_byte_table(f, "unicode_rgi_emoji_tag_sequence", rgi_emoji_tag_sequence.buf, rgi_emoji_tag_sequence.size);
   2453 
   2454     build_rgi_emoji_zwj_sequence(f, &rgi_emoji_zwj_sequence);
   2455 }
   2456 
   2457 #ifdef USE_TEST
   2458 int check_conv(uint32_t *res, uint32_t c, int conv_type)
   2459 {
   2460     return lre_case_conv(res, c, conv_type);
   2461 }
   2462 
   2463 void check_case_conv(void)
   2464 {
   2465     CCInfo *tab = unicode_db;
   2466     uint32_t res[3];
   2467     int l, error;
   2468     CCInfo ci_s, *ci1, *ci = &ci_s;
   2469     int code;
   2470 
   2471     for(code = 0; code <= CHARCODE_MAX; code++) {
   2472         ci1 = &tab[code];
   2473         *ci = *ci1;
   2474         if (ci->l_len == 0) {
   2475             ci->l_len = 1;
   2476             ci->l_data[0] = code;
   2477         }
   2478         if (ci->u_len == 0) {
   2479             ci->u_len = 1;
   2480             ci->u_data[0] = code;
   2481         }
   2482         if (ci->f_len == 0) {
   2483             ci->f_len = 1;
   2484             ci->f_data[0] = code;
   2485         }
   2486 
   2487         error = 0;
   2488         l = check_conv(res, code, 0);
   2489         if (l != ci->u_len || tabcmp((int *)res, ci->u_data, l)) {
   2490             printf("ERROR: L\n");
   2491             error++;
   2492         }
   2493         l = check_conv(res, code, 1);
   2494         if (l != ci->l_len || tabcmp((int *)res, ci->l_data, l)) {
   2495             printf("ERROR: U\n");
   2496             error++;
   2497         }
   2498         l = check_conv(res, code, 2);
   2499         if (l != ci->f_len || tabcmp((int *)res, ci->f_data, l)) {
   2500             printf("ERROR: F\n");
   2501             error++;
   2502         }
   2503         if (error) {
   2504             dump_cc_info(ci, code);
   2505             exit(1);
   2506         }
   2507     }
   2508 }
   2509 
   2510 #ifdef PROFILE
   2511 static int64_t get_time_ns(void)
   2512 {
   2513     struct timespec ts;
   2514     clock_gettime(CLOCK_MONOTONIC, &ts);
   2515     return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
   2516 }
   2517 #endif
   2518 
   2519 
   2520 void check_flags(void)
   2521 {
   2522     int c;
   2523     BOOL flag_ref, flag;
   2524     for(c = 0; c <= CHARCODE_MAX; c++) {
   2525         flag_ref = get_prop(c, PROP_Cased);
   2526         flag = !!lre_is_cased(c);
   2527         if (flag != flag_ref) {
   2528             printf("ERROR: c=%05x cased=%d ref=%d\n",
   2529                    c, flag, flag_ref);
   2530             exit(1);
   2531         }
   2532 
   2533         flag_ref = get_prop(c, PROP_Case_Ignorable);
   2534         flag = !!lre_is_case_ignorable(c);
   2535         if (flag != flag_ref) {
   2536             printf("ERROR: c=%05x case_ignorable=%d ref=%d\n",
   2537                    c, flag, flag_ref);
   2538             exit(1);
   2539         }
   2540 
   2541         flag_ref = get_prop(c, PROP_ID_Start);
   2542         flag = !!lre_is_id_start(c);
   2543         if (flag != flag_ref) {
   2544             printf("ERROR: c=%05x id_start=%d ref=%d\n",
   2545                    c, flag, flag_ref);
   2546             exit(1);
   2547         }
   2548 
   2549         flag_ref = get_prop(c, PROP_ID_Continue);
   2550         flag = !!lre_is_id_continue(c);
   2551         if (flag != flag_ref) {
   2552             printf("ERROR: c=%05x id_cont=%d ref=%d\n",
   2553                    c, flag, flag_ref);
   2554             exit(1);
   2555         }
   2556     }
   2557 #ifdef PROFILE
   2558     {
   2559         int64_t ti, count;
   2560         ti = get_time_ns();
   2561         count = 0;
   2562         for(c = 0x20; c <= 0xffff; c++) {
   2563             flag_ref = get_prop(c, PROP_ID_Start);
   2564             flag = !!lre_is_id_start(c);
   2565             assert(flag == flag_ref);
   2566             count++;
   2567         }
   2568         ti = get_time_ns() - ti;
   2569         printf("flags time=%0.1f ns/char\n",
   2570                (double)ti / count);
   2571     }
   2572 #endif
   2573 }
   2574 
   2575 #endif
   2576 
   2577 #define CC_BLOCK_LEN 32
   2578 
   2579 void build_cc_table(FILE *f)
   2580 {
   2581     // Compress combining class table
   2582     // see: https://www.unicode.org/reports/tr44/#Canonical_Combining_Class_Values
   2583     int i, cc, n, type, n1, block_end_pos;
   2584     DynBuf dbuf_s, *dbuf = &dbuf_s;
   2585     DynBuf dbuf1_s, *dbuf1 = &dbuf1_s;
   2586 #if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
   2587     int cw_len_tab[3], cw_start, cc_table_len;
   2588 #endif
   2589     uint32_t v;
   2590 
   2591     dbuf_init(dbuf);
   2592     dbuf_init(dbuf1);
   2593 #if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
   2594     cc_table_len = 0;
   2595     for(i = 0; i < countof(cw_len_tab); i++)
   2596         cw_len_tab[i] = 0;
   2597 #endif
   2598     block_end_pos = CC_BLOCK_LEN;
   2599     for(i = 0; i <= CHARCODE_MAX;) {
   2600         cc = unicode_db[i].combining_class;
   2601         assert(cc <= 255);
   2602         /* check increasing values */
   2603         n = 1;
   2604         while ((i + n) <= CHARCODE_MAX &&
   2605                unicode_db[i + n].combining_class == (cc + n))
   2606             n++;
   2607         if (n >= 2) {
   2608             type = 1;
   2609         } else {
   2610             type = 0;
   2611             n = 1;
   2612             while ((i + n) <= CHARCODE_MAX &&
   2613                    unicode_db[i + n].combining_class == cc)
   2614                 n++;
   2615         }
   2616         /* no need to encode the last run */
   2617         if (cc == 0 && (i + n - 1) == CHARCODE_MAX)
   2618             break;
   2619 #ifdef DUMP_CC_TABLE
   2620         printf("%05x %6d %d %d\n", i, n, type, cc);
   2621 #endif
   2622         if (type == 0) {
   2623             if (cc == 0)
   2624                 type = 2;
   2625             else if (cc == 230)
   2626                 type = 3;
   2627         }
   2628         n1 = n - 1;
   2629 
   2630         /* add an entry to the index if necessary */
   2631         if (dbuf->size >= block_end_pos) {
   2632             v = i | ((dbuf->size - block_end_pos) << 21);
   2633             dbuf_putc(dbuf1, v);
   2634             dbuf_putc(dbuf1, v >> 8);
   2635             dbuf_putc(dbuf1, v >> 16);
   2636             block_end_pos += CC_BLOCK_LEN;
   2637         }
   2638 #if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
   2639         cw_start = dbuf->size;
   2640 #endif
   2641         /* Compressed run length encoding:
   2642            - 2 high order bits are combining class type
   2643            -         0:0, 1:230, 2:extra byte linear progression, 3:extra byte
   2644            - 00..2F: range length (add 1)
   2645            - 30..37: 3-bit range-length + 1 extra byte
   2646            - 38..3F: 3-bit range-length + 2 extra byte
   2647          */
   2648         if (n1 < 48) {
   2649             dbuf_putc(dbuf, n1 | (type << 6));
   2650         } else if (n1 < 48 + (1 << 11)) {
   2651             n1 -= 48;
   2652             dbuf_putc(dbuf, ((n1 >> 8) + 48) | (type << 6));
   2653             dbuf_putc(dbuf, n1);
   2654         } else {
   2655             n1 -= 48 + (1 << 11);
   2656             assert(n1 < (1 << 20));
   2657             dbuf_putc(dbuf, ((n1 >> 16) + 56) | (type << 6));
   2658             dbuf_putc(dbuf, n1 >> 8);
   2659             dbuf_putc(dbuf, n1);
   2660         }
   2661 #if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
   2662         cw_len_tab[dbuf->size - cw_start - 1]++;
   2663         cc_table_len++;
   2664 #endif
   2665         if (type == 0 || type == 1)
   2666             dbuf_putc(dbuf, cc);
   2667         i += n;
   2668     }
   2669 
   2670     /* last index entry */
   2671     v = i;
   2672     dbuf_putc(dbuf1, v);
   2673     dbuf_putc(dbuf1, v >> 8);
   2674     dbuf_putc(dbuf1, v >> 16);
   2675 
   2676     dump_byte_table(f, "unicode_cc_table", dbuf->buf, dbuf->size);
   2677     dump_index_table(f, "unicode_cc_index", dbuf1->buf, dbuf1->size);
   2678 
   2679 #if defined(DUMP_CC_TABLE) || defined(DUMP_TABLE_SIZE)
   2680     printf("CC table: size=%d (%d entries) [",
   2681            (int)(dbuf->size + dbuf1->size),
   2682            cc_table_len);
   2683     for(i = 0; i < countof(cw_len_tab); i++)
   2684         printf(" %d", cw_len_tab[i]);
   2685     printf(" ]\n");
   2686 #endif
   2687     dbuf_free(dbuf);
   2688     dbuf_free(dbuf1);
   2689 }
   2690 
   2691 /* maximum length of decomposition: 18 chars (1), then 8 */
   2692 #ifndef USE_TEST
   2693 typedef enum {
   2694     DECOMP_TYPE_C1, /* 16 bit char */
   2695     DECOMP_TYPE_L1, /* 16 bit char table */
   2696     DECOMP_TYPE_L2,
   2697     DECOMP_TYPE_L3,
   2698     DECOMP_TYPE_L4,
   2699     DECOMP_TYPE_L5, /* XXX: not used */
   2700     DECOMP_TYPE_L6, /* XXX: could remove */
   2701     DECOMP_TYPE_L7, /* XXX: could remove */
   2702     DECOMP_TYPE_LL1, /* 18 bit char table */
   2703     DECOMP_TYPE_LL2,
   2704     DECOMP_TYPE_S1, /* 8 bit char table */
   2705     DECOMP_TYPE_S2,
   2706     DECOMP_TYPE_S3,
   2707     DECOMP_TYPE_S4,
   2708     DECOMP_TYPE_S5,
   2709     DECOMP_TYPE_I1, /* increment 16 bit char value */
   2710     DECOMP_TYPE_I2_0,
   2711     DECOMP_TYPE_I2_1,
   2712     DECOMP_TYPE_I3_1,
   2713     DECOMP_TYPE_I3_2,
   2714     DECOMP_TYPE_I4_1,
   2715     DECOMP_TYPE_I4_2,
   2716     DECOMP_TYPE_B1, /* 16 bit base + 8 bit offset */
   2717     DECOMP_TYPE_B2,
   2718     DECOMP_TYPE_B3,
   2719     DECOMP_TYPE_B4,
   2720     DECOMP_TYPE_B5,
   2721     DECOMP_TYPE_B6,
   2722     DECOMP_TYPE_B7,
   2723     DECOMP_TYPE_B8,
   2724     DECOMP_TYPE_B18,
   2725     DECOMP_TYPE_LS2,
   2726     DECOMP_TYPE_PAT3,
   2727     DECOMP_TYPE_S2_UL,
   2728     DECOMP_TYPE_LS2_UL,
   2729 } DecompTypeEnum;
   2730 #endif
   2731 
   2732 const char *decomp_type_str[] = {
   2733     "C1",
   2734     "L1",
   2735     "L2",
   2736     "L3",
   2737     "L4",
   2738     "L5",
   2739     "L6",
   2740     "L7",
   2741     "LL1",
   2742     "LL2",
   2743     "S1",
   2744     "S2",
   2745     "S3",
   2746     "S4",
   2747     "S5",
   2748     "I1",
   2749     "I2_0",
   2750     "I2_1",
   2751     "I3_1",
   2752     "I3_2",
   2753     "I4_1",
   2754     "I4_2",
   2755     "B1",
   2756     "B2",
   2757     "B3",
   2758     "B4",
   2759     "B5",
   2760     "B6",
   2761     "B7",
   2762     "B8",
   2763     "B18",
   2764     "LS2",
   2765     "PAT3",
   2766     "S2_UL",
   2767     "LS2_UL",
   2768 };
   2769 
   2770 const int decomp_incr_tab[4][4] = {
   2771     { DECOMP_TYPE_I1, 0, -1 },
   2772     { DECOMP_TYPE_I2_0, 0, 1, -1 },
   2773     { DECOMP_TYPE_I3_1, 1, 2, -1 },
   2774     { DECOMP_TYPE_I4_1, 1, 2, -1 },
   2775 };
   2776 
   2777 /*
   2778   entry size:
   2779   type   bits
   2780   code   18
   2781   len    7
   2782   compat 1
   2783   type   5
   2784   index  16
   2785   total  47
   2786 */
   2787 
   2788 typedef struct {
   2789     int code;
   2790     uint8_t len;
   2791     uint8_t type;
   2792     uint8_t c_len;
   2793     uint16_t c_min;
   2794     uint16_t data_index;
   2795     int cost; /* size in bytes from this entry to the end */
   2796 } DecompEntry;
   2797 
   2798 int get_decomp_run_size(const DecompEntry *de)
   2799 {
   2800     int s;
   2801     s = 6;
   2802     if (de->type <= DECOMP_TYPE_C1) {
   2803         /* nothing more */
   2804     } else if (de->type <= DECOMP_TYPE_L7) {
   2805         s += de->len * de->c_len * 2;
   2806     } else if (de->type <= DECOMP_TYPE_LL2) {
   2807         /* 18 bits per char */
   2808         s += (de->len * de->c_len * 18 + 7) / 8;
   2809     } else if (de->type <= DECOMP_TYPE_S5) {
   2810         s += de->len * de->c_len;
   2811     } else if (de->type <= DECOMP_TYPE_I4_2) {
   2812         s += de->c_len * 2;
   2813     } else if (de->type <= DECOMP_TYPE_B18) {
   2814         s += 2 + de->len * de->c_len;
   2815     } else if (de->type <= DECOMP_TYPE_LS2) {
   2816         s += de->len * 3;
   2817     } else if (de->type <= DECOMP_TYPE_PAT3) {
   2818         s += 4 + de->len * 2;
   2819     } else if (de->type <= DECOMP_TYPE_S2_UL) {
   2820         s += de->len;
   2821     } else if (de->type <= DECOMP_TYPE_LS2_UL) {
   2822         s += (de->len / 2) * 3;
   2823     } else {
   2824         abort();
   2825     }
   2826     return s;
   2827 }
   2828 
   2829 static const uint16_t unicode_short_table[2] = { 0x2044, 0x2215 };
   2830 
   2831 /* return -1 if not found */
   2832 int get_short_code(int c)
   2833 {
   2834     int i;
   2835     if (c < 0x80) {
   2836         return c;
   2837     } else if (c >= 0x300 && c < 0x350) {
   2838         return c - 0x300 + 0x80;
   2839     } else {
   2840         for(i = 0; i < countof(unicode_short_table); i++) {
   2841             if (c == unicode_short_table[i])
   2842                 return i + 0x80 + 0x50;
   2843         }
   2844         return -1;
   2845     }
   2846 }
   2847 
   2848 static BOOL is_short(int code)
   2849 {
   2850     return get_short_code(code) >= 0;
   2851 }
   2852 
   2853 static BOOL is_short_tab(const int *tab, int len)
   2854 {
   2855     int i;
   2856     for(i = 0; i < len; i++) {
   2857         if (!is_short(tab[i]))
   2858             return FALSE;
   2859     }
   2860     return TRUE;
   2861 }
   2862 
   2863 static BOOL is_16bit(const int *tab, int len)
   2864 {
   2865     int i;
   2866     for(i = 0; i < len; i++) {
   2867         if (tab[i] > 0xffff)
   2868             return FALSE;
   2869     }
   2870     return TRUE;
   2871 }
   2872 
   2873 static uint32_t to_lower_simple(uint32_t c)
   2874 {
   2875     /* Latin1 and Cyrillic */
   2876     if (c < 0x100 || (c >= 0x410 && c <= 0x42f))
   2877         c += 0x20;
   2878     else
   2879         c++;
   2880     return c;
   2881 }
   2882 
   2883 /* select best encoding with dynamic programming */
   2884 void find_decomp_run(DecompEntry *tab_de, int i)
   2885 {
   2886     DecompEntry de_s, *de = &de_s;
   2887     CCInfo *ci, *ci1, *ci2;
   2888     int l, j, n, len_max;
   2889 
   2890     ci = &unicode_db[i];
   2891     l = ci->decomp_len;
   2892     if (l == 0) {
   2893         tab_de[i].cost = tab_de[i + 1].cost;
   2894         return;
   2895     }
   2896 
   2897     /* the offset for the compose table has only 6 bits, so we must
   2898        limit if it can be used by the compose table */
   2899     if (!ci->is_compat && !ci->is_excluded && l == 2)
   2900         len_max = 64;
   2901     else
   2902         len_max = 127;
   2903 
   2904     tab_de[i].cost = 0x7fffffff;
   2905 
   2906     if (!is_16bit(ci->decomp_data, l)) {
   2907         assert(l <= 2);
   2908 
   2909         n = 1;
   2910         for(;;) {
   2911             de->code = i;
   2912             de->len = n;
   2913             de->type = DECOMP_TYPE_LL1 + l - 1;
   2914             de->c_len = l;
   2915             de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;
   2916             if (de->cost < tab_de[i].cost) {
   2917                 tab_de[i] = *de;
   2918             }
   2919             if (!((i + n) <= CHARCODE_MAX && n < len_max))
   2920                 break;
   2921             ci1 = &unicode_db[i + n];
   2922             /* Note: we accept a hole */
   2923             if (!(ci1->decomp_len == 0 ||
   2924                   (ci1->decomp_len == l &&
   2925                    ci1->is_compat == ci->is_compat)))
   2926                 break;
   2927             n++;
   2928         }
   2929         return;
   2930     }
   2931 
   2932     if (l <= 7) {
   2933         n = 1;
   2934         for(;;) {
   2935             de->code = i;
   2936             de->len = n;
   2937             if (l == 1 && n == 1) {
   2938                 de->type = DECOMP_TYPE_C1;
   2939             } else {
   2940                 assert(l <= 8);
   2941                 de->type = DECOMP_TYPE_L1 + l - 1;
   2942             }
   2943             de->c_len = l;
   2944             de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;
   2945             if (de->cost < tab_de[i].cost) {
   2946                 tab_de[i] = *de;
   2947             }
   2948 
   2949             if (!((i + n) <= CHARCODE_MAX && n < len_max))
   2950                 break;
   2951             ci1 = &unicode_db[i + n];
   2952             /* Note: we accept a hole */
   2953             if (!(ci1->decomp_len == 0 ||
   2954                   (ci1->decomp_len == l &&
   2955                    ci1->is_compat == ci->is_compat &&
   2956                    is_16bit(ci1->decomp_data, l))))
   2957                 break;
   2958             n++;
   2959         }
   2960     }
   2961 
   2962     if (l <= 8 || l == 18) {
   2963         int c_min, c_max, c;
   2964         c_min = c_max = -1;
   2965         n = 1;
   2966         for(;;) {
   2967             ci1 = &unicode_db[i + n - 1];
   2968             for(j = 0; j < l; j++) {
   2969                 c = ci1->decomp_data[j];
   2970                 if (c == 0x20) {
   2971                     /* we accept space for Arabic */
   2972                 } else if (c_min == -1) {
   2973                     c_min = c_max = c;
   2974                 } else {
   2975                     c_min = min_int(c_min, c);
   2976                     c_max = max_int(c_max, c);
   2977                 }
   2978             }
   2979             if ((c_max - c_min) > 254)
   2980                 break;
   2981             de->code = i;
   2982             de->len = n;
   2983             if (l == 18)
   2984                 de->type = DECOMP_TYPE_B18;
   2985             else
   2986                 de->type = DECOMP_TYPE_B1 + l - 1;
   2987             de->c_len = l;
   2988             de->c_min = c_min;
   2989             de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;
   2990             if (de->cost < tab_de[i].cost) {
   2991                 tab_de[i] = *de;
   2992             }
   2993             if (!((i + n) <= CHARCODE_MAX && n < len_max))
   2994                 break;
   2995             ci1 = &unicode_db[i + n];
   2996             if (!(ci1->decomp_len == l &&
   2997                   ci1->is_compat == ci->is_compat))
   2998                 break;
   2999             n++;
   3000         }
   3001     }
   3002 
   3003     /* find an ascii run */
   3004     if (l <= 5 && is_short_tab(ci->decomp_data, l)) {
   3005         n = 1;
   3006         for(;;) {
   3007             de->code = i;
   3008             de->len = n;
   3009             de->type = DECOMP_TYPE_S1 + l - 1;
   3010             de->c_len = l;
   3011             de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;
   3012             if (de->cost < tab_de[i].cost) {
   3013                 tab_de[i] = *de;
   3014             }
   3015 
   3016             if (!((i + n) <= CHARCODE_MAX && n < len_max))
   3017                 break;
   3018             ci1 = &unicode_db[i + n];
   3019             /* Note: we accept a hole */
   3020             if (!(ci1->decomp_len == 0 ||
   3021                   (ci1->decomp_len == l &&
   3022                    ci1->is_compat == ci->is_compat &&
   3023                    is_short_tab(ci1->decomp_data, l))))
   3024                 break;
   3025             n++;
   3026         }
   3027     }
   3028 
   3029     /* check if a single char is increasing */
   3030     if (l <= 4) {
   3031         int idx1, idx;
   3032 
   3033         for(idx1 = 1; (idx = decomp_incr_tab[l - 1][idx1]) >= 0; idx1++) {
   3034             n = 1;
   3035             for(;;) {
   3036                 de->code = i;
   3037                 de->len = n;
   3038                 de->type = decomp_incr_tab[l - 1][0] + idx1 - 1;
   3039                 de->c_len = l;
   3040                 de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;
   3041                 if (de->cost < tab_de[i].cost) {
   3042                     tab_de[i] = *de;
   3043                 }
   3044 
   3045                 if (!((i + n) <= CHARCODE_MAX && n < len_max))
   3046                     break;
   3047                 ci1 = &unicode_db[i + n];
   3048                 if (!(ci1->decomp_len == l &&
   3049                       ci1->is_compat == ci->is_compat))
   3050                     goto next1;
   3051                 for(j = 0; j < l; j++) {
   3052                     if (j == idx) {
   3053                         if (ci1->decomp_data[j] != ci->decomp_data[j] + n)
   3054                             goto next1;
   3055                     } else {
   3056                         if (ci1->decomp_data[j] != ci->decomp_data[j])
   3057                             goto next1;
   3058                     }
   3059                 }
   3060                 n++;
   3061             }
   3062         next1: ;
   3063         }
   3064     }
   3065 
   3066     if (l == 3) {
   3067         n = 1;
   3068         for(;;) {
   3069             de->code = i;
   3070             de->len = n;
   3071             de->type = DECOMP_TYPE_PAT3;
   3072             de->c_len = l;
   3073             de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;
   3074             if (de->cost < tab_de[i].cost) {
   3075                 tab_de[i] = *de;
   3076             }
   3077             if (!((i + n) <= CHARCODE_MAX && n < len_max))
   3078                 break;
   3079             ci1 = &unicode_db[i + n];
   3080             if (!(ci1->decomp_len == l &&
   3081                   ci1->is_compat == ci->is_compat &&
   3082                   ci1->decomp_data[1] <= 0xffff &&
   3083                   ci1->decomp_data[0] == ci->decomp_data[0] &&
   3084                   ci1->decomp_data[l - 1] == ci->decomp_data[l - 1]))
   3085                 break;
   3086             n++;
   3087         }
   3088     }
   3089 
   3090     if (l == 2 && is_short(ci->decomp_data[1])) {
   3091         n = 1;
   3092         for(;;) {
   3093             de->code = i;
   3094             de->len = n;
   3095             de->type = DECOMP_TYPE_LS2;
   3096             de->c_len = l;
   3097             de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;
   3098             if (de->cost < tab_de[i].cost) {
   3099                 tab_de[i] = *de;
   3100             }
   3101             if (!((i + n) <= CHARCODE_MAX && n < len_max))
   3102                 break;
   3103             ci1 = &unicode_db[i + n];
   3104             if (!(ci1->decomp_len == 0 ||
   3105                   (ci1->decomp_len == l &&
   3106                    ci1->is_compat == ci->is_compat &&
   3107                    ci1->decomp_data[0] <= 0xffff &&
   3108                    is_short(ci1->decomp_data[1]))))
   3109                 break;
   3110             n++;
   3111         }
   3112     }
   3113 
   3114     if (l == 2) {
   3115         BOOL is_16bit;
   3116 
   3117         n = 0;
   3118         is_16bit = FALSE;
   3119         for(;;) {
   3120             if (!((i + n + 1) <= CHARCODE_MAX && n + 2 <= len_max))
   3121                 break;
   3122             ci1 = &unicode_db[i + n];
   3123             if (!(ci1->decomp_len == l &&
   3124                   ci1->is_compat == ci->is_compat &&
   3125                   is_short(ci1->decomp_data[1])))
   3126                 break;
   3127             if (!is_16bit && !is_short(ci1->decomp_data[0]))
   3128                 is_16bit = TRUE;
   3129             ci2 = &unicode_db[i + n + 1];
   3130             if (!(ci2->decomp_len == l &&
   3131                   ci2->is_compat == ci->is_compat &&
   3132                   ci2->decomp_data[0] == to_lower_simple(ci1->decomp_data[0])  &&
   3133                   ci2->decomp_data[1] == ci1->decomp_data[1]))
   3134                 break;
   3135             n += 2;
   3136             de->code = i;
   3137             de->len = n;
   3138             de->type = DECOMP_TYPE_S2_UL + is_16bit;
   3139             de->c_len = l;
   3140             de->cost = get_decomp_run_size(de) + tab_de[i + n].cost;
   3141             if (de->cost < tab_de[i].cost) {
   3142                 tab_de[i] = *de;
   3143             }
   3144         }
   3145     }
   3146 }
   3147 
   3148 void put16(uint8_t *data_buf, int *pidx, uint16_t c)
   3149 {
   3150     int idx;
   3151     idx = *pidx;
   3152     data_buf[idx++] = c;
   3153     data_buf[idx++] = c >> 8;
   3154     *pidx = idx;
   3155 }
   3156 
   3157 void add_decomp_data(uint8_t *data_buf, int *pidx, DecompEntry *de)
   3158 {
   3159     int i, j, idx, c;
   3160     CCInfo *ci;
   3161 
   3162     idx = *pidx;
   3163     de->data_index = idx;
   3164     if (de->type <= DECOMP_TYPE_C1) {
   3165         ci = &unicode_db[de->code];
   3166         assert(ci->decomp_len == 1);
   3167         de->data_index = ci->decomp_data[0];
   3168     } else if (de->type <= DECOMP_TYPE_L7) {
   3169         for(i = 0; i < de->len; i++) {
   3170             ci = &unicode_db[de->code + i];
   3171             for(j = 0; j < de->c_len; j++) {
   3172                 if (ci->decomp_len == 0)
   3173                     c = 0;
   3174                 else
   3175                     c = ci->decomp_data[j];
   3176                 put16(data_buf, &idx,  c);
   3177             }
   3178         }
   3179     } else if (de->type <= DECOMP_TYPE_LL2) {
   3180         int n, p, k;
   3181         n = (de->len * de->c_len * 18 + 7) / 8;
   3182         p = de->len * de->c_len * 2;
   3183         memset(data_buf + idx, 0, n);
   3184         k = 0;
   3185         for(i = 0; i < de->len; i++) {
   3186             ci = &unicode_db[de->code + i];
   3187             for(j = 0; j < de->c_len; j++) {
   3188                 if (ci->decomp_len == 0)
   3189                     c = 0;
   3190                 else
   3191                     c = ci->decomp_data[j];
   3192                 data_buf[idx + k * 2] = c;
   3193                 data_buf[idx + k * 2 + 1] = c >> 8;
   3194                 data_buf[idx + p + (k / 4)] |= (c >> 16) << ((k % 4) * 2);
   3195                 k++;
   3196             }
   3197         }
   3198         idx += n;
   3199     } else if (de->type <= DECOMP_TYPE_S5) {
   3200         for(i = 0; i < de->len; i++) {
   3201             ci = &unicode_db[de->code + i];
   3202             for(j = 0; j < de->c_len; j++) {
   3203                 if (ci->decomp_len == 0)
   3204                     c = 0;
   3205                 else
   3206                     c = ci->decomp_data[j];
   3207                 c = get_short_code(c);
   3208                 assert(c >= 0);
   3209                 data_buf[idx++] = c;
   3210             }
   3211         }
   3212     } else if (de->type <= DECOMP_TYPE_I4_2) {
   3213         ci = &unicode_db[de->code];
   3214         assert(ci->decomp_len == de->c_len);
   3215         for(j = 0; j < de->c_len; j++)
   3216             put16(data_buf, &idx, ci->decomp_data[j]);
   3217     } else if (de->type <= DECOMP_TYPE_B18) {
   3218         c = de->c_min;
   3219         data_buf[idx++] = c;
   3220         data_buf[idx++] = c >> 8;
   3221         for(i = 0; i < de->len; i++) {
   3222             ci = &unicode_db[de->code + i];
   3223             for(j = 0; j < de->c_len; j++) {
   3224                 assert(ci->decomp_len == de->c_len);
   3225                 c = ci->decomp_data[j];
   3226                 if (c == 0x20) {
   3227                     c = 0xff;
   3228                 } else {
   3229                     c -= de->c_min;
   3230                     assert((uint32_t)c <= 254);
   3231                 }
   3232                 data_buf[idx++] = c;
   3233             }
   3234         }
   3235     } else if (de->type <= DECOMP_TYPE_LS2) {
   3236         assert(de->c_len == 2);
   3237         for(i = 0; i < de->len; i++) {
   3238             ci = &unicode_db[de->code + i];
   3239             if (ci->decomp_len == 0)
   3240                 c = 0;
   3241             else
   3242                 c = ci->decomp_data[0];
   3243             put16(data_buf, &idx,  c);
   3244 
   3245             if (ci->decomp_len == 0)
   3246                 c = 0;
   3247             else
   3248                 c = ci->decomp_data[1];
   3249             c = get_short_code(c);
   3250             assert(c >= 0);
   3251             data_buf[idx++] = c;
   3252         }
   3253     } else if (de->type <= DECOMP_TYPE_PAT3) {
   3254         ci = &unicode_db[de->code];
   3255         assert(ci->decomp_len == 3);
   3256         put16(data_buf, &idx,  ci->decomp_data[0]);
   3257         put16(data_buf, &idx,  ci->decomp_data[2]);
   3258         for(i = 0; i < de->len; i++) {
   3259             ci = &unicode_db[de->code + i];
   3260             assert(ci->decomp_len == 3);
   3261             put16(data_buf, &idx,  ci->decomp_data[1]);
   3262         }
   3263     } else if (de->type <= DECOMP_TYPE_S2_UL) {
   3264         for(i = 0; i < de->len; i += 2) {
   3265             ci = &unicode_db[de->code + i];
   3266             c = ci->decomp_data[0];
   3267             c = get_short_code(c);
   3268             assert(c >= 0);
   3269             data_buf[idx++] = c;
   3270             c = ci->decomp_data[1];
   3271             c = get_short_code(c);
   3272             assert(c >= 0);
   3273             data_buf[idx++] = c;
   3274         }
   3275     } else if (de->type <= DECOMP_TYPE_LS2_UL) {
   3276         for(i = 0; i < de->len; i += 2) {
   3277             ci = &unicode_db[de->code + i];
   3278             c = ci->decomp_data[0];
   3279             put16(data_buf, &idx,  c);
   3280             c = ci->decomp_data[1];
   3281             c = get_short_code(c);
   3282             assert(c >= 0);
   3283             data_buf[idx++] = c;
   3284         }
   3285     } else {
   3286         abort();
   3287     }
   3288     *pidx = idx;
   3289 }
   3290 
   3291 #if 0
   3292 void dump_large_char(void)
   3293 {
   3294     int i, j;
   3295     for(i = 0; i <= CHARCODE_MAX; i++) {
   3296         CCInfo *ci = &unicode_db[i];
   3297         for(j = 0; j < ci->decomp_len; j++) {
   3298             if (ci->decomp_data[j] > 0xffff)
   3299                 printf("%05x\n", ci->decomp_data[j]);
   3300         }
   3301     }
   3302 }
   3303 #endif
   3304 
   3305 void build_compose_table(FILE *f, const DecompEntry *tab_de);
   3306 
   3307 void build_decompose_table(FILE *f)
   3308 {
   3309     int i, array_len, code_max, data_len, count;
   3310     DecompEntry *tab_de, de_s, *de = &de_s;
   3311     uint8_t *data_buf;
   3312 
   3313     code_max = CHARCODE_MAX;
   3314 
   3315     tab_de = mallocz((code_max + 2) * sizeof(*tab_de));
   3316 
   3317     for(i = code_max; i >= 0; i--) {
   3318         find_decomp_run(tab_de, i);
   3319     }
   3320 
   3321     /* build the data buffer */
   3322     data_buf = malloc(100000);
   3323     data_len = 0;
   3324     array_len = 0;
   3325     for(i = 0; i <= code_max; i++) {
   3326         de = &tab_de[i];
   3327         if (de->len != 0) {
   3328             add_decomp_data(data_buf, &data_len, de);
   3329             i += de->len - 1;
   3330             array_len++;
   3331         }
   3332     }
   3333 
   3334 #ifdef DUMP_DECOMP_TABLE
   3335     /* dump */
   3336     {
   3337         int size, size1;
   3338 
   3339         printf("START LEN   TYPE  L C SIZE\n");
   3340         size = 0;
   3341         for(i = 0; i <= code_max; i++) {
   3342             de = &tab_de[i];
   3343             if (de->len != 0) {
   3344                 size1 = get_decomp_run_size(de);
   3345                 printf("%05x %3d %6s %2d %1d %4d\n", i, de->len,
   3346                        decomp_type_str[de->type], de->c_len,
   3347                        unicode_db[i].is_compat, size1);
   3348                 i += de->len - 1;
   3349                 size += size1;
   3350             }
   3351         }
   3352 
   3353         printf("array_len=%d estimated size=%d bytes actual=%d bytes\n",
   3354                array_len, size, array_len * 6 + data_len);
   3355     }
   3356 #endif
   3357 
   3358     total_tables++;
   3359     total_table_bytes += array_len * sizeof(uint32_t);
   3360     fprintf(f, "static const uint32_t unicode_decomp_table1[%d] = {", array_len);
   3361     count = 0;
   3362     for(i = 0; i <= code_max; i++) {
   3363         de = &tab_de[i];
   3364         if (de->len != 0) {
   3365             uint32_t v;
   3366             if (count++ % 4 == 0)
   3367                 fprintf(f, "\n   ");
   3368             v = (de->code << (32 - 18)) |
   3369                 (de->len << (32 - 18 - 7)) |
   3370                 (de->type << (32 - 18 - 7 - 6)) |
   3371                 unicode_db[de->code].is_compat;
   3372             fprintf(f, " 0x%08x,", v);
   3373             i += de->len - 1;
   3374         }
   3375     }
   3376     fprintf(f, "\n};\n\n");
   3377 
   3378     total_tables++;
   3379     total_table_bytes += array_len * sizeof(uint16_t);
   3380     fprintf(f, "static const uint16_t unicode_decomp_table2[%d] = {", array_len);
   3381     count = 0;
   3382     for(i = 0; i <= code_max; i++) {
   3383         de = &tab_de[i];
   3384         if (de->len != 0) {
   3385             if (count++ % 8 == 0)
   3386                 fprintf(f, "\n   ");
   3387             fprintf(f, " 0x%04x,", de->data_index);
   3388             i += de->len - 1;
   3389         }
   3390     }
   3391     fprintf(f, "\n};\n\n");
   3392 
   3393     total_tables++;
   3394     total_table_bytes += data_len;
   3395     fprintf(f, "static const uint8_t unicode_decomp_data[%d] = {", data_len);
   3396     for(i = 0; i < data_len; i++) {
   3397         if (i % 8 == 0)
   3398             fprintf(f, "\n   ");
   3399         fprintf(f, " 0x%02x,", data_buf[i]);
   3400     }
   3401     fprintf(f, "\n};\n\n");
   3402 
   3403     build_compose_table(f, tab_de);
   3404 
   3405     free(data_buf);
   3406 
   3407     free(tab_de);
   3408 }
   3409 
   3410 typedef struct {
   3411     uint32_t c[2];
   3412     uint32_t p;
   3413 } ComposeEntry;
   3414 
   3415 #define COMPOSE_LEN_MAX 10000
   3416 
   3417 static int ce_cmp(const void *p1, const void *p2)
   3418 {
   3419     const ComposeEntry *ce1 = p1;
   3420     const ComposeEntry *ce2 = p2;
   3421     int i;
   3422 
   3423     for(i = 0; i < 2; i++) {
   3424         if (ce1->c[i] < ce2->c[i])
   3425             return -1;
   3426         else if (ce1->c[i] > ce2->c[i])
   3427             return 1;
   3428     }
   3429     return 0;
   3430 }
   3431 
   3432 
   3433 static int get_decomp_pos(const DecompEntry *tab_de, int c)
   3434 {
   3435     int i, v, k;
   3436     const DecompEntry *de;
   3437 
   3438     k = 0;
   3439     for(i = 0; i <= CHARCODE_MAX; i++) {
   3440         de = &tab_de[i];
   3441         if (de->len != 0) {
   3442             if (c >= de->code && c < de->code + de->len) {
   3443                 v = c - de->code;
   3444                 assert(v < 64);
   3445                 v |= k << 6;
   3446                 assert(v < 65536);
   3447                 return v;
   3448             }
   3449             i += de->len - 1;
   3450             k++;
   3451         }
   3452     }
   3453     return -1;
   3454 }
   3455 
   3456 void build_compose_table(FILE *f, const DecompEntry *tab_de)
   3457 {
   3458     int i, v, tab_ce_len;
   3459     ComposeEntry *ce, *tab_ce;
   3460 
   3461     tab_ce = malloc(sizeof(*tab_ce) * COMPOSE_LEN_MAX);
   3462     tab_ce_len = 0;
   3463     for(i = 0; i <= CHARCODE_MAX; i++) {
   3464         CCInfo *ci = &unicode_db[i];
   3465         if (ci->decomp_len == 2 && !ci->is_compat &&
   3466             !ci->is_excluded) {
   3467             assert(tab_ce_len < COMPOSE_LEN_MAX);
   3468             ce = &tab_ce[tab_ce_len++];
   3469             ce->c[0] = ci->decomp_data[0];
   3470             ce->c[1] = ci->decomp_data[1];
   3471             ce->p = i;
   3472         }
   3473     }
   3474     qsort(tab_ce, tab_ce_len, sizeof(*tab_ce), ce_cmp);
   3475 
   3476 #if 0
   3477     {
   3478         printf("tab_ce_len=%d\n", tab_ce_len);
   3479         for(i = 0; i < tab_ce_len; i++) {
   3480             ce = &tab_ce[i];
   3481             printf("%05x %05x %05x\n", ce->c[0], ce->c[1], ce->p);
   3482         }
   3483     }
   3484 #endif
   3485 
   3486     total_tables++;
   3487     total_table_bytes += tab_ce_len * sizeof(uint16_t);
   3488     fprintf(f, "static const uint16_t unicode_comp_table[%u] = {", tab_ce_len);
   3489     for(i = 0; i < tab_ce_len; i++) {
   3490         if (i % 8 == 0)
   3491             fprintf(f, "\n   ");
   3492         v = get_decomp_pos(tab_de, tab_ce[i].p);
   3493         if (v < 0) {
   3494             printf("ERROR: entry for c=%04x not found\n",
   3495                    tab_ce[i].p);
   3496             exit(1);
   3497         }
   3498         fprintf(f, " 0x%04x,", v);
   3499     }
   3500     fprintf(f, "\n};\n\n");
   3501 
   3502     free(tab_ce);
   3503 }
   3504 
   3505 #ifdef USE_TEST
   3506 void check_decompose_table(void)
   3507 {
   3508     int c;
   3509     CCInfo *ci;
   3510     int res[UNICODE_DECOMP_LEN_MAX], *ref;
   3511     int len, ref_len, is_compat;
   3512 
   3513     for(is_compat = 0; is_compat <= 1; is_compat++) {
   3514         for(c = 0; c < CHARCODE_MAX; c++) {
   3515             ci = &unicode_db[c];
   3516             ref_len = ci->decomp_len;
   3517             ref = ci->decomp_data;
   3518             if (!is_compat && ci->is_compat) {
   3519                 ref_len = 0;
   3520             }
   3521             len = unicode_decomp_char((uint32_t *)res, c, is_compat);
   3522             if (len != ref_len ||
   3523                 tabcmp(res, ref, ref_len) != 0) {
   3524                 printf("ERROR c=%05x compat=%d\n", c, is_compat);
   3525                 dump_str("res", res, len);
   3526                 dump_str("ref", ref, ref_len);
   3527                 exit(1);
   3528             }
   3529         }
   3530     }
   3531 }
   3532 
   3533 void check_compose_table(void)
   3534 {
   3535     int i, p;
   3536     /* XXX: we don't test all the cases */
   3537 
   3538     for(i = 0; i <= CHARCODE_MAX; i++) {
   3539         CCInfo *ci = &unicode_db[i];
   3540         if (ci->decomp_len == 2 && !ci->is_compat &&
   3541             !ci->is_excluded) {
   3542             p = unicode_compose_pair(ci->decomp_data[0], ci->decomp_data[1]);
   3543             if (p != i) {
   3544                 printf("ERROR compose: c=%05x %05x -> %05x ref=%05x\n",
   3545                        ci->decomp_data[0], ci->decomp_data[1], p, i);
   3546                 exit(1);
   3547             }
   3548         }
   3549     }
   3550 
   3551 
   3552 
   3553 }
   3554 
   3555 #endif
   3556 
   3557 
   3558 
   3559 #ifdef USE_TEST
   3560 
   3561 void check_str(const char *msg, int num, const int *in_buf, int in_len,
   3562                const int *buf1, int len1,
   3563                const int *buf2, int len2)
   3564 {
   3565     if (len1 != len2 || tabcmp(buf1, buf2, len1) != 0) {
   3566         printf("%d: ERROR %s:\n", num, msg);
   3567         dump_str(" in", in_buf, in_len);
   3568         dump_str("res", buf1, len1);
   3569         dump_str("ref", buf2, len2);
   3570         exit(1);
   3571     }
   3572 }
   3573 
   3574 void check_cc_table(void)
   3575 {
   3576     int cc, cc_ref, c;
   3577 
   3578     for(c = 0; c <= CHARCODE_MAX; c++) {
   3579         cc_ref = unicode_db[c].combining_class;
   3580         cc = unicode_get_cc(c);
   3581         if (cc != cc_ref) {
   3582             printf("ERROR: c=%04x cc=%d cc_ref=%d\n",
   3583                    c, cc, cc_ref);
   3584             exit(1);
   3585         }
   3586     }
   3587 #ifdef PROFILE
   3588     {
   3589         int64_t ti, count;
   3590 
   3591         ti = get_time_ns();
   3592         count = 0;
   3593         /* only do it on meaningful chars */
   3594         for(c = 0x20; c <= 0xffff; c++) {
   3595             cc_ref = unicode_db[c].combining_class;
   3596             cc = unicode_get_cc(c);
   3597             count++;
   3598         }
   3599         ti = get_time_ns() - ti;
   3600         printf("cc time=%0.1f ns/char\n",
   3601                (double)ti / count);
   3602     }
   3603 #endif
   3604 }
   3605 
   3606 void normalization_test(const char *filename)
   3607 {
   3608     FILE *f;
   3609     char line[4096], *p;
   3610     int *in_str, *nfc_str, *nfd_str, *nfkc_str, *nfkd_str;
   3611     int in_len, nfc_len, nfd_len, nfkc_len, nfkd_len;
   3612     int *buf, buf_len, pos;
   3613 
   3614     f = fopen(filename, "rb");
   3615     if (!f) {
   3616         perror(filename);
   3617         exit(1);
   3618     }
   3619     pos = 0;
   3620     for(;;) {
   3621         if (!get_line(line, sizeof(line), f))
   3622             break;
   3623         pos++;
   3624         p = line;
   3625         while (isspace(*p))
   3626             p++;
   3627         if (*p == '#' || *p == '@')
   3628             continue;
   3629         in_str = get_field_str(&in_len, p, 0);
   3630         nfc_str = get_field_str(&nfc_len, p, 1);
   3631         nfd_str = get_field_str(&nfd_len, p, 2);
   3632         nfkc_str = get_field_str(&nfkc_len, p, 3);
   3633         nfkd_str = get_field_str(&nfkd_len, p, 4);
   3634 
   3635         //        dump_str("in", in_str, in_len);
   3636 
   3637         buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFD, NULL, NULL);
   3638         check_str("nfd", pos, in_str, in_len, buf, buf_len, nfd_str, nfd_len);
   3639         free(buf);
   3640 
   3641         buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFKD, NULL, NULL);
   3642         check_str("nfkd", pos, in_str, in_len, buf, buf_len, nfkd_str, nfkd_len);
   3643         free(buf);
   3644 
   3645         buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFC, NULL, NULL);
   3646         check_str("nfc", pos, in_str, in_len, buf, buf_len, nfc_str, nfc_len);
   3647         free(buf);
   3648 
   3649         buf_len = unicode_normalize((uint32_t **)&buf, (uint32_t *)in_str, in_len, UNICODE_NFKC, NULL, NULL);
   3650         check_str("nfkc", pos, in_str, in_len, buf, buf_len, nfkc_str, nfkc_len);
   3651         free(buf);
   3652 
   3653         free(in_str);
   3654         free(nfc_str);
   3655         free(nfd_str);
   3656         free(nfkc_str);
   3657         free(nfkd_str);
   3658     }
   3659     fclose(f);
   3660 }
   3661 #endif
   3662 
   3663 int main(int argc, char *argv[])
   3664 {
   3665     const char *unicode_db_path, *outfilename;
   3666     char filename[1024];
   3667     int arg = 1;
   3668 
   3669     if (arg >= argc || (!strcmp(argv[arg], "-h") || !strcmp(argv[arg], "--help"))) {
   3670         printf("usage: %s PATH [OUTPUT]\n"
   3671                "  PATH    path to the Unicode database directory\n"
   3672                "  OUTPUT  name of the output file.  If omitted, a self test is performed\n"
   3673                "          using the files from the Unicode library\n"
   3674                , argv[0]);
   3675         return 1;
   3676     }
   3677     unicode_db_path = argv[arg++];
   3678     outfilename = NULL;
   3679     if (arg < argc)
   3680         outfilename = argv[arg++];
   3681 
   3682     unicode_db = mallocz(sizeof(unicode_db[0]) * (CHARCODE_MAX + 1));
   3683     re_string_list_init(&rgi_emoji_zwj_sequence);
   3684     dbuf_init(&rgi_emoji_tag_sequence);
   3685 
   3686     snprintf(filename, sizeof(filename), "%s/UnicodeData.txt", unicode_db_path);
   3687 
   3688     parse_unicode_data(filename);
   3689 
   3690     snprintf(filename, sizeof(filename), "%s/SpecialCasing.txt", unicode_db_path);
   3691     parse_special_casing(unicode_db, filename);
   3692 
   3693     snprintf(filename, sizeof(filename), "%s/CaseFolding.txt", unicode_db_path);
   3694     parse_case_folding(unicode_db, filename);
   3695 
   3696     snprintf(filename, sizeof(filename), "%s/CompositionExclusions.txt", unicode_db_path);
   3697     parse_composition_exclusions(filename);
   3698 
   3699     snprintf(filename, sizeof(filename), "%s/DerivedCoreProperties.txt", unicode_db_path);
   3700     parse_derived_core_properties(filename);
   3701 
   3702     snprintf(filename, sizeof(filename), "%s/DerivedNormalizationProps.txt", unicode_db_path);
   3703     parse_derived_norm_properties(filename);
   3704 
   3705     snprintf(filename, sizeof(filename), "%s/PropList.txt", unicode_db_path);
   3706     parse_prop_list(filename);
   3707 
   3708     snprintf(filename, sizeof(filename), "%s/Scripts.txt", unicode_db_path);
   3709     parse_scripts(filename);
   3710 
   3711     snprintf(filename, sizeof(filename), "%s/ScriptExtensions.txt",
   3712              unicode_db_path);
   3713     parse_script_extensions(filename);
   3714 
   3715     snprintf(filename, sizeof(filename), "%s/emoji-data.txt",
   3716              unicode_db_path);
   3717     parse_prop_list(filename);
   3718 
   3719     snprintf(filename, sizeof(filename), "%s/emoji-sequences.txt",
   3720              unicode_db_path);
   3721     parse_sequence_prop_list(filename);
   3722 
   3723     snprintf(filename, sizeof(filename), "%s/emoji-zwj-sequences.txt",
   3724              unicode_db_path);
   3725     parse_sequence_prop_list(filename);
   3726 
   3727     //    dump_unicode_data(unicode_db);
   3728     build_conv_table(unicode_db);
   3729 
   3730 #ifdef DUMP_CASE_FOLDING_SPECIAL_CASES
   3731     dump_case_folding_special_cases(unicode_db);
   3732 #endif
   3733 
   3734     if (!outfilename) {
   3735 #ifdef USE_TEST
   3736         check_case_conv();
   3737         check_flags();
   3738         check_decompose_table();
   3739         check_compose_table();
   3740         check_cc_table();
   3741         snprintf(filename, sizeof(filename), "%s/NormalizationTest.txt", unicode_db_path);
   3742         normalization_test(filename);
   3743 #else
   3744         fprintf(stderr, "Tests are not compiled\n");
   3745         exit(1);
   3746 #endif
   3747     } else
   3748     {
   3749         FILE *fo = fopen(outfilename, "wb");
   3750 
   3751         if (!fo) {
   3752             perror(outfilename);
   3753             exit(1);
   3754         }
   3755         fprintf(fo,
   3756                 "/* Compressed unicode tables */\n"
   3757                 "/* Automatically generated file - do not edit */\n"
   3758                 "\n"
   3759                 "#include <stdint.h>\n"
   3760                 "\n");
   3761         dump_case_conv_table(fo);
   3762         compute_internal_props();
   3763         build_flags_tables(fo);
   3764         fprintf(fo, "#ifdef CONFIG_ALL_UNICODE\n\n");
   3765         build_cc_table(fo);
   3766         build_decompose_table(fo);
   3767         build_general_category_table(fo);
   3768         build_script_table(fo);
   3769         build_script_ext_table(fo);
   3770         build_prop_list_table(fo);
   3771         build_sequence_prop_list_table(fo);
   3772         fprintf(fo, "#endif /* CONFIG_ALL_UNICODE */\n");
   3773         fprintf(fo, "/* %u tables / %u bytes, %u index / %u bytes */\n",
   3774                 total_tables, total_table_bytes, total_index, total_index_bytes);
   3775         fclose(fo);
   3776     }
   3777     re_string_list_free(&rgi_emoji_zwj_sequence);
   3778     return 0;
   3779 }