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 <gsf@research.att.com> * 18 * David Korn <dgk@research.att.com> * 19 * Phong Vo <kpv@research.att.com> * 20 * * 21 ***********************************************************************/ 22 #pragma prototyped 23 /* 24 * Glenn Fowler 25 * AT&T Research 26 * 27 * time conversion support 28 */ 29 30 #include <tm.h> 31 #include <ctype.h> 32 #include <namval.h> 33 34 #include "FEATURE/tmlib" 35 36 #ifndef tzname 37 # if defined(__DYNAMIC__) 38 # undef _dat_tzname 39 # define tzname __DYNAMIC__(tzname) 40 # else 41 # if !_dat_tzname 42 # if _dat__tzname 43 # undef _dat_tzname 44 # define _dat_tzname 1 45 # define tzname _tzname 46 # endif 47 # endif 48 # endif 49 # if _dat_tzname && !defined(tzname) 50 extern char* tzname[]; 51 # endif 52 #endif 53 54 #define TM_type (-1) 55 56 static const Namval_t options[] = 57 { 58 "adjust", TM_ADJUST, 59 "format", TM_DEFAULT, 60 "leap", TM_LEAP, 61 "subsecond", TM_SUBSECOND, 62 "type", TM_type, 63 "utc", TM_UTC, 64 0, 0 65 }; 66 67 /* 68 * 2007-03-19 move tm_info from _tm_info_ to (*_tm_infop_) 69 * to allow future Tm_info_t growth 70 * by 2009 _tm_info_ can be static 71 */ 72 73 #if _BLD_ast && defined(__EXPORT__) 74 #define extern extern __EXPORT__ 75 #endif 76 77 extern Tm_info_t _tm_info_; 78 79 #undef extern 80 81 Tm_info_t _tm_info_ = { 0 }; 82 83 __EXTERN__(Tm_info_t, _tm_info_); 84 85 __EXTERN__(Tm_info_t*, _tm_infop_); 86 87 Tm_info_t* _tm_infop_ = &_tm_info_; 88 89 #if _tzset_environ 90 91 static char TZ[256]; 92 static char* TE[2]; 93 94 struct tm* 95 _tm_localtime(const time_t* t) 96 { 97 struct tm* r; 98 char* e; 99 char** v = environ; 100 101 if (TZ[0]) 102 { 103 if (!environ || !*environ) 104 environ = TE; 105 else 106 e = environ[0]; 107 environ[0] = TZ; 108 } 109 r = localtime(t); 110 if (TZ[0]) 111 { 112 if (environ != v) 113 environ = v; 114 else 115 environ[0] = e; 116 } 117 return r; 118 } 119 120 #endif 121 122 /* 123 * return minutes west of GMT for local time clock 124 * 125 * isdst will point to non-zero if DST is in effect 126 * this routine also kicks in the local initialization 127 */ 128 129 static int 130 tzwest(time_t* clock, int* isdst) 131 { 132 register struct tm* tp; 133 register int n; 134 register int m; 135 int h; 136 time_t epoch; 137 138 /* 139 * convert to GMT assuming local time 140 */ 141 142 if (!(tp = gmtime(clock))) 143 { 144 /* 145 * some systems return 0 for negative time_t 146 */ 147 148 epoch = 0; 149 clock = &epoch; 150 tp = gmtime(clock); 151 } 152 n = tp->tm_yday; 153 h = tp->tm_hour; 154 m = tp->tm_min; 155 156 /* 157 * tmlocaltime() handles DST and GMT offset 158 */ 159 160 tp = tmlocaltime(clock); 161 if (n = tp->tm_yday - n) 162 { 163 if (n > 1) 164 n = -1; 165 else if (n < -1) 166 n = 1; 167 } 168 *isdst = tp->tm_isdst; 169 return (h - tp->tm_hour - n * 24) * 60 + m - tp->tm_min; 170 } 171 172 /* 173 * stropt() option handler 174 */ 175 176 static int 177 tmopt(void* a, const void* p, int n, const char* v) 178 { 179 Tm_zone_t* zp; 180 181 NoP(a); 182 if (p) 183 switch (((Namval_t*)p)->value) 184 { 185 case TM_DEFAULT: 186 tm_info.deformat = (n && (n = strlen(v)) > 0 && (n < 2 || v[n-2] != '%' || v[n-1] != '?')) ? strdup(v) : tm_info.format[TM_DEFAULT]; 187 break; 188 case TM_type: 189 tm_info.local->type = (n && *v) ? ((zp = tmtype(v, NiL)) ? zp->type : strdup(v)) : 0; 190 break; 191 default: 192 if (n) 193 tm_info.flags |= ((Namval_t*)p)->value; 194 else 195 tm_info.flags &= ~((Namval_t*)p)->value; 196 break; 197 } 198 return 0; 199 } 200 201 /* 202 * initialize the local timezone 203 */ 204 205 static void 206 tmlocal(void) 207 { 208 register Tm_zone_t* zp; 209 register int n; 210 register char* s; 211 register char* e; 212 int i; 213 int m; 214 int isdst; 215 char* t; 216 struct tm* tp; 217 time_t now; 218 char buf[16]; 219 220 static Tm_zone_t local; 221 222 #if _tzset_environ 223 { 224 char** v = environ; 225 226 if (s = getenv("TZ")) 227 { 228 sfsprintf(TZ, sizeof(TZ), "TZ=%s", s); 229 if (!environ || !*environ) 230 environ = TE; 231 else 232 e = environ[0]; 233 environ[0] = TZ; 234 } 235 else 236 { 237 TZ[0] = 0; 238 e = 0; 239 } 240 #endif 241 #if _lib_tzset 242 tzset(); 243 #endif 244 #if _tzset_environ 245 if (environ != v) 246 environ = v; 247 else if (e) 248 environ[0] = e; 249 } 250 #endif 251 #if _dat_tzname 252 local.standard = strdup(tzname[0]); 253 local.daylight = strdup(tzname[1]); 254 #endif 255 tmlocale(); 256 257 /* 258 * tm_info.local 259 */ 260 261 tm_info.zone = tm_info.local = &local; 262 time(&now); 263 n = tzwest(&now, &isdst); 264 265 /* 266 * compute local DST offset by roaming 267 * through the last 12 months until tzwest() changes 268 */ 269 270 for (i = 0; i < 12; i++) 271 { 272 now -= 31 * 24 * 60 * 60; 273 if ((m = tzwest(&now, &isdst)) != n) 274 { 275 if (!isdst) 276 { 277 isdst = n; 278 n = m; 279 m = isdst; 280 } 281 m -= n; 282 break; 283 } 284 } 285 local.west = n; 286 local.dst = m; 287 288 /* 289 * now get the time zone names 290 */ 291 292 #if _dat_tzname 293 if (tzname[0]) 294 { 295 /* 296 * POSIX 297 */ 298 299 if (!local.standard) 300 local.standard = strdup(tzname[0]); 301 if (!local.daylight) 302 local.daylight = strdup(tzname[1]); 303 } 304 else 305 #endif 306 if ((s = getenv("TZNAME")) && *s && (s = strdup(s))) 307 { 308 /* 309 * BSD 310 */ 311 312 local.standard = s; 313 if (s = strchr(s, ',')) 314 *s++ = 0; 315 else 316 s = ""; 317 local.daylight = s; 318 } 319 else if ((s = getenv("TZ")) && *s && *s != ':' && (s = strdup(s))) 320 { 321 /* 322 * POSIX style but skipped by tmlocaltime() 323 */ 324 325 local.standard = s; 326 if (*++s && *++s && *++s) 327 { 328 *s++ = 0; 329 tmgoff(s, &t, 0); 330 for (s = t; isalpha(*t); t++); 331 *t = 0; 332 } 333 else 334 s = ""; 335 local.daylight = s; 336 } 337 else 338 { 339 /* 340 * tm_data.zone table lookup 341 */ 342 343 t = 0; 344 for (zp = tm_data.zone; zp->standard; zp++) 345 { 346 if (zp->type) 347 t = zp->type; 348 if (zp->west == n && zp->dst == m) 349 { 350 local.type = t; 351 local.standard = zp->standard; 352 if (!(s = zp->daylight)) 353 { 354 e = (s = buf) + sizeof(buf); 355 s = tmpoff(s, e - s, zp->standard, 0, 0); 356 if (s < e - 1) 357 { 358 *s++ = ' '; 359 tmpoff(s, e - s, tm_info.format[TM_DT], m, TM_DST); 360 } 361 s = strdup(buf); 362 } 363 local.daylight = s; 364 break; 365 } 366 } 367 if (!zp->standard) 368 { 369 /* 370 * not in the table 371 */ 372 373 e = (s = buf) + sizeof(buf); 374 s = tmpoff(s, e - s, tm_info.format[TM_UT], n, 0); 375 local.standard = strdup(buf); 376 if (s < e - 1) 377 { 378 *s++ = ' '; 379 tmpoff(s, e - s, tm_info.format[TM_UT], m, TM_DST); 380 local.daylight = strdup(buf); 381 } 382 } 383 } 384 385 /* 386 * set the options 387 */ 388 389 stropt(getenv("TM_OPTIONS"), options, sizeof(*options), tmopt, NiL); 390 391 /* 392 * the time zone type is probably related to the locale 393 */ 394 395 if (!local.type) 396 { 397 s = local.standard; 398 t = 0; 399 for (zp = tm_data.zone; zp->standard; zp++) 400 { 401 if (zp->type) 402 t = zp->type; 403 if (tmword(s, NiL, zp->standard, NiL, 0)) 404 { 405 local.type = t; 406 break; 407 } 408 } 409 } 410 411 /* 412 * tm_info.flags 413 */ 414 415 if (!(tm_info.flags & TM_ADJUST)) 416 { 417 now = (time_t)78811200; /* Jun 30 1972 23:59:60 */ 418 tp = tmlocaltime(&now); 419 if (tp->tm_sec != 60) 420 tm_info.flags |= TM_ADJUST; 421 } 422 if (!(tm_info.flags & TM_UTC)) 423 { 424 s = local.standard; 425 zp = tm_data.zone; 426 if (local.daylight) 427 zp++; 428 for (; !zp->type && zp->standard; zp++) 429 if (tmword(s, NiL, zp->standard, NiL, 0)) 430 { 431 tm_info.flags |= TM_UTC; 432 break; 433 } 434 } 435 } 436 437 /* 438 * initialize tm data 439 */ 440 441 void 442 tminit(register Tm_zone_t* zp) 443 { 444 static uint32_t serial = ~(uint32_t)0; 445 446 if (serial != ast.env_serial) 447 { 448 serial = ast.env_serial; 449 if (tm_info.local) 450 { 451 memset(tm_info.local, 0, sizeof(*tm_info.local)); 452 tm_info.local = 0; 453 } 454 } 455 if (!tm_info.local) 456 tmlocal(); 457 if (!zp) 458 zp = tm_info.local; 459 tm_info.zone = zp; 460 } 461