Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
6725 siemargl 1
/*
2
  Copyright (c) 1990-2001 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
/* Replacement time library functions, based on platform independent public
10
 * domain timezone code from ftp://elsie.nci.nih.gov/pub, with mktime and
11
 * mkgmtime from our own mktime.c in Zip.
12
 *
13
 * Contains:  tzset()
14
 *            __tzset()
15
 *            gmtime()
16
 *            localtime()
17
 *            mktime()
18
 *            mkgmtime()
19
 *            GetPlatformLocalTimezone()  [different versions]
20
 */
21
 
22
/* HISTORY/CHANGES
23
 * 17 Jun 00, Paul Kienitz, added the PD-based tzset(), localtime(), and so on
24
 *            to amiga/filedate.c, replacing GNU-based functions which had
25
 *            replaced time_lib.c, both having been rejected for licensing
26
 *            reasons.  Support for timezone files and leap seconds was removed.
27
 *
28
 * 23 Aug 00, Paul Kienitz, split into separate timezone.c file, made platform
29
 *            independent, copied in mktime() and mkgmtime() from Zip, renamed
30
 *            locale_TZ as GetPlatformLocalTimezone(), for use as a generic
31
 *            hook by other platforms.
32
 */
33
 
34
#ifndef __timezone_c
35
#define __timezone_c
36
 
37
 
38
#include "zip.h"
39
#include "timezone.h"
40
#include 
41
#include 
42
 
43
#ifdef IZTZ_DEFINESTDGLOBALS
44
long timezone = 0;
45
int daylight = 0;
46
char *tzname[2];
47
#endif
48
 
49
#ifndef IZTZ_GETLOCALETZINFO
50
#  define IZTZ_GETLOCALETZINFO(ptzstruct, pgenrulefunct) (FALSE)
51
#endif
52
 
53
int real_timezone_is_set = FALSE;       /* set by tzset() */
54
 
55
 
56
#define TZDEFRULESTRING ",M4.1.0,M10.5.0"
57
#define TZDEFAULT       "EST5EDT"
58
 
59
#define SECSPERMIN      60
60
#define MINSPERHOUR     60
61
#define HOURSPERDAY     24
62
#define DAYSPERWEEK     7
63
#define DAYSPERNYEAR    365
64
#define DAYSPERLYEAR    366
65
#define SECSPERHOUR     (SECSPERMIN * MINSPERHOUR)
66
#define SECSPERDAY      ((long) SECSPERHOUR * HOURSPERDAY)
67
#define MONSPERYEAR 12
68
 
69
#define EPOCH_WDAY      4     /* Jan 1, 1970 was thursday */
70
#define EPOCH_YEAR      1970
71
#define TM_YEAR_BASE    1900
72
#define FIRST_GOOD_YEAR ((time_t) -1 < (time_t) 1 ? EPOCH_YEAR-68 : EPOCH_YEAR)
73
#define LAST_GOOD_YEAR  (EPOCH_YEAR + ((time_t) -1 < (time_t) 1 ? 67 : 135))
74
 
75
#define YDAYS(month, year) yr_days[leap(year)][month]
76
 
77
/* Nonzero if `y' is a leap year, else zero. */
78
#define leap(y)  (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
79
 
80
/* Number of leap years from EPOCH_YEAR  to `y' (not including `y' itself). */
81
#define _P4      ((EPOCH_YEAR / 4) * 4 + 1)
82
#define _P100    ((EPOCH_YEAR / 100) * 100 + 1)
83
#define _P400    ((EPOCH_YEAR / 400) * 400 + 1)
84
#define nleap(y) (((y) - _P4) / 4 - ((y) - _P100) / 100 + ((y) - _P400) / 400)
85
 
86
/* Length of month `m' (0 .. 11) */
87
#define monthlen(m, y) (yr_days[0][(m)+1] - yr_days[0][m] + \
88
                        ((m) == 1 && leap(y)))
89
 
