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