~centralelyon2010/inkscape/imagelinks2

« back to all changes in this revision

Viewing changes to src/dom/js/prmjtime.c

  • Committer: ishmal
  • Date: 2006-04-12 13:25:21 UTC
  • Revision ID: ishmal@users.sourceforge.net-20060412132521-5ynoezpwbzq4d1c3
Add new rearranged /dom directory

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 *
 
3
 * ***** BEGIN LICENSE BLOCK *****
 
4
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 
5
 *
 
6
 * The contents of this file are subject to the Mozilla Public License Version
 
7
 * 1.1 (the "License"); you may not use this file except in compliance with
 
8
 * the License. You may obtain a copy of the License at
 
9
 * http://www.mozilla.org/MPL/
 
10
 *
 
11
 * Software distributed under the License is distributed on an "AS IS" basis,
 
12
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
13
 * for the specific language governing rights and limitations under the
 
14
 * License.
 
15
 *
 
16
 * The Original Code is Mozilla Communicator client code, released
 
17
 * March 31, 1998.
 
18
 *
 
19
 * The Initial Developer of the Original Code is
 
20
 * Netscape Communications Corporation.
 
21
 * Portions created by the Initial Developer are Copyright (C) 1998
 
22
 * the Initial Developer. All Rights Reserved.
 
23
 *
 
24
 * Contributor(s):
 
25
 *
 
26
 * Alternatively, the contents of this file may be used under the terms of
 
27
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 
28
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
29
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
30
 * of those above. If you wish to allow use of your version of this file only
 
31
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
32
 * use your version of this file under the terms of the MPL, indicate your
 
33
 * decision by deleting the provisions above and replace them with the notice
 
34
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
35
 * the provisions above, a recipient may use your version of this file under
 
36
 * the terms of any one of the MPL, the GPL or the LGPL.
 
37
 *
 
38
 * ***** END LICENSE BLOCK ***** */
 
39
 
 
40
/*
 
41
 * PR time code.
 
42
 */
 
43
#include "jsstddef.h"
 
44
#ifdef SOLARIS
 
45
#define _REENTRANT 1
 
46
#endif
 
47
#include <string.h>
 
48
#include <time.h>
 
49
#include "jstypes.h"
 
50
#include "jsutil.h"
 
51
 
 
52
#include "jsprf.h"
 
53
#include "prmjtime.h"
 
54
 
 
55
#define PRMJ_DO_MILLISECONDS 1
 
56
 
 
57
#ifdef XP_OS2
 
58
#include <sys/timeb.h>
 
59
#endif
 
60
#ifdef XP_WIN
 
61
#include <windef.h>
 
62
#include <winbase.h>
 
63
#endif
 
64
 
 
65
#ifdef XP_MAC
 
66
#include <OSUtils.h>
 
67
#include <TextUtils.h>
 
68
#include <Resources.h>
 
69
#include <Timer.h>
 
70
#include <UTCUtils.h>
 
71
#include <Power.h>
 
72
#include <CodeFragments.h>
 
73
#if !TARGET_CARBON
 
74
#include <Traps.h>
 
75
#endif
 
76
#endif
 
77
 
 
78
#if defined(XP_UNIX) || defined(XP_BEOS)
 
79
 
 
80
#ifdef _SVID_GETTOD   /* Defined only on Solaris, see Solaris <sys/types.h> */
 
81
extern int gettimeofday(struct timeval *tv);
 
82
#endif
 
83
 
 
84
#include <sys/time.h>
 
85
 
 
86
#endif /* XP_UNIX */
 
87
 
 
88
#ifdef XP_MAC
 
89
static uint64                    dstLocalBaseMicroseconds;
 
90
static unsigned long     gJanuaryFirst1970Seconds;
 
91
 
 
92
static void MacintoshInitializeTime(void)
 