90
/* internal module-level constants */
91
#ifndef IZ_MKTIME_ONLY
92
static ZCONST char  gmt[] = "GMT";
93
static ZCONST int    mon_lengths[2][MONSPERYEAR] = {
94
    { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
95
    { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
96
};
97
#endif /* !IZ_MKTIME_ONLY */
98
static ZCONST int    yr_days[2][MONSPERYEAR+1] = {
99
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
100
    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
101
};
102
#ifndef IZ_MKTIME_ONLY
103
static ZCONST int   year_lengths[2] = {
104
    DAYSPERNYEAR, DAYSPERLYEAR
105
};
106
 
107
/* internal variables */
108
static struct state statism;
109
 
110
 
111
/* prototypes of static functions */
112
static time_t transtime OF((ZCONST time_t janfirst, ZCONST int year,
113
                            ZCONST struct rule * ZCONST rulep,
114
                            ZCONST long offset));
115
static void generate_transitions OF((register struct state * ZCONST sp,
116
                                     ZCONST struct rule * ZCONST start,
117
                                     ZCONST struct rule * ZCONST end));
118
static ZCONST char *getzname OF((ZCONST char *strp));
119
static ZCONST char *getnum OF((ZCONST char *strp, int * ZCONST nump,
120
                               ZCONST int min, ZCONST int max));
121
static ZCONST char *getsecs OF((ZCONST char *strp, long * ZCONST secsp));
122
static ZCONST char *getoffset OF((ZCONST char *strp, long * ZCONST offsetp));
123
static ZCONST char *getrule OF((ZCONST char *strp, struct rule * ZCONST rulep));
124
static int Parse_TZ OF((ZCONST char *name, register struct state * ZCONST sp));
125
 
126
 
127
static time_t transtime(janfirst, year, rulep, offset)
128
     ZCONST time_t janfirst;
129
     ZCONST int year;
130
     ZCONST struct rule * ZCONST rulep;
131
     ZCONST long offset;
132
{
133
    register int    leapyear;
134
    register time_t value;
135
    register int    i;
136
    int             d, m1, yy0, yy1, yy2, dow;
137
 
138
    value = 0;
139
    leapyear = leap(year);
140
    switch (rulep->r_type) {
141
 
142
    case JULIAN_DAY:
143
        /*
144
        ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
145
        ** years.
146
        ** In non-leap years, or if the day number is 59 or less, just
147
        ** add SECSPERDAY times the day number-1 to the time of
148
        ** January 1, midnight, to get the day.
149
        */
150
        value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
151
        if (leapyear && rulep->r_day >= 60)
152
            value += SECSPERDAY;
153
        break;
154
 
155
    case DAY_OF_YEAR:
156
        /*
157
        ** n - day of year.
158
        ** Just add SECSPERDAY times the day number to the time of
159
        ** January 1, midnight, to get the day.
160
        */
161
        value = janfirst + rulep->r_day * SECSPERDAY;
162
        break;
163
 
164
    case MONTH_NTH_DAY_OF_WEEK:
165
        /*
166
        ** Mm.n.d - nth "dth day" of month m.
167
        */
168
        value = janfirst;
169
/*
170
        for (i = 0; i < rulep->r_mon - 1; ++i)
171
            value += mon_lengths[leapyear][i] * SECSPERDAY;
172
*/
173
        value += yr_days[leapyear][rulep->r_mon - 1] * SECSPERDAY;
174
 
175
        /*
176
        ** Use Zeller's Congruence to get day-of-week of first day of
177
        ** month.
178
        */
179
        m1 = (rulep->r_mon + 9) % 12 + 1;
180
        yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
181
        yy1 = yy0 / 100;
182
        yy2 = yy0 % 100;
183
        dow = ((26 * m1 - 2) / 10 +
184
            1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
185
        if (dow < 0)
186
            dow += DAYSPERWEEK;
187
 
188
        /*
189
        ** "dow" is the day-of-week of the first day of the month.  Get
190
        ** the day-of-month (zero-origin) of the first "dow" day of the
191
        ** month.
192
        */
193
        d = rulep->r_day - dow;
194
        if (d < 0)
195
            d += DAYSPERWEEK;
196
        for (i = 1; i < rulep->r_week; ++i) {
197
            if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1])
198
                break;
199
            d += DAYSPERWEEK;
200
        }
201
 
202
        /*
203
        ** "d" is the day-of-month (zero-origin) of the day we want.
204
        */
205
        value += d * SECSPERDAY;
206
        break;
207
    }
208
 
209
    /*
210
    ** "value" is the Epoch-relative time of 00:00:00 UTC on the day in
211
    ** question.  To get the Epoch-relative time of the specified local
212
    ** time on that day, add the transition time and the current offset
213
    ** from UTC.
214
    */
215
    return value + rulep->r_time + offset;
216
}
217
 
218
static void generate_transitions(sp, start, end)
219
     register struct state * ZCONST sp;
220
     ZCONST struct rule * ZCONST start;
221
     ZCONST struct rule * ZCONST end;
222
{
223
    register int             year;
224
    register time_t          janfirst;
225
    time_t                   starttime;
226
    time_t                   endtime;
227
    long                     stdoffset = -sp->ttis[0].tt_gmtoff;
228
    long                     dstoffset = -sp->ttis[1].tt_gmtoff;
229
    register time_t *        atp;
230
    register unsigned char * typep;
231
 
232
    /*
233
    ** Two transitions per year, from EPOCH_YEAR to LAST_GOOD_YEAR.
234
    */
235
    sp->timecnt = 2 * (LAST_GOOD_YEAR - EPOCH_YEAR + 1);
236
    atp = sp->ats;
237
    typep = sp->types;
238
    janfirst = 0;
239
    for (year = EPOCH_YEAR; year <= LAST_GOOD_YEAR; ++year) {
240
        starttime = transtime(janfirst, year, start, stdoffset);
241
        endtime = transtime(janfirst, year, end, dstoffset);
242
        if (starttime > endtime) {
243
            *atp++ = endtime;
244
            *typep++ = 0;   /* DST ends */
245
            *atp++ = starttime;
246
            *typep++ = 1;   /* DST begins */
247
        } else {
248
            *atp++ = starttime;
249
            *typep++ = 1;   /* DST begins */
250
            *atp++ = endtime;
251
            *typep++ = 0;   /* DST ends */
252
        }
253
        janfirst += year_lengths[leap(year)] * SECSPERDAY;
254
    }
255
}
256
 
257
static ZCONST char *getzname(strp)
258
     ZCONST char *strp;
259
{
260
    register char   c;
261
 
262
    while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
263
        c != '+')
264
            ++strp;
265
    return strp;
266
}
267
 
