1 /*
2 Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
3
4 See the accompanying file LICENSE, version 2000-Apr-09 or later
5 (the contents of which are also included in zip.h) for terms of use.
6 If, for some reason, all these files are missing, the Info-ZIP license
7 also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /* -----------------------------------------------------------------------------
10
11 The original functions (Metrowerks Codewarrior pro 3.0) gmtime, localtime,
12 mktime and time do not work correctly. The supplied link library mactime.c
13 contains replacement functions for them.
14
15 * Caveat: On a Mac, we only know the GMT and DST offsets for
16 * the current time, not for the time in question.
17 * Mac has no support for DST handling.
18 * DST changeover is all manually set by the user.
19
20
21 ------------------------------------------------------------------------------*/
22
23 /*****************************************************************************/
24 /* Includes */
25 /*****************************************************************************/
26
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <time.h>
31 #include <OSUtils.h>
32
33 #include "mactime.h"
34
35
36 /*
37 The MacOS function GetDateTime returns the
38 number of seconds elapsed since midnight, January 1, 1904.
39 */
40 const unsigned long MacOS_2_Unix = 2082844800L;
41
42
43 /*****************************************************************************/
44 /* Macros, typedefs */
45 /*****************************************************************************/
46
47
48 #ifndef TEST_TIME_LIB
49 #define my_gmtime gmtime
50 #define my_localtime localtime
51 #define my_mktime mktime
52 #define my_time time
53 #endif
54
55
56 /*****************************************************************************/
57 /* Prototypes */
58 /*****************************************************************************/
59 /* internal prototypes */
60 static void clear_tm(struct tm * tm);
61 static long GMTDelta(void);
62 static Boolean DaylightSaving(void);
63 static time_t GetTimeMac(void);
64 static time_t Mactime(time_t *timer);
65 static void normalize(int *i,int *j,int norm);
66 static struct tm *time2tm(const time_t *timer);
67 static time_t tm2time(struct tm *tp);
68
69 /* Because serial port and SLIP conflict with ReadXPram calls,
70 we cache the call here so we don't hang on calling ReadLocation() */
71 static void myReadLocation(MachineLocation * loc);
72
73
74 /* prototypes for STD lib replacement functions */
75 struct tm *my_gmtime(const time_t *t);
76 struct tm *my_localtime(const time_t *t);
77 time_t my_mktime(struct tm *tp);
78 time_t my_time(time_t *t);
79
80
81 /*****************************************************************************/
82 /* Functions */
83 /*****************************************************************************/
84
85 /*
86 * Mac file times are based on 1904 Jan 1 00:00 local time,
87 * not 1970 Jan 1 00:00 UTC.
88 * So we have to convert the time stamps into UNIX UTC
89 * compatible values.
90 */
MacFtime2UnixFtime(unsigned long macftime)91 time_t MacFtime2UnixFtime(unsigned long macftime)
92 {
93 long UTCoffset;
94
95 GetGMToffsetMac(macftime, &UTCoffset);
96 MACOS_TO_UNIX(macftime);
97 macftime -= UTCoffset;
98
99 return macftime;
100 }
101
102
103 /*
104 * Mac file times are based on 1904 Jan 1 00:00 local time,
105 * not 1970 Jan 1 00:00 UTC.
106 * So we have to convert the time stamps into MacOS local
107 * compatible values.
108 */
UnixFtime2MacFtime(time_t unxftime)109 unsigned long UnixFtime2MacFtime(time_t unxftime)
110 {
111 long UTCoffset;
112 unsigned long macftime = unxftime;
113
114 UNIX_TO_MACOS(macftime);
115 GetGMToffsetMac(macftime, &UTCoffset);
116 macftime += UTCoffset;
117
118 return macftime;
119 }
120
121
122
123
124
125 /*
126 * This function convert a file-localtime to an another
127 * file-localtime.
128 */
AdjustForTZmoveMac(unsigned long macloctim,long s_gmtoffs)129 time_t AdjustForTZmoveMac(unsigned long macloctim, long s_gmtoffs)
130 {
131 time_t MacGMTTime;
132 long UTCoffset;
133
134 /* convert macloctim into corresponding UTC value */
135 MacGMTTime = macloctim - s_gmtoffs;
136 GetGMToffsetMac(macloctim, &UTCoffset);
137
138 return (MacGMTTime + UTCoffset);
139 } /* AdjustForTZmove() */
140
141
142
143
144 /*
145 * This function calculates the difference between the supplied Mac
146 * ftime value (local time) and the corresponding UTC time in seconds.
147 */
GetGMToffsetMac(unsigned long mactime,long * UTCoffset)148 Boolean GetGMToffsetMac(unsigned long mactime, long *UTCoffset)
149 {
150
151 mactime = mactime;
152 /*
153 * Caveat: On a Mac, we only know the GMT and DST offsets for
154 * the current time, not for the time in question.
155 * Mac has no support for DST handling.
156 * DST changeover is all manually set by the user.
157
158 May be later I can include a support of GMT offset calculation for the
159 time in question here.
160 */
161 *UTCoffset = GMTDelta();
162
163 return true;
164 }
165
166
167
168
169
170
171
172 /*****************************************************************************
173 * Standard Library Replacement Functions
174 * gmtime(), mktime(), localtime(), time()
175 *
176 * The unix epoch is used here.
177 * These functions gmtime(), mktime(), localtime() and time()
178 * expects and returns unix times.
179 *
180 * At midnight Jan. 1, 1970 GMT, the local time was
181 * midnight Jan. 1, 1970 + GMTDelta().
182 *
183 *
184 *****************************************************************************/
185
186
my_gmtime(const time_t * timer)187 struct tm *my_gmtime(const time_t *timer)
188 {
189 return time2tm(timer);
190 }
191
192
193
194
my_localtime(const time_t * timer)195 struct tm *my_localtime(const time_t *timer)
196 {
197 time_t maclocal;
198
199 maclocal = *timer;
200 maclocal += GMTDelta();
201
202 return time2tm(&maclocal);
203 }
204
205
206
207
my_mktime(struct tm * tp)208 time_t my_mktime(struct tm *tp)
209 {
210 time_t maclocal;
211
212 maclocal = tm2time(tp);
213 maclocal -= GMTDelta();
214
215 return maclocal;
216 }
217
218
219
220
221
222
my_time(time_t * time)223 time_t my_time(time_t *time)
224 {
225 time_t tmp_time;
226
227 GetDateTime(&tmp_time);
228
229 MACOS_TO_UNIX(tmp_time);
230
231 if (time)
232 {
233 *time = tmp_time;
234 }
235
236 return tmp_time;
237 }
238
239
240
241 /*****************************************************************************/
242 /* static module level functions
243 /*****************************************************************************/
244
245
246 /*
247 * The geographic location and time zone information of a Mac
248 * are stored in extended parameter RAM. The ReadLocation
249 * produdure uses the geographic location record, MachineLocation,
250 * to read the geographic location and time zone information in
251 * extended parameter RAM.
252 *
253 * Because serial port and SLIP conflict with ReadXPram calls,
254 * we cache the call here.
255 *
256 * Caveat: this caching will give the wrong result if a session
257 * extend across the DST changeover time, but
258 * this function resets itself every 2 hours.
259 */
myReadLocation(MachineLocation * loc)260 static void myReadLocation(MachineLocation * loc)
261 {
262 static MachineLocation storedLoc; /* InsideMac, OSUtilities, page 4-20 */
263 static time_t first_call = 0, last_call = 86400;
264
265 if ((last_call - first_call) > 7200)
266 {
267 GetDateTime(&first_call);
268 ReadLocation(&storedLoc);
269 }
270
271 GetDateTime(&last_call);
272 *loc = storedLoc;
273 }
274
275
276
277
DaylightSaving(void)278 static Boolean DaylightSaving(void)
279 {
280 MachineLocation loc;
281 unsigned char dlsDelta;
282
283 myReadLocation(&loc);
284 dlsDelta = loc.u.dlsDelta;
285
286 return (dlsDelta != 0);
287 }
288
289
290
291
292 /* current local time = GMTDelta() + GMT
293 GMT = local time - GMTDelta() */
GMTDelta(void)294 static long GMTDelta(void)
295 {
296 MachineLocation loc;
297 long gmtDelta;
298
299 myReadLocation(&loc);
300
301 /*
302 * On a Mac, the GMT value is in seconds east of GMT. For example,
303 * San Francisco is at -28,800 seconds (8 hours * 3600 seconds per hour)
304 * east of GMT. The gmtDelta field is a 3-byte value contained in a
305 * long word, so you must take care to get it properly.
306 */
307 gmtDelta = loc.u.gmtDelta & 0x00FFFFFF;
308 if ((gmtDelta & 0x00800000) != 0)
309 {
310 gmtDelta |= 0xFF000000;
311 }
312
313 return gmtDelta;
314 }
315
316
317
318 /* This routine simulates stdclib time(), time in seconds since 1.1.1970
319 The time is in GMT */
GetTimeMac(void)320 static time_t GetTimeMac(void)
321 {
322 unsigned long maclocal;
323
324
325 /*
326 * Get the current time expressed as the number of seconds
327 * elapsed since the Mac epoch, midnight, Jan. 1, 1904 (local time).
328 * On a Mac, current time accuracy is up to a second.
329 */
330
331 GetDateTime(&maclocal); /* Get Mac local time */
332 maclocal -= GMTDelta(); /* Get Mac GMT */
333 MACOS_TO_UNIX(maclocal);
334
335 return maclocal; /* return unix GMT */
336 }
337
338
339
340
341 /*
342 * clear_tm - sets a broken-down time to the equivalent of 1970/1/1 00:00:00
343 */
344
clear_tm(struct tm * tm)345 static void clear_tm(struct tm * tm)
346 {
347 tm->tm_sec = 0;
348 tm->tm_min = 0;
349 tm->tm_hour = 0;
350 tm->tm_mday = 1;
351 tm->tm_mon = 0;
352 tm->tm_year = 0;
353 tm->tm_wday = 1;
354 tm->tm_yday = 0;
355 tm->tm_isdst = -1;
356 }
357
358
normalize(int * i,int * j,int norm)359 static void normalize(int *i,int *j,int norm)
360 {
361 while(*i < 0)
362 {
363 *i += norm;
364 (*j)--;
365 }
366
367 while(*i >= norm)
368 {
369 *i -= norm;
370 (*j)++;
371 }
372 }
373
374
375
376 /* Returns the GMT times */
Mactime(time_t * timer)377 static time_t Mactime(time_t *timer)
378 {
379 time_t t = GetTimeMac();
380
381 if (timer != NULL)
382 *timer = t;
383
384 return t;
385 }
386
387
388
389
time2tm(const time_t * timer)390 static struct tm *time2tm(const time_t *timer)
391 {
392 DateTimeRec dtr;
393 MachineLocation loc;
394 time_t macLocal = *timer;
395
396 static struct tm statictime;
397 static const short monthday[12] =
398 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
399
400 UNIX_TO_MACOS(macLocal);
401 SecondsToDate(macLocal, &dtr);
402
403 statictime.tm_sec = dtr.second; /* second, from 0 to 59 */
404 statictime.tm_min = dtr.minute; /* minute, from 0 to 59 */
405 statictime.tm_hour = dtr.hour; /* hour, from 0 to 23 */
406 statictime.tm_mday = dtr.day; /* day of the month, from 1 to 31 */
407 statictime.tm_mon = dtr.month - 1; /* month, 1= January and 12 = December */
408 statictime.tm_year = dtr.year - 1900; /* year, ranging from 1904 to 2040 */
409 statictime.tm_wday = dtr.dayOfWeek - 1; /* day of the week, 1 = Sun, 7 = Sat */
410
411 statictime.tm_yday = monthday[statictime.tm_mon]
412 + statictime.tm_mday - 1;
413
414 if (2 < statictime.tm_mon && !(statictime.tm_year & 3))
415 {
416 ++statictime.tm_yday;
417 }
418
419 myReadLocation(&loc);
420 statictime.tm_isdst = DaylightSaving();
421
422 return(&statictime);
423 }
424
425
426
427
428
tm2time(struct tm * tp)429 static time_t tm2time(struct tm *tp)
430 {
431 time_t intMacTime;
432 DateTimeRec dtr;
433
434 normalize(&tp->tm_sec, &tp->tm_min, 60);
435 normalize(&tp->tm_min, &tp->tm_hour,60);
436 normalize(&tp->tm_hour,&tp->tm_mday,24);
437 normalize(&tp->tm_mon, &tp->tm_year,12);
438
439 dtr.year = tp->tm_year + 1900; /* years since 1900 */
440 dtr.month = tp->tm_mon + 1; /* month, 0 = January and 11 = December */
441 dtr.day = tp->tm_mday; /* day of the month, from 1 to 31 */
442 dtr.hour = tp->tm_hour; /* hour, from 0 to 23 */
443 dtr.minute = tp->tm_min; /* minute, from 0 to 59 */
444 dtr.second = tp->tm_sec; /* second, from 0 to 59 */
445
446 DateToSeconds(&dtr, &intMacTime);
447
448 MACOS_TO_UNIX(intMacTime);
449
450 return intMacTime;
451 }
452