93
{
 
94
    uint64                                      upTime;
 
95
    unsigned long                       currentLocalTimeSeconds,
 
96
           startupTimeSeconds;
 
97
    uint64                              startupTimeMicroSeconds;
 
98
    uint32                              upTimeSeconds;
 
99
    uint64                              oneMillion, upTimeSecondsLong, microSecondsToSeconds;
 
100
    DateTimeRec                         firstSecondOfUnixTime;
 
101
 
 
102
    /*
 
103
     * Figure out in local time what time the machine started up. This information can be added to
 
104
     * upTime to figure out the current local time as well as GMT.
 
105
     */
 
106
 
 
107
    Microseconds((UnsignedWide*)&upTime);
 
108
 
 
109
    GetDateTime(&currentLocalTimeSeconds);
 
110
 
 
111
    JSLL_I2L(microSecondsToSeconds, PRMJ_USEC_PER_SEC);
 
112
    JSLL_DIV(upTimeSecondsLong, upTime, microSecondsToSeconds);
 
113
    JSLL_L2I(upTimeSeconds, upTimeSecondsLong);
 
114
 
 
115
    startupTimeSeconds = currentLocalTimeSeconds - upTimeSeconds;
 
116
 
 
117
    /*  Make sure that we normalize the macintosh base seconds to the unix base of January 1, 1970.
 
118
     */
 
119
 
 
120
    firstSecondOfUnixTime.year = 1970;
 
121
    firstSecondOfUnixTime.month = 1;
 
122
    firstSecondOfUnixTime.day = 1;
 
123
    firstSecondOfUnixTime.hour = 0;
 
124
    firstSecondOfUnixTime.minute = 0;
 
125
    firstSecondOfUnixTime.second = 0;
 
126
    firstSecondOfUnixTime.dayOfWeek = 0;
 
127
 
 
128
    DateToSeconds(&firstSecondOfUnixTime, &gJanuaryFirst1970Seconds);
 
129
 
 
130
    startupTimeSeconds -= gJanuaryFirst1970Seconds;
 
131
 
 
132
    /*  Now convert the startup time into a wide so that we can figure out GMT and DST.
 
133
     */
 
134
 
 
135
    JSLL_I2L(startupTimeMicroSeconds, startupTimeSeconds);
 
136
    JSLL_I2L(oneMillion, PRMJ_USEC_PER_SEC);
 
137
    JSLL_MUL(dstLocalBaseMicroseconds, oneMillion, startupTimeMicroSeconds);
 
138
}
 
139
 
 
140
static SleepQRec  gSleepQEntry = { NULL, sleepQType, NULL, 0 };
 
141
static JSBool     gSleepQEntryInstalled = JS_FALSE;
 
142
 
 
143
static pascal long MySleepQProc(long message, SleepQRecPtr sleepQ)
 
144
{
 
145
    /* just woke up from sleeping, so must recompute dstLocalBaseMicroseconds. */
 
146
    if (message == kSleepWakeUp)
 
147
        MacintoshInitializeTime();
 
148
    return 0;
 
149
}
 
150
 
 
151
/* Because serial port and SLIP conflict with ReadXPram calls,
 
152
 * we cache the call here
 
153
 */
 
154
 
 
155
static void MyReadLocation(MachineLocation * loc)
 
156
{
 
157
    static MachineLocation storedLoc;   /* InsideMac, OSUtilities, page 4-20 */
 
158
    static JSBool didReadLocation = JS_FALSE;
 
159
    if (!didReadLocation)
 
160
    {
 
161
        MacintoshInitializeTime();
 
162
        ReadLocation(&storedLoc);
 
163
        /* install a sleep queue routine, so that when the machine wakes up, time can be recomputed. */
 
164
        if (&SleepQInstall != (void*)kUnresolvedCFragSymbolAddress
 
165
#if !TARGET_CARBON
 
166
            && NGetTrapAddress(0xA28A, OSTrap) != NGetTrapAddress(_Unimplemented, ToolTrap)
 
167
#endif
 
168
           ) {
 
169
            if ((gSleepQEntry.sleepQProc = NewSleepQUPP(MySleepQProc)) != NULL) {
 
170
                SleepQInstall(&gSleepQEntry);
 
171
                gSleepQEntryInstalled = JS_TRUE;
 
172
            }
 
173
        }
 
174
        didReadLocation = JS_TRUE;
 
175
     }
 
176
     *loc = storedLoc;
 
177
}
 
178
 
 
179
 
 
180
#ifndef XP_MACOSX
 
181
 
 
182
/* CFM library init and terminate routines. We'll use the terminate routine
 
183
   to clean up the sleep Q entry. On Mach-O, the sleep Q entry gets cleaned
 
184
   up for us, so nothing to do there.
 
185
*/
 
186
 
 
187
extern pascal OSErr __NSInitialize(const CFragInitBlock* initBlock);
 