268
static ZCONST char *getnum(strp, nump, min, max)
269
     ZCONST char *strp;
270
     int * ZCONST nump;
271
     ZCONST int min;
272
     ZCONST int max;
273
{
274
    register char   c;
275
    register int    num;
276
 
277
    if (strp == NULL || !isdigit(c = *strp))
278
        return NULL;
279
    num = 0;
280
    do {
281
        num = num * 10 + (c - '0');
282
        if (num > max)
283
            return NULL;    /* illegal value */
284
        c = *++strp;
285
    } while (isdigit(c));
286
    if (num < min)
287
        return NULL;        /* illegal value */
288
    *nump = num;
289
    return strp;
290
}
291
 
292
static ZCONST char *getsecs(strp, secsp)
293
     ZCONST char *strp;
294
     long * ZCONST secsp;
295
{
296
    int num;
297
 
298
    /*
299
    ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
300
    ** "M10.4.6/26", which does not conform to Posix,
301
    ** but which specifies the equivalent of
302
    ** ``02:00 on the first Sunday on or after 23 Oct''.
303
    */
304
    strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
305
    if (strp == NULL)
306
        return NULL;
307
    *secsp = num * (long) SECSPERHOUR;
308
    if (*strp == ':') {
309
        ++strp;
310
        strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
311
        if (strp == NULL)
312
            return NULL;
313
        *secsp += num * SECSPERMIN;
314
        if (*strp == ':') {
315
            ++strp;
316
            /* `SECSPERMIN' allows for leap seconds.  */
317
            strp = getnum(strp, &num, 0, SECSPERMIN);
318
            if (strp == NULL)
319
                return NULL;
320
            *secsp += num;
321
        }
322
    }
323
    return strp;
324
}
325
 
