No empty .Rs/.Re
[netbsd-mini2440.git] / usr.sbin / chrtbl / chrtbl.c
blob2dc9f8b15cb2802d1e3ff833613ef5fa99dd1a23
1 /* $NetBSD: chrtbl.c,v 1.11 2009/04/15 00:43:29 lukem Exp $ */
3 /*
4 * Copyright (c) 1997 Christos Zoulas. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include <ctype.h>
28 #include <err.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
34 #include "ctypeio.h"
36 struct chartbl {
37 size_t maxchar;
38 char *ctypefilename;
39 unsigned char *ctype;
40 unsigned short *uptab;
41 unsigned short *lotab;
42 char *numericfilename;
43 unsigned char decimal_point;
44 unsigned char thousands_sep;
47 static void usage __P((void));
48 static int numeric __P((struct chartbl *, const char *, int, char *, size_t));
49 static int cswidth __P((struct chartbl *, const char *, int, char *, size_t));
50 static int setfilename __P((struct chartbl *, const char *, int, char *,
51 size_t));
52 static int addattr __P((struct chartbl *, const char *, int, char *, size_t));
53 static int uplow __P((struct chartbl *, const char *, int, char *, size_t));
54 static void printctype __P((FILE *, unsigned int));
55 static int output_ascii __P((const char *, const struct chartbl *));
56 static int output_binary __P((const struct chartbl *));
58 int main __P((int, char *[]));
60 static const struct toklist {
61 const char *name;
62 int (*func) __P((struct chartbl *, const char *, int arg,
63 char *, size_t lno));
64 int arg;
65 } tokens[] = {
66 { "LC_CTYPE", setfilename, 0 },
67 { "isupper", addattr, _U },
68 { "islower", addattr, _L },
69 { "isdigit", addattr, _N },
70 { "isspace", addattr, _S },
71 { "ispunct", addattr, _P },
72 { "iscntrl", addattr, _C },
73 { "isblank", addattr, _B },
74 { "isxdigit", addattr, _X },
75 { "ul", uplow, 0 },
76 { "cswidth", cswidth, 0 },
77 { "LC_NUMERIC", setfilename, 1 },
78 { "decimal_point", numeric, 0 },
79 { "thousands_sep", numeric, 0 },
80 { NULL, NULL, 0 }
83 /* usage():
84 * Print a usage message and exit
86 static void
87 usage()
90 (void) fprintf(stderr, "usage: %s [-o <filename>] <description>\n",
91 getprogname());
92 exit(1);
96 /* numeric():
97 * Parse a decimal_point or thousands_sep line
99 static int
100 numeric(cs, token, arg, line, lnum)
101 struct chartbl *cs;
102 const char *token;
103 int arg;
104 char *line;
105 size_t lnum;
107 return 1;
111 /* cswidth():
112 * Parse a cswidth line. This is of the form:
113 * cswidth: <n1>:<s1>,<n2>:<s2>,<n3>:<s3>
114 * Where:
115 * n1,n2,n3: byte widths of the supplementary codes 1,2,3
116 * s1,s2,s3: screen widths " " "
118 static int
119 cswidth(cs, token, arg, line, lnum)
120 struct chartbl *cs;
121 const char *token;
122 int arg;
123 char *line;
124 size_t lnum;
126 return 1;
129 /* setfilename():
130 * Set the output file name for LC_CTYPE or LC_NUMERIC
132 static int
133 setfilename(cs, token, arg, line, lnum)
134 struct chartbl *cs;
135 const char *token;
136 int arg;
137 char *line;
138 size_t lnum;
140 char *p = strtok(line, " \t");
142 if (p == NULL || *p == '\0')
143 return 0;
145 if ((p = strdup(p)) == NULL)
146 err(1, "Out of memory at line %lu", (u_long)lnum);
148 switch (arg) {
149 case 0:
150 cs->ctypefilename = p;
151 return 0;
152 case 1:
153 cs->numericfilename = p;
154 return 0;
155 default:
156 warn("%s: Bad filename argument %d at line %lu", token, arg,
157 (u_long)lnum);
158 free(p);
159 return 1;
164 /* addattr():
165 * Parse a character attribute line
166 * The line is of the form <attribute>: <char> | <char> - <char>
168 static int
169 addattr(cs, token, arg, line, lnum)
170 struct chartbl *cs;
171 const char *token;
172 int arg;
173 char *line;
174 size_t lnum;
176 static const char sep[] = "\t ";
177 size_t b = 0, e = 0, n;
178 int st = 0;
179 char *ptr, *ep;
181 for (ptr = strtok(line, sep); ptr; ptr = strtok(NULL, sep)) {
182 if (strcmp(ptr, "-") == 0) {
183 if (st++ == 0)
184 goto badrange;
185 continue;
188 n = (size_t) strtoul(ptr, &ep, 0);
189 if (ptr == ep || *ep) {
190 warnx("%s: Bad number `%s' at line %lu", token,
191 ptr, (u_long)lnum);
192 return 1;
194 switch (++st) {
195 case 1:
196 b = n;
197 continue;
198 case 2:
199 if (b > cs->maxchar) {
200 n = b;
201 goto oorange;
203 cs->ctype[b+1] |= arg;
204 st = 1;
205 b = n;
206 continue;
207 case 3:
208 e = n;
209 if (e > cs->maxchar) {
210 n = e;
211 goto oorange;
213 for (n = b; n <= e; n++)
214 cs->ctype[n+1] |= arg;
215 st = 0;
216 continue;
217 default:
218 goto badstate;
221 switch (st) {
222 case 0:
223 return 0;
224 case 1:
225 if (b > cs->maxchar) {
226 n = b;
227 goto oorange;
229 cs->ctype[b+1] |= arg;
230 return 0;
231 case 2:
232 goto badrange;
233 default:
234 goto badstate;
237 oorange:
238 warnx("%s: Character %lu out of range at line %lu", token, (u_long)n,
239 (u_long)lnum);
240 return 1;
241 badstate:
242 warnx("%s: Unexpected state %d at line %lu", token, st,
243 (u_long)lnum);
244 return 1;
245 badrange:
246 warnx("%s: Missing %s range at line %lu", token,
247 st == 1 ? "begin" : "end", (u_long)lnum);
248 return 1;
252 /* uplow():
253 * Parse an upper<->lower case transformation. The format of the line
254 * is ul <upper lower> ...
256 static int
257 uplow(cs, token, arg, line, lnum)
258 struct chartbl *cs;
259 const char *token;
260 int arg;
261 char *line;
262 size_t lnum;
264 size_t lo, up;
265 char *p, *ep;
267 for (p = line;;) {
268 while (*p && isspace((u_char) *p))
269 p++;
270 switch (*p) {
271 case '\0':
272 return 0;
273 case '<':
274 p++;
275 break;
276 default:
277 goto badtoken;
279 while (*p && isspace((u_char) *p))
280 p++;
281 if (*p == '\0')
282 goto badtoken;
283 lo = (size_t) strtol(p, &ep, 0);
284 if (p == ep || !isspace((u_char) *ep))
285 goto badtoken;
286 p = ep + 1;
287 while (*p && isspace((u_char) *p))
288 p++;
289 up = (size_t) strtol(p, &ep, 0);
290 if (p == ep)
291 goto badtoken;
292 if (lo > cs->maxchar)
293 goto oorange;
294 if (up > cs->maxchar) {
295 lo = up;
296 goto oorange;
298 cs->lotab[up + 1] = lo;
299 cs->uptab[lo + 1] = up;
300 p = ep;
301 switch (*ep) {
302 case '\0':
303 return 0;
304 case ' ':
305 case '\t':
306 case '>':
307 p++;
308 break;
309 default:
310 goto badtoken;
314 badtoken:
315 warnx("%s: Bad token `%s' at line %lu", token, p, (u_long)lnum);
316 return 1;
317 oorange:
318 warnx("%s: Out of range character %lx at line %lu", token, (u_long)lo,
319 (u_long)lnum);
320 return 1;
324 /* printctype():
325 * Symbolically print an ascii character.
327 static void
328 printctype(fp, ct)
329 FILE *fp;
330 unsigned int ct;
332 int did = 0;
334 #define DO(a) if (__CONCAT(_,a) & ct) { \
335 if (did) \
336 (void) fputc('|', fp); \
337 did = 1; \
338 (void) fputc('_', fp); \
339 (void) fputs(__STRING(a), fp); \
341 DO(U)
342 DO(L)
343 DO(N)
344 DO(S)
345 DO(P)
346 DO(C)
347 DO(B)
348 DO(X)
349 if (!did)
350 (void) fputc('0', fp);
354 /* output_ascii():
355 * Print a `c' symbolic description of the character set
357 static int
358 output_ascii(fn, ct)
359 const char *fn;
360 const struct chartbl *ct;
362 size_t i;
363 FILE *fp;
365 if ((fp = fopen(fn, "w")) == NULL) {
366 warn("Cannot open `%s'", fn);
367 return 1;
370 (void) fprintf(fp, "/* Automatically generated file; do not edit */\n");
371 (void) fprintf(fp, "#include <ctype.h>\n");
372 (void) fprintf(fp, "unsigned char _ctype_[] = { 0");
373 for (i = 1; i <= ct->maxchar; i++) {
374 if (((i - 1) & 7) == 0)
375 (void) fputs(",\n\t", fp);
376 printctype(fp, ct->ctype[i]);
377 if ((i & 7) != 0)
378 (void) fputs(",\t", fp);
380 (void) fprintf(fp, "\n};\n");
382 (void) fprintf(fp, "short _tolower_tab_[] = { -1");
383 for (i = 1; i <= ct->maxchar; i++) {
384 if (((i - 1) & 7) == 0)
385 (void) fputs(",\n\t", fp);
386 (void) fprintf(fp, "0x%x", ct->lotab[i]);
387 if ((i & 7) != 0)
388 (void) fputs(",\t", fp);
390 (void) fprintf(fp, "\n};\n");
392 (void) fprintf(fp, "short _toupper_tab_[] = { -1");
393 for (i = 1; i <= ct->maxchar; i++) {
394 if (((i - 1) & 7) == 0)
395 (void) fputs(",\n\t", fp);
396 (void) fprintf(fp, "0x%x", ct->uptab[i]);
397 if ((i & 7) != 0)
398 (void) fputs(",\t", fp);
400 (void) fprintf(fp, "\n};\n");
401 (void) fclose(fp);
402 return 0;
406 /* output_binary():
407 * Print a binary description of the requested character set.
409 static int
410 output_binary(ct)
411 const struct chartbl *ct;
413 int error = 0;
415 if (ct->ctypefilename != NULL) {
416 if (!__savectype(ct->ctypefilename, ct->ctype, ct->lotab,
417 ct->uptab))
418 err(1, "Cannot creating/writing `%s'",
419 ct->ctypefilename);
421 else {
422 warnx("No output file for LC_CTYPE specified");
423 error |= 1;
425 return error;
430 main(argc, argv)
431 int argc;
432 char *argv[];
434 size_t lnum, size;
435 FILE *fp;
436 char *line, *token, *p;
437 const struct toklist *t;
438 struct chartbl ct;
439 int c;
440 size_t i;
441 char *ifname, *ofname = NULL;
442 int error = 0;
444 while ((c = getopt(argc, argv, "o:")) != -1)
445 switch (c) {
446 case 'o':
447 ofname = optarg;
448 break;
449 default:
450 usage();
451 break;
454 if (argc - 1 != optind)
455 usage();
457 ifname = argv[optind];
459 if ((fp = fopen(ifname, "r")) == NULL)
460 err(1, "Cannot open `%s'", ifname);
462 ct.maxchar = 256;
463 ct.ctype = malloc(sizeof(ct.ctype[0]) * (ct.maxchar + 1));
464 ct.uptab = malloc(sizeof(ct.uptab[0]) * (ct.maxchar + 1));
465 ct.lotab = malloc(sizeof(ct.lotab[0]) * (ct.maxchar + 1));
466 ct.ctypefilename = NULL;
467 ct.numericfilename = NULL;
468 ct.decimal_point = '.';
469 ct.thousands_sep = ',';
471 if (ct.ctype == NULL || ct.uptab == NULL || ct.lotab == NULL)
472 err(1, "Out of memory");
474 (void) memset(ct.ctype, 0, sizeof(ct.ctype[0]) * (ct.maxchar * 1));
475 (void) memset(ct.uptab, 0, sizeof(ct.uptab[0]) * (ct.maxchar * 1));
476 (void) memset(ct.lotab, 0, sizeof(ct.lotab[0]) * (ct.maxchar * 1));
478 for (lnum = 1; (line = fparseln(fp, &size, &lnum, NULL, 0)) != NULL;
479 free(line)) {
480 for (token = line; *token && isspace((u_char) *token); token++)
481 continue;
482 if (*token == '\0')
483 continue;
484 for (p = token; *p && !isspace((u_char) *p); p++)
485 continue;
486 if (*p == '\0')
487 continue;
488 *p = '\0';
489 for (p++; *p && isspace((u_char) *p); p++)
490 continue;
491 for (t = tokens; t->name != NULL; t++)
492 if (strcmp(t->name, token) == 0)
493 break;
494 if (t->name == NULL) {
495 warnx("Unknown token %s at line %lu", token,
496 (u_long)lnum);
497 error |= 1;
498 continue;
500 error |= (*t->func)(&ct, token, t->arg, p, lnum);
502 (void) fclose(fp);
504 for (i = 1; i <= ct.maxchar; i++) {
505 if (ct.uptab[i] == 0)
506 ct.uptab[i] = i - 1;
507 if (ct.lotab[i] == 0)
508 ct.lotab[i] = i - 1;
511 if (ofname != NULL)
512 error |= output_ascii(ofname, &ct);
513 error |= output_binary(&ct);
514 return error;