188
extern pascal void __NSTerminate();
 
189
 
 
190
pascal OSErr __JSInitialize(const CFragInitBlock* initBlock);
 
191
pascal void __JSTerminate(void);
 
192
 
 
193
pascal OSErr __JSInitialize(const CFragInitBlock* initBlock)
 
194
{
 
195
        return __NSInitialize(initBlock);
 
196
}
 
197
 
 
198
pascal void __JSTerminate()
 
199
{
 
200
  /* clean up the sleepQ entry */
 
201
  if (gSleepQEntryInstalled)
 
202
    SleepQRemove(&gSleepQEntry);
 
203
 
 
204
        __NSTerminate();
 
205
}
 
206
#endif /* XP_MACOSX */
 
207
 
 
208
#endif /* XP_MAC */
 
209
 
 
210
#define IS_LEAP(year) \
 
211
   (year != 0 && ((((year & 0x3) == 0) &&  \
 
212
                   ((year - ((year/100) * 100)) != 0)) || \
 
213
                  (year - ((year/400) * 400)) == 0))
 
214
 
 
215
#define PRMJ_HOUR_SECONDS  3600L
 
216
#define PRMJ_DAY_SECONDS  (24L * PRMJ_HOUR_SECONDS)
 
217
#define PRMJ_YEAR_SECONDS (PRMJ_DAY_SECONDS * 365L)
 
218
#define PRMJ_MAX_UNIX_TIMET 2145859200L /*time_t value equiv. to 12/31/2037 */
 
219
/* function prototypes */
 
220
static void PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm);
 
221
/*
 
222
 * get the difference in seconds between this time zone and UTC (GMT)
 
223
 */
 
224
JSInt32
 
225
PRMJ_LocalGMTDifference()
 
226
{
 
227
#if defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)
 
228
    struct tm ltime;
 
229
 
 
230
    /* get the difference between this time zone and GMT */
 
231
    memset((char *)&ltime,0,sizeof(ltime));
 
232
    ltime.tm_mday = 2;
 
233
    ltime.tm_year = 70;
 
234
#ifdef SUNOS4
 
235
    ltime.tm_zone = 0;
 
236
    ltime.tm_gmtoff = 0;
 
237
    return timelocal(&ltime) - (24 * 3600);
 
238
#else
 
239
    return mktime(&ltime) - (24L * 3600L);
 
240
#endif
 
241
#endif
 
242
#if defined(XP_MAC)
 
243
    static JSInt32   zone = -1L;
 
244
    MachineLocation  machineLocation;
 
245
    JSInt32          gmtOffsetSeconds;
 
246
 
 
247
    /* difference has been set no need to recalculate */
 
248
    if (zone != -1)
 
249
        return zone;
 
250
 
 
251
    /* Get the information about the local machine, including
 
252
     * its GMT offset and its daylight savings time info.
 
253
     * Convert each into wides that we can add to
 
254
     * startupTimeMicroSeconds.
 
255
     */
 
256
 
 
257
    MyReadLocation(&machineLocation);
 
258
 
 
259
    /* Mask off top eight bits of gmtDelta, sign extend lower three. */
 
260
    gmtOffsetSeconds = (machineLocation.u.gmtDelta << 8);
 
261
    gmtOffsetSeconds >>= 8;
 
262
 
 
263
    /* Backout OS adjustment for DST, to give consistent GMT offset. */
 
264
    if (machineLocation.u.dlsDelta != 0)
 
265
        gmtOffsetSeconds -= PRMJ_HOUR_SECONDS;
 
266
    return (zone = -gmtOffsetSeconds);
 
267
#endif
 
268
}
 
269
 
 
270
/* Constants for GMT offset from 1970 */
 
271
#define G1970GMTMICROHI        0x00dcdcad /* micro secs to 1970 hi */
 
272
#define G1970GMTMICROLOW       0x8b3fa000 /* micro secs to 1970 low */
 
273
 
 
274
#define G2037GMTMICROHI        0x00e45fab /* micro secs to 2037 high */
 
275
#define G2037GMTMICROLOW       0x7a238000 /* micro secs to 2037 low */
 
276
 
 
277
/* Convert from base time to extended time */
 
278
static JSInt64
 
279
PRMJ_ToExtendedTime(JSInt32 base_time)
 