326
static ZCONST char *getoffset(strp, offsetp)
327
     ZCONST char *strp;
328
     long * ZCONST offsetp;
329
{
330
    register int    neg = 0;
331
 
332
    if (*strp == '-') {
333
        neg = 1;
334
        ++strp;
335
    } else if (*strp == '+')
336
        ++strp;
337
    strp = getsecs(strp, offsetp);
338
    if (strp == NULL)
339
        return NULL;        /* illegal time */
340
    if (neg)
341
        *offsetp = -*offsetp;
342
    return strp;
343
}
344
 
345
static ZCONST char *getrule(strp, rulep)
346
     ZCONST char *strp;
347
     struct rule * ZCONST rulep;
348
{
349
    if (*strp == 'J') {
350
        /*
351
        ** Julian day.
352
        */
353
        rulep->r_type = JULIAN_DAY;
354
        ++strp;
355
        strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
356
    } else if (*strp == 'M') {
357
        /*
358
        ** Month, week, day.
359
        */
360
        rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
361
        ++strp;
362
        strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
363
        if (strp == NULL)
364
            return NULL;
365
        if (*strp++ != '.')
366
            return NULL;
367
        strp = getnum(strp, &rulep->r_week, 1, 5);
368
        if (strp == NULL)
369
            return NULL;
370
        if (*strp++ != '.')
371
            return NULL;
372
        strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
373
    } else if (isdigit(*strp)) {
374
        /*
375
        ** Day of year.
376
        */
377
        rulep->r_type = DAY_OF_YEAR;
378
        strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
379
    } else  return NULL;        /* invalid format */
380
    if (strp == NULL)
381
        return NULL;
382
    if (*strp == '/') {
383
        /*
384
        ** Time specified.
385
        */
386
        ++strp;
387
        strp = getsecs(strp, &rulep->r_time);
388
    } else
389
        rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
390
    return strp;
391
}
392
 
393
static int Parse_TZ(name, sp)
394
     ZCONST char *name;
395
     register struct state * ZCONST sp;
396
{
397
    ZCONST char *            stdname;
398
    ZCONST char *            dstname;
399
    size_t                   stdlen;
400
    size_t                   dstlen;
401
    long                     stdoffset;
402
    long                     dstoffset;
403
    register char *          cp;
404
 
405
    dstname = NULL;
406
    stdname = name;
407
    name = getzname(name);
408
    stdlen = name - stdname;
409
    if (stdlen < 3)
410
        return -1;
411
    if (*name == '\0')
412
        return -1;
413
    name = getoffset(name, &stdoffset);
414
    if (name == NULL)
415
        return -1;
416
    if (*name != '\0') {
417
        dstname = name;
418
        name = getzname(name);
419
        dstlen = name - dstname;    /* length of DST zone name */
420
        if (dstlen < 3)
421
            return -1;
422
        if (*name != '\0' && *name != ',' && *name != ';') {
423
            name = getoffset(name, &dstoffset);
424
            if (name == NULL)
425
                return -1;
426
        } else
427
            dstoffset = stdoffset - SECSPERHOUR;
428
        if (*name == '\0')
429
            name = TZDEFRULESTRING;
430
        if (*name == ',' || *name == ';') {
431
            struct rule     start;
432
            struct rule     end;
433
 
434
            ++name;
435
            if ((name = getrule(name, &start)) == NULL)
436
                return -1;
437
            if (*name++ != ',')
438
                return -1;
439
            if ((name = getrule(name, &end)) == NULL)
440
                return -1;
441
            if (*name != '\0')
442
                return -1;
443
            sp->typecnt = 2;    /* standard time and DST */
444
            sp->ttis[0].tt_gmtoff = -stdoffset;
445
            sp->ttis[0].tt_isdst = 0;
446
            sp->ttis[0].tt_abbrind = 0;
447
            sp->ttis[1].tt_gmtoff = -dstoffset;
448
            sp->ttis[1].tt_isdst = 1;
449
            sp->ttis[1].tt_abbrind = stdlen + 1;
450
            generate_transitions(sp, &start, &end);
451
        }
452
    } else {
453
        dstlen = 0;
454
        sp->typecnt = 1;        /* only standard time */
455
        sp->timecnt = 0;
456
        sp->ttis[0].tt_gmtoff = -stdoffset;
457
        sp->ttis[0].tt_isdst = 0;
458
        sp->ttis[0].tt_abbrind = 0;
459
    }
460
    sp->charcnt = stdlen + 1;
461
    if (dstlen != 0)
462
        sp->charcnt += dstlen + 1;
463
    if ((size_t) sp->charcnt > sizeof(sp->chars))
464
        return -1;
465
    cp = sp->chars;
466
    (void) strncpy(cp, stdname, stdlen);
467
    cp += stdlen;
468
    *cp++ = '\0';
469
    if (dstlen != 0) {
470
        (void) strncpy(cp, dstname, dstlen);
471
        *(cp + dstlen) = '\0';
472
    }
473
    return 0;
474
}
475
 
