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
44typedef struct Link_s
45{
46	struct Link_s*		next;
47	char*			code;
48	int			index;
49} Link_t;
50
51typedef struct Table_s
52{
53	Link_t*			root;
54	int			count;
55} Table_t;
56
57typedef struct Abbreviation_s
58{
59	Link_t			link;
60	char*			value;
61} Abbreviation_t;
62
63typedef struct Attribute_s
64{
65	Link_t			link;
66} Attribute_t;
67
68typedef struct Attribute_list_s
69{
70	struct Attribute_list_s*next;
71	Attribute_t*		attribute;
72} Attribute_list_t;
73
74typedef struct Charset_s
75{
76	Link_t			link;
77	char*			alternates;
78	char*			ms;
79} Charset_t;
80
81typedef 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
90typedef struct Language_list_s
91{
92	struct Language_list_s*	next;
93	Language_t*		language;
94} Language_list_t;
95
96typedef 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
105typedef 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
114static 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
132static Link_t*
133#if defined(__STDC__) || defined(__cplusplus)
134enter(register Table_t* tab, register Link_t* v)
135#else
136enter(tab, v)
137register Table_t*	tab;
138register 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
156static Link_t*
157#if defined(__STDC__) || defined(__cplusplus)
158lookup(register Table_t* tab, register char* s)
159#else
160lookup(tab, s)
161register Table_t*	tab;
162register 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
173static char*
174#if defined(__STDC__) || defined(__cplusplus)
175copy(char** p, register char* f)
176#else
177copy(p, f)
178char**		p;
179register 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
193static void
194#if defined(__STDC__) || defined(__cplusplus)
195macro(FILE* f, char* p1, char* p2, char* p3)
196#else
197macro(f, p1, p2, p3)
198FILE*		f;
199char*		p1;
200char*		p2;
201char*		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)
256int
257main(int argc, char** argv)
258#else
259int
260main(argc, argv)
261int		argc;
262char**		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