280
{
 
281
    JSInt64 exttime;
 
282
    JSInt64 g1970GMTMicroSeconds;
 
283
    JSInt64 low;
 
284
    JSInt32 diff;
 
285
    JSInt64  tmp;
 
286
    JSInt64  tmp1;
 
287
 
 
288
    diff = PRMJ_LocalGMTDifference();
 
289
    JSLL_UI2L(tmp, PRMJ_USEC_PER_SEC);
 
290
    JSLL_I2L(tmp1,diff);
 
291
    JSLL_MUL(tmp,tmp,tmp1);
 
292
 
 
293
    JSLL_UI2L(g1970GMTMicroSeconds,G1970GMTMICROHI);
 
294
    JSLL_UI2L(low,G1970GMTMICROLOW);
 
295
#ifndef JS_HAVE_LONG_LONG
 
296
    JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
 
297
    JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
 
298
#else
 
299
    JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,32);
 
300
#endif
 
301
    JSLL_ADD(g1970GMTMicroSeconds,g1970GMTMicroSeconds,low);
 
302
 
 
303
    JSLL_I2L(exttime,base_time);
 
304
    JSLL_ADD(exttime,exttime,g1970GMTMicroSeconds);
 
305
    JSLL_SUB(exttime,exttime,tmp);
 
306
    return exttime;
 
307
}
 
308
 
 
309
JSInt64
 
310
PRMJ_Now(void)
 
311
{
 
312
#ifdef XP_OS2
 
313
    JSInt64 s, us, ms2us, s2us;
 
314
    struct timeb b;
 
315
#endif
 
316
#ifdef XP_WIN
 
317
    JSInt64 s, us,
 
318
    win2un = JSLL_INIT(0x19DB1DE, 0xD53E8000),
 
319
    ten = JSLL_INIT(0, 10);
 
320
    FILETIME time, midnight;
 
321
#endif
 
322
#if defined(XP_UNIX) || defined(XP_BEOS)
 
323
    struct timeval tv;
 
324
    JSInt64 s, us, s2us;
 
325
#endif /* XP_UNIX */
 
326
#ifdef XP_MAC
 
327
    JSUint64 upTime;
 
328
    JSInt64      localTime;
 
329
    JSInt64       gmtOffset;
 
330
    JSInt64    dstOffset;
 
331
    JSInt32       gmtDiff;
 
332
    JSInt64      s2us;
 
333
#endif /* XP_MAC */
 
334
 
 
335
#ifdef XP_OS2
 
336
    ftime(&b);
 
337
    JSLL_UI2L(ms2us, PRMJ_USEC_PER_MSEC);
 
338
    JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC);
 
339
    JSLL_UI2L(s, b.time);
 
340
    JSLL_UI2L(us, b.millitm);
 
341
    JSLL_MUL(us, us, ms2us);
 
342
    JSLL_MUL(s, s, s2us);
 
343
    JSLL_ADD(s, s, us);
 
344
    return s;
 
345
#endif
 
346
#ifdef XP_WIN
 
347
    /* The windows epoch is around 1600. The unix epoch is around 1970.
 
348
       win2un is the difference (in windows time units which are 10 times
 
349
       more precise than the JS time unit) */
 
350
    GetSystemTimeAsFileTime(&time);
 
351
    /* Win9x gets confused at midnight
 
352
       http://support.microsoft.com/default.aspx?scid=KB;en-us;q224423
 
353
       So if the low part (precision <8mins) is 0 then we get the time
 
354
       again. */
 
355
    if (!time.dwLowDateTime) {
 
356
        GetSystemTimeAsFileTime(&midnight);
 
357
        time.dwHighDateTime = midnight.dwHighDateTime;
 
358
    }
 
359
    JSLL_UI2L(s, time.dwHighDateTime);
 
360
    JSLL_UI2L(us, time.dwLowDateTime);
 
361
    JSLL_SHL(s, s, 32);
 
362
    JSLL_ADD(s, s, us);
 
363
    JSLL_SUB(s, s, win2un);
 
364
    JSLL_DIV(s, s, ten);
 
365
    return s;
 
366
#endif
 
367
 
 
368
#if defined(XP_UNIX) || defined(XP_BEOS)
 
369
#ifdef _SVID_GETTOD   /* Defined only on Solaris, see Solaris <sys/types.h> */
 
370
    gettimeofday(&tv);
 
371
#else
 