476
void tzset()
477
{
478
    char *TZstring;
479
    int dstfirst;
480
    static char *old_TZstring = NULL;
481
 
482
    TZstring = getenv("TZ");    /* read TZ envvar */
483
    if (old_TZstring && TZstring && !strcmp(old_TZstring, TZstring))
484
        /* do not repeatedly parse an unchanged TZ specification */
485
        return;
486
    if ((TZstring && TZstring[0] && Parse_TZ(TZstring, &statism) == 0)
487
                || IZTZ_GETLOCALETZINFO(&statism, generate_transitions)
488
                || Parse_TZ(gmt, &statism) == 0) {
489
        daylight  = statism.typecnt > 1;
490
        dstfirst  = daylight && statism.ttis[0].tt_isdst && !statism.ttis[1].tt_isdst;
491
        timezone  = -statism.ttis[dstfirst].tt_gmtoff;
492
        tzname[0] = statism.chars + statism.ttis[dstfirst].tt_abbrind;
493
        tzname[1] = statism.chars + statism.ttis[!dstfirst].tt_abbrind;
494
        real_timezone_is_set = TRUE;
495
        if (TZstring) {
496
            if (old_TZstring)
497
                old_TZstring = realloc(old_TZstring, strlen(TZstring) + 1);
498
            else
499
                old_TZstring = malloc(strlen(TZstring) + 1);
500
            if (old_TZstring)
501
                strcpy(old_TZstring, TZstring);
502
        }
503
    } else {
504
        timezone = 0;   /* default is GMT0 which means no offsets */
505
        daylight = 0;   /* from local system time                 */
506
        real_timezone_is_set = FALSE;
507
        if (old_TZstring) {
508
            free(old_TZstring);
509
            old_TZstring = NULL;
510
        }
511
    }
512
#ifdef IZTZ_SETLOCALTZINFO
513
    /* Some SAS/C library functions, e.g. stat(), call library       */
514
    /* __tzset() themselves. So envvar TZ *must* exist in order to   */
515
    /* to get the right offset from GMT.  XXX  TRY HARD to fix this! */
516
    set_TZ(timezone, daylight);
517
#endif /* IZTZ_SETLOCALTZINFO */
518
}
519
 
520
/* XXX  Does this also help SAS/C library work? */
521
void __tzset()
522
{
523
    if (!real_timezone_is_set) tzset();
524
}
525
 
526
static struct tm _tmbuf;
527
 
528
struct tm *gmtime(when)
529
     ZCONST time_t *when;
530
{
531
    long days = *when / SECSPERDAY;
532
    long secs = *when % SECSPERDAY;
533
    int isleap;
534
 
535
    memset(&_tmbuf, 0, sizeof(_tmbuf));   /* get any nonstandard fields */
536
    _tmbuf.tm_wday = (days + EPOCH_WDAY) % 7;
537
    _tmbuf.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
538
    isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE);
