1 /* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3 of the License ONLY.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 static char *trim (char *str
) {
25 if (str
== NULL
) return NULL
;
26 for (s
= str
; *s
&& isspace(*s
); ++s
) ;
27 if (s
> str
) memmove(str
, s
, strlen(s
)+1);
28 for (s
= str
+strlen(str
)-1; s
>= str
&& isspace(*s
); --s
) ;
34 static int hex2num (char *s
) {
39 res
= strtol(s
, &end
, 16);
40 if (end
[0] || res
< 0) return -1;
54 static char *stx
= NULL
;
56 static char *tok (void) {
58 for (; *stx
&& *stx
!= ';'; ++stx
) ;
64 // <0: eof; 0: bad record; >0: good record
65 static int read_record (FILE *fi
, UCInfo
*ui
) {
66 static char str
[8192];
69 if (fgets(str
, sizeof(str
)-1, fi
) == NULL
) return -1;
71 if ((tk
= tok()) == NULL
) return 0;
72 if ((ui
->code
= hex2num(tk
)) < 0) return 0;
73 if (ui
->code
> 65535) return -1;
74 if ((ui
->name
= trim(tok())) == NULL
) return 0;
75 if ((ui
->class = trim(tok())) == NULL
) return 0;
77 for (f
= 9; f
> 0; --f
) if (tok() == NULL
) { printf("%d\n", f
); return 0; }
78 if ((u
= trim(tok())) == NULL
) return 0;
79 if ((l
= trim(tok())) == NULL
) return 0;
80 if (!u
[0]) ui
->upper
= ui
->code
; else ui
->upper
= hex2num(u
);
81 if (!l
[0]) ui
->lower
= ui
->code
; else ui
->lower
= hex2num(l
);
82 if (ui
->upper
< 0 || ui
->lower
< 0) return 0;
83 if (ui
->upper
> 65535 || ui
->lower
> 65535) abort();
95 static int mm_cmp (const void *p0
, const void *p1
) {
96 const mm
*i0
= (const mm
*)p0
;
97 const mm
*i1
= (const mm
*)p1
;
98 return (i0
->code
< i1
->code
? -1 : (i0
->code
> i1
->code
? 1 : 0));
102 int main (int argc
, char *argv
[]) {
104 int rc
, f
, totalmap
= 0;
106 if (argc
!= 3) { fprintf(stderr
, "usage: %s unitable.c unitable.txt\n", argv
[0]); exit(1); }
107 if ((fi
= fopen(argv
[2], "r")) == NULL
) { fprintf(stderr
, "FATAL: can't open input file: '%s'\n", argv
[2]); exit(1); }
109 rc
= read_record(fi
, &ui
);
111 if (rc
== 0) continue;
112 if (ui
.code
< 128) continue;
113 if (strcmp(ui
.class, "Lu") != 0 && strcmp(ui
.class, "Ll") != 0) continue;
114 if (ui
.upper
== ui
.code
&& ui
.lower
== ui
.code
) continue;
115 for (f
= 0; f
< totalmap
; ++f
) {
116 if (map
[f
].code
== ui
.code
) { fprintf(stderr
, "FATAL: duplicate entries in the map!\n"); exit(1); }
117 if (map
[f
].code
> ui
.code
) { fprintf(stderr
, "FATAL: invalid entry order in the map!\n"); exit(1); }
119 if (totalmap
> 65535) { fprintf(stderr
, "FATAL: too many entries in the map!\n"); exit(1); }
120 map
[totalmap
].code
= ui
.code
;
121 map
[totalmap
].l
= ui
.lower
;
122 map
[totalmap
].u
= ui
.upper
;
126 qsort(map
, totalmap
, sizeof(map
[0]), mm_cmp
);
127 fo
= fopen(argv
[1], "w");
128 if (fo
== NULL
) { fprintf(stderr
, "FATAL: can't create output file: '%s'\n", argv
[1]); exit(1); }
129 fprintf(fo
, "static const struct casemap unicode_case_mapping[%d] = {\n", totalmap
);
130 for (f
= 0; f
< totalmap
; ++f
) fprintf(fo
, "{0x%04x,0x%04x,0x%04x},\n", map
[f
].code
, map
[f
].l
, map
[f
].u
);
131 fprintf(fo
, "%s\n", "};");