372
    gettimeofday(&tv, 0);
 
373
#endif /* _SVID_GETTOD */
 
374
    JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC);
 
375
    JSLL_UI2L(s, tv.tv_sec);
 
376
    JSLL_UI2L(us, tv.tv_usec);
 
377
    JSLL_MUL(s, s, s2us);
 
378
    JSLL_ADD(s, s, us);
 
379
    return s;
 
380
#endif /* XP_UNIX */
 
381
#ifdef XP_MAC
 
382
    JSLL_UI2L(localTime,0);
 
383
    gmtDiff = PRMJ_LocalGMTDifference();
 
384
    JSLL_I2L(gmtOffset,gmtDiff);
 
385
    JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC);
 
386
    JSLL_MUL(gmtOffset,gmtOffset,s2us);
 
387
 
 
388
    /* don't adjust for DST since it sets ctime and gmtime off on the MAC */
 
389
    Microseconds((UnsignedWide*)&upTime);
 
390
    JSLL_ADD(localTime,localTime,gmtOffset);
 
391
    JSLL_ADD(localTime,localTime, dstLocalBaseMicroseconds);
 
392
    JSLL_ADD(localTime,localTime, upTime);
 
393
 
 
394
    dstOffset = PRMJ_DSTOffset(localTime);
 
395
    JSLL_SUB(localTime,localTime,dstOffset);
 
396
 
 
397
    return *((JSUint64 *)&localTime);
 
398
#endif /* XP_MAC */
 
399
}
 
400
 
 
401
/* Get the DST timezone offset for the time passed in */
 
402
JSInt64
 
403
PRMJ_DSTOffset(JSInt64 local_time)
 
404
{
 
405
    JSInt64 us2s;
 
406
#ifdef XP_MAC
 
407
    /*
 
408
     * Convert the local time passed in to Macintosh epoch seconds. Use UTC utilities to convert
 
409
     * to UTC time, then compare difference with our GMT offset. If they are the same, then
 
410
     * DST must not be in effect for the input date/time.
 
411
     */
 
412
    UInt32 macLocalSeconds = (local_time / PRMJ_USEC_PER_SEC) + gJanuaryFirst1970Seconds, utcSeconds;
 
413
    ConvertLocalTimeToUTC(macLocalSeconds, &utcSeconds);
 
414
    if ((utcSeconds - macLocalSeconds) == PRMJ_LocalGMTDifference())
 
415
        return 0;
 
416
    else {
 
417
        JSInt64 dlsOffset;
 
418
        JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC);
 
419
        JSLL_UI2L(dlsOffset, PRMJ_HOUR_SECONDS);
 
420
        JSLL_MUL(dlsOffset, dlsOffset, us2s);
 
421
        return dlsOffset;
 
422
    }
 
423
#else
 
424
    time_t local;
 
425
    JSInt32 diff;
 
426
    JSInt64  maxtimet;
 
427
    struct tm tm;
 
428
    PRMJTime prtm;
 
429
#ifndef HAVE_LOCALTIME_R
 
430
    struct tm *ptm;
 
431
#endif
 
432
 
 
433
 
 
434
    JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC);
 
435
    JSLL_DIV(local_time, local_time, us2s);
 
436
 
 
437
    /* get the maximum of time_t value */
 
438
    JSLL_UI2L(maxtimet,PRMJ_MAX_UNIX_TIMET);
 
439
 
 
440
    if(JSLL_CMP(local_time,>,maxtimet)){
 
441
        JSLL_UI2L(local_time,PRMJ_MAX_UNIX_TIMET);
 
442
    } else if(!JSLL_GE_ZERO(local_time)){
 
443
        /*go ahead a day to make localtime work (does not work with 0) */
 
444
        JSLL_UI2L(local_time,PRMJ_DAY_SECONDS);
 
445
    }
 
446
    JSLL_L2UI(local,local_time);
 
447
    PRMJ_basetime(local_time,&prtm);
 
448
#ifndef HAVE_LOCALTIME_R
 
449
    ptm = localtime(&local);
 
450
    if(!ptm){
 
451
        return JSLL_ZERO;
 
452
    }
 
453
    tm = *ptm;
 
454
#else
 
455
    localtime_r(&local,&tm); /* get dst information */
 
456
#endif
 
457
 
 
458
    diff = ((tm.tm_hour - prtm.tm_hour) * PRMJ_HOUR_SECONDS) +
 