539
    while (days >= year_lengths[isleap]) {
540
        days -= year_lengths[isleap];
541
        _tmbuf.tm_year++;
542
        isleap = leap(_tmbuf.tm_year + TM_YEAR_BASE);
543
    }
544
    _tmbuf.tm_mon = 0;
545
    _tmbuf.tm_yday = days;
546
    while (days >= mon_lengths[isleap][_tmbuf.tm_mon])
547
        days -= mon_lengths[isleap][_tmbuf.tm_mon++];
548
    _tmbuf.tm_mday = days + 1;
549
    _tmbuf.tm_isdst = 0;
550
    _tmbuf.tm_sec = secs % SECSPERMIN;
551
    _tmbuf.tm_min = (secs / SECSPERMIN) % SECSPERMIN;
552
    _tmbuf.tm_hour = secs / SECSPERHOUR;
553
    return &_tmbuf;
554
}
555
 
556
struct tm *localtime(when)
557
     ZCONST time_t *when;
558
{
559
    time_t     localwhen = *when;
560
    int        timetype;
561
    struct tm *ret;
562
 
563
    __tzset();
564
    if (statism.timecnt == 0 || localwhen < statism.ats[0])
565
        timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 &&
566
                   !statism.ttis[1].tt_isdst;
567
    else {
568
        for (timetype = 1; timetype < statism.timecnt; ++timetype)
569
            if (localwhen < statism.ats[timetype])
570
                break;
571
        timetype = statism.types[timetype - 1];
572
    }
573
    localwhen += statism.ttis[timetype].tt_gmtoff;
574
    ret = gmtime(&localwhen);
575
    ret->tm_isdst = statism.ttis[timetype].tt_isdst;
576
    return ret;
577
}
578
 
579
#ifdef NEED__ISINDST
580
int _isindst(tb)
581
    struct tm *tb;
582
{
583
    time_t     localt;          /* time_t equivalent of given tm struct */
584
    time_t     univt;           /* assumed UTC value of given time */
585
    long       tzoffset_adj;    /* timezone-adjustment `remainder' */
586
    int        bailout_cnt;     /* counter of tries for tz correction */
587
    int        timetype;
588
 
589
    __tzset();
590
 
591
    /* when DST is unsupported in current timezone, DST is always off */
592
    if (statism.typecnt <= 1) return FALSE;
593
 
594
    localt = mkgmtime(tb);
595
    if (localt == (time_t)-1)
596
        /* specified time is out-of-range, default to FALSE */
597
        return FALSE;
598
 
599
    univt = localt - statism.ttis[0].tt_gmtoff;
600
    bailout_cnt = 3;
601
    do {
602
        if (statism.timecnt == 0 || univt < statism.ats[0])
603
            timetype = statism.ttis[0].tt_isdst && statism.typecnt > 1 &&
604
                       !statism.ttis[1].tt_isdst;
605
        else {
606
            for (timetype = 1; timetype < statism.timecnt; ++timetype)
607
                if (univt < statism.ats[timetype])
608
                    break;
609
            timetype = statism.types[timetype - 1];
610
        }
611
        if ((tzoffset_adj = localt - univt - statism.ttis[timetype].tt_gmtoff)
612
            == 0L)
613
            break;
614
        univt += tzoffset_adj;
615
    } while (--bailout_cnt > 0);
616
 
617
    /* return TRUE when DST is active at given time */
618
    return (statism.ttis[timetype].tt_isdst);
619
}
620
#endif /* NEED__ISINDST */
621
#endif /* !IZ_MKTIME_ONLY */
622
 
623
/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
624
   of the local time and date in the exploded time structure `tm',
625
   adjust out of range fields in `tm' and set `tm->tm_yday', `tm->tm_wday'.
626
   If `tm->tm_isdst < 0' was passed to mktime(), the correct setting of
627
   tm_isdst is determined and returned. Otherwise, mktime() assumes this
