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