xref: /titanic_44/usr/src/lib/libast/common/port/lcgen.c (revision 8339b41da2395f0525c46ceedfeb01961893ec44)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                 Glenn Fowler <gsf@research.att.com>                  *
18 *                  David Korn <dgk@research.att.com>                   *
19 *                   Phong Vo <kpv@research.att.com>                    *
20 *                                                                      *
21 ***********************************************************************/
22 /*
23  * generate <lc.h> implementation tables from lc.tab
24  * this must make it through vanilla cc with no -last
25  *
26  *	# comment
27  *	:charset:
28  *		code	name	ms-codepage
29  *	:language:
30  *		code	name	alt1|alt2...	charset|... attr1|attr2|...
31  *		...
32  *	:territory:
33  *		code	name	lang1|lang2...
34  *	:abbreviation:
35  */
36 
37 #include <stdio.h>
38 #include <ctype.h>
39 #ifdef __STDC__
40 #include <stdlib.h>
41 #include <string.h>
42 #endif
43 
44 typedef struct Link_s
45 {
46 	struct Link_s*		next;
47 	char*			code;
48 	int			index;
49 } Link_t;
50 
51 typedef struct Table_s
52 {
53 	Link_t*			root;
54 	int			count;
55 } Table_t;
56 
57 typedef struct Abbreviation_s
58 {
59 	Link_t			link;
60 	char*			value;
61 } Abbreviation_t;
62 
63 typedef struct Attribute_s
64 {
65 	Link_t			link;
66 } Attribute_t;
67 
68 typedef struct Attribute_list_s
69 {
70 	struct Attribute_list_s*next;
71 	Attribute_t*		attribute;
72 } Attribute_list_t;
73 
74 typedef struct Charset_s
75 {
76 	Link_t			link;
77 	char*			alternates;
78 	char*			ms;
79 } Charset_t;
80 
81 typedef struct Language_s
82 {
83 	Link_t			link;
84 	char*			name;
85 	char*			alternates;
86 	Charset_t*		charset;
87 	Attribute_list_t*	attributes;
88 } Language_t;
89 
90 typedef struct Language_list_s
91 {
92 	struct Language_list_s*	next;
93 	Language_t*		language;
94 } Language_list_t;
95 
96 typedef struct Territory_s
97 {
98 	Link_t			link;
99 	char*			name;
100 	Language_list_t*	languages;
101 	int			primary;
102 	int			index;
103 } Territory_t;
104 
105 typedef struct Map_s
106 {
107 	Link_t			link;
108 	Language_t*		language;
109 	Territory_t*		territory;
110 	Charset_t*		charset;
111 	Attribute_t*		attribute;
112 } Map_t;
113 
114 static struct State_s
115 {
116 	Table_t			attribute;
117 	Table_t			charset;
118 	Table_t			language;
119 	Table_t			territory;
120 	Table_t			map;
121 } state;
122 
123 #define INIT		0
124 #define CHARSET		1
125 #define LANGUAGE	2
126 #define TERRITORY	3
127 #define MAP		4
128 
129 #define elementsof(x)	(sizeof(x)/sizeof(x[0]))
130 #define newof(p,t,n,x)	((t*)malloc(sizeof(t)*(n)+(x)))
131 
132 static Link_t*
133 #if defined(__STDC__) || defined(__cplusplus)
134 enter(register Table_t* tab, register Link_t* v)
135 #else
136 enter(tab, v)
137 register Table_t*	tab;
138 register Link_t*	v;
139 #endif
140 {
141 	register Link_t*	x;
142 	register Link_t*	p;
143 
144 	for (p = 0, x = tab->root; x; p = x, x = x->next)
145 		if (!strcmp(x->code, v->code))
146 			return x;
147 	if (p)
148 		p->next = v;
149 	else
150 		tab->root = v;
151 	v->next = 0;
152 	v->index = tab->count++;
153 	return v;
154 }
155 
156 static Link_t*
157 #if defined(__STDC__) || defined(__cplusplus)
158 lookup(register Table_t* tab, register char* s)
159 #else
160 lookup(tab, s)
161 register Table_t*	tab;
162 register char*		s;
163 #endif
164 {
165 	register Link_t*	x;
166 
167 	for (x = tab->root; x; x = x->next)
168 		if (!strcmp(x->code, s))
169 			return x;
170 	return 0;
171 }
172 
173 static char*
174 #if defined(__STDC__) || defined(__cplusplus)
175 copy(char** p, register char* f)
176 #else
177 copy(p, f)
178 char**		p;
179 register char*	f;
180 #endif
181 {
182 	register char*	t;
183 	char*		b;
184 
185 	if (!f)
186 		return 0;
187 	b = t = *p;
188 	while (*t++ = *f++);
189 	*p = t;
190 	return b;
191 }
192 
193 static void
194 #if defined(__STDC__) || defined(__cplusplus)
195 macro(FILE* f, char* p1, char* p2, char* p3)
196 #else
197 macro(f, p1, p2, p3)
198 FILE*		f;
199 char*		p1;
200 char*		p2;
201 char*		p3;
202 #endif
203 {
204 	register int	c;
205 	register char*	s;
206 	register char*	b;
207 	register char*	e;
208 	int		i;
209 	int		m;
210 	int		n;
211 	char*		part[4];
212 	char		buf[128];
213 
214 	part[0] = p1;
215 	part[1] = p2;
216 	part[2] = p3;
217 	part[3] = 0;
218 	n = 0;
219 	fprintf(f, "\n");
220 	do
221 	{
222 		i = m = 0;
223 		b = buf;
224 		e = &buf[sizeof(buf)-1];
225 		while (b < e)
226 		{
227 			if (!(s = part[i++]))
228 				break;
229 			if (i > 1)
230 				*b++ = '_';
231 			while ((c = *s++) && b < e)
232 			{
233 				if (c == '|')
234 				{
235 					part[i-1] = s;
236 					m = 1;
237 					break;
238 				}
239 				else if (islower(c))
240 					c = toupper(c);
241 				else if (!isalnum(c))
242 					c = '_';
243 				*b++ = c;
244 			}
245 		}
246 		*b = 0;
247 		fprintf(f, "#ifdef %s\n%s,\n#else\n", buf, buf);
248 		n++;
249 	} while (m);
250 	fprintf(f, "0,\n");
251 	while (n-- > 0)
252 		fprintf(f, "#endif\n");
253 }
254 
255 #if defined(__STDC__) || defined(__cplusplus)
256 int
257 main(int argc, char** argv)
258 #else
259 int
260 main(argc, argv)
261 int		argc;
262 char**		argv;
263 #endif
264 {
265 	register char*		s;
266 	register char**		vp;
267 	register char**		ve;
268 	Attribute_t*		ap;
269 	Attribute_list_t*	al;
270 	Attribute_list_t*	az;
271 	Charset_t*		cp;
272 	Territory_t*		tp;
273 	Language_t*		lp;
274 	Language_list_t*	ll;
275 	Language_list_t*	lz;
276 	Map_t*			mp;
277 	char*			b;
278 	char*			f;
279 	char*			command;
280 	char*			hdr;
281 	char*			lib;
282 	FILE*			hf;
283 	FILE*			lf;
284 	int			c;
285 	int			i;
286 	int			line;
287 	int			type;
288 	int			language_attribute_max;
289 	int			territory_language_max;
290 	char*			arg[5];
291 	char			buf[1024];
292 
293 	command = *argv++;
294 	line = 0;
295 	if (!(hdr = *argv++) || !(lib = *argv++) || *argv)
296 	{
297 		fprintf(stderr, "%s: { hdr lib tab } arguments expected\n", command);
298 		return 1;
299 	}
300 	if (!(hf = fopen(hdr, "w")))
301 	{
302 		fprintf(stderr, "%s: %s: cannot write\n", command, hdr);
303 		return 1;
304 	}
305 	if (!(lf = fopen(lib, "w")))
306 	{
307 		fprintf(stderr, "%s: %s: cannot write\n", command, lib);
308 		return 1;
309 	}
310 	type = 0;
311 	language_attribute_max = 0;
312 	territory_language_max = 0;
313 	state.language.count = 2;
314 	state.territory.count = 2;
315 	ve = &arg[elementsof(arg)];
316 	fprintf(hf, "/* : : generated by %s : : */\n", command);
317 	fprintf(hf, "#pragma prototyped\n");
318 	fprintf(hf, "\n");
319 	fprintf(hf, "#ifndef _LC_H\n");
320 	fprintf(hf, "#define _LC_H\t\t\t1\n");
321 	fprintf(hf, "\n");
322 	fprintf(hf, "#include <ast.h>\n");
323 	fprintf(hf, "\n");
324 	fprintf(hf, "#define LC_abbreviated\t\t0x00001\n");
325 	fprintf(hf, "#define LC_checked\t\t0x00002\n");
326 	fprintf(hf, "#define LC_debug\t\t0x00004\n");
327 	fprintf(hf, "#define LC_default\t\t0x00008\n");
328 	fprintf(hf, "#define LC_defined\t\t0x00010\n");
329 	fprintf(hf, "#define LC_local\t\t0x00020\n");
330 	fprintf(hf, "#define LC_primary\t\t0x00040\n");
331 	fprintf(hf, "#define LC_qualified\t\t0x00080\n");
332 	fprintf(hf, "#define LC_undefined\t\t0x00100\n");
333 	fprintf(hf, "#define LC_utf8\t\t\t0x00200\n");
334 	fprintf(hf, "#define LC_verbose\t\t0x00400\n");
335 	fprintf(hf, "#define LC_setlocale\t\t\t0x10000\n");
336 	fprintf(hf, "#define LC_setenv\t\t\t0x20000\n");
337 	fprintf(hf, "#define LC_user\t\t\t0x40000\n");
338 	fprintf(lf, "/* : : generated by %s : : */\n", command);
339 	fprintf(lf, "\n");
340 	fprintf(lf, "#include \"lclib.h\"\n");
341 	fprintf(lf, "#include \"lclang.h\"\n");
342 	fprintf(lf, "\n");
343 	while (s = fgets(buf, sizeof(buf), stdin))
344 	{
345 		line++;
346 		while (isspace(*s))
347 			s++;
348 		if (!*s || *s == '#')
349 			continue;
350 		b = s;
351 		vp = arg;
352 		for (;;)
353 		{
354 			for (*vp++ = s; *s && !isspace(*s); s++);
355 			if (!*s)
356 				break;
357 			for (*s++ = 0; isspace(*s); s++);
358 			if (!strcmp(*(vp - 1), "-"))
359 				*(vp - 1) = 0;
360 			if (!*s || vp >= ve)
361 				break;
362 		}
363 		while (vp < ve)
364 			*vp++ = 0;
365 		if (*arg[0] == ':')
366 		{
367 			if (!strcmp(arg[0], ":map:"))
368 			{
369 				if (type != TERRITORY)
370 				{
371 					fprintf(stderr, "%s: %d: %s: must be specified after :territory:\n", command, line, arg[0]);
372 					return 1;
373 				}
374 				type = MAP;
375 				continue;
376 			}
377 			else if (!strcmp(arg[0], ":charset:"))
378 			{
379 				if (type != INIT)
380 				{
381 					fprintf(stderr, "%s: %d: %s must be specified first\n", command, line, arg[0]);
382 					return 1;
383 				}
384 				type = CHARSET;
385 				continue;
386 			}
387 			else if (!strcmp(arg[0], ":territory:"))
388 			{
389 				if (type != LANGUAGE)
390 				{
391 					fprintf(stderr, "%s: %d: %s: must be specified after :language:\n", command, line, arg[0]);
392 					return 1;
393 				}
394 				type = TERRITORY;
395 				continue;
396 			}
397 			else if (!strcmp(arg[0], ":language:"))
398 			{
399 				if (type != CHARSET)
400 				{
401 					fprintf(stderr, "%s: %d: %s must be specified after :charset:\n", command, line, arg[0]);
402 					return 1;
403 				}
404 				type = LANGUAGE;
405 				continue;
406 			}
407 			else
408 			{
409 				fprintf(stderr, "%s: %d: %s invalid\n", command, line, arg[0]);
410 				return 1;
411 			}
412 		}
413 		if (!arg[1])
414 		{
415 			fprintf(stderr, "%s: %d: at least two arguments expected\n", command, line);
416 			return 1;
417 		}
418 		switch (type)
419 		{
420 		case CHARSET:
421 			if (!(cp = newof(0, Charset_t, 1, s - b + 1)))
422 			{
423 				fprintf(stderr, "%s: %d: out of space\n", command, line);
424 				return 1;
425 			}
426 			b = (char*)(cp + 1);
427 			cp->link.code = copy(&b, arg[0]);
428 			cp->alternates = copy(&b, arg[1]);
429 			cp->ms = copy(&b, arg[2]);
430 			if (cp != (Charset_t*)enter(&state.charset, (Link_t*)cp))
431 			{
432 				fprintf(stderr, "%s: %d: %s: duplicate charset\n", command, line, cp->link.code);
433 				return 1;
434 			}
435 			break;
436 		case TERRITORY:
437 			if (!(tp = newof(0, Territory_t, 1, s - b + 1)))
438 			{
439 				fprintf(stderr, "%s: %d: out of space\n", command, line);
440 				return 1;
441 			}
442 			b = (char*)(tp + 1);
443 			tp->link.code = copy(&b, arg[0]);
444 			tp->name = copy(&b, arg[1]);
445 			tp->languages = 0;
446 			if (s = copy(&b, arg[2]))
447 			{
448 				i = 0;
449 				while (*(b = s))
450 				{
451 					for (; *s && *s != ':' && *s != '|'; s++);
452 					if (c = *s)
453 						*s++ = 0;
454 					if (!(lp = (Language_t*)lookup(&state.language, b)))
455 					{
456 						fprintf(stderr, "%s: %d: %s: unknown language\n", command, line, b);
457 						return 1;
458 					}
459 					if (!(ll = newof(0, Language_list_t, 1, 0)))
460 					{
461 						fprintf(stderr, "%s: %d: out of space\n", command, line);
462 						return 1;
463 					}
464 					if (!tp->languages)
465 						tp->languages = ll;
466 					else
467 						lz->next = ll;
468 					lz = ll;
469 					ll->language = lp;
470 					ll->next = 0;
471 					i++;
472 					if (c == ':')
473 					{
474 						for (b = s; *s && *s != '|'; s++);
475 						if (*s)
476 							*s++ = 0;
477 						if (!strcmp(b, "primary"))
478 							tp->primary = 1;
479 					}
480 				}
481 				if (territory_language_max < i)
482 					territory_language_max = i;
483 			}
484 			if (tp != (Territory_t*)enter(&state.territory, (Link_t*)tp))
485 			{
486 				fprintf(stderr, "%s: %d: %s: duplicate territory\n", command, line, tp->link.code);
487 				return 1;
488 			}
489 			break;
490 		case LANGUAGE:
491 			if (!(lp = newof(0, Language_t, 1, s - b + 1)))
492 			{
493 				fprintf(stderr, "%s: %d: out of space\n", command, line);
494 				return 1;
495 			}
496 			b = (char*)(lp + 1);
497 			lp->link.code = copy(&b, arg[0]);
498 			lp->name = copy(&b, arg[1]);
499 			lp->alternates = copy(&b, arg[2]);
500 			if (!arg[3])
501 				lp->charset = 0;
502 			else if (!(lp->charset = (Charset_t*)lookup(&state.charset, arg[3])))
503 			{
504 				fprintf(stderr, "%s: %d: %s: unknown charset\n", command, line, arg[3]);
505 				return 1;
506 			}
507 			lp->attributes = 0;
508 			if (s = copy(&b, arg[4]))
509 			{
510 				i = 0;
511 				fprintf(lf, "\nconst Lc_attribute_t attribute_%s[] =\n{\n", lp->link.code);
512 				while (*(b = s))
513 				{
514 					for (f = 0; *s && *s != '|'; s++)
515 						if (*s == ':')
516 						{
517 							*s++ = 0;
518 							f = s;
519 						}
520 					if (*s)
521 						*s++ = 0;
522 					fprintf(lf, "{\"%s\",", b);
523 					if (f)
524 						fprintf(lf, "LC_%s,", f);
525 					else
526 						fprintf(lf, "0,");
527 					if (!(ap = newof(0, Attribute_t, 1, 0)))
528 					{
529 						fprintf(stderr, "%s: %d: out of space\n", command, line);
530 						return 1;
531 					}
532 					ap->link.code = b;
533 					ap->link.index = i++;
534 					if (!(al = newof(0, Attribute_list_t, 1, 0)))
535 					{
536 						fprintf(stderr, "%s: %d: out of space\n", command, line);
537 						return 1;
538 					}
539 					if (!lp->attributes)
540 						lp->attributes = al;
541 					else
542 						az->next = al;
543 					az = al;
544 					al->attribute = ap;
545 					al->next = 0;
546 					macro(lf, "SUBLANG", lp->name, b);
547 					fprintf(lf, "\n},\n");
548 				}
549 				if (language_attribute_max < i)
550 					language_attribute_max = i;
551 				fprintf(lf, "};\n");
552 			}
553 			if (lp != (Language_t*)enter(&state.language, (Link_t*)lp))
554 			{
555 				fprintf(stderr, "%s: %d: %s: duplicate language\n", command, line, lp->link.code);
556 				return 1;
557 			}
558 			break;
559 		case MAP:
560 			if (!(mp = newof(0, Map_t, 1, s - b + 1)))
561 			{
562 				fprintf(stderr, "%s: %d: out of space\n", command, line);
563 				return 1;
564 			}
565 			b = (char*)(mp + 1);
566 			mp->link.code = copy(&b, arg[0]);
567 			if (!arg[2])
568 			{
569 				fprintf(stderr, "%s: %d: territory code expected\n", command, line);
570 				return 1;
571 			}
572 			if (!(mp->language = (Language_t*)lookup(&state.language, arg[1])))
573 			{
574 				fprintf(stderr, "%s: %d: %s: unknown language\n", command, line, arg[1]);
575 				return 1;
576 			}
577 			if (!(mp->territory = (Territory_t*)lookup(&state.territory, arg[2])))
578 			{
579 				fprintf(stderr, "%s: %d: %s: unknown territory\n", command, line, arg[2]);
580 				return 1;
581 			}
582 			if (!arg[3])
583 				mp->charset = 0;
584 			else if (!(mp->charset = (Charset_t*)lookup(&state.charset, arg[3])))
585 			{
586 				fprintf(stderr, "%s: %d: %s: unknown charset\n", command, line, arg[3]);
587 				return 1;
588 			}
589 			mp->attribute = 0;
590 			if (arg[4])
591 			{
592 				for (al = mp->language->attributes; al; al = al->next)
593 					if (!strcmp(al->attribute->link.code, arg[4]))
594 					{
595 						mp->attribute = al->attribute;
596 						break;
597 					}
598 				if (!mp->attribute)
599 				{
600 					fprintf(stderr, "%s: %d: %s: unknown attribute\n", command, line, arg[4]);
601 					return 1;
602 				}
603 			}
604 			if (mp != (Map_t*)enter(&state.map, (Link_t*)mp))
605 			{
606 				fprintf(stderr, "%s: %d: %s: duplicate map\n", command, line, mp->link.code);
607 				return 1;
608 			}
609 			break;
610 		}
611 	}
612 	fprintf(hf, "#define LC_language_attribute_max\t\t%d\n", language_attribute_max);
613 	fprintf(hf, "#define LC_territory_language_max\t\t%d\n", territory_language_max);
614 	fprintf(hf, "\nstruct Lc_s;\n");
615 	fprintf(hf, "\ntypedef struct Lc_info_s\n{\n");
616 	fprintf(hf, "\tconst struct Lc_s*\tlc;\n");
617 	fprintf(hf, "\tunsigned long\t\tnumber;\n");
618 	fprintf(hf, "\tvoid*\t\t\tdata;\n");
619 	fprintf(hf, "} Lc_info_t;\n");
620 	fprintf(hf, "\ntypedef struct Lc_attribute_s\n{\n");
621 	fprintf(hf, "\tconst char*\t\tname;\n");
622 	fprintf(hf, "\tunsigned long\t\tflags;\n");
623 	fprintf(hf, "\tunsigned long\t\tindex;\n");
624 	fprintf(hf, "} Lc_attribute_t;\n");
625 	fprintf(hf, "\ntypedef struct Lc_charset_s\n{\n");
626 	fprintf(hf, "\tconst char*\t\tcode;\n");
627 	fprintf(hf, "\tconst char*\t\talternates;\n");
628 	fprintf(hf, "\tconst char*\t\tms;\n");
629 	fprintf(hf, "\tunsigned long\t\tindex;\n");
630 	fprintf(hf, "} Lc_charset_t;\n");
631 	fprintf(hf, "\ntypedef struct Lc_language_s\n{\n");
632 	fprintf(hf, "\tconst char*\t\tcode;\n");
633 	fprintf(hf, "\tconst char*\t\tname;\n");
634 	fprintf(hf, "\tconst char*\t\talternates;\n");
635 	fprintf(hf, "\tconst Lc_charset_t*\tcharset;\n");
636 	fprintf(hf, "\tunsigned long\t\tflags;\n");
637 	fprintf(hf, "\tunsigned long\t\tindex;\n");
638 	fprintf(hf, "\tconst Lc_attribute_t*\tattributes[LC_language_attribute_max];\n");
639 	fprintf(hf, "} Lc_language_t;\n");
640 	fprintf(hf, "\ntypedef struct Lc_territory_s\n{\n");
641 	fprintf(hf, "\tconst char*\t\tcode;\n");
642 	fprintf(hf, "\tconst char*\t\tname;\n");
643 	fprintf(hf, "\tunsigned long\t\tflags;\n");
644 	fprintf(hf, "\tunsigned long\t\tindex;\n");
645 	fprintf(hf, "\tconst Lc_language_t*\tlanguages[LC_territory_language_max];\n");
646 	fprintf(hf, "#ifdef _LC_TERRITORY_PRIVATE_\n");
647 	fprintf(hf, "\t_LC_TERRITORY_PRIVATE_\n");
648 	fprintf(hf, "#endif\n");
649 	fprintf(hf, "} Lc_territory_t;\n");
650 	fprintf(hf, "\ntypedef struct Lc_map_s\n{\n");
651 	fprintf(hf, "\tconst char*\t\tcode;\n");
652 	fprintf(hf, "\tconst Lc_language_t*\tlanguage;\n");
653 	fprintf(hf, "\tconst Lc_territory_t*\tterritory;\n");
654 	fprintf(hf, "\tconst Lc_charset_t*\tcharset;\n");
655 	fprintf(hf, "\tconst Lc_attribute_t*\tattribute;\n");
656 	fprintf(hf, "} Lc_map_t;\n");
657 	fprintf(hf, "\ntypedef struct Lc_attribute_list_s\n{\n");
658 	fprintf(hf, "\tstruct Lc_attribute_list_s*\tnext;\n");
659 	fprintf(hf, "\tconst Lc_attribute_t*\t\tattribute;\n");
660 	fprintf(hf, "} Lc_attribute_list_t;\n");
661 	fprintf(hf, "\ntypedef struct Lc_s\n{\n");
662 	fprintf(hf, "\tconst char*\t\tname;\n");
663 	fprintf(hf, "\tconst char*\t\tcode;\n");
664 	fprintf(hf, "\tconst Lc_language_t*\tlanguage;\n");
665 	fprintf(hf, "\tconst Lc_territory_t*\tterritory;\n");
666 	fprintf(hf, "\tconst Lc_charset_t*\tcharset;\n");
667 	fprintf(hf, "\tconst Lc_attribute_list_t*\tattributes;\n");
668 	fprintf(hf, "\tunsigned long\t\tflags;\n");
669 	fprintf(hf, "\tunsigned long\t\tindex;\n");
670 	fprintf(hf, "#ifdef _LC_PRIVATE_\n");
671 	fprintf(hf, "\t_LC_PRIVATE_\n");
672 	fprintf(hf, "#endif\n");
673 	fprintf(hf, "} Lc_t;\n");
674 	fprintf(hf, "\nstruct Lc_category_s;\n");
675 	fprintf(hf, "\ntypedef int (*Lc_category_set_f)(struct Lc_category_s*);\n");
676 	fprintf(hf, "\ntypedef struct Lc_category_s\n{\n");
677 	fprintf(hf, "\tconst char*\t\tname;\n");
678 	fprintf(hf, "\tint\t\t\texternal;\n");
679 	fprintf(hf, "\tint\t\t\tinternal;\n");
680 	fprintf(hf, "\tLc_category_set_f\tsetf;\n");
681 	fprintf(hf, "\tLc_t*\t\t\tprev;\n");
682 	fprintf(hf, "\tunsigned int\t\tflags;\n");
683 	fprintf(hf, "} Lc_category_t;\n");
684 	fprintf(hf, "\n");
685 	fprintf(hf, "#if _BLD_ast && defined(__EXPORT__)\n");
686 	fprintf(hf, "#define extern\t\t__EXPORT__\n");
687 	fprintf(hf, "#endif\n");
688 	fprintf(hf, "\n");
689 	fprintf(hf, "extern size_t\t\tlccanon(Lc_t*, unsigned long flags, char*, size_t);\n");
690 	fprintf(hf, "extern Lc_category_t*\tlccategories(void);\n");
691 	fprintf(hf, "extern int\t\tlcindex(int, int);\n");
692 	fprintf(hf, "extern Lc_info_t*\tlcinfo(int);\n");
693 	fprintf(hf, "extern Lc_t*\t\tlcmake(const char*);\n");
694 	fprintf(hf, "extern Lc_t*\t\tlcscan(Lc_t*);\n");
695 	fprintf(hf, "\n");
696 	fprintf(hf, "#undef\textern\n");
697 	fprintf(lf, "\nconst Lc_charset_t lc_charsets[] =\n{\n");
698 	for (cp = (Charset_t*)state.charset.root; cp; cp = (Charset_t*)cp->link.next)
699 	{
700 		fprintf(lf, "{\"%s\",", cp->link.code);
701 		if (cp->alternates)
702 			fprintf(lf, "\"%s\",", cp->alternates);
703 		else
704 			fprintf(lf, "0,");
705 		if (cp->ms)
706 			fprintf(lf, "\"%s\",", cp->ms);
707 		else
708 			fprintf(lf, "0");
709 		fprintf(lf, "},\n");
710 	}
711 	fprintf(lf, "\t0\n};\n");
712 	fprintf(lf, "\nconst Lc_language_t lc_languages[] =\n{\n");
713 	fprintf(lf, "{\"C\",\"C\",\"POSIX\",&lc_charsets[0],LC_default,0,");
714 	for (i = 0; i < language_attribute_max; i++)
715 		fprintf(lf, "0,");
716 	fprintf(lf, "},\n");
717 	fprintf(lf, "{\"debug\",\"debug\",0,&lc_charsets[0],LC_debug,0,");
718 	for (i = 0; i < language_attribute_max; i++)
719 		fprintf(lf, "0,");
720 	fprintf(lf, "},\n");
721 	for (lp = (Language_t*)state.language.root; lp; lp = (Language_t*)lp->link.next)
722 	{
723 		fprintf(lf, "{\"%s\",\"%s\",", lp->link.code, lp->name);
724 		if (lp->alternates)
725 			fprintf(lf, "\"%s\",", lp->alternates);
726 		else
727 			fprintf(lf, "0,");
728 		fprintf(lf, "&lc_charsets[%d],0,", lp->charset ? lp->charset->link.index : 0);
729 		macro(lf, "LANG", lp->name, (char*)0);
730 		for (i = 0, al = lp->attributes; al; al = al->next, i++)
731 			fprintf(lf, "&attribute_%s[%d],", lp->link.code, al->attribute->link.index);
732 		for (; i < language_attribute_max; i++)
733 			fprintf(lf, "0,");
734 		fprintf(lf, "\n},\n");
735 	}
736 	fprintf(lf, "\t0\n};\n");
737 	fprintf(lf, "\nconst Lc_territory_t lc_territories[] =\n{\n");
738 	fprintf(lf, "{\"C\",\"C\",LC_default,0,&lc_languages[0],");
739 	for (i = 1; i < 2 * territory_language_max; i++)
740 		fprintf(lf, "0,");
741 	fprintf(lf, "},\n");
742 	fprintf(lf, "{\"debug\",\"debug\",LC_debug,0,&lc_languages[1],");
743 	for (i = 1; i < 2 * territory_language_max; i++)
744 		fprintf(lf, "0,");
745 	fprintf(lf, "},\n");
746 	for (tp = (Territory_t*)state.territory.root; tp; tp = (Territory_t*)tp->link.next)
747 	{
748 		fprintf(lf, "{\"%s\",\"%s\",", tp->link.code, tp->name);
749 		if (tp->primary)
750 			fprintf(lf, "LC_primary,");
751 		else
752 			fprintf(lf, "0,");
753 		macro(lf, "CTRY", tp->name, (char*)0);
754 		for (i = 0, ll = tp->languages; ll; ll = ll->next, i++)
755 			fprintf(lf, "&lc_languages[%d],", ll->language->link.index);
756 		for (; i < territory_language_max; i++)
757 			fprintf(lf, "0,");
758 		for (i = 0, ll = tp->languages; ll; ll = ll->next, i++)
759 			macro(lf, "SUBLANG", ll->language->name, tp->name);
760 		for (; i < territory_language_max; i++)
761 			fprintf(lf, "0,");
762 		fprintf(lf, "\n},\n");
763 	}
764 	fprintf(lf, "\t0\n};\n");
765 	fprintf(lf, "\nconst Lc_map_t lc_maps[] =\n{\n");
766 	for (mp = (Map_t*)state.map.root; mp; mp = (Map_t*)mp->link.next)
767 	{
768 		fprintf(lf, "{\"%s\",", mp->link.code);
769 		fprintf(lf, "&lc_languages[%d],", mp->language->link.index);
770 		fprintf(lf, "&lc_territories[%d],", mp->territory->link.index);
771 		fprintf(lf, "&lc_charsets[%d],", mp->charset ? mp->charset->link.index : 0);
772 		if (mp->attribute)
773 			fprintf(lf, "&attribute_%s[%d]", mp->language->link.code, mp->attribute->link.index);
774 		else
775 			fprintf(lf, "0");
776 		fprintf(lf, "},\n");
777 	}
778 	fprintf(lf, "\t0\n};\n");
779 	fclose(lf);
780 	fprintf(hf, "\n#endif\n");
781 	fclose(hf);
782 	return 0;
783 }
784