628
   field as valid; its information is used when converting local time
629
   to UTC.
630
   Return -1 if time in `tm' cannot be represented as time_t value. */
631
 
632
time_t mktime(tm)
633
     struct tm *tm;
634
{
635
  struct tm *ltm;               /* Local time. */
636
  time_t loctime;               /* The time_t value of local time. */
637
  time_t then;                  /* The time to return. */
638
  long tzoffset_adj;            /* timezone-adjustment `remainder' */
639
  int bailout_cnt;              /* counter of tries for tz correction */
640
  int save_isdst;               /* Copy of the tm->isdst input value */
641
 
642
  save_isdst = tm->tm_isdst;
643
  loctime = mkgmtime(tm);
644
  if (loctime == -1) {
645
    tm->tm_isdst = save_isdst;
646
    return (time_t)-1;
647
  }
648
 
649
  /* Correct for the timezone and any daylight savings time.
650
     The correction is verified and repeated when not correct, to
651
     take into account the rare case that a change to or from daylight
652
     savings time occurs between when it is the time in `tm' locally
653
     and when it is that time in Greenwich. After the second correction,
654
     the "timezone & daylight" offset should be correct in all cases. To
655
     be sure, we allow a third try, but then the loop is stopped. */
656
  bailout_cnt = 3;
657
  then = loctime;
658
  do {
659
    ltm = localtime(&then);
660
    if (ltm == (struct tm *)NULL ||
661
        (tzoffset_adj = loctime - mkgmtime(ltm)) == 0L)
662
      break;
663
    then += tzoffset_adj;
664
  } while (--bailout_cnt > 0);
665
 
666
  if (ltm == (struct tm *)NULL || tzoffset_adj != 0L) {
667
    /* Signal failure if timezone adjustment did not converge. */
668
    tm->tm_isdst = save_isdst;
669
    return (time_t)-1;
670
  }
671
 
672
  if (save_isdst >= 0) {
673
    if (ltm->tm_isdst  && !save_isdst)
674
    {
675
      if (then + 3600 < then)
676
        then = (time_t)-1;
677
      else
678
        then += 3600;
679
    }
680
    else if (!ltm->tm_isdst && save_isdst)
681
    {
682
      if (then - 3600 > then)
683
        then = (time_t)-1;
684
      else
685
        then -= 3600;
686
    }
687
    ltm->tm_isdst = save_isdst;
688
  }
689
 
690
  if (tm != ltm)  /* `tm' may already point to localtime's internal storage */
691
    *tm = *ltm;
692
 
693
  return then;
694
}
695
 
696
 
697
#ifndef NO_TIME_T_MAX
698
   /* Provide default values for the upper limit of the time_t range.
699
      These are the result of the decomposition into a `struct tm' for
700
      the time value 0xFFFFFFFEL ( = (time_t)-2 ).
701
      Note: `(time_t)-1' is reserved for "invalid time"!  */
702
#  ifndef TM_YEAR_MAX
703
#    define TM_YEAR_MAX         2106
704
#  endif
705
#  ifndef TM_MON_MAX
706
#    define TM_MON_MAX          1       /* February */
707
#  endif
708
#  ifndef TM_MDAY_MAX
709
#    define TM_MDAY_MAX         7
710
#  endif
711
#  ifndef TM_HOUR_MAX
712
#    define TM_HOUR_MAX         6
713
#  endif
714
#  ifndef TM_MIN_MAX
715
#    define TM_MIN_MAX          28
716
#  endif
717
#  ifndef TM_SEC_MAX
718
#    define TM_SEC_MAX          14
719
#  endif
720
#endif /* NO_TIME_T_MAX */
721
 
722
/* Adjusts out-of-range values for `tm' field `tm_member'. */
723
#define ADJUST_TM(tm_member, tm_carry, modulus) \
724
  if ((tm_member) < 0) { \
725
    tm_carry -= (1 - ((tm_member)+1) / (modulus)); \
726
    tm_member = (modulus-1) + (((tm_member)+1) % (modulus)); \
727
  } else if ((tm_member) >= (modulus)) { \
728
    tm_carry += (tm_member) / (modulus); \
729
    tm_member = (tm_member) % (modulus); \
730
  }
