1 /* 2 * Copyright (c) 1987 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific written prior permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 * 12 * This code was supplied by Arthur Olson, originally, and has been 13 * slightly modified at the University of California. 14 */ 15 16 #if defined(LIBC_SCCS) && !defined(lint) 17 static char sccsid[] = "@(#)ctime.c 5.12 (Berkeley) 12/03/87"; 18 #endif /* LIBC_SCCS and not lint */ 19 20 #include "sys/param.h" 21 #include "sys/time.h" 22 #include "tzfile.h" 23 24 char * 25 ctime(t) 26 time_t *t; 27 { 28 struct tm *localtime(); 29 char *asctime(); 30 31 return(asctime(localtime(t))); 32 } 33 34 /* 35 ** A la X3J11 36 */ 37 38 char * 39 asctime(timeptr) 40 register struct tm * timeptr; 41 { 42 static char wday_name[DAYS_PER_WEEK][3] = { 43 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 44 }; 45 static char mon_name[MONS_PER_YEAR][3] = { 46 "Jan", "Feb", "Mar", "Apr", "May", "Jun", 47 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 48 }; 49 static char result[26]; 50 51 (void) sprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n", 52 wday_name[timeptr->tm_wday], 53 mon_name[timeptr->tm_mon], 54 timeptr->tm_mday, timeptr->tm_hour, 55 timeptr->tm_min, timeptr->tm_sec, 56 TM_YEAR_BASE + timeptr->tm_year); 57 return result; 58 } 59 60 #ifndef TRUE 61 #define TRUE 1 62 #define FALSE 0 63 #endif /* !TRUE */ 64 65 extern char * getenv(); 66 extern char * strcpy(); 67 extern char * strcat(); 68 struct tm * offtime(); 69 70 struct ttinfo { /* time type information */ 71 long tt_gmtoff; /* GMT offset in seconds */ 72 int tt_isdst; /* used to set tm_isdst */ 73 int tt_abbrind; /* abbreviation list index */ 74 }; 75 76 struct state { 77 int timecnt; 78 int typecnt; 79 int charcnt; 80 time_t ats[TZ_MAX_TIMES]; 81 unsigned char types[TZ_MAX_TIMES]; 82 struct ttinfo ttis[TZ_MAX_TYPES]; 83 char chars[TZ_MAX_CHARS + 1]; 84 }; 85 86 static struct state s; 87 88 static int tz_is_set; 89 90 char * tzname[2] = { 91 "GMT", 92 "GMT" 93 }; 94 95 #ifdef USG_COMPAT 96 time_t timezone = 0; 97 int daylight = 0; 98 #endif /* USG_COMPAT */ 99 100 static long 101 detzcode(codep) 102 char * codep; 103 { 104 register long result; 105 register int i; 106 107 result = 0; 108 for (i = 0; i < 4; ++i) 109 result = (result << 8) | (codep[i] & 0xff); 110 return result; 111 } 112 113 static 114 tzload(name) 115 register char * name; 116 { 117 register int i; 118 register int fid; 119 120 if (name == 0 && (name = TZDEFAULT) == 0) 121 return -1; 122 { 123 register char * p; 124 register int doaccess; 125 char fullname[MAXPATHLEN]; 126 127 doaccess = name[0] == '/'; 128 if (!doaccess) { 129 if ((p = TZDIR) == 0) 130 return -1; 131 if ((strlen(p) + strlen(name) + 1) >= sizeof fullname) 132 return -1; 133 (void) strcpy(fullname, p); 134 (void) strcat(fullname, "/"); 135 (void) strcat(fullname, name); 136 /* 137 ** Set doaccess if '.' (as in "../") shows up in name. 138 */ 139 while (*name != '\0') 140 if (*name++ == '.') 141 doaccess = TRUE; 142 name = fullname; 143 } 144 if (doaccess && access(name, 4) != 0) 145 return -1; 146 if ((fid = open(name, 0)) == -1) 147 return -1; 148 } 149 { 150 register char * p; 151 register struct tzhead * tzhp; 152 char buf[sizeof s]; 153 154 i = read(fid, buf, sizeof buf); 155 if (close(fid) != 0 || i < sizeof *tzhp) 156 return -1; 157 tzhp = (struct tzhead *) buf; 158 s.timecnt = (int) detzcode(tzhp->tzh_timecnt); 159 s.typecnt = (int) detzcode(tzhp->tzh_typecnt); 160 s.charcnt = (int) detzcode(tzhp->tzh_charcnt); 161 if (s.timecnt > TZ_MAX_TIMES || 162 s.typecnt == 0 || 163 s.typecnt > TZ_MAX_TYPES || 164 s.charcnt > TZ_MAX_CHARS) 165 return -1; 166 if (i < sizeof *tzhp + 167 s.timecnt * (4 + sizeof (char)) + 168 s.typecnt * (4 + 2 * sizeof (char)) + 169 s.charcnt * sizeof (char)) 170 return -1; 171 p = buf + sizeof *tzhp; 172 for (i = 0; i < s.timecnt; ++i) { 173 s.ats[i] = detzcode(p); 174 p += 4; 175 } 176 for (i = 0; i < s.timecnt; ++i) 177 s.types[i] = (unsigned char) *p++; 178 for (i = 0; i < s.typecnt; ++i) { 179 register struct ttinfo * ttisp; 180 181 ttisp = &s.ttis[i]; 182 ttisp->tt_gmtoff = detzcode(p); 183 p += 4; 184 ttisp->tt_isdst = (unsigned char) *p++; 185 ttisp->tt_abbrind = (unsigned char) *p++; 186 } 187 for (i = 0; i < s.charcnt; ++i) 188 s.chars[i] = *p++; 189 s.chars[i] = '\0'; /* ensure '\0' at end */ 190 } 191 /* 192 ** Check that all the local time type indices are valid. 193 */ 194 for (i = 0; i < s.timecnt; ++i) 195 if (s.types[i] >= s.typecnt) 196 return -1; 197 /* 198 ** Check that all abbreviation indices are valid. 199 */ 200 for (i = 0; i < s.typecnt; ++i) 201 if (s.ttis[i].tt_abbrind >= s.charcnt) 202 return -1; 203 /* 204 ** Set tzname elements to initial values. 205 */ 206 tzname[0] = tzname[1] = &s.chars[0]; 207 #ifdef USG_COMPAT 208 timezone = -s.ttis[0].tt_gmtoff; 209 daylight = 0; 210 #endif /* USG_COMPAT */ 211 for (i = 1; i < s.typecnt; ++i) { 212 register struct ttinfo * ttisp; 213 214 ttisp = &s.ttis[i]; 215 if (ttisp->tt_isdst) { 216 tzname[1] = &s.chars[ttisp->tt_abbrind]; 217 #ifdef USG_COMPAT 218 daylight = 1; 219 #endif /* USG_COMPAT */ 220 } else { 221 tzname[0] = &s.chars[ttisp->tt_abbrind]; 222 #ifdef USG_COMPAT 223 timezone = -ttisp->tt_gmtoff; 224 #endif /* USG_COMPAT */ 225 } 226 } 227 return 0; 228 } 229 230 static 231 tzsetkernel() 232 { 233 struct timeval tv; 234 struct timezone tz; 235 char *_tztab(); 236 237 if (gettimeofday(&tv, &tz)) 238 return -1; 239 s.timecnt = 0; /* UNIX counts *west* of Greenwich */ 240 s.ttis[0].tt_gmtoff = tz.tz_minuteswest * -SECS_PER_MIN; 241 s.ttis[0].tt_abbrind = 0; 242 (void)strcpy(s.chars, _tztab(tz.tz_minuteswest, 0)); 243 tzname[0] = tzname[1] = s.chars; 244 #ifdef USG_COMPAT 245 timezone = tz.tz_minuteswest * 60; 246 daylight = tz.tz_dsttime; 247 #endif /* USG_COMPAT */ 248 return 0; 249 } 250 251 static 252 tzsetgmt() 253 { 254 s.timecnt = 0; 255 s.ttis[0].tt_gmtoff = 0; 256 s.ttis[0].tt_abbrind = 0; 257 (void) strcpy(s.chars, "GMT"); 258 tzname[0] = tzname[1] = s.chars; 259 #ifdef USG_COMPAT 260 timezone = 0; 261 daylight = 0; 262 #endif /* USG_COMPAT */ 263 } 264 265 void 266 tzset() 267 { 268 register char * name; 269 270 tz_is_set = TRUE; 271 name = getenv("TZ"); 272 if (!name || *name) { /* did not request GMT */ 273 if (name && !tzload(name)) /* requested name worked */ 274 return; 275 if (!tzload((char *)0)) /* default name worked */ 276 return; 277 if (!tzsetkernel()) /* kernel guess worked */ 278 return; 279 } 280 tzsetgmt(); /* GMT is default */ 281 } 282 283 struct tm * 284 localtime(timep) 285 time_t * timep; 286 { 287 register struct ttinfo * ttisp; 288 register struct tm * tmp; 289 register int i; 290 time_t t; 291 292 if (!tz_is_set) 293 (void) tzset(); 294 t = *timep; 295 if (s.timecnt == 0 || t < s.ats[0]) { 296 i = 0; 297 while (s.ttis[i].tt_isdst) 298 if (++i >= s.timecnt) { 299 i = 0; 300 break; 301 } 302 } else { 303 for (i = 1; i < s.timecnt; ++i) 304 if (t < s.ats[i]) 305 break; 306 i = s.types[i - 1]; 307 } 308 ttisp = &s.ttis[i]; 309 /* 310 ** To get (wrong) behavior that's compatible with System V Release 2.0 311 ** you'd replace the statement below with 312 ** tmp = offtime((time_t) (t + ttisp->tt_gmtoff), 0L); 313 */ 314 tmp = offtime(&t, ttisp->tt_gmtoff); 315 tmp->tm_isdst = ttisp->tt_isdst; 316 tzname[tmp->tm_isdst] = &s.chars[ttisp->tt_abbrind]; 317 tmp->tm_zone = &s.chars[ttisp->tt_abbrind]; 318 return tmp; 319 } 320 321 struct tm * 322 gmtime(clock) 323 time_t * clock; 324 { 325 register struct tm * tmp; 326 327 tmp = offtime(clock, 0L); 328 tzname[0] = "GMT"; 329 tmp->tm_zone = "GMT"; /* UCT ? */ 330 return tmp; 331 } 332 333 static int mon_lengths[2][MONS_PER_YEAR] = { 334 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 335 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 336 }; 337 338 static int year_lengths[2] = { 339 DAYS_PER_NYEAR, DAYS_PER_LYEAR 340 }; 341 342 struct tm * 343 offtime(clock, offset) 344 time_t * clock; 345 long offset; 346 { 347 register struct tm * tmp; 348 register long days; 349 register long rem; 350 register int y; 351 register int yleap; 352 register int * ip; 353 static struct tm tm; 354 355 tmp = &tm; 356 days = *clock / SECS_PER_DAY; 357 rem = *clock % SECS_PER_DAY; 358 rem += offset; 359 while (rem < 0) { 360 rem += SECS_PER_DAY; 361 --days; 362 } 363 while (rem >= SECS_PER_DAY) { 364 rem -= SECS_PER_DAY; 365 ++days; 366 } 367 tmp->tm_hour = (int) (rem / SECS_PER_HOUR); 368 rem = rem % SECS_PER_HOUR; 369 tmp->tm_min = (int) (rem / SECS_PER_MIN); 370 tmp->tm_sec = (int) (rem % SECS_PER_MIN); 371 tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYS_PER_WEEK); 372 if (tmp->tm_wday < 0) 373 tmp->tm_wday += DAYS_PER_WEEK; 374 y = EPOCH_YEAR; 375 if (days >= 0) 376 for ( ; ; ) { 377 yleap = isleap(y); 378 if (days < (long) year_lengths[yleap]) 379 break; 380 ++y; 381 days = days - (long) year_lengths[yleap]; 382 } 383 else do { 384 --y; 385 yleap = isleap(y); 386 days = days + (long) year_lengths[yleap]; 387 } while (days < 0); 388 tmp->tm_year = y - TM_YEAR_BASE; 389 tmp->tm_yday = (int) days; 390 ip = mon_lengths[yleap]; 391 for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 392 days = days - (long) ip[tmp->tm_mon]; 393 tmp->tm_mday = (int) (days + 1); 394 tmp->tm_isdst = 0; 395 tmp->tm_zone = ""; 396 tmp->tm_gmtoff = offset; 397 return tmp; 398 } 399