8 static char *trim (char *str
) {
10 if (str
== NULL
) return NULL
;
11 for (s
= str
; *s
&& isspace(*s
); ++s
) ;
12 if (s
> str
) memmove(str
, s
, strlen(s
)+1);
13 for (s
= str
+strlen(str
)-1; s
>= str
&& isspace(*s
); --s
) ;
19 static int hex2num (char *s
) {
24 res
= strtol(s
, &end
, 16);
25 if (end
[0] || res
< 0) return -1;
39 static char *stx
= NULL
;
41 static char *tok (void) {
43 for (; *stx
&& *stx
!= ';'; ++stx
) ;
49 // <0: eof; 0: bad record; >0: good record
50 static int read_record (FILE *fi
, UCInfo
*ui
) {
51 static char str
[8192];
54 if (fgets(str
, sizeof(str
)-1, fi
) == NULL
) return -1;
56 if ((tk
= tok()) == NULL
) return 0;
57 if ((ui
->code
= hex2num(tk
)) < 0) return 0;
58 if (ui
->code
> 65535) return -1;
59 if ((ui
->name
= trim(tok())) == NULL
) return 0;
60 if ((ui
->class = trim(tok())) == NULL
) return 0;
62 for (f
= 9; f
> 0; --f
) if (tok() == NULL
) { printf("%d\n", f
); return 0; }
63 if ((u
= trim(tok())) == NULL
) return 0;
64 if ((l
= trim(tok())) == NULL
) return 0;
65 if (!u
[0]) ui
->upper
= ui
->code
; else ui
->upper
= hex2num(u
);
66 if (!l
[0]) ui
->lower
= ui
->code
; else ui
->lower
= hex2num(l
);
67 if (ui
->upper
< 0 || ui
->lower
< 0) return 0;
68 if (ui
->upper
> 65535 || ui
->lower
> 65535) abort();
80 int main (int argc
, char *argv
[]) {
82 int rc
, f
, totalmap
= 0;
84 if (argc
!= 3) { fprintf(stderr
, "usage: %s unitable.c unitable.txt\n", argv
[0]); exit(1); }
85 if ((fi
= fopen(argv
[2], "r")) == NULL
) { fprintf(stderr
, "FATAL: can't open input file: '%s'\n", argv
[2]); exit(1); }
87 rc
= read_record(fi
, &ui
);
89 if (rc
== 0) continue;
90 if (ui
.code
< 128) continue;
91 if (strcmp(ui
.class, "Lu") != 0 && strcmp(ui
.class, "Ll") != 0) continue;
92 if (ui
.upper
== ui
.code
&& ui
.lower
== ui
.code
) continue;
93 for (f
= 0; f
< totalmap
; ++f
) {
94 if (map
[f
].code
== ui
.code
) { fprintf(stderr
, "FATAL: duplicate entries in the map!\n"); exit(1); }
95 if (map
[f
].code
> ui
.code
) { fprintf(stderr
, "FATAL: invalid entry order in the map!\n"); exit(1); }
97 if (totalmap
> 65535) { fprintf(stderr
, "FATAL: too many entries in the map!\n"); exit(1); }
98 map
[totalmap
].code
= ui
.code
;
99 map
[totalmap
].l
= ui
.lower
;
100 map
[totalmap
].u
= ui
.upper
;
104 qsort(map
, totalmap
, sizeof(map
[0]), ({
105 int cmp (const void *p0
, const void *p1
) {
106 const mm
*i0
= (const mm
*)p0
;
107 const mm
*i1
= (const mm
*)p1
;
108 return (i0
->code
< i1
->code
? -1 : (i0
->code
> i1
->code
? 1 : 0));
112 fo
= fopen(argv
[1], "w");
113 if (fo
== NULL
) { fprintf(stderr
, "FATAL: can't create output file: '%s'\n", argv
[1]); exit(1); }
114 fprintf(fo
, "static const struct casemap unicode_case_mapping[%d] = {\n", totalmap
);
115 for (f
= 0; f
< totalmap
; ++f
) fprintf(fo
, "{0x%04x,0x%04x,0x%04x},\n", map
[f
].code
, map
[f
].l
, map
[f
].u
);
116 fprintf(fo
, "%s\n", "};");