731
 
732
/* Return the equivalent in seconds past 12:00:00 a.m. Jan 1, 1970 GMT
733
   of the Greenwich Mean time and date in the exploded time structure `tm'.
734
   This function does always put back normalized values into the `tm' struct,
735
   parameter, including the calculated numbers for `tm->tm_yday',
736
   `tm->tm_wday', and `tm->tm_isdst'.
737
   Returns -1 if the time in the `tm' parameter cannot be represented
738
   as valid `time_t' number. */
739
 
740
time_t mkgmtime(tm)
741
     struct tm *tm;
742
{
743
  int years, months, days, hours, minutes, seconds;
744
 
745
  years = tm->tm_year + TM_YEAR_BASE;   /* year - 1900 -> year */
746
  months = tm->tm_mon;                  /* 0..11 */
747
  days = tm->tm_mday - 1;               /* 1..31 -> 0..30 */
748
  hours = tm->tm_hour;                  /* 0..23 */
749
  minutes = tm->tm_min;                 /* 0..59 */
750
  seconds = tm->tm_sec;                 /* 0..61 in ANSI C. */
751
 
752
  ADJUST_TM(seconds, minutes, 60)
753
  ADJUST_TM(minutes, hours, 60)
754
  ADJUST_TM(hours, days, 24)
755
  ADJUST_TM(months, years, 12)
756
  if (days < 0)
757
    do {
758
      if (--months < 0) {
759
        --years;
760
        months = 11;
761
      }
762
      days += monthlen(months, years);
763
    } while (days < 0);
764
  else
765
    while (days >= monthlen(months, years)) {
766
      days -= monthlen(months, years);
767
      if (++months >= 12) {
768
        ++years;
769
        months = 0;
770
      }
771
    }
772
 
773
  /* Restore adjusted values in tm structure */
774
  tm->tm_year = years - TM_YEAR_BASE;
775
  tm->tm_mon = months;
776
  tm->tm_mday = days + 1;
777
  tm->tm_hour = hours;
778
  tm->tm_min = minutes;
779
  tm->tm_sec = seconds;
780
 
781
  /* Set `days' to the number of days into the year. */
782
  days += YDAYS(months, years);
783
  tm->tm_yday = days;
784
 
785
  /* Now calculate `days' to the number of days since Jan 1, 1970. */
786
  days = (unsigned)days + 365 * (unsigned)(years - EPOCH_YEAR) +
787
         (unsigned)(nleap (years));
788
  tm->tm_wday = ((unsigned)days + EPOCH_WDAY) % 7;
789
  tm->tm_isdst = 0;
790
 
791
  if (years < EPOCH_YEAR)
792
    return (time_t)-1;
793
 
794
#if (defined(TM_YEAR_MAX) && defined(TM_MON_MAX) && defined(TM_MDAY_MAX))
795
#if (defined(TM_HOUR_MAX) && defined(TM_MIN_MAX) && defined(TM_SEC_MAX))
796
  if (years > TM_YEAR_MAX ||
797
      (years == TM_YEAR_MAX &&
798
       (tm->tm_yday > (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) ||
799
        (tm->tm_yday == (YDAYS(TM_MON_MAX, TM_YEAR_MAX) + (TM_MDAY_MAX - 1)) &&
800
         (hours > TM_HOUR_MAX ||
801
          (hours == TM_HOUR_MAX &&
802
           (minutes > TM_MIN_MAX ||
803
            (minutes == TM_MIN_MAX && seconds > TM_SEC_MAX) )))))))
804
    return (time_t)-1;
805
#endif
806
#endif
807
 
808
  return (time_t)(SECSPERDAY * (unsigned long)(unsigned)days +
809
                  SECSPERHOUR * (unsigned long)hours +
810
                  (unsigned long)(SECSPERMIN * minutes + seconds));
811
}
812
 
813
#endif /* __timezone_c */