1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * conmakehash.c |
4 | * |
5 | * Create arrays for initializing the kernel folded tables (using a hash |
6 | * table turned out to be to limiting...) Unfortunately we can't simply |
7 | * preinitialize the tables at compile time since kfree() cannot accept |
8 | * memory not allocated by kmalloc(), and doing our own memory management |
9 | * just for this seems like massive overkill. |
10 | * |
11 | * Copyright (C) 1995-1997 H. Peter Anvin |
12 | */ |
13 | |
14 | #include <stdio.h> |
15 | #include <stdlib.h> |
16 | #include <sysexits.h> |
17 | #include <string.h> |
18 | #include <ctype.h> |
19 | |
20 | #define MAX_FONTLEN 256 |
21 | |
22 | typedef unsigned short unicode; |
23 | |
24 | static void usage(char *argv0) |
25 | { |
26 | fprintf(stderr, format: "Usage: \n" |
27 | " %s chartable [hashsize] [hashstep] [maxhashlevel]\n" , argv0); |
28 | exit(EX_USAGE); |
29 | } |
30 | |
31 | static int getunicode(char **p0) |
32 | { |
33 | char *p = *p0; |
34 | |
35 | while (*p == ' ' || *p == '\t') |
36 | p++; |
37 | if (*p != 'U' || p[1] != '+' || |
38 | !isxdigit(p[2]) || !isxdigit(p[3]) || !isxdigit(p[4]) || |
39 | !isxdigit(p[5]) || isxdigit(p[6])) |
40 | return -1; |
41 | *p0 = p+6; |
42 | return strtol(nptr: p+2,endptr: 0,base: 16); |
43 | } |
44 | |
45 | unicode unitable[MAX_FONTLEN][255]; |
46 | /* Massive overkill, but who cares? */ |
47 | int unicount[MAX_FONTLEN]; |
48 | |
49 | static void addpair(int fp, int un) |
50 | { |
51 | int i; |
52 | |
53 | if ( un <= 0xfffe ) |
54 | { |
55 | /* Check it isn't a duplicate */ |
56 | |
57 | for ( i = 0 ; i < unicount[fp] ; i++ ) |
58 | if ( unitable[fp][i] == un ) |
59 | return; |
60 | |
61 | /* Add to list */ |
62 | |
63 | if ( unicount[fp] > 254 ) |
64 | { |
65 | fprintf(stderr, format: "ERROR: Only 255 unicodes/glyph permitted!\n" ); |
66 | exit(EX_DATAERR); |
67 | } |
68 | |
69 | unitable[fp][unicount[fp]] = un; |
70 | unicount[fp]++; |
71 | } |
72 | |
73 | /* otherwise: ignore */ |
74 | } |
75 | |
76 | int main(int argc, char *argv[]) |
77 | { |
78 | FILE *ctbl; |
79 | char *tblname; |
80 | char buffer[65536]; |
81 | int fontlen; |
82 | int i, nuni, nent; |
83 | int fp0, fp1, un0, un1; |
84 | char *p, *p1; |
85 | |
86 | if ( argc < 2 || argc > 5 ) |
87 | usage(argv0: argv[0]); |
88 | |
89 | if ( !strcmp(s1: argv[1],s2: "-" ) ) |
90 | { |
91 | ctbl = stdin; |
92 | tblname = "stdin" ; |
93 | } |
94 | else |
95 | { |
96 | ctbl = fopen(filename: tblname = argv[1], modes: "r" ); |
97 | if ( !ctbl ) |
98 | { |
99 | perror(s: tblname); |
100 | exit(EX_NOINPUT); |
101 | } |
102 | } |
103 | |
104 | /* For now we assume the default font is always 256 characters. */ |
105 | fontlen = 256; |
106 | |
107 | /* Initialize table */ |
108 | |
109 | for ( i = 0 ; i < fontlen ; i++ ) |
110 | unicount[i] = 0; |
111 | |
112 | /* Now we come to the tricky part. Parse the input table. */ |
113 | |
114 | while ( fgets(s: buffer, n: sizeof(buffer), stream: ctbl) != NULL ) |
115 | { |
116 | if ( (p = strchr(s: buffer, c: '\n')) != NULL ) |
117 | *p = '\0'; |
118 | else |
119 | fprintf(stderr, format: "%s: Warning: line too long\n" , tblname); |
120 | |
121 | p = buffer; |
122 | |
123 | /* |
124 | * Syntax accepted: |
125 | * <fontpos> <unicode> <unicode> ... |
126 | * <range> idem |
127 | * <range> <unicode range> |
128 | * |
129 | * where <range> ::= <fontpos>-<fontpos> |
130 | * and <unicode> ::= U+<h><h><h><h> |
131 | * and <h> ::= <hexadecimal digit> |
132 | */ |
133 | |
134 | while (*p == ' ' || *p == '\t') |
135 | p++; |
136 | if (!*p || *p == '#') |
137 | continue; /* skip comment or blank line */ |
138 | |
139 | fp0 = strtol(nptr: p, endptr: &p1, base: 0); |
140 | if (p1 == p) |
141 | { |
142 | fprintf(stderr, format: "Bad input line: %s\n" , buffer); |
143 | exit(EX_DATAERR); |
144 | } |
145 | p = p1; |
146 | |
147 | while (*p == ' ' || *p == '\t') |
148 | p++; |
149 | if (*p == '-') |
150 | { |
151 | p++; |
152 | fp1 = strtol(nptr: p, endptr: &p1, base: 0); |
153 | if (p1 == p) |
154 | { |
155 | fprintf(stderr, format: "Bad input line: %s\n" , buffer); |
156 | exit(EX_DATAERR); |
157 | } |
158 | p = p1; |
159 | } |
160 | else |
161 | fp1 = 0; |
162 | |
163 | if ( fp0 < 0 || fp0 >= fontlen ) |
164 | { |
165 | fprintf(stderr, |
166 | format: "%s: Glyph number (0x%x) larger than font length\n" , |
167 | tblname, fp0); |
168 | exit(EX_DATAERR); |
169 | } |
170 | if ( fp1 && (fp1 < fp0 || fp1 >= fontlen) ) |
171 | { |
172 | fprintf(stderr, |
173 | format: "%s: Bad end of range (0x%x)\n" , |
174 | tblname, fp1); |
175 | exit(EX_DATAERR); |
176 | } |
177 | |
178 | if (fp1) |
179 | { |
180 | /* we have a range; expect the word "idem" or a Unicode range of the |
181 | same length */ |
182 | while (*p == ' ' || *p == '\t') |
183 | p++; |
184 | if (!strncmp(s1: p, s2: "idem" , n: 4)) |
185 | { |
186 | for (i=fp0; i<=fp1; i++) |
187 | addpair(fp: i,un: i); |
188 | p += 4; |
189 | } |
190 | else |
191 | { |
192 | un0 = getunicode(p0: &p); |
193 | while (*p == ' ' || *p == '\t') |
194 | p++; |
195 | if (*p != '-') |
196 | { |
197 | fprintf(stderr, |
198 | format: "%s: Corresponding to a range of font positions, there should be a Unicode range\n" , |
199 | tblname); |
200 | exit(EX_DATAERR); |
201 | } |
202 | p++; |
203 | un1 = getunicode(p0: &p); |
204 | if (un0 < 0 || un1 < 0) |
205 | { |
206 | fprintf(stderr, |
207 | format: "%s: Bad Unicode range corresponding to font position range 0x%x-0x%x\n" , |
208 | tblname, fp0, fp1); |
209 | exit(EX_DATAERR); |
210 | } |
211 | if (un1 - un0 != fp1 - fp0) |
212 | { |
213 | fprintf(stderr, |
214 | format: "%s: Unicode range U+%x-U+%x not of the same length as font position range 0x%x-0x%x\n" , |
215 | tblname, un0, un1, fp0, fp1); |
216 | exit(EX_DATAERR); |
217 | } |
218 | for(i=fp0; i<=fp1; i++) |
219 | addpair(fp: i,un: un0-fp0+i); |
220 | } |
221 | } |
222 | else |
223 | { |
224 | /* no range; expect a list of unicode values for a single font position */ |
225 | |
226 | while ( (un0 = getunicode(p0: &p)) >= 0 ) |
227 | addpair(fp: fp0, un: un0); |
228 | } |
229 | while (*p == ' ' || *p == '\t') |
230 | p++; |
231 | if (*p && *p != '#') |
232 | fprintf(stderr, format: "%s: trailing junk (%s) ignored\n" , tblname, p); |
233 | } |
234 | |
235 | /* Okay, we hit EOF, now output hash table */ |
236 | |
237 | fclose(stream: ctbl); |
238 | |
239 | |
240 | /* Compute total size of Unicode list */ |
241 | nuni = 0; |
242 | for ( i = 0 ; i < fontlen ; i++ ) |
243 | nuni += unicount[i]; |
244 | |
245 | printf(format: "\ |
246 | /*\n\ |
247 | * Do not edit this file; it was automatically generated by\n\ |
248 | *\n\ |
249 | * conmakehash %s > [this file]\n\ |
250 | *\n\ |
251 | */\n\ |
252 | \n\ |
253 | #include <linux/types.h>\n\ |
254 | \n\ |
255 | u8 dfont_unicount[%d] = \n\ |
256 | {\n\t" , argv[1], fontlen); |
257 | |
258 | for ( i = 0 ; i < fontlen ; i++ ) |
259 | { |
260 | printf(format: "%3d" , unicount[i]); |
261 | if ( i == fontlen-1 ) |
262 | printf(format: "\n};\n" ); |
263 | else if ( i % 8 == 7 ) |
264 | printf(format: ",\n\t" ); |
265 | else |
266 | printf(format: ", " ); |
267 | } |
268 | |
269 | printf(format: "\nu16 dfont_unitable[%d] = \n{\n\t" , nuni); |
270 | |
271 | fp0 = 0; |
272 | nent = 0; |
273 | for ( i = 0 ; i < nuni ; i++ ) |
274 | { |
275 | while ( nent >= unicount[fp0] ) |
276 | { |
277 | fp0++; |
278 | nent = 0; |
279 | } |
280 | printf(format: "0x%04x" , unitable[fp0][nent++]); |
281 | if ( i == nuni-1 ) |
282 | printf(format: "\n};\n" ); |
283 | else if ( i % 8 == 7 ) |
284 | printf(format: ",\n\t" ); |
285 | else |
286 | printf(format: ", " ); |
287 | } |
288 | |
289 | exit(EX_OK); |
290 | } |
291 | |