1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
27 * time conversion translation support
35 #include <ast_nl_types.h>
47 * this is unix dadgummit
51 standardized(Lc_info_t
* li
, register char** b
)
53 if ((li
->lc
->language
->flags
& (LC_debug
|LC_default
)) || streq(li
->lc
->language
->code
, "en"))
55 b
[TM_TIME
] = "%H:%M:%S";
56 b
[TM_DATE
] = "%m/%d/%y";
57 b
[TM_DEFAULT
] = "%a %b %e %T %Z %Y";
64 * fix up LC_TIME data after loading
68 fixup(Lc_info_t
* li
, register char** b
)
88 for (v
= b
, e
= b
+ TM_NFORM
; v
< e
; v
++)
91 for (n
= 0; n
< elementsof(must
); n
++)
93 b
[must
[n
]] = tm_data
.format
[must
[n
]];
94 if (li
->lc
->flags
& LC_default
)
95 for (n
= 0; n
< TM_NFORM
; n
++)
97 b
[n
] = tm_data
.format
[n
];
98 if (strchr(b
[TM_UT
], '%'))
100 tm_info
.deformat
= b
[TM_UT
];
101 for (n
= TM_UT
; n
< TM_DT
; n
++)
105 tm_info
.deformat
= b
[TM_DEFAULT
];
107 if (!(tm_info
.deformat
= state
.format
))
108 tm_info
.deformat
= tm_info
.format
[TM_DEFAULT
];
114 #include <ast_windows.h>
122 static const Map_t map
[] =
124 LOCALE_S1159
, (TM_MERIDIAN
+0),
125 LOCALE_S2359
, (TM_MERIDIAN
+1),
126 LOCALE_SABBREVDAYNAME1
, (TM_DAY_ABBREV
+1),
127 LOCALE_SABBREVDAYNAME2
, (TM_DAY_ABBREV
+2),
128 LOCALE_SABBREVDAYNAME3
, (TM_DAY_ABBREV
+3),
129 LOCALE_SABBREVDAYNAME4
, (TM_DAY_ABBREV
+4),
130 LOCALE_SABBREVDAYNAME5
, (TM_DAY_ABBREV
+5),
131 LOCALE_SABBREVDAYNAME6
, (TM_DAY_ABBREV
+6),
132 LOCALE_SABBREVDAYNAME7
, (TM_DAY_ABBREV
+0),
133 LOCALE_SABBREVMONTHNAME1
, (TM_MONTH_ABBREV
+0),
134 LOCALE_SABBREVMONTHNAME2
, (TM_MONTH_ABBREV
+1),
135 LOCALE_SABBREVMONTHNAME3
, (TM_MONTH_ABBREV
+2),
136 LOCALE_SABBREVMONTHNAME4
, (TM_MONTH_ABBREV
+3),
137 LOCALE_SABBREVMONTHNAME5
, (TM_MONTH_ABBREV
+4),
138 LOCALE_SABBREVMONTHNAME6
, (TM_MONTH_ABBREV
+5),
139 LOCALE_SABBREVMONTHNAME7
, (TM_MONTH_ABBREV
+6),
140 LOCALE_SABBREVMONTHNAME8
, (TM_MONTH_ABBREV
+7),
141 LOCALE_SABBREVMONTHNAME9
, (TM_MONTH_ABBREV
+8),
142 LOCALE_SABBREVMONTHNAME10
, (TM_MONTH_ABBREV
+9),
143 LOCALE_SABBREVMONTHNAME11
, (TM_MONTH_ABBREV
+10),
144 LOCALE_SABBREVMONTHNAME12
, (TM_MONTH_ABBREV
+11),
145 LOCALE_SDAYNAME1
, (TM_DAY
+1),
146 LOCALE_SDAYNAME2
, (TM_DAY
+2),
147 LOCALE_SDAYNAME3
, (TM_DAY
+3),
148 LOCALE_SDAYNAME4
, (TM_DAY
+4),
149 LOCALE_SDAYNAME5
, (TM_DAY
+5),
150 LOCALE_SDAYNAME6
, (TM_DAY
+6),
151 LOCALE_SDAYNAME7
, (TM_DAY
+0),
152 LOCALE_SMONTHNAME1
, (TM_MONTH
+0),
153 LOCALE_SMONTHNAME2
, (TM_MONTH
+1),
154 LOCALE_SMONTHNAME3
, (TM_MONTH
+2),
155 LOCALE_SMONTHNAME4
, (TM_MONTH
+3),
156 LOCALE_SMONTHNAME5
, (TM_MONTH
+4),
157 LOCALE_SMONTHNAME6
, (TM_MONTH
+5),
158 LOCALE_SMONTHNAME7
, (TM_MONTH
+6),
159 LOCALE_SMONTHNAME8
, (TM_MONTH
+7),
160 LOCALE_SMONTHNAME9
, (TM_MONTH
+8),
161 LOCALE_SMONTHNAME10
, (TM_MONTH
+9),
162 LOCALE_SMONTHNAME11
, (TM_MONTH
+10),
163 LOCALE_SMONTHNAME12
, (TM_MONTH
+11),
169 * convert ms word date spec w to posix strftime format f
170 * next char after f returned
171 * the caller already made sure f is big enough
175 word2posix(register char* f
, register char* w
, int alternate
)
187 if ((n
= w
- r
) > 3 && alternate
)
193 if (!strncasecmp(w
, "am/pm", 5))
195 else if (!strncasecmp(w
, "a/p", 3))
293 for (w
= r
+ 1; *w
; *f
++ = *w
++)
322 * load the native LC_TIME data for the current locale
326 native_lc_time(Lc_info_t
* li
)
342 lcid
= li
->lc
->index
;
343 nt
= 2 * GetLocaleInfo(lcid
, LOCALE_STIME
, 0, 0) + 7; /* HH:MM:SS */
344 ns
= 3 * GetLocaleInfo(lcid
, LOCALE_SSHORTDATE
, 0, 0);
345 nl
= 3 * GetLocaleInfo(lcid
, LOCALE_SLONGDATE
, 0, 0);
347 for (i
= 0; i
< elementsof(map
); i
++)
348 n
+= GetLocaleInfo(lcid
, map
[i
].native
, 0, 0);
349 if (!(b
= newof(0, char*, TM_NFORM
, n
)))
351 s
= (char*)(b
+ TM_NFORM
);
352 for (i
= 0; i
< elementsof(map
); i
++)
354 if (!(m
= GetLocaleInfo(lcid
, map
[i
].native
, s
, n
)))
359 if (!standardized(li
, b
))
362 * synthesize TM_TIME format from the ms word template
365 if (!GetLocaleInfo(lcid
, LOCALE_ITIME
, buf
, sizeof(buf
)))
367 clock_24
= atoi(buf
);
368 if (!GetLocaleInfo(lcid
, LOCALE_ITLZERO
, buf
, sizeof(buf
)))
370 leading_0
= atoi(buf
);
371 if (!GetLocaleInfo(lcid
, LOCALE_STIME
, buf
, sizeof(buf
)))
377 *s
++ = clock_24
? 'H' : 'I';
378 for (t
= buf
; *s
= *t
++; s
++);
383 for (t
= buf
; *s
= *t
++; s
++);
391 * synthesize TM_DATE format
394 if (!GetLocaleInfo(lcid
, LOCALE_SSHORTDATE
, buf
, sizeof(buf
)))
397 s
= word2posix(s
, buf
, 1);
400 * synthesize TM_DEFAULT format
403 if (!GetLocaleInfo(lcid
, LOCALE_SLONGDATE
, buf
, sizeof(buf
)))
406 s
= word2posix(s
, buf
, 1);
407 strcpy(s
- 1, " %X");
422 #if _lib_nl_langinfo && _hdr_langinfo
425 #include <nl_types.h>
428 #include <langinfo.h>
436 static const Map_t map
[] =
438 AM_STR
, (TM_MERIDIAN
+0),
439 PM_STR
, (TM_MERIDIAN
+1),
440 ABDAY_1
, (TM_DAY_ABBREV
+0),
441 ABDAY_2
, (TM_DAY_ABBREV
+1),
442 ABDAY_3
, (TM_DAY_ABBREV
+2),
443 ABDAY_4
, (TM_DAY_ABBREV
+3),
444 ABDAY_5
, (TM_DAY_ABBREV
+4),
445 ABDAY_6
, (TM_DAY_ABBREV
+5),
446 ABDAY_7
, (TM_DAY_ABBREV
+6),
447 ABMON_1
, (TM_MONTH_ABBREV
+0),
448 ABMON_2
, (TM_MONTH_ABBREV
+1),
449 ABMON_3
, (TM_MONTH_ABBREV
+2),
450 ABMON_4
, (TM_MONTH_ABBREV
+3),
451 ABMON_5
, (TM_MONTH_ABBREV
+4),
452 ABMON_6
, (TM_MONTH_ABBREV
+5),
453 ABMON_7
, (TM_MONTH_ABBREV
+6),
454 ABMON_8
, (TM_MONTH_ABBREV
+7),
455 ABMON_9
, (TM_MONTH_ABBREV
+8),
456 ABMON_10
, (TM_MONTH_ABBREV
+9),
457 ABMON_11
, (TM_MONTH_ABBREV
+10),
458 ABMON_12
, (TM_MONTH_ABBREV
+11),
475 MON_10
, (TM_MONTH
+9),
476 MON_11
, (TM_MONTH
+10),
477 MON_12
, (TM_MONTH
+11),
479 _DATE_FMT
, TM_DEFAULT
,
487 ERA_D_T_FMT
, TM_ERA_DEFAULT
,
488 ERA_D_FMT
, TM_ERA_DATE
,
489 ERA_T_FMT
, TM_ERA_TIME
,
492 ALT_DIGITS
, TM_DIGITS
,
497 native_lc_time(Lc_info_t
* li
)
506 for (i
= 0; i
< elementsof(map
); i
++)
508 if (!(t
= nl_langinfo(map
[i
].native
)))
509 t
= tm_data
.format
[map
[i
].local
];
512 if (!(b
= newof(0, char*, TM_NFORM
, n
)))
514 s
= (char*)(b
+ TM_NFORM
);
515 for (i
= 0; i
< elementsof(map
); i
++)
518 if (!(t
= nl_langinfo(map
[i
].native
)))
519 t
= tm_data
.format
[map
[i
].local
];
527 #define native_lc_time(li) ((li->data=(void*)(tm_info.format=tm_data.format)),(tm_info.deformat=tm_info.format[TM_DEFAULT]))
534 * load the LC_TIME data for the current locale
551 if (b
= (char**)li
->data
)
554 if (!(tm_info
.deformat
= state
.format
))
555 tm_info
.deformat
= tm_info
.format
[TM_DEFAULT
];
558 tm_info
.format
= tm_data
.format
;
559 if (!(tm_info
.deformat
= state
.format
))
560 tm_info
.deformat
= tm_info
.format
[TM_DEFAULT
];
561 if (mcfind(path
, NiL
, NiL
, LC_TIME
, 0) && (sp
= sfopen(NiL
, path
, "r")))
565 if (u
= (unsigned char*)sfreserve(sp
, 3, 1))
567 if (u
[0] == 0xef && u
[1] == 0xbb && u
[2] == 0xbf && (cvt
= iconv_open("", "utf")) != (iconv_t
)(-1))
569 if (tp
= sfstropen())
572 n
= iconv_move(cvt
, sp
, tp
, SF_UNBOUND
, NiL
);
579 if (b
= newof(0, char*, TM_NFORM
, n
+ 2))
584 if (tp
&& memcpy(s
, sfstrbase(tp
), n
) || !tp
&& sfread(sp
, s
, n
) == n
)
590 if (!(s
= strchr(s
, '\n')))
608 * check that tm_info.format matches the current locale
618 tm_info
.format
= tm_data
.format
;
619 if (!tm_info
.deformat
)
620 tm_info
.deformat
= tm_info
.format
[TM_DEFAULT
];
621 else if (tm_info
.deformat
!= tm_info
.format
[TM_DEFAULT
])
622 state
.format
= tm_info
.deformat
;
624 li
= LCINFO(AST_LC_TIME
);
627 return tm_info
.format
;