1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*b30d1939SAndy Fiddaman *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6*b30d1939SAndy Fiddaman *                 Eclipse Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10*b30d1939SAndy Fiddaman *          http://www.eclipse.org/org/documents/epl-v10.html           *
11*b30d1939SAndy Fiddaman *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12da2e3ebdSchin *                                                                      *
13da2e3ebdSchin *              Information and Software Systems Research               *
14da2e3ebdSchin *                            AT&T Research                             *
15da2e3ebdSchin *                           Florham Park NJ                            *
16da2e3ebdSchin *                                                                      *
17da2e3ebdSchin *                 Glenn Fowler <gsf@research.att.com>                  *
18da2e3ebdSchin *                  David Korn <dgk@research.att.com>                   *
19da2e3ebdSchin *                   Phong Vo <kpv@research.att.com>                    *
20da2e3ebdSchin *                                                                      *
21da2e3ebdSchin ***********************************************************************/
22da2e3ebdSchin #pragma prototyped
23da2e3ebdSchin /*
24da2e3ebdSchin  * Glenn Fowler
25da2e3ebdSchin  * AT&T Research
26da2e3ebdSchin  *
27da2e3ebdSchin  * time conversion translation support
28da2e3ebdSchin  */
29da2e3ebdSchin 
30da2e3ebdSchin #include <ast.h>
31da2e3ebdSchin #include <cdt.h>
32da2e3ebdSchin #include <iconv.h>
33da2e3ebdSchin #include <mc.h>
34da2e3ebdSchin #include <tm.h>
353e14f97fSRoger A. Faulkner #include <ast_nl_types.h>
36da2e3ebdSchin 
37da2e3ebdSchin #include "lclib.h"
38da2e3ebdSchin 
39da2e3ebdSchin static struct
40da2e3ebdSchin {
41da2e3ebdSchin 	char*		format;
42da2e3ebdSchin 	Lc_info_t*	locale;
43da2e3ebdSchin 	char		null[1];
44da2e3ebdSchin } state;
45da2e3ebdSchin 
46da2e3ebdSchin /*
47da2e3ebdSchin  * this is unix dadgummit
48da2e3ebdSchin  */
49da2e3ebdSchin 
50da2e3ebdSchin static int
standardized(Lc_info_t * li,register char ** b)51da2e3ebdSchin standardized(Lc_info_t* li, register char** b)
52da2e3ebdSchin {
53da2e3ebdSchin 	if ((li->lc->language->flags & (LC_debug|LC_default)) || streq(li->lc->language->code, "en"))
54da2e3ebdSchin 	{
55da2e3ebdSchin 		b[TM_TIME] = "%H:%M:%S";
56da2e3ebdSchin 		b[TM_DATE] = "%m/%d/%y";
57da2e3ebdSchin 		b[TM_DEFAULT] = "%a %b %e %T %Z %Y";
58da2e3ebdSchin 		return 1;
59da2e3ebdSchin 	}
60da2e3ebdSchin 	return 0;
61da2e3ebdSchin }
62da2e3ebdSchin 
63da2e3ebdSchin /*
64da2e3ebdSchin  * fix up LC_TIME data after loading
65da2e3ebdSchin  */
66da2e3ebdSchin 
67da2e3ebdSchin static void
fixup(Lc_info_t * li,register char ** b)68da2e3ebdSchin fixup(Lc_info_t* li, register char** b)
69da2e3ebdSchin {
70da2e3ebdSchin 	register char**		v;
71da2e3ebdSchin 	register char**		e;
72da2e3ebdSchin 	register int		n;
73da2e3ebdSchin 
74da2e3ebdSchin 	static int		must[] =
75da2e3ebdSchin 	{
76da2e3ebdSchin 					TM_TIME,
77da2e3ebdSchin 					TM_DATE,
78da2e3ebdSchin 					TM_DEFAULT,
79*b30d1939SAndy Fiddaman 					TM_MERIDIAN,
80*b30d1939SAndy Fiddaman 					TM_UT,
81*b30d1939SAndy Fiddaman 					TM_DT,
82*b30d1939SAndy Fiddaman 					TM_SUFFIXES,
83*b30d1939SAndy Fiddaman 					TM_PARTS,
84*b30d1939SAndy Fiddaman 					TM_HOURS,
85*b30d1939SAndy Fiddaman 					TM_DAYS,
86*b30d1939SAndy Fiddaman 					TM_LAST,
87*b30d1939SAndy Fiddaman 					TM_THIS,
88*b30d1939SAndy Fiddaman 					TM_NEXT,
89*b30d1939SAndy Fiddaman 					TM_EXACT,
90*b30d1939SAndy Fiddaman 					TM_NOISE,
91*b30d1939SAndy Fiddaman 					TM_ORDINAL,
92da2e3ebdSchin 					TM_CTIME,
93da2e3ebdSchin 					TM_DATE_1,
94da2e3ebdSchin 					TM_INTERNATIONAL,
95da2e3ebdSchin 					TM_RECENT,
96da2e3ebdSchin 					TM_DISTANT,
97da2e3ebdSchin 					TM_MERIDIAN_TIME,
98*b30d1939SAndy Fiddaman 					TM_ORDINALS,
99*b30d1939SAndy Fiddaman 					TM_FINAL,
100*b30d1939SAndy Fiddaman 					TM_WORK,
101da2e3ebdSchin 	};
102da2e3ebdSchin 
103da2e3ebdSchin 	standardized(li, b);
104da2e3ebdSchin 	for (v = b, e = b + TM_NFORM; v < e; v++)
105da2e3ebdSchin 		if (!*v)
106da2e3ebdSchin 			*v = state.null;
107da2e3ebdSchin 	for (n = 0; n < elementsof(must); n++)
108da2e3ebdSchin 		if (!*b[must[n]])
109da2e3ebdSchin 			b[must[n]] = tm_data.format[must[n]];
110da2e3ebdSchin 	if (li->lc->flags & LC_default)
111da2e3ebdSchin 		for (n = 0; n < TM_NFORM; n++)
112da2e3ebdSchin 			if (!*b[n])
113da2e3ebdSchin 				b[n] = tm_data.format[n];
114da2e3ebdSchin 	if (strchr(b[TM_UT], '%'))
115da2e3ebdSchin 	{
116da2e3ebdSchin 		tm_info.deformat = b[TM_UT];
117da2e3ebdSchin 		for (n = TM_UT; n < TM_DT; n++)
118da2e3ebdSchin 			b[n] = state.null;
119da2e3ebdSchin 	}
120da2e3ebdSchin 	else
121da2e3ebdSchin 		tm_info.deformat = b[TM_DEFAULT];
122da2e3ebdSchin 	tm_info.format = b;
123da2e3ebdSchin 	if (!(tm_info.deformat = state.format))
124da2e3ebdSchin 		tm_info.deformat = tm_info.format[TM_DEFAULT];
125da2e3ebdSchin 	li->data = (void*)b;
126da2e3ebdSchin }
127da2e3ebdSchin 
128da2e3ebdSchin #if _WINIX
129da2e3ebdSchin 
130da2e3ebdSchin #include <ast_windows.h>
131da2e3ebdSchin 
132da2e3ebdSchin typedef struct Map_s
133da2e3ebdSchin {
134da2e3ebdSchin 	LCID		native;
135da2e3ebdSchin 	int		local;
136da2e3ebdSchin } Map_t;
137da2e3ebdSchin 
138da2e3ebdSchin static const Map_t map[] =
139da2e3ebdSchin {
140da2e3ebdSchin 	LOCALE_S1159,			(TM_MERIDIAN+0),
141da2e3ebdSchin 	LOCALE_S2359,			(TM_MERIDIAN+1),
142da2e3ebdSchin 	LOCALE_SABBREVDAYNAME1,		(TM_DAY_ABBREV+1),
143da2e3ebdSchin 	LOCALE_SABBREVDAYNAME2,		(TM_DAY_ABBREV+2),
144da2e3ebdSchin 	LOCALE_SABBREVDAYNAME3,		(TM_DAY_ABBREV+3),
145da2e3ebdSchin 	LOCALE_SABBREVDAYNAME4,		(TM_DAY_ABBREV+4),
146da2e3ebdSchin 	LOCALE_SABBREVDAYNAME5,		(TM_DAY_ABBREV+5),
147da2e3ebdSchin 	LOCALE_SABBREVDAYNAME6,		(TM_DAY_ABBREV+6),
148da2e3ebdSchin 	LOCALE_SABBREVDAYNAME7,		(TM_DAY_ABBREV+0),
149da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME1,	(TM_MONTH_ABBREV+0),
150da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME2,	(TM_MONTH_ABBREV+1),
151da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME3,	(TM_MONTH_ABBREV+2),
152da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME4,	(TM_MONTH_ABBREV+3),
153da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME5,	(TM_MONTH_ABBREV+4),
154da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME6,	(TM_MONTH_ABBREV+5),
155da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME7,	(TM_MONTH_ABBREV+6),
156da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME8,	(TM_MONTH_ABBREV+7),
157da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME9,	(TM_MONTH_ABBREV+8),
158da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME10,	(TM_MONTH_ABBREV+9),
159da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME11,	(TM_MONTH_ABBREV+10),
160da2e3ebdSchin 	LOCALE_SABBREVMONTHNAME12,	(TM_MONTH_ABBREV+11),
161da2e3ebdSchin 	LOCALE_SDAYNAME1,		(TM_DAY+1),
162da2e3ebdSchin 	LOCALE_SDAYNAME2,		(TM_DAY+2),
163da2e3ebdSchin 	LOCALE_SDAYNAME3,		(TM_DAY+3),
164da2e3ebdSchin 	LOCALE_SDAYNAME4,		(TM_DAY+4),
165da2e3ebdSchin 	LOCALE_SDAYNAME5,		(TM_DAY+5),
166da2e3ebdSchin 	LOCALE_SDAYNAME6,		(TM_DAY+6),
167da2e3ebdSchin 	LOCALE_SDAYNAME7,		(TM_DAY+0),
168da2e3ebdSchin 	LOCALE_SMONTHNAME1,		(TM_MONTH+0),
169da2e3ebdSchin 	LOCALE_SMONTHNAME2,		(TM_MONTH+1),
170da2e3ebdSchin 	LOCALE_SMONTHNAME3,		(TM_MONTH+2),
171da2e3ebdSchin 	LOCALE_SMONTHNAME4,		(TM_MONTH+3),
172da2e3ebdSchin 	LOCALE_SMONTHNAME5,		(TM_MONTH+4),
173da2e3ebdSchin 	LOCALE_SMONTHNAME6,		(TM_MONTH+5),
174da2e3ebdSchin 	LOCALE_SMONTHNAME7,		(TM_MONTH+6),
175da2e3ebdSchin 	LOCALE_SMONTHNAME8,		(TM_MONTH+7),
176da2e3ebdSchin 	LOCALE_SMONTHNAME9,		(TM_MONTH+8),
177da2e3ebdSchin 	LOCALE_SMONTHNAME10,		(TM_MONTH+9),
178da2e3ebdSchin 	LOCALE_SMONTHNAME11,		(TM_MONTH+10),
179da2e3ebdSchin 	LOCALE_SMONTHNAME12,		(TM_MONTH+11),
180da2e3ebdSchin };
181da2e3ebdSchin 
182da2e3ebdSchin #undef	extern
183da2e3ebdSchin 
184da2e3ebdSchin /*
185da2e3ebdSchin  * convert ms word date spec w to posix strftime format f
186da2e3ebdSchin  * next char after f returned
187da2e3ebdSchin  * the caller already made sure f is big enough
188da2e3ebdSchin  */
189da2e3ebdSchin 
190da2e3ebdSchin static char*
word2posix(register char * f,register char * w,int alternate)191da2e3ebdSchin word2posix(register char* f, register char* w, int alternate)
192da2e3ebdSchin {
193da2e3ebdSchin 	register char*	r;
194da2e3ebdSchin 	register int	c;
195da2e3ebdSchin 	register int	p;
196da2e3ebdSchin 	register int	n;
197da2e3ebdSchin 
198da2e3ebdSchin 	while (*w)
199da2e3ebdSchin 	{
200da2e3ebdSchin 		p = 0;
201da2e3ebdSchin 		r = w;
202da2e3ebdSchin 		while (*++w == *r);
203da2e3ebdSchin 		if ((n = w - r) > 3 && alternate)
204da2e3ebdSchin 			n--;
205da2e3ebdSchin 		switch (*r)
206da2e3ebdSchin 		{
207da2e3ebdSchin 		case 'a':
208da2e3ebdSchin 		case 'A':
209da2e3ebdSchin 			if (!strncasecmp(w, "am/pm", 5))
210da2e3ebdSchin 				w += 5;
211da2e3ebdSchin 			else if (!strncasecmp(w, "a/p", 3))
212da2e3ebdSchin 				w += 3;
213da2e3ebdSchin 			c = 'p';
214da2e3ebdSchin 			break;
215da2e3ebdSchin 		case 'd':
216da2e3ebdSchin 			switch (n)
217da2e3ebdSchin 			{
218da2e3ebdSchin 			case 1:
219da2e3ebdSchin 				p = '-';
220da2e3ebdSchin 				/*FALLTHROUGH*/
221da2e3ebdSchin 			case 2:
222da2e3ebdSchin 				c = 'd';
223da2e3ebdSchin 				break;
224da2e3ebdSchin 			case 3:
225da2e3ebdSchin 				c = 'a';
226da2e3ebdSchin 				break;
227da2e3ebdSchin 			default:
228da2e3ebdSchin 				c = 'A';
229da2e3ebdSchin 				break;
230da2e3ebdSchin 			}
231da2e3ebdSchin 			break;
232da2e3ebdSchin 		case 'h':
233da2e3ebdSchin 			switch (n)
234da2e3ebdSchin 			{
235da2e3ebdSchin 			case 1:
236da2e3ebdSchin 				p = '-';
237da2e3ebdSchin 				/*FALLTHROUGH*/
238da2e3ebdSchin 			default:
239da2e3ebdSchin 				c = 'I';
240da2e3ebdSchin 				break;
241da2e3ebdSchin 			}
242da2e3ebdSchin 			break;
243da2e3ebdSchin 		case 'H':
244da2e3ebdSchin 			switch (n)
245da2e3ebdSchin 			{
246da2e3ebdSchin 			case 1:
247da2e3ebdSchin 				p = '-';
248da2e3ebdSchin 				/*FALLTHROUGH*/
249da2e3ebdSchin 			default:
250da2e3ebdSchin 				c = 'H';
251da2e3ebdSchin 				break;
252da2e3ebdSchin 			}
253da2e3ebdSchin 			break;
254da2e3ebdSchin 		case 'M':
255da2e3ebdSchin 			switch (n)
256da2e3ebdSchin 			{
257da2e3ebdSchin 			case 1:
258da2e3ebdSchin 				p = '-';
259da2e3ebdSchin 				/*FALLTHROUGH*/
260da2e3ebdSchin 			case 2:
261da2e3ebdSchin 				c = 'm';
262da2e3ebdSchin 				break;
263da2e3ebdSchin 			case 3:
264da2e3ebdSchin 				c = 'b';
265da2e3ebdSchin 				break;
266da2e3ebdSchin 			default:
267da2e3ebdSchin 				c = 'B';
268da2e3ebdSchin 				break;
269da2e3ebdSchin 			}
270da2e3ebdSchin 			break;
271da2e3ebdSchin 		case 'm':
272da2e3ebdSchin 			switch (n)
273da2e3ebdSchin 			{
274da2e3ebdSchin 			case 1:
275da2e3ebdSchin 				p = '-';
276da2e3ebdSchin 				/*FALLTHROUGH*/
277da2e3ebdSchin 			default:
278da2e3ebdSchin 				c = 'M';
279da2e3ebdSchin 				break;
280da2e3ebdSchin 			}
281da2e3ebdSchin 			break;
282da2e3ebdSchin 		case 's':
283da2e3ebdSchin 			switch (n)
284da2e3ebdSchin 			{
285da2e3ebdSchin 			case 1:
286da2e3ebdSchin 				p = '-';
287da2e3ebdSchin 				/*FALLTHROUGH*/
288da2e3ebdSchin 			default:
289da2e3ebdSchin 				c = 'S';
290da2e3ebdSchin 				break;
291da2e3ebdSchin 			}
292da2e3ebdSchin 			break;
293da2e3ebdSchin 		case 'y':
294da2e3ebdSchin 			switch (n)
295da2e3ebdSchin 			{
296da2e3ebdSchin 			case 1:
297da2e3ebdSchin 				p = '-';
298da2e3ebdSchin 				/*FALLTHROUGH*/
299da2e3ebdSchin 			case 2:
300da2e3ebdSchin 				c = 'y';
301da2e3ebdSchin 				break;
302da2e3ebdSchin 			default:
303da2e3ebdSchin 				c = 'Y';
304da2e3ebdSchin 				break;
305da2e3ebdSchin 			}
306da2e3ebdSchin 			break;
307da2e3ebdSchin 		case '\'':
308da2e3ebdSchin 			if (n & 1)
309da2e3ebdSchin 				for (w = r + 1; *w; *f++ = *w++)
310da2e3ebdSchin 					if (*w == '\'')
311da2e3ebdSchin 					{
312da2e3ebdSchin 						w++;
313da2e3ebdSchin 						break;
314da2e3ebdSchin 					}
315da2e3ebdSchin 			continue;
316da2e3ebdSchin 		case '%':
317da2e3ebdSchin 			while (r < w)
318da2e3ebdSchin 			{
319da2e3ebdSchin 				*f++ = *r++;
320da2e3ebdSchin 				*f++ = *r++;
321da2e3ebdSchin 			}
322da2e3ebdSchin 			continue;
323da2e3ebdSchin 		default:
324da2e3ebdSchin 			while (r < w)
325da2e3ebdSchin 				*f++ = *r++;
326da2e3ebdSchin 			continue;
327da2e3ebdSchin 		}
328da2e3ebdSchin 		*f++ = '%';
329da2e3ebdSchin 		if (p)
330da2e3ebdSchin 			*f++ = '-';
331da2e3ebdSchin 		*f++ = c;
332da2e3ebdSchin 	}
333da2e3ebdSchin 	*f++ = 0;
334da2e3ebdSchin 	return f;
335da2e3ebdSchin }
336da2e3ebdSchin 
337da2e3ebdSchin /*
338da2e3ebdSchin  * load the native LC_TIME data for the current locale
339da2e3ebdSchin  */
340da2e3ebdSchin 
341da2e3ebdSchin static void
native_lc_time(Lc_info_t * li)342da2e3ebdSchin native_lc_time(Lc_info_t* li)
343da2e3ebdSchin {
344da2e3ebdSchin 	register char*	s;
345da2e3ebdSchin 	register char*	t;
346da2e3ebdSchin 	register char**	b;
347da2e3ebdSchin 	register int	n;
348da2e3ebdSchin 	register int	m;
349da2e3ebdSchin 	register int	i;
350da2e3ebdSchin 	LCID		lcid;
351da2e3ebdSchin 	int		nt;
352da2e3ebdSchin 	int		ns;
353da2e3ebdSchin 	int		nl;
354da2e3ebdSchin 	int		clock_24;
355da2e3ebdSchin 	int		leading_0;
356da2e3ebdSchin 	char		buf[256];
357da2e3ebdSchin 
358da2e3ebdSchin 	lcid = li->lc->index;
359da2e3ebdSchin 	nt = 2 * GetLocaleInfo(lcid, LOCALE_STIME, 0, 0) + 7; /* HH:MM:SS */
360da2e3ebdSchin 	ns = 3 * GetLocaleInfo(lcid, LOCALE_SSHORTDATE, 0, 0);
361da2e3ebdSchin 	nl = 3 * GetLocaleInfo(lcid, LOCALE_SLONGDATE, 0, 0);
362da2e3ebdSchin 	n = nt + ns + nl;
363da2e3ebdSchin 	for (i = 0; i < elementsof(map); i++)
364da2e3ebdSchin 		n += GetLocaleInfo(lcid, map[i].native, 0, 0);
365da2e3ebdSchin 	if (!(b = newof(0, char*, TM_NFORM, n)))
366da2e3ebdSchin 		return;
367da2e3ebdSchin 	s = (char*)(b + TM_NFORM);
368da2e3ebdSchin 	for (i = 0; i < elementsof(map); i++)
369da2e3ebdSchin 	{
370da2e3ebdSchin 		if (!(m = GetLocaleInfo(lcid, map[i].native, s, n)))
371da2e3ebdSchin 			goto bad;
372da2e3ebdSchin 		b[map[i].local] = s;
373da2e3ebdSchin 		s += m;
374da2e3ebdSchin 	}
375da2e3ebdSchin 	if (!standardized(li, b))
376da2e3ebdSchin 	{
377da2e3ebdSchin 		/*
378da2e3ebdSchin 		 * synthesize TM_TIME format from the ms word template
379da2e3ebdSchin 		 */
380da2e3ebdSchin 
381da2e3ebdSchin 		if (!GetLocaleInfo(lcid, LOCALE_ITIME, buf, sizeof(buf)))
382da2e3ebdSchin 			goto bad;
383da2e3ebdSchin 		clock_24 = atoi(buf);
384da2e3ebdSchin 		if (!GetLocaleInfo(lcid, LOCALE_ITLZERO, buf, sizeof(buf)))
385da2e3ebdSchin 			goto bad;
386da2e3ebdSchin 		leading_0 = atoi(buf);
387da2e3ebdSchin 		if (!GetLocaleInfo(lcid, LOCALE_STIME, buf, sizeof(buf)))
388da2e3ebdSchin 			goto bad;
389da2e3ebdSchin 		b[TM_TIME] = s;
390da2e3ebdSchin 		*s++ = '%';
391da2e3ebdSchin 		if (!leading_0)
392da2e3ebdSchin 			*s++ = '-';
393da2e3ebdSchin 		*s++ = clock_24 ? 'H' : 'I';
394da2e3ebdSchin 		for (t = buf; *s = *t++; s++);
395da2e3ebdSchin 		*s++ = '%';
396da2e3ebdSchin 		if (!leading_0)
397da2e3ebdSchin 			*s++ = '-';
398da2e3ebdSchin 		*s++ = 'M';
399da2e3ebdSchin 		for (t = buf; *s = *t++; s++);
400da2e3ebdSchin 		*s++ = '%';
401da2e3ebdSchin 		if (!leading_0)
402da2e3ebdSchin 			*s++ = '-';
403da2e3ebdSchin 		*s++ = 'S';
404da2e3ebdSchin 		*s++ = 0;
405da2e3ebdSchin 
406da2e3ebdSchin 		/*
407da2e3ebdSchin 		 * synthesize TM_DATE format
408da2e3ebdSchin 		 */
409da2e3ebdSchin 
410da2e3ebdSchin 		if (!GetLocaleInfo(lcid, LOCALE_SSHORTDATE, buf, sizeof(buf)))
411da2e3ebdSchin 			goto bad;
412da2e3ebdSchin 		b[TM_DATE] = s;
413da2e3ebdSchin 		s = word2posix(s, buf, 1);
414da2e3ebdSchin 
415da2e3ebdSchin 		/*
416da2e3ebdSchin 		 * synthesize TM_DEFAULT format
417da2e3ebdSchin 		 */
418da2e3ebdSchin 
419da2e3ebdSchin 		if (!GetLocaleInfo(lcid, LOCALE_SLONGDATE, buf, sizeof(buf)))
420da2e3ebdSchin 			goto bad;
421da2e3ebdSchin 		b[TM_DEFAULT] = s;
422da2e3ebdSchin 		s = word2posix(s, buf, 1);
423da2e3ebdSchin 		strcpy(s - 1, " %X");
424da2e3ebdSchin 	}
425da2e3ebdSchin 
426da2e3ebdSchin 	/*
427da2e3ebdSchin 	 * done
428da2e3ebdSchin 	 */
429da2e3ebdSchin 
430da2e3ebdSchin 	fixup(li, b);
431da2e3ebdSchin 	return;
432da2e3ebdSchin  bad:
433da2e3ebdSchin 	free(b);
434da2e3ebdSchin }
435da2e3ebdSchin 
436da2e3ebdSchin #else
437da2e3ebdSchin 
438da2e3ebdSchin #if _lib_nl_langinfo && _hdr_langinfo
439da2e3ebdSchin 
440da2e3ebdSchin #if _hdr_nl_types
441da2e3ebdSchin #include <nl_types.h>
442da2e3ebdSchin #endif
443da2e3ebdSchin 
444da2e3ebdSchin #include <langinfo.h>
445da2e3ebdSchin 
446da2e3ebdSchin typedef struct Map_s
447da2e3ebdSchin {
448da2e3ebdSchin 	int		native;
449da2e3ebdSchin 	int		local;
450da2e3ebdSchin } Map_t;
451da2e3ebdSchin 
452da2e3ebdSchin static const Map_t map[] =
453da2e3ebdSchin {
454da2e3ebdSchin 	AM_STR,				(TM_MERIDIAN+0),
455da2e3ebdSchin 	PM_STR,				(TM_MERIDIAN+1),
456da2e3ebdSchin 	ABDAY_1,			(TM_DAY_ABBREV+0),
457da2e3ebdSchin 	ABDAY_2,			(TM_DAY_ABBREV+1),
458da2e3ebdSchin 	ABDAY_3,			(TM_DAY_ABBREV+2),
459da2e3ebdSchin 	ABDAY_4,			(TM_DAY_ABBREV+3),
460da2e3ebdSchin 	ABDAY_5,			(TM_DAY_ABBREV+4),
461da2e3ebdSchin 	ABDAY_6,			(TM_DAY_ABBREV+5),
462da2e3ebdSchin 	ABDAY_7,			(TM_DAY_ABBREV+6),
463da2e3ebdSchin 	ABMON_1,			(TM_MONTH_ABBREV+0),
464da2e3ebdSchin 	ABMON_2,			(TM_MONTH_ABBREV+1),
465da2e3ebdSchin 	ABMON_3,			(TM_MONTH_ABBREV+2),
466da2e3ebdSchin 	ABMON_4,			(TM_MONTH_ABBREV+3),
467da2e3ebdSchin 	ABMON_5,			(TM_MONTH_ABBREV+4),
468da2e3ebdSchin 	ABMON_6,			(TM_MONTH_ABBREV+5),
469da2e3ebdSchin 	ABMON_7,			(TM_MONTH_ABBREV+6),
470da2e3ebdSchin 	ABMON_8,			(TM_MONTH_ABBREV+7),
471da2e3ebdSchin 	ABMON_9,			(TM_MONTH_ABBREV+8),
472da2e3ebdSchin 	ABMON_10,			(TM_MONTH_ABBREV+9),
473da2e3ebdSchin 	ABMON_11,			(TM_MONTH_ABBREV+10),
474da2e3ebdSchin 	ABMON_12,			(TM_MONTH_ABBREV+11),
475da2e3ebdSchin 	DAY_1,				(TM_DAY+0),
476da2e3ebdSchin 	DAY_2,				(TM_DAY+1),
477da2e3ebdSchin 	DAY_3,				(TM_DAY+2),
478da2e3ebdSchin 	DAY_4,				(TM_DAY+3),
479da2e3ebdSchin 	DAY_5,				(TM_DAY+4),
480da2e3ebdSchin 	DAY_6,				(TM_DAY+5),
481da2e3ebdSchin 	DAY_7,				(TM_DAY+6),
482da2e3ebdSchin 	MON_1,				(TM_MONTH+0),
483da2e3ebdSchin 	MON_2,				(TM_MONTH+1),
484da2e3ebdSchin 	MON_3,				(TM_MONTH+2),
485da2e3ebdSchin 	MON_4,				(TM_MONTH+3),
486da2e3ebdSchin 	MON_5,				(TM_MONTH+4),
487da2e3ebdSchin 	MON_6,				(TM_MONTH+5),
488da2e3ebdSchin 	MON_7,				(TM_MONTH+6),
489da2e3ebdSchin 	MON_8,				(TM_MONTH+7),
490da2e3ebdSchin 	MON_9,				(TM_MONTH+8),
491da2e3ebdSchin 	MON_10,				(TM_MONTH+9),
492da2e3ebdSchin 	MON_11,				(TM_MONTH+10),
493da2e3ebdSchin 	MON_12,				(TM_MONTH+11),
4947c2fbfb3SApril Chin #ifdef _DATE_FMT
4957c2fbfb3SApril Chin 	_DATE_FMT,			TM_DEFAULT,
4967c2fbfb3SApril Chin #else
497da2e3ebdSchin 	D_T_FMT,			TM_DEFAULT,
4987c2fbfb3SApril Chin #endif
499da2e3ebdSchin 	D_FMT,				TM_DATE,
500da2e3ebdSchin 	T_FMT,				TM_TIME,
501da2e3ebdSchin #ifdef ERA
502da2e3ebdSchin 	ERA,				TM_ERA,
503da2e3ebdSchin 	ERA_D_T_FMT,			TM_ERA_DEFAULT,
504da2e3ebdSchin 	ERA_D_FMT,			TM_ERA_DATE,
505da2e3ebdSchin 	ERA_T_FMT,			TM_ERA_TIME,
506da2e3ebdSchin #endif
507da2e3ebdSchin #ifdef ALT_DIGITS
508da2e3ebdSchin 	ALT_DIGITS,			TM_DIGITS,
509da2e3ebdSchin #endif
510da2e3ebdSchin };
511da2e3ebdSchin 
512da2e3ebdSchin static void
native_lc_time(Lc_info_t * li)513da2e3ebdSchin native_lc_time(Lc_info_t* li)
514da2e3ebdSchin {
515da2e3ebdSchin 	register char*	s;
516da2e3ebdSchin 	register char*	t;
517da2e3ebdSchin 	register char**	b;
518da2e3ebdSchin 	register int	n;
519da2e3ebdSchin 	register int	i;
520da2e3ebdSchin 
521da2e3ebdSchin 	n = 0;
522da2e3ebdSchin 	for (i = 0; i < elementsof(map); i++)
5233e14f97fSRoger A. Faulkner 	{
5243e14f97fSRoger A. Faulkner 		if (!(t = nl_langinfo(map[i].native)))
5253e14f97fSRoger A. Faulkner 			t = tm_data.format[map[i].local];
5263e14f97fSRoger A. Faulkner 		n += strlen(t) + 1;
5273e14f97fSRoger A. Faulkner 	}
528da2e3ebdSchin 	if (!(b = newof(0, char*, TM_NFORM, n)))
529da2e3ebdSchin 		return;
530da2e3ebdSchin 	s = (char*)(b + TM_NFORM);
531da2e3ebdSchin 	for (i = 0; i < elementsof(map); i++)
532da2e3ebdSchin 	{
533da2e3ebdSchin 		b[map[i].local] = s;
5343e14f97fSRoger A. Faulkner 		if (!(t = nl_langinfo(map[i].native)))
5353e14f97fSRoger A. Faulkner 			t = tm_data.format[map[i].local];
536da2e3ebdSchin 		while (*s++ = *t++);
537da2e3ebdSchin 	}
538da2e3ebdSchin 	fixup(li, b);
539da2e3ebdSchin }
540da2e3ebdSchin 
541da2e3ebdSchin #else
542da2e3ebdSchin 
543da2e3ebdSchin #define native_lc_time(li)	((li->data=(void*)(tm_info.format=tm_data.format)),(tm_info.deformat=tm_info.format[TM_DEFAULT]))
544da2e3ebdSchin 
545da2e3ebdSchin #endif
546da2e3ebdSchin 
547da2e3ebdSchin #endif
548da2e3ebdSchin 
549da2e3ebdSchin /*
550da2e3ebdSchin  * load the LC_TIME data for the current locale
551da2e3ebdSchin  */
552da2e3ebdSchin 
553da2e3ebdSchin static void
load(Lc_info_t * li)554da2e3ebdSchin load(Lc_info_t* li)
555da2e3ebdSchin {
556da2e3ebdSchin 	register char*		s;
557da2e3ebdSchin 	register char**		b;
558da2e3ebdSchin 	register char**		v;
559da2e3ebdSchin 	register char**		e;
560da2e3ebdSchin 	unsigned char*		u;
561da2e3ebdSchin 	ssize_t			n;
562da2e3ebdSchin 	iconv_t			cvt;
563da2e3ebdSchin 	Sfio_t*			sp;
564da2e3ebdSchin 	Sfio_t*			tp;
565da2e3ebdSchin 	char			path[PATH_MAX];
566da2e3ebdSchin 
567da2e3ebdSchin 	if (b = (char**)li->data)
568da2e3ebdSchin 	{
569da2e3ebdSchin 		tm_info.format = b;
570da2e3ebdSchin 		if (!(tm_info.deformat = state.format))
571da2e3ebdSchin 			tm_info.deformat = tm_info.format[TM_DEFAULT];
572da2e3ebdSchin 		return;
573da2e3ebdSchin 	}
574da2e3ebdSchin 	tm_info.format = tm_data.format;
575da2e3ebdSchin 	if (!(tm_info.deformat = state.format))
576da2e3ebdSchin 		tm_info.deformat = tm_info.format[TM_DEFAULT];
577*b30d1939SAndy Fiddaman 	if (mcfind(NiL, NiL, LC_TIME, 0, path, sizeof(path)) && (sp = sfopen(NiL, path, "r")))
578da2e3ebdSchin 	{
579da2e3ebdSchin 		n = sfsize(sp);
580da2e3ebdSchin 		tp = 0;
581da2e3ebdSchin 		if (u = (unsigned char*)sfreserve(sp, 3, 1))
582da2e3ebdSchin 		{
583da2e3ebdSchin 			if (u[0] == 0xef && u[1] == 0xbb && u[2] == 0xbf && (cvt = iconv_open("", "utf")) != (iconv_t)(-1))
584da2e3ebdSchin 			{
585da2e3ebdSchin 				if (tp = sfstropen())
586da2e3ebdSchin 				{
587da2e3ebdSchin 					sfread(sp, u, 3);
588da2e3ebdSchin 					n = iconv_move(cvt, sp, tp, SF_UNBOUND, NiL);
589da2e3ebdSchin 				}
590da2e3ebdSchin 				iconv_close(cvt);
591da2e3ebdSchin 			}
592da2e3ebdSchin 			if (!tp)
593da2e3ebdSchin 				sfread(sp, u, 0);
594da2e3ebdSchin 		}
595da2e3ebdSchin 		if (b = newof(0, char*, TM_NFORM, n + 2))
596da2e3ebdSchin 		{
597da2e3ebdSchin 			v = b;
598da2e3ebdSchin 			e = b + TM_NFORM;
599da2e3ebdSchin 			s = (char*)e;
600da2e3ebdSchin 			if (tp && memcpy(s, sfstrbase(tp), n) || !tp && sfread(sp, s, n) == n)
601da2e3ebdSchin 			{
602da2e3ebdSchin 				s[n] = '\n';
603da2e3ebdSchin 				while (v < e)
604da2e3ebdSchin 				{
605da2e3ebdSchin 					*v++ = s;
606da2e3ebdSchin 					if (!(s = strchr(s, '\n')))
607da2e3ebdSchin 						break;
608da2e3ebdSchin 					*s++ = 0;
609da2e3ebdSchin 				}
610da2e3ebdSchin 				fixup(li, b);
611da2e3ebdSchin 			}
612da2e3ebdSchin 			else
613da2e3ebdSchin 				free(b);
614da2e3ebdSchin 		}
615da2e3ebdSchin 		if (tp)
616da2e3ebdSchin 			sfclose(tp);
617da2e3ebdSchin 		sfclose(sp);
618da2e3ebdSchin 	}
619da2e3ebdSchin 	else
620da2e3ebdSchin 		native_lc_time(li);
621da2e3ebdSchin }
622da2e3ebdSchin 
623da2e3ebdSchin /*
624da2e3ebdSchin  * check that tm_info.format matches the current locale
625da2e3ebdSchin  */
626da2e3ebdSchin 
627da2e3ebdSchin char**
tmlocale(void)628da2e3ebdSchin tmlocale(void)
629da2e3ebdSchin {
630da2e3ebdSchin 	Lc_info_t*	li;
631da2e3ebdSchin 
632da2e3ebdSchin 	if (!tm_info.format)
633da2e3ebdSchin 	{
634da2e3ebdSchin 		tm_info.format = tm_data.format;
635da2e3ebdSchin 		if (!tm_info.deformat)
636da2e3ebdSchin 			tm_info.deformat = tm_info.format[TM_DEFAULT];
637da2e3ebdSchin 		else if (tm_info.deformat != tm_info.format[TM_DEFAULT])
638da2e3ebdSchin 			state.format = tm_info.deformat;
639da2e3ebdSchin 	}
640da2e3ebdSchin 	li = LCINFO(AST_LC_TIME);
641da2e3ebdSchin 	if (!li->data)
642da2e3ebdSchin 		load(li);
643da2e3ebdSchin 	return tm_info.format;
644da2e3ebdSchin }
645