| /* Copyright (C) 1999-2003, 2005, 2011-2012, 2016, 2018, 2020 Free Software Foundation, Inc. | |
| This file is part of the GNU LIBICONV Library. | |
| The GNU LIBICONV Library is free software; you can redistribute it | |
| and/or modify it under the terms of the GNU Lesser General Public | |
| License as published by the Free Software Foundation; either version 2.1 | |
| of the License, or (at your option) any later version. | |
| The GNU LIBICONV Library is distributed in the hope that it will be | |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| Lesser General Public License for more details. | |
| You should have received a copy of the GNU Lesser General Public | |
| License along with the GNU LIBICONV Library; see the file COPYING.LIB. | |
| If not, see <https://www.gnu.org/licenses/>. */ | |
| /* | |
| * Generates a table of small strings, used for transliteration, from a table | |
| * containing lines of the form | |
| * Unicode <tab> utf-8 replacement <tab> # comment | |
| */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <stdbool.h> | |
| int main (int argc, char *argv[]) | |
| { | |
| unsigned int *data; | |
| int *uni2index; | |
| int index; | |
| if (argc != 1) | |
| exit(1); | |
| data = malloc(0x100000 * sizeof(*data)); | |
| uni2index = malloc(0x110000 * sizeof(*uni2index)); | |
| if (data == NULL || uni2index == NULL) { | |
| fprintf(stderr, "out of memory\n"); | |
| exit(1); | |
| } | |
| printf("/*\n"); | |
| printf(" * Copyright (C) 1999-2003 Free Software Foundation, Inc.\n"); | |
| printf(" * This file is part of the GNU LIBICONV Library.\n"); | |
| printf(" *\n"); | |
| printf(" * The GNU LIBICONV Library is free software; you can redistribute it\n"); | |
| printf(" * and/or modify it under the terms of the GNU Lesser General Public\n"); | |
| printf(" * License as published by the Free Software Foundation; either version 2\n"); | |
| printf(" * of the License, or (at your option) any later version.\n"); | |
| printf(" *\n"); | |
| printf(" * The GNU LIBICONV Library is distributed in the hope that it will be\n"); | |
| printf(" * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); | |
| printf(" * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"); | |
| printf(" * Lesser General Public License for more details.\n"); | |
| printf(" *\n"); | |
| printf(" * You should have received a copy of the GNU Lesser General Public\n"); | |
| printf(" * License along with the GNU LIBICONV Library; see the file COPYING.LIB.\n"); | |
| printf(" * If not, see <https://www.gnu.org/licenses/>.\n"); | |
| printf(" */\n"); | |
| printf("\n"); | |
| printf("/*\n"); | |
| printf(" * Transliteration table\n"); | |
| printf(" */\n"); | |
| printf("\n"); | |
| { | |
| int c; | |
| int j; | |
| for (j = 0; j < 0x110000; j++) | |
| uni2index[j] = -1; | |
| index = 0; | |
| for (;;) { | |
| c = getc(stdin); | |
| if (c == EOF) | |
| break; | |
| if (c == '#') { | |
| do { c = getc(stdin); } while (!(c == EOF || c == '\n')); | |
| continue; | |
| } | |
| ungetc(c,stdin); | |
| if (scanf("%x",&j) != 1) | |
| exit(1); | |
| c = getc(stdin); | |
| if (c != '\t') | |
| exit(1); | |
| for (;;) { | |
| c = getc(stdin); | |
| if (c == EOF || c == '\n') | |
| exit(1); | |
| if (c == '\t') | |
| break; | |
| if (uni2index[j] < 0) { | |
| uni2index[j] = index; | |
| data[index++] = 0; | |
| } | |
| if (c >= 0x80) { | |
| /* Finish reading an UTF-8 character. */ | |
| if (c < 0xc0) | |
| exit(1); | |
| else { | |
| unsigned int i = (c < 0xe0 ? 2 : c < 0xf0 ? 3 : c < 0xf8 ? 4 : c < 0xfc ? 5 : 6); | |
| c &= (1 << (8-i)) - 1; | |
| while (--i > 0) { | |
| int cc = getc(stdin); | |
| if (!(cc >= 0x80 && cc < 0xc0)) | |
| exit(1); | |
| c <<= 6; c |= (cc & 0x3f); | |
| } | |
| } | |
| } | |
| data[index++] = (unsigned int) c; | |
| } | |
| if (uni2index[j] >= 0) | |
| data[uni2index[j]] = index - uni2index[j] - 1; | |
| do { c = getc(stdin); } while (!(c == EOF || c == '\n')); | |
| } | |
| } | |
| printf("static const unsigned int translit_data[%d] = {",index); | |
| { | |
| int i; | |
| for (i = 0; i < index; i++) { | |
| if (data[i] < 32) | |
| printf("\n %3d,",data[i]); | |
| else if (data[i] == '\'') | |
| printf("'\\'',"); | |
| else if (data[i] == '\\') | |
| printf("'\\\\',"); | |
| else if (data[i] < 127) | |
| printf(" '%c',",data[i]); | |
| else if (data[i] < 256) | |
| printf("0x%02X,",data[i]); | |
| else | |
| printf("0x%04X,",data[i]); | |
| } | |
| printf("\n};\n"); | |
| } | |
| printf("\n"); | |
| { | |
| int line[0x22000]; | |
| int tableno; | |
| struct { int minline; int maxline; int usecount; const char* suffix; } tables[0x2000]; | |
| int i, j, p, j1, j2, t; | |
| for (j1 = 0; j1 < 0x22000; j1++) { | |
| bool all_invalid = true; | |
| for (j2 = 0; j2 < 8; j2++) { | |
| j = 8*j1+j2; | |
| if (uni2index[j] >= 0) | |
| all_invalid = false; | |
| } | |
| if (all_invalid) | |
| line[j1] = -1; | |
| else | |
| line[j1] = 0; | |
| } | |
| tableno = 0; | |
| for (j1 = 0; j1 < 0x22000; j1++) { | |
| if (line[j1] >= 0) { | |
| if (tableno > 0 | |
| && ((j1 > 0 && line[j1-1] == tableno-1) | |
| || ((tables[tableno-1].maxline >> 5) == (j1 >> 5) | |
| && j1 - tables[tableno-1].maxline <= 8))) { | |
| line[j1] = tableno-1; | |
| tables[tableno-1].maxline = j1; | |
| } else { | |
| tableno++; | |
| line[j1] = tableno-1; | |
| tables[tableno-1].minline = tables[tableno-1].maxline = j1; | |
| } | |
| } | |
| } | |
| for (t = 0; t < tableno; t++) { | |
| tables[t].usecount = 0; | |
| j1 = 8*tables[t].minline; | |
| j2 = 8*(tables[t].maxline+1); | |
| for (j = j1; j < j2; j++) | |
| if (uni2index[j] >= 0) | |
| tables[t].usecount++; | |
| } | |
| for (t = 0, p = -1, i = 0; t < tableno; t++) { | |
| if (tables[t].usecount > 1) { | |
| char* s; | |
| if (p == tables[t].minline >> 5) { | |
| i++; | |
| /* i is the number of tables with the same (tables[t].minline >> 5) | |
| that we have seen so far. Since the tables[t].minline values are | |
| strongly monotonically increasing, there are at most 32 of them. */ | |
| if (!(i >= 0 && i <= 32)) abort(); | |
| s = (char*) malloc(4+1+2+1); | |
| sprintf(s, "%02x_%d", p, i); | |
| } else { | |
| p = tables[t].minline >> 5; | |
| i = 0; | |
| s = (char*) malloc(4+1); | |
| sprintf(s, "%02x", p); | |
| } | |
| tables[t].suffix = s; | |
| } else | |
| tables[t].suffix = NULL; | |
| } | |
| { | |
| p = -1; | |
| for (t = 0; t < tableno; t++) | |
| if (tables[t].usecount > 1) { | |
| p = 0; | |
| printf("static const short translit_page%s[%d] = {\n", tables[t].suffix, 8*(tables[t].maxline-tables[t].minline+1)); | |
| for (j1 = tables[t].minline; j1 <= tables[t].maxline; j1++) { | |
| if ((j1 % 0x20) == 0 && j1 > tables[t].minline) | |
| printf(" /* 0x%04x */\n", 8*j1); | |
| printf(" "); | |
| for (j2 = 0; j2 < 8; j2++) { | |
| j = 8*j1+j2; | |
| printf(" %4d,", uni2index[j]); | |
| } | |
| printf(" /* 0x%02x-0x%02x */\n", 8*(j1 % 0x20), 8*(j1 % 0x20)+7); | |
| } | |
| printf("};\n"); | |
| } | |
| if (p >= 0) | |
| printf("\n"); | |
| } | |
| printf("#define translit_index(wc) \\\n ("); | |
| for (j1 = 0; j1 < 0x22000;) { | |
| t = line[j1]; | |
| for (j2 = j1; j2 < 0x22000 && line[j2] == t; j2++); | |
| if (t >= 0) { | |
| if (j1 != tables[t].minline) abort(); | |
| if (j2 > tables[t].maxline+1) abort(); | |
| j2 = tables[t].maxline+1; | |
| } | |
| if (t == -1) { | |
| } else { | |
| if (t >= 0 && tables[t].usecount == 0) abort(); | |
| if (t >= 0 && tables[t].usecount == 1) { | |
| if (j2 != j1+1) abort(); | |
| for (j = 8*j1; j < 8*j2; j++) | |
| if (uni2index[j] >= 0) { | |
| printf("wc == 0x%04x ? %d", j, uni2index[j]); | |
| break; | |
| } | |
| } else { | |
| if (j1 == 0) { | |
| printf("wc < 0x%04x", 8*j2); | |
| } else { | |
| printf("wc >= 0x%04x && wc < 0x%04x", 8*j1, 8*j2); | |
| } | |
| printf(" ? translit_page%s[wc", tables[t].suffix); | |
| if (tables[t].minline > 0) | |
| printf("-0x%04x", 8*j1); | |
| printf("]"); | |
| } | |
| printf(" : \\\n "); | |
| } | |
| j1 = j2; | |
| } | |
| printf("-1)\n"); | |
| } | |
| if (ferror(stdout) || fclose(stdout)) | |
| exit(1); | |
| exit(0); | |
| } |