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