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