1: /* 2: * Copyright (c) 1987 Regents of the University of California. 3: * This file may be freely redistributed provided that this 4: * notice remains attached. 5: */ 6: 7: #if defined(LIBC_SCCS) && !defined(lint) 8: static char sccsid[] = "@(#)ctime.c 1.1 (Berkeley) 3/25/87"; 9: #endif LIBC_SCCS and not lint 10: 11: #include "sys/param.h" 12: #include "sys/time.h" 13: #include "tzfile.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 %02d:%02d:%02d %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: tzsetkernel() 223: { 224: struct timeval tv; 225: struct timezone tz; 226: char *tztab(); 227: 228: if (gettimeofday(&tv, &tz)) 229: return -1; 230: s.timecnt = 0; /* UNIX counts *west* of Greenwich */ 231: s.ttis[0].tt_gmtoff = tz.tz_minuteswest * -SECS_PER_MIN; 232: s.ttis[0].tt_abbrind = 0; 233: (void)strcpy(s.chars, tztab(tz.tz_minuteswest, 0)); 234: tzname[0] = tzname[1] = s.chars; 235: #ifdef USG_COMPAT 236: timezone = tz.tz_minuteswest * 60; 237: daylight = tz.tz_dsttime; 238: #endif /* USG_COMPAT */ 239: return 0; 240: } 241: 242: static 243: tzsetgmt() 244: { 245: s.timecnt = 0; 246: s.ttis[0].tt_gmtoff = 0; 247: s.ttis[0].tt_abbrind = 0; 248: (void) strcpy(s.chars, "GMT"); 249: tzname[0] = tzname[1] = s.chars; 250: #ifdef USG_COMPAT 251: timezone = 0; 252: daylight = 0; 253: #endif /* USG_COMPAT */ 254: } 255: 256: void 257: tzset() 258: { 259: register char * name; 260: 261: tz_is_set = TRUE; 262: name = getenv("TZ"); 263: if (!name || *name) { /* did not request GMT */ 264: if (name && !tzload(name)) /* requested name worked */ 265: return; 266: if (!tzload((char *)0)) /* default name worked */ 267: return; 268: if (!tzsetkernel()) /* kernel guess worked */ 269: return; 270: } 271: tzsetgmt(); /* GMT is default */ 272: } 273: 274: struct tm * 275: localtime(timep) 276: time_t * timep; 277: { 278: register struct ttinfo * ttisp; 279: register struct tm * tmp; 280: register int i; 281: time_t t; 282: 283: if (!tz_is_set) 284: (void) tzset(); 285: t = *timep; 286: if (s.timecnt == 0 || t < s.ats[0]) { 287: i = 0; 288: while (s.ttis[i].tt_isdst) 289: if (++i >= s.timecnt) { 290: i = 0; 291: break; 292: } 293: } else { 294: for (i = 1; i < s.timecnt; ++i) 295: if (t < s.ats[i]) 296: break; 297: i = s.types[i - 1]; 298: } 299: ttisp = &s.ttis[i]; 300: /* 301: ** To get (wrong) behavior that's compatible with System V Release 2.0 302: ** you'd replace the statement below with 303: ** tmp = offtime((time_t) (t + ttisp->tt_gmtoff), 0L); 304: */ 305: tmp = offtime(&t, ttisp->tt_gmtoff); 306: tmp->tm_isdst = ttisp->tt_isdst; 307: tzname[tmp->tm_isdst] = &s.chars[ttisp->tt_abbrind]; 308: tmp->tm_zone = &s.chars[ttisp->tt_abbrind]; 309: return tmp; 310: } 311: 312: struct tm * 313: gmtime(clock) 314: time_t * clock; 315: { 316: register struct tm * tmp; 317: 318: tmp = offtime(clock, 0L); 319: tzname[0] = "GMT"; 320: tmp->tm_zone = "GMT"; /* UCT ? */ 321: return tmp; 322: } 323: 324: static int mon_lengths[2][MONS_PER_YEAR] = { 325: 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 326: 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 327: }; 328: 329: static int year_lengths[2] = { 330: DAYS_PER_NYEAR, DAYS_PER_LYEAR 331: }; 332: 333: struct tm * 334: offtime(clock, offset) 335: time_t * clock; 336: long offset; 337: { 338: register struct tm * tmp; 339: register long days; 340: register long rem; 341: register int y; 342: register int yleap; 343: register int * ip; 344: static struct tm tm; 345: 346: tmp = &tm; 347: days = *clock / SECS_PER_DAY; 348: rem = *clock % SECS_PER_DAY; 349: rem += offset; 350: while (rem < 0) { 351: rem += SECS_PER_DAY; 352: --days; 353: } 354: while (rem >= SECS_PER_DAY) { 355: rem -= SECS_PER_DAY; 356: ++days; 357: } 358: tmp->tm_hour = (int) (rem / SECS_PER_HOUR); 359: rem = rem % SECS_PER_HOUR; 360: tmp->tm_min = (int) (rem / SECS_PER_MIN); 361: tmp->tm_sec = (int) (rem % SECS_PER_MIN); 362: tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYS_PER_WEEK); 363: if (tmp->tm_wday < 0) 364: tmp->tm_wday += DAYS_PER_WEEK; 365: y = EPOCH_YEAR; 366: if (days >= 0) 367: for ( ; ; ) { 368: yleap = isleap(y); 369: if (days < (long) year_lengths[yleap]) 370: break; 371: ++y; 372: days = days - (long) year_lengths[yleap]; 373: } 374: else do { 375: --y; 376: yleap = isleap(y); 377: days = days + (long) year_lengths[yleap]; 378: } while (days < 0); 379: tmp->tm_year = y - TM_YEAR_BASE; 380: tmp->tm_yday = (int) days; 381: ip = mon_lengths[yleap]; 382: for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon)) 383: days = days - (long) ip[tmp->tm_mon]; 384: tmp->tm_mday = (int) (days + 1); 385: tmp->tm_isdst = 0; 386: tmp->tm_zone = ""; 387: tmp->tm_gmtoff = offset; 388: return tmp; 389: }