459
        ((tm.tm_min - prtm.tm_min) * 60);
 
460
 
 
461
    if(diff < 0){
 
462
        diff += PRMJ_DAY_SECONDS;
 
463
    }
 
464
 
 
465
    JSLL_UI2L(local_time,diff);
 
466
 
 
467
    JSLL_MUL(local_time,local_time,us2s);
 
468
 
 
469
    return(local_time);
 
470
#endif
 
471
}
 
472
 
 
473
/* Format a time value into a buffer. Same semantics as strftime() */
 
474
size_t
 
475
PRMJ_FormatTime(char *buf, int buflen, char *fmt, PRMJTime *prtm)
 
476
{
 
477
#if defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_MAC) || defined(XP_BEOS)
 
478
    struct tm a;
 
479
 
 
480
    /* Zero out the tm struct.  Linux, SunOS 4 struct tm has extra members int
 
481
     * tm_gmtoff, char *tm_zone; when tm_zone is garbage, strftime gets
 
482
     * confused and dumps core.  NSPR20 prtime.c attempts to fill these in by
 
483
     * calling mktime on the partially filled struct, but this doesn't seem to
 
484
     * work as well; the result string has "can't get timezone" for ECMA-valid
 
485
     * years.  Might still make sense to use this, but find the range of years
 
486
     * for which valid tz information exists, and map (per ECMA hint) from the
 
487
     * given year into that range.
 
488
 
 
489
     * N.B. This hasn't been tested with anything that actually _uses_
 
490
     * tm_gmtoff; zero might be the wrong thing to set it to if you really need
 
491
     * to format a time.  This fix is for jsdate.c, which only uses
 
492
     * JS_FormatTime to get a string representing the time zone.  */
 
493
    memset(&a, 0, sizeof(struct tm));
 
494
 
 
495
    a.tm_sec = prtm->tm_sec;
 
496
    a.tm_min = prtm->tm_min;
 
497
    a.tm_hour = prtm->tm_hour;
 
498
    a.tm_mday = prtm->tm_mday;
 
499
    a.tm_mon = prtm->tm_mon;
 
500
    a.tm_wday = prtm->tm_wday;
 
501
    a.tm_year = prtm->tm_year - 1900;
 
502
    a.tm_yday = prtm->tm_yday;
 
503
    a.tm_isdst = prtm->tm_isdst;
 
504
 
 
505
    /* Even with the above, SunOS 4 seems to detonate if tm_zone and tm_gmtoff
 
506
     * are null.  This doesn't quite work, though - the timezone is off by
 
507
     * tzoff + dst.  (And mktime seems to return -1 for the exact dst
 
508
     * changeover time.)
 
509
 
 
510
     */
 
511
 
 
512
#if defined(SUNOS4)
 
513
    if (mktime(&a) == -1) {
 
514
        /* Seems to fail whenever the requested date is outside of the 32-bit
 
515
         * UNIX epoch.  We could proceed at this point (setting a.tm_zone to
 
516
         * "") but then strftime returns a string with a 2-digit field of
 
517
         * garbage for the year.  So we return 0 and hope jsdate.c
 
518
         * will fall back on toString.
 
519
         */
 
520
        return 0;
 
521
    }
 
522
#endif
 
523
 
 
524
    return strftime(buf, buflen, fmt, &a);
 
525
#endif
 
526
}
 
527
 
 
528
/* table for number of days in a month */
 
529
static int mtab[] = {
 
530
    /* jan, feb,mar,apr,may,jun */
 
531
    31,28,31,30,31,30,
 
532
    /* july,aug,sep,oct,nov,dec */
 
533
    31,31,30,31,30,31
 
534
};
 
535
 
 
536
/*
 
537
 * basic time calculation functionality for localtime and gmtime
 
538
 * setups up prtm argument with correct values based upon input number
 
539
 * of seconds.
 
540
 */
 
541
static void
 
542
PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm)
 
