import less(1)
[unleashed/tickless.git] / usr / src / lib / libast / common / tm / tminit.c
blob26e870213fe809b2786be08c37fd3b8913aecab3
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 #pragma prototyped
24 * Glenn Fowler
25 * AT&T Research
27 * time conversion support
30 #include <tm.h>
31 #include <ctype.h>
32 #include <namval.h>
34 #include "FEATURE/tmlib"
36 #ifndef tzname
37 # if defined(__DYNAMIC__)
38 # define tzname __DYNAMIC__(tzname)
39 # else
40 # if !_dat_tzname
41 # if _dat__tzname
42 # undef _dat_tzname
43 # define _dat_tzname 1
44 # define tzname _tzname
45 # endif
46 # endif
47 # endif
48 # if _dat_tzname
49 extern char* tzname[];
50 # endif
51 #endif
53 #define TM_type (-1)
55 static const Namval_t options[] =
57 "adjust", TM_ADJUST,
58 "format", TM_DEFAULT,
59 "leap", TM_LEAP,
60 "subsecond", TM_SUBSECOND,
61 "type", TM_type,
62 "utc", TM_UTC,
63 0, 0
67 * 2007-03-19 move tm_info from _tm_info_ to (*_tm_infop_)
68 * to allow future Tm_info_t growth
69 * by 2009 _tm_info_ can be static
72 #if _BLD_ast && defined(__EXPORT__)
73 #define extern extern __EXPORT__
74 #endif
76 extern Tm_info_t _tm_info_;
78 #undef extern
80 Tm_info_t _tm_info_ = { 0 };
82 __EXTERN__(Tm_info_t, _tm_info_);
84 __EXTERN__(Tm_info_t*, _tm_infop_);
86 Tm_info_t* _tm_infop_ = &_tm_info_;
88 #if _tzset_environ
90 static char TZ[256];
91 static char* TE[2];
93 struct tm*
94 _tm_localtime(const time_t* t)
96 struct tm* r;
97 char* e;
98 char** v = environ;
100 if (TZ[0])
102 if (!environ || !*environ)
103 environ = TE;
104 else
105 e = environ[0];
106 environ[0] = TZ;
108 r = localtime(t);
109 if (TZ[0])
111 if (environ != v)
112 environ = v;
113 else
114 environ[0] = e;
116 return r;
119 #endif
122 * return minutes west of GMT for local time clock
124 * isdst will point to non-zero if DST is in effect
125 * this routine also kicks in the local initialization
128 static int
129 tzwest(time_t* clock, int* isdst)
131 register struct tm* tp;
132 register int n;
133 register int m;
134 int h;
135 time_t epoch;
138 * convert to GMT assuming local time
141 if (!(tp = gmtime(clock)))
144 * some systems return 0 for negative time_t
147 epoch = 0;
148 clock = &epoch;
149 tp = gmtime(clock);
151 n = tp->tm_yday;
152 h = tp->tm_hour;
153 m = tp->tm_min;
156 * tmlocaltime() handles DST and GMT offset
159 tp = tmlocaltime(clock);
160 if (n = tp->tm_yday - n)
162 if (n > 1)
163 n = -1;
164 else if (n < -1)
165 n = 1;
167 *isdst = tp->tm_isdst;
168 return (h - tp->tm_hour - n * 24) * 60 + m - tp->tm_min;
172 * stropt() option handler
175 static int
176 tmopt(void* a, const void* p, int n, const char* v)
178 Tm_zone_t* zp;
180 NoP(a);
181 if (p)
182 switch (((Namval_t*)p)->value)
184 case TM_DEFAULT:
185 tm_info.deformat = (n && (n = strlen(v)) > 0 && (n < 2 || v[n-2] != '%' || v[n-1] != '?')) ? strdup(v) : tm_info.format[TM_DEFAULT];
186 break;
187 case TM_type:
188 tm_info.local->type = (n && *v) ? ((zp = tmtype(v, NiL)) ? zp->type : strdup(v)) : 0;
189 break;
190 default:
191 if (n)
192 tm_info.flags |= ((Namval_t*)p)->value;
193 else
194 tm_info.flags &= ~((Namval_t*)p)->value;
195 break;
197 return 0;
201 * initialize the local timezone
204 static void
205 tmlocal(void)
207 register Tm_zone_t* zp;
208 register int n;
209 register char* s;
210 register char* e;
211 int i;
212 int m;
213 int isdst;
214 char* t;
215 struct tm* tp;
216 time_t now;
217 char buf[16];
219 static Tm_zone_t local;
221 #if _tzset_environ
223 char** v = environ;
225 if (s = getenv("TZ"))
227 sfsprintf(TZ, sizeof(TZ), "TZ=%s", s);
228 if (!environ || !*environ)
229 environ = TE;
230 else
231 e = environ[0];
232 environ[0] = TZ;
234 else
236 TZ[0] = 0;
237 e = 0;
239 #endif
240 #if _lib_tzset
241 tzset();
242 #endif
243 #if _tzset_environ
244 if (environ != v)
245 environ = v;
246 else if (e)
247 environ[0] = e;
249 #endif
250 #if _dat_tzname
251 local.standard = strdup(tzname[0]);
252 local.daylight = strdup(tzname[1]);
253 #endif
254 tmlocale();
257 * tm_info.local
260 tm_info.zone = tm_info.local = &local;
261 time(&now);
262 n = tzwest(&now, &isdst);
265 * compute local DST offset by roaming
266 * through the last 12 months until tzwest() changes
269 for (i = 0; i < 12; i++)
271 now -= 31 * 24 * 60 * 60;
272 if ((m = tzwest(&now, &isdst)) != n)
274 if (!isdst)
276 isdst = n;
277 n = m;
278 m = isdst;
280 m -= n;
281 break;
284 local.west = n;
285 local.dst = m;
288 * now get the time zone names
291 #if _dat_tzname
292 if (tzname[0])
295 * POSIX
298 if (!local.standard)
299 local.standard = strdup(tzname[0]);
300 if (!local.daylight)
301 local.daylight = strdup(tzname[1]);
303 else
304 #endif
305 if ((s = getenv("TZNAME")) && *s && (s = strdup(s)))
308 * BSD
311 local.standard = s;
312 if (s = strchr(s, ','))
313 *s++ = 0;
314 else
315 s = "";
316 local.daylight = s;
318 else if ((s = getenv("TZ")) && *s && *s != ':' && (s = strdup(s)))
321 * POSIX style but skipped by tmlocaltime()
324 local.standard = s;
325 if (*++s && *++s && *++s)
327 *s++ = 0;
328 tmgoff(s, &t, 0);
329 for (s = t; isalpha(*t); t++);
330 *t = 0;
332 else
333 s = "";
334 local.daylight = s;
336 else
339 * tm_data.zone table lookup
342 t = 0;
343 for (zp = tm_data.zone; zp->standard; zp++)
345 if (zp->type)
346 t = zp->type;
347 if (zp->west == n && zp->dst == m)
349 local.type = t;
350 local.standard = zp->standard;
351 if (!(s = zp->daylight))
353 e = (s = buf) + sizeof(buf);
354 s = tmpoff(s, e - s, zp->standard, 0, 0);
355 if (s < e - 1)
357 *s++ = ' ';
358 tmpoff(s, e - s, tm_info.format[TM_DT], m, TM_DST);
360 s = strdup(buf);
362 local.daylight = s;
363 break;
366 if (!zp->standard)
369 * not in the table
372 e = (s = buf) + sizeof(buf);
373 s = tmpoff(s, e - s, tm_info.format[TM_UT], n, 0);
374 local.standard = strdup(buf);
375 if (s < e - 1)
377 *s++ = ' ';
378 tmpoff(s, e - s, tm_info.format[TM_UT], m, TM_DST);
379 local.daylight = strdup(buf);
385 * set the options
388 stropt(getenv("TM_OPTIONS"), options, sizeof(*options), tmopt, NiL);
391 * the time zone type is probably related to the locale
394 if (!local.type)
396 s = local.standard;
397 t = 0;
398 for (zp = tm_data.zone; zp->standard; zp++)
400 if (zp->type)
401 t = zp->type;
402 if (tmword(s, NiL, zp->standard, NiL, 0))
404 local.type = t;
405 break;
411 * tm_info.flags
414 if (!(tm_info.flags & TM_ADJUST))
416 now = (time_t)78811200; /* Jun 30 1972 23:59:60 */
417 tp = tmlocaltime(&now);
418 if (tp->tm_sec != 60)
419 tm_info.flags |= TM_ADJUST;
421 if (!(tm_info.flags & TM_UTC))
423 s = local.standard;
424 zp = tm_data.zone;
425 if (local.daylight)
426 zp++;
427 for (; !zp->type && zp->standard; zp++)
428 if (tmword(s, NiL, zp->standard, NiL, 0))
430 tm_info.flags |= TM_UTC;
431 break;
437 * initialize tm data
440 void
441 tminit(register Tm_zone_t* zp)
443 static uint32_t serial = ~(uint32_t)0;
445 if (serial != ast.env_serial)
447 serial = ast.env_serial;
448 if (tm_info.local)
450 memset(tm_info.local, 0, sizeof(*tm_info.local));
451 tm_info.local = 0;
454 if (!tm_info.local)
455 tmlocal();
456 if (!zp)
457 zp = tm_info.local;
458 tm_info.zone = zp;