543
{
 
544
    /* convert tsecs back to year,month,day,hour,secs */
 
545
    JSInt32 year    = 0;
 
546
    JSInt32 month   = 0;
 
547
    JSInt32 yday    = 0;
 
548
    JSInt32 mday    = 0;
 
549
    JSInt32 wday    = 6; /* start on a Sunday */
 
550
    JSInt32 days    = 0;
 
551
    JSInt32 seconds = 0;
 
552
    JSInt32 minutes = 0;
 
553
    JSInt32 hours   = 0;
 
554
    JSInt32 isleap  = 0;
 
555
    JSInt64 result;
 
556
    JSInt64     result1;
 
557
    JSInt64     result2;
 
558
    JSInt64 base;
 
559
 
 
560
    JSLL_UI2L(result,0);
 
561
    JSLL_UI2L(result1,0);
 
562
    JSLL_UI2L(result2,0);
 
563
 
 
564
    /* get the base time via UTC */
 
565
    base = PRMJ_ToExtendedTime(0);
 
566
    JSLL_UI2L(result,  PRMJ_USEC_PER_SEC);
 
567
    JSLL_DIV(base,base,result);
 
568
    JSLL_ADD(tsecs,tsecs,base);
 
569
 
 
570
    JSLL_UI2L(result, PRMJ_YEAR_SECONDS);
 
571
    JSLL_UI2L(result1,PRMJ_DAY_SECONDS);
 
572
    JSLL_ADD(result2,result,result1);
 
573
 
 
574
    /* get the year */
 
575
    while ((isleap == 0) ? !JSLL_CMP(tsecs,<,result) : !JSLL_CMP(tsecs,<,result2)) {
 
576
        /* subtract a year from tsecs */
 
577
        JSLL_SUB(tsecs,tsecs,result);
 
578
        days += 365;
 
579
        /* is it a leap year ? */
 
580
        if(IS_LEAP(year)){
 
581
            JSLL_SUB(tsecs,tsecs,result1);
 
582
            days++;
 
583
        }
 
584
        year++;
 
585
        isleap = IS_LEAP(year);
 
586
    }
 
587
 
 
588
    JSLL_UI2L(result1,PRMJ_DAY_SECONDS);
 
589
 
 
590
    JSLL_DIV(result,tsecs,result1);
 
591
    JSLL_L2I(mday,result);
 
592
 
 
593
    /* let's find the month */
 
594
    while(((month == 1 && isleap) ?
 
595
            (mday >= mtab[month] + 1) :
 
596
            (mday >= mtab[month]))){
 
597
         yday += mtab[month];
 
598
         days += mtab[month];
 
599
 
 
600
         mday -= mtab[month];
 
601
 
 
602
         /* it's a Feb, check if this is a leap year */
 
603
         if(month == 1 && isleap != 0){
 
604
             yday++;
 
605
             days++;
 
606
             mday--;
 
607
         }
 
608
         month++;
 
609
    }
 
610
 
 
611
    /* now adjust tsecs */
 
612
    JSLL_MUL(result,result,result1);
 
613
    JSLL_SUB(tsecs,tsecs,result);
 
614
 
 
615
    mday++; /* day of month always start with 1 */
 
616
    days += mday;
 
617
    wday = (days + wday) % 7;
 
618
 
 
619
    yday += mday;
 
620
 
 
621
    /* get the hours */
 
622
    JSLL_UI2L(result1,PRMJ_HOUR_SECONDS);
 
623
    JSLL_DIV(result,tsecs,result1);
 
624
    JSLL_L2I(hours,result);
 
625
    JSLL_MUL(result,result,result1);
 
626
    JSLL_SUB(tsecs,tsecs,result);
 
627
 
 
628
    /* get minutes */
 
629
    JSLL_UI2L(result1,60);
 
630
    JSLL_DIV(result,tsecs,result1);
 
631
    JSLL_L2I(minutes,result);
 
632
    JSLL_MUL(result,result,result1);
 
633
    JSLL_SUB(tsecs,tsecs,result);
 
634
 
 
635
    JSLL_L2I(seconds,tsecs);
 
636
 
 
637
    prtm->tm_usec  = 0L;
 
638
    prtm->tm_sec   = (JSInt8)seconds;
 
639
    prtm->tm_min   = (JSInt8)minutes;
 
640
    prtm->tm_hour  = (JSInt8)hours;
 
641
    prtm->tm_mday  = (JSInt8)mday;
 
642
    prtm->tm_mon   = (JSInt8)month;
 
643
    prtm->tm_wday  = (JSInt8)wday;
 
644
    prtm->tm_year  = (JSInt16)year;
 
645
    prtm->tm_yday  = (JSInt16)yday;
 
646
}