Annotation of 43BSDReno/lib/libc/gen/ctime.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1987, 1989 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * This code is derived from software contributed to Berkeley by
                      6:  * Arthur David Olson of the National Cancer Institute.
                      7:  *
                      8:  * Redistribution and use in source and binary forms are permitted provided
                      9:  * that: (1) source distributions retain this entire copyright notice and
                     10:  * comment, and (2) distributions including binaries display the following
                     11:  * acknowledgement:  ``This product includes software developed by the
                     12:  * University of California, Berkeley and its contributors'' in the
                     13:  * documentation or other materials provided with the distribution and in
                     14:  * all advertising materials mentioning features or use of this software.
                     15:  * Neither the name of the University nor the names of its contributors may
                     16:  * be used to endorse or promote products derived from this software without
                     17:  * specific prior written permission.
                     18:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     19:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     20:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     21:  */
                     22: 
                     23: #if defined(LIBC_SCCS) && !defined(lint)
                     24: static char sccsid[] = "@(#)ctime.c    5.23 (Berkeley) 6/22/90";
                     25: #endif /* LIBC_SCCS and not lint */
                     26: 
                     27: /*
                     28: ** Leap second handling from Bradley White ([email protected]).
                     29: ** POSIX-style TZ environment variable handling from Guy Harris
                     30: ** ([email protected]).
                     31: */
                     32: 
                     33: /*LINTLIBRARY*/
                     34: 
                     35: #include <sys/param.h>
                     36: #include <fcntl.h>
                     37: #include <time.h>
                     38: #include <tzfile.h>
                     39: #include <string.h>
                     40: #include <ctype.h>
                     41: #include <stdio.h>
                     42: 
                     43: #ifdef __STDC__
                     44: #include <stdlib.h>
                     45: 
                     46: #define P(s)           s
                     47: #define alloc_size_t   size_t
                     48: #define qsort_size_t   size_t
                     49: #define fread_size_t   size_t
                     50: #define fwrite_size_t  size_t
                     51: 
                     52: #else /* !defined __STDC__ */
                     53: 
                     54: #define P(s)           ()
                     55: #define const
                     56: #define volatile
                     57: 
                     58: typedef char *         genericptr_t;
                     59: typedef unsigned       alloc_size_t;
                     60: typedef int            qsort_size_t;
                     61: typedef int            fread_size_t;
                     62: typedef int            fwrite_size_t;
                     63: 
                     64: extern char *  calloc();
                     65: extern char *  malloc();
                     66: extern char *  realloc();
                     67: extern char *  getenv();
                     68: 
                     69: #endif /* !defined __STDC__ */
                     70: 
                     71: extern time_t  time();
                     72: 
                     73: #define FILENAME_MAX   MAXPATHLEN
                     74: #define ACCESS_MODE    O_RDONLY
                     75: #define OPEN_MODE      O_RDONLY
                     76: 
                     77: #ifndef WILDABBR
                     78: /*
                     79: ** Someone might make incorrect use of a time zone abbreviation:
                     80: **     1.      They might reference tzname[0] before calling tzset (explicitly
                     81: **             or implicitly).
                     82: **     2.      They might reference tzname[1] before calling tzset (explicitly
                     83: **             or implicitly).
                     84: **     3.      They might reference tzname[1] after setting to a time zone
                     85: **             in which Daylight Saving Time is never observed.
                     86: **     4.      They might reference tzname[0] after setting to a time zone
                     87: **             in which Standard Time is never observed.
                     88: **     5.      They might reference tm.TM_ZONE after calling offtime.
                     89: ** What's best to do in the above cases is open to debate;
                     90: ** for now, we just set things up so that in any of the five cases
                     91: ** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
                     92: ** string "tzname[0] used before set", and similarly for the other cases.
                     93: ** And another:  initialize tzname[0] to "ERA", with an explanation in the
                     94: ** manual page of what this "time zone abbreviation" means (doing this so
                     95: ** that tzname[0] has the "normal" length of three characters).
                     96: */
                     97: #define WILDABBR       "   "
                     98: #endif /* !defined WILDABBR */
                     99: 
                    100: #ifndef TRUE
                    101: #define TRUE           1
                    102: #define FALSE          0
                    103: #endif /* !defined TRUE */
                    104: 
                    105: static const char GMT[] = "GMT";
                    106: 
                    107: struct ttinfo {                                /* time type information */
                    108:        long            tt_gmtoff;      /* GMT offset in seconds */
                    109:        int             tt_isdst;       /* used to set tm_isdst */
                    110:        int             tt_abbrind;     /* abbreviation list index */
                    111:        int             tt_ttisstd;     /* TRUE if transition is std time */
                    112: };
                    113: 
                    114: struct lsinfo {                                /* leap second information */
                    115:        time_t          ls_trans;       /* transition time */
                    116:        long            ls_corr;        /* correction to apply */
                    117: };
                    118: 
                    119: struct state {
                    120:        int             leapcnt;
                    121:        int             timecnt;
                    122:        int             typecnt;
                    123:        int             charcnt;
                    124:        time_t          ats[TZ_MAX_TIMES];
                    125:        unsigned char   types[TZ_MAX_TIMES];
                    126:        struct ttinfo   ttis[TZ_MAX_TYPES];
                    127:        char            chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ?
                    128:                                TZ_MAX_CHARS + 1 : sizeof GMT];
                    129:        struct lsinfo   lsis[TZ_MAX_LEAPS];
                    130: };
                    131: 
                    132: struct rule {
                    133:        int             r_type;         /* type of rule--see below */
                    134:        int             r_day;          /* day number of rule */
                    135:        int             r_week;         /* week number of rule */
                    136:        int             r_mon;          /* month number of rule */
                    137:        long            r_time;         /* transition time of rule */
                    138: };
                    139: 
                    140: #define        JULIAN_DAY              0       /* Jn - Julian day */
                    141: #define        DAY_OF_YEAR             1       /* n - day of year */
                    142: #define        MONTH_NTH_DAY_OF_WEEK   2       /* Mm.n.d - month, week, day of week */
                    143: 
                    144: /*
                    145: ** Prototypes for static functions.
                    146: */
                    147: 
                    148: static long            detzcode P((const char * codep));
                    149: static const char *    getzname P((const char * strp));
                    150: static const char *    getnum P((const char * strp, int * nump, int min,
                    151:                                int max));
                    152: static const char *    getsecs P((const char * strp, long * secsp));
                    153: static const char *    getoffset P((const char * strp, long * offsetp));
                    154: static const char *    getrule P((const char * strp, struct rule * rulep));
                    155: static void            gmtload P((struct state * sp));
                    156: static void            gmtsub P((const time_t * timep, long offset,
                    157:                                struct tm * tmp));
                    158: static void            localsub P((const time_t * timep, long offset,
                    159:                                struct tm * tmp));
                    160: static void            normalize P((int * tensptr, int * unitsptr, int base));
                    161: static void            settzname P((void));
                    162: static time_t          time1 P((struct tm * tmp, void (* funcp)(),
                    163:                                long offset));
                    164: static time_t          time2 P((struct tm *tmp, void (* funcp)(),
                    165:                                long offset, int * okayp));
                    166: static void            timesub P((const time_t * timep, long offset,
                    167:                                const struct state * sp, struct tm * tmp));
                    168: static int             tmcomp P((const struct tm * atmp,
                    169:                                const struct tm * btmp));
                    170: static time_t          transtime P((time_t janfirst, int year,
                    171:                                const struct rule * rulep, long offset));
                    172: static int             tzload P((const char * name, struct state * sp));
                    173: static int             tzparse P((const char * name, struct state * sp,
                    174:                                int lastditch));
                    175: 
                    176: #ifdef ALL_STATE
                    177: static struct state *  lclptr;
                    178: static struct state *  gmtptr;
                    179: #endif /* defined ALL_STATE */
                    180: 
                    181: #ifndef ALL_STATE
                    182: static struct state    lclmem;
                    183: static struct state    gmtmem;
                    184: #define lclptr         (&lclmem)
                    185: #define gmtptr         (&gmtmem)
                    186: #endif /* State Farm */
                    187: 
                    188: static int             lcl_is_set;
                    189: static int             gmt_is_set;
                    190: 
                    191: char *                 tzname[2] = {
                    192:        WILDABBR,
                    193:        WILDABBR
                    194: };
                    195: 
                    196: #ifdef USG_COMPAT
                    197: time_t                 timezone = 0;
                    198: int                    daylight = 0;
                    199: #endif /* defined USG_COMPAT */
                    200: 
                    201: #ifdef ALTZONE
                    202: time_t                 altzone = 0;
                    203: #endif /* defined ALTZONE */
                    204: 
                    205: static long
                    206: detzcode(codep)
                    207: const char * const     codep;
                    208: {
                    209:        register long   result;
                    210:        register int    i;
                    211: 
                    212:        result = 0;
                    213:        for (i = 0; i < 4; ++i)
                    214:                result = (result << 8) | (codep[i] & 0xff);
                    215:        return result;
                    216: }
                    217: 
                    218: static void
                    219: settzname()
                    220: {
                    221:        register const struct state * const     sp = lclptr;
                    222:        register int                            i;
                    223: 
                    224:        tzname[0] = WILDABBR;
                    225:        tzname[1] = WILDABBR;
                    226: #ifdef USG_COMPAT
                    227:        daylight = 0;
                    228:        timezone = 0;
                    229: #endif /* defined USG_COMPAT */
                    230: #ifdef ALTZONE
                    231:        altzone = 0;
                    232: #endif /* defined ALTZONE */
                    233: #ifdef ALL_STATE
                    234:        if (sp == NULL) {
                    235:                tzname[0] = tzname[1] = GMT;
                    236:                return;
                    237:        }
                    238: #endif /* defined ALL_STATE */
                    239:        for (i = 0; i < sp->typecnt; ++i) {
                    240:                register const struct ttinfo * const    ttisp = &sp->ttis[i];
                    241: 
                    242:                tzname[ttisp->tt_isdst] =
                    243:                        (char *) &sp->chars[ttisp->tt_abbrind];
                    244: #ifdef USG_COMPAT
                    245:                if (ttisp->tt_isdst)
                    246:                        daylight = 1;
                    247:                if (i == 0 || !ttisp->tt_isdst)
                    248:                        timezone = -(ttisp->tt_gmtoff);
                    249: #endif /* defined USG_COMPAT */
                    250: #ifdef ALTZONE
                    251:                if (i == 0 || ttisp->tt_isdst)
                    252:                        altzone = -(ttisp->tt_gmtoff);
                    253: #endif /* defined ALTZONE */
                    254:        }
                    255:        /*
                    256:        ** And to get the latest zone names into tzname. . .
                    257:        */
                    258:        for (i = 0; i < sp->timecnt; ++i) {
                    259:                register const struct ttinfo * const    ttisp =
                    260:                                                        &sp->ttis[sp->types[i]];
                    261: 
                    262:                tzname[ttisp->tt_isdst] =
                    263:                        (char *) &sp->chars[ttisp->tt_abbrind];
                    264:        }
                    265: }
                    266: 
                    267: static int
                    268: tzload(name, sp)
                    269: register const char *          name;
                    270: register struct state * const  sp;
                    271: {
                    272:        register const char *   p;
                    273:        register int            i;
                    274:        register int            fid;
                    275: 
                    276:        if (name == NULL && (name = TZDEFAULT) == NULL)
                    277:                return -1;
                    278:        {
                    279:                char            fullname[FILENAME_MAX + 1];
                    280: 
                    281:                if (name[0] == ':')
                    282:                        ++name;
                    283:                if (name[0] != '/') {
                    284:                        if ((p = TZDIR) == NULL)
                    285:                                return -1;
                    286:                        if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
                    287:                                return -1;
                    288:                        (void) strcpy(fullname, p);
                    289:                        (void) strcat(fullname, "/");
                    290:                        (void) strcat(fullname, name);
                    291:                        name = fullname;
                    292:                }
                    293:                if ((fid = open(name, OPEN_MODE)) == -1)
                    294:                        return -1;
                    295:        }
                    296:        {
                    297:                register const struct tzhead *  tzhp;
                    298:                char                            buf[sizeof *sp + sizeof *tzhp];
                    299:                int                             ttisstdcnt;
                    300: 
                    301:                i = read(fid, buf, sizeof buf);
                    302:                if (close(fid) != 0 || i < sizeof *tzhp)
                    303:                        return -1;
                    304:                tzhp = (struct tzhead *) buf;
                    305:                ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
                    306:                sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
                    307:                sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
                    308:                sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
                    309:                sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
                    310:                if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
                    311:                        sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
                    312:                        sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
                    313:                        sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
                    314:                        (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
                    315:                                return -1;
                    316:                if (i < sizeof *tzhp +
                    317:                        sp->timecnt * (4 + sizeof (char)) +
                    318:                        sp->typecnt * (4 + 2 * sizeof (char)) +
                    319:                        sp->charcnt * sizeof (char) +
                    320:                        sp->leapcnt * 2 * 4 +
                    321:                        ttisstdcnt * sizeof (char))
                    322:                                return -1;
                    323:                p = buf + sizeof *tzhp;
                    324:                for (i = 0; i < sp->timecnt; ++i) {
                    325:                        sp->ats[i] = detzcode(p);
                    326:                        p += 4;
                    327:                }
                    328:                for (i = 0; i < sp->timecnt; ++i) {
                    329:                        sp->types[i] = (unsigned char) *p++;
                    330:                        if (sp->types[i] >= sp->typecnt)
                    331:                                return -1;
                    332:                }
                    333:                for (i = 0; i < sp->typecnt; ++i) {
                    334:                        register struct ttinfo *        ttisp;
                    335: 
                    336:                        ttisp = &sp->ttis[i];
                    337:                        ttisp->tt_gmtoff = detzcode(p);
                    338:                        p += 4;
                    339:                        ttisp->tt_isdst = (unsigned char) *p++;
                    340:                        if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
                    341:                                return -1;
                    342:                        ttisp->tt_abbrind = (unsigned char) *p++;
                    343:                        if (ttisp->tt_abbrind < 0 ||
                    344:                                ttisp->tt_abbrind > sp->charcnt)
                    345:                                        return -1;
                    346:                }
                    347:                for (i = 0; i < sp->charcnt; ++i)
                    348:                        sp->chars[i] = *p++;
                    349:                sp->chars[i] = '\0';    /* ensure '\0' at end */
                    350:                for (i = 0; i < sp->leapcnt; ++i) {
                    351:                        register struct lsinfo *        lsisp;
                    352: 
                    353:                        lsisp = &sp->lsis[i];
                    354:                        lsisp->ls_trans = detzcode(p);
                    355:                        p += 4;
                    356:                        lsisp->ls_corr = detzcode(p);
                    357:                        p += 4;
                    358:                }
                    359:                for (i = 0; i < sp->typecnt; ++i) {
                    360:                        register struct ttinfo *        ttisp;
                    361: 
                    362:                        ttisp = &sp->ttis[i];
                    363:                        if (ttisstdcnt == 0)
                    364:                                ttisp->tt_ttisstd = FALSE;
                    365:                        else {
                    366:                                ttisp->tt_ttisstd = *p++;
                    367:                                if (ttisp->tt_ttisstd != TRUE &&
                    368:                                        ttisp->tt_ttisstd != FALSE)
                    369:                                                return -1;
                    370:                        }
                    371:                }
                    372:        }
                    373:        return 0;
                    374: }
                    375: 
                    376: static const int       mon_lengths[2][MONSPERYEAR] = {
                    377:        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
                    378:        31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
                    379: };
                    380: 
                    381: static const int       year_lengths[2] = {
                    382:        DAYSPERNYEAR, DAYSPERLYEAR
                    383: };
                    384: 
                    385: /*
                    386: ** Given a pointer into a time zone string, scan until a character that is not
                    387: ** a valid character in a zone name is found.  Return a pointer to that
                    388: ** character.
                    389: */
                    390: 
                    391: static const char *
                    392: getzname(strp)
                    393: register const char *  strp;
                    394: {
                    395:        register char   c;
                    396: 
                    397:        while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
                    398:                c != '+')
                    399:                        ++strp;
                    400:        return strp;
                    401: }
                    402: 
                    403: /*
                    404: ** Given a pointer into a time zone string, extract a number from that string.
                    405: ** Check that the number is within a specified range; if it is not, return
                    406: ** NULL.
                    407: ** Otherwise, return a pointer to the first character not part of the number.
                    408: */
                    409: 
                    410: static const char *
                    411: getnum(strp, nump, min, max)
                    412: register const char *  strp;
                    413: int * const            nump;
                    414: const int              min;
                    415: const int              max;
                    416: {
                    417:        register char   c;
                    418:        register int    num;
                    419: 
                    420:        if (strp == NULL || !isdigit(*strp))
                    421:                return NULL;
                    422:        num = 0;
                    423:        while ((c = *strp) != '\0' && isdigit(c)) {
                    424:                num = num * 10 + (c - '0');
                    425:                if (num > max)
                    426:                        return NULL;    /* illegal value */
                    427:                ++strp;
                    428:        }
                    429:        if (num < min)
                    430:                return NULL;            /* illegal value */
                    431:        *nump = num;
                    432:        return strp;
                    433: }
                    434: 
                    435: /*
                    436: ** Given a pointer into a time zone string, extract a number of seconds,
                    437: ** in hh[:mm[:ss]] form, from the string.
                    438: ** If any error occurs, return NULL.
                    439: ** Otherwise, return a pointer to the first character not part of the number
                    440: ** of seconds.
                    441: */
                    442: 
                    443: static const char *
                    444: getsecs(strp, secsp)
                    445: register const char *  strp;
                    446: long * const           secsp;
                    447: {
                    448:        int     num;
                    449: 
                    450:        strp = getnum(strp, &num, 0, HOURSPERDAY);
                    451:        if (strp == NULL)
                    452:                return NULL;
                    453:        *secsp = num * SECSPERHOUR;
                    454:        if (*strp == ':') {
                    455:                ++strp;
                    456:                strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
                    457:                if (strp == NULL)
                    458:                        return NULL;
                    459:                *secsp += num * SECSPERMIN;
                    460:                if (*strp == ':') {
                    461:                        ++strp;
                    462:                        strp = getnum(strp, &num, 0, SECSPERMIN - 1);
                    463:                        if (strp == NULL)
                    464:                                return NULL;
                    465:                        *secsp += num;
                    466:                }
                    467:        }
                    468:        return strp;
                    469: }
                    470: 
                    471: /*
                    472: ** Given a pointer into a time zone string, extract an offset, in
                    473: ** [+-]hh[:mm[:ss]] form, from the string.
                    474: ** If any error occurs, return NULL.
                    475: ** Otherwise, return a pointer to the first character not part of the time.
                    476: */
                    477: 
                    478: static const char *
                    479: getoffset(strp, offsetp)
                    480: register const char *  strp;
                    481: long * const           offsetp;
                    482: {
                    483:        register int    neg;
                    484: 
                    485:        if (*strp == '-') {
                    486:                neg = 1;
                    487:                ++strp;
                    488:        } else if (isdigit(*strp) || *strp++ == '+')
                    489:                neg = 0;
                    490:        else    return NULL;            /* illegal offset */
                    491:        strp = getsecs(strp, offsetp);
                    492:        if (strp == NULL)
                    493:                return NULL;            /* illegal time */
                    494:        if (neg)
                    495:                *offsetp = -*offsetp;
                    496:        return strp;
                    497: }
                    498: 
                    499: /*
                    500: ** Given a pointer into a time zone string, extract a rule in the form
                    501: ** date[/time].  See POSIX section 8 for the format of "date" and "time".
                    502: ** If a valid rule is not found, return NULL.
                    503: ** Otherwise, return a pointer to the first character not part of the rule.
                    504: */
                    505: 
                    506: static const char *
                    507: getrule(strp, rulep)
                    508: const char *                   strp;
                    509: register struct rule * const   rulep;
                    510: {
                    511:        if (*strp == 'J') {
                    512:                /*
                    513:                ** Julian day.
                    514:                */
                    515:                rulep->r_type = JULIAN_DAY;
                    516:                ++strp;
                    517:                strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
                    518:        } else if (*strp == 'M') {
                    519:                /*
                    520:                ** Month, week, day.
                    521:                */
                    522:                rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
                    523:                ++strp;
                    524:                strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
                    525:                if (strp == NULL)
                    526:                        return NULL;
                    527:                if (*strp++ != '.')
                    528:                        return NULL;
                    529:                strp = getnum(strp, &rulep->r_week, 1, 5);
                    530:                if (strp == NULL)
                    531:                        return NULL;
                    532:                if (*strp++ != '.')
                    533:                        return NULL;
                    534:                strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
                    535:        } else if (isdigit(*strp)) {
                    536:                /*
                    537:                ** Day of year.
                    538:                */
                    539:                rulep->r_type = DAY_OF_YEAR;
                    540:                strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
                    541:        } else  return NULL;            /* invalid format */
                    542:        if (strp == NULL)
                    543:                return NULL;
                    544:        if (*strp == '/') {
                    545:                /*
                    546:                ** Time specified.
                    547:                */
                    548:                ++strp;
                    549:                strp = getsecs(strp, &rulep->r_time);
                    550:        } else  rulep->r_time = 2 * SECSPERHOUR;        /* default = 2:00:00 */
                    551:        return strp;
                    552: }
                    553: 
                    554: /*
                    555: ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
                    556: ** year, a rule, and the offset from GMT at the time that rule takes effect,
                    557: ** calculate the Epoch-relative time that rule takes effect.
                    558: */
                    559: 
                    560: static time_t
                    561: transtime(janfirst, year, rulep, offset)
                    562: const time_t                           janfirst;
                    563: const int                              year;
                    564: register const struct rule * const     rulep;
                    565: const long                             offset;
                    566: {
                    567:        register int    leapyear;
                    568:        register time_t value;
                    569:        register int    i;
                    570:        int             d, m1, yy0, yy1, yy2, dow;
                    571: 
                    572:        leapyear = isleap(year);
                    573:        switch (rulep->r_type) {
                    574: 
                    575:        case JULIAN_DAY:
                    576:                /*
                    577:                ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
                    578:                ** years.
                    579:                ** In non-leap years, or if the day number is 59 or less, just
                    580:                ** add SECSPERDAY times the day number-1 to the time of
                    581:                ** January 1, midnight, to get the day.
                    582:                */
                    583:                value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
                    584:                if (leapyear && rulep->r_day >= 60)
                    585:                        value += SECSPERDAY;
                    586:                break;
                    587: 
                    588:        case DAY_OF_YEAR:
                    589:                /*
                    590:                ** n - day of year.
                    591:                ** Just add SECSPERDAY times the day number to the time of
                    592:                ** January 1, midnight, to get the day.
                    593:                */
                    594:                value = janfirst + rulep->r_day * SECSPERDAY;
                    595:                break;
                    596: 
                    597:        case MONTH_NTH_DAY_OF_WEEK:
                    598:                /*
                    599:                ** Mm.n.d - nth "dth day" of month m.
                    600:                */
                    601:                value = janfirst;
                    602:                for (i = 0; i < rulep->r_mon - 1; ++i)
                    603:                        value += mon_lengths[leapyear][i] * SECSPERDAY;
                    604: 
                    605:                /*
                    606:                ** Use Zeller's Congruence to get day-of-week of first day of
                    607:                ** month.
                    608:                */
                    609:                m1 = (rulep->r_mon + 9) % 12 + 1;
                    610:                yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
                    611:                yy1 = yy0 / 100;
                    612:                yy2 = yy0 % 100;
                    613:                dow = ((26 * m1 - 2) / 10 +
                    614:                        1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
                    615:                if (dow < 0)
                    616:                        dow += DAYSPERWEEK;
                    617: 
                    618:                /*
                    619:                ** "dow" is the day-of-week of the first day of the month.  Get
                    620:                ** the day-of-month (zero-origin) of the first "dow" day of the
                    621:                ** month.
                    622:                */
                    623:                d = rulep->r_day - dow;
                    624:                if (d < 0)
                    625:                        d += DAYSPERWEEK;
                    626:                for (i = 1; i < rulep->r_week; ++i) {
                    627:                        if (d + DAYSPERWEEK >=
                    628:                                mon_lengths[leapyear][rulep->r_mon - 1])
                    629:                                        break;
                    630:                        d += DAYSPERWEEK;
                    631:                }
                    632: 
                    633:                /*
                    634:                ** "d" is the day-of-month (zero-origin) of the day we want.
                    635:                */
                    636:                value += d * SECSPERDAY;
                    637:                break;
                    638:        }
                    639: 
                    640:        /*
                    641:        ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
                    642:        ** question.  To get the Epoch-relative time of the specified local
                    643:        ** time on that day, add the transition time and the current offset
                    644:        ** from GMT.
                    645:        */
                    646:        return value + rulep->r_time + offset;
                    647: }
                    648: 
                    649: /*
                    650: ** Given a POSIX section 8-style TZ string, fill in the rule tables as
                    651: ** appropriate.
                    652: */
                    653: 
                    654: static int
                    655: tzparse(name, sp, lastditch)
                    656: const char *                   name;
                    657: register struct state * const  sp;
                    658: const int                      lastditch;
                    659: {
                    660:        const char *                    stdname;
                    661:        const char *                    dstname;
                    662:        int                             stdlen;
                    663:        int                             dstlen;
                    664:        long                            stdoffset;
                    665:        long                            dstoffset;
                    666:        register time_t *               atp;
                    667:        register unsigned char *        typep;
                    668:        register char *                 cp;
                    669:        register int                    load_result;
                    670: 
                    671:        stdname = name;
                    672:        if (lastditch) {
                    673:                stdlen = strlen(name);  /* length of standard zone name */
                    674:                name += stdlen;
                    675:                if (stdlen >= sizeof sp->chars)
                    676:                        stdlen = (sizeof sp->chars) - 1;
                    677:        } else {
                    678:                name = getzname(name);
                    679:                stdlen = name - stdname;
                    680:                if (stdlen < 3)
                    681:                        return -1;
                    682:        }
                    683:        if (*name == '\0')
                    684:                return -1;
                    685:        else {
                    686:                name = getoffset(name, &stdoffset);
                    687:                if (name == NULL)
                    688:                        return -1;
                    689:        }
                    690:        load_result = tzload(TZDEFRULES, sp);
                    691:        if (load_result != 0)
                    692:                sp->leapcnt = 0;                /* so, we're off a little */
                    693:        if (*name != '\0') {
                    694:                dstname = name;
                    695:                name = getzname(name);
                    696:                dstlen = name - dstname;        /* length of DST zone name */
                    697:                if (dstlen < 3)
                    698:                        return -1;
                    699:                if (*name != '\0' && *name != ',' && *name != ';') {
                    700:                        name = getoffset(name, &dstoffset);
                    701:                        if (name == NULL)
                    702:                                return -1;
                    703:                } else  dstoffset = stdoffset - SECSPERHOUR;
                    704:                if (*name == ',' || *name == ';') {
                    705:                        struct rule     start;
                    706:                        struct rule     end;
                    707:                        register int    year;
                    708:                        register time_t janfirst;
                    709:                        time_t          starttime;
                    710:                        time_t          endtime;
                    711: 
                    712:                        ++name;
                    713:                        if ((name = getrule(name, &start)) == NULL)
                    714:                                return -1;
                    715:                        if (*name++ != ',')
                    716:                                return -1;
                    717:                        if ((name = getrule(name, &end)) == NULL)
                    718:                                return -1;
                    719:                        if (*name != '\0')
                    720:                                return -1;
                    721:                        sp->typecnt = 2;        /* standard time and DST */
                    722:                        /*
                    723:                        ** Two transitions per year, from EPOCH_YEAR to 2037.
                    724:                        */
                    725:                        sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
                    726:                        if (sp->timecnt > TZ_MAX_TIMES)
                    727:                                return -1;
                    728:                        sp->ttis[0].tt_gmtoff = -dstoffset;
                    729:                        sp->ttis[0].tt_isdst = 1;
                    730:                        sp->ttis[0].tt_abbrind = stdlen + 1;
                    731:                        sp->ttis[1].tt_gmtoff = -stdoffset;
                    732:                        sp->ttis[1].tt_isdst = 0;
                    733:                        sp->ttis[1].tt_abbrind = 0;
                    734:                        atp = sp->ats;
                    735:                        typep = sp->types;
                    736:                        janfirst = 0;
                    737:                        for (year = EPOCH_YEAR; year <= 2037; ++year) {
                    738:                                starttime = transtime(janfirst, year, &start,
                    739:                                        stdoffset);
                    740:                                endtime = transtime(janfirst, year, &end,
                    741:                                        dstoffset);
                    742:                                if (starttime > endtime) {
                    743:                                        *atp++ = endtime;
                    744:                                        *typep++ = 1;   /* DST ends */
                    745:                                        *atp++ = starttime;
                    746:                                        *typep++ = 0;   /* DST begins */
                    747:                                } else {
                    748:                                        *atp++ = starttime;
                    749:                                        *typep++ = 0;   /* DST begins */
                    750:                                        *atp++ = endtime;
                    751:                                        *typep++ = 1;   /* DST ends */
                    752:                                }
                    753:                                janfirst +=
                    754:                                        year_lengths[isleap(year)] * SECSPERDAY;
                    755:                        }
                    756:                } else {
                    757:                        int             sawstd;
                    758:                        int             sawdst;
                    759:                        long            stdfix;
                    760:                        long            dstfix;
                    761:                        long            oldfix;
                    762:                        int             isdst;
                    763:                        register int    i;
                    764: 
                    765:                        if (*name != '\0')
                    766:                                return -1;
                    767:                        if (load_result != 0)
                    768:                                return -1;
                    769:                        /*
                    770:                        ** Compute the difference between the real and
                    771:                        ** prototype standard and summer time offsets
                    772:                        ** from GMT, and put the real standard and summer
                    773:                        ** time offsets into the rules in place of the
                    774:                        ** prototype offsets.
                    775:                        */
                    776:                        sawstd = FALSE;
                    777:                        sawdst = FALSE;
                    778:                        stdfix = 0;
                    779:                        dstfix = 0;
                    780:                        for (i = 0; i < sp->typecnt; ++i) {
                    781:                                if (sp->ttis[i].tt_isdst) {
                    782:                                        oldfix = dstfix;
                    783:                                        dstfix =
                    784:                                            sp->ttis[i].tt_gmtoff + dstoffset;
                    785:                                        if (sawdst && (oldfix != dstfix))
                    786:                                                return -1;
                    787:                                        sp->ttis[i].tt_gmtoff = -dstoffset;
                    788:                                        sp->ttis[i].tt_abbrind = stdlen + 1;
                    789:                                        sawdst = TRUE;
                    790:                                } else {
                    791:                                        oldfix = stdfix;
                    792:                                        stdfix =
                    793:                                            sp->ttis[i].tt_gmtoff + stdoffset;
                    794:                                        if (sawstd && (oldfix != stdfix))
                    795:                                                return -1;
                    796:                                        sp->ttis[i].tt_gmtoff = -stdoffset;
                    797:                                        sp->ttis[i].tt_abbrind = 0;
                    798:                                        sawstd = TRUE;
                    799:                                }
                    800:                        }
                    801:                        /*
                    802:                        ** Make sure we have both standard and summer time.
                    803:                        */
                    804:                        if (!sawdst || !sawstd)
                    805:                                return -1;
                    806:                        /*
                    807:                        ** Now correct the transition times by shifting
                    808:                        ** them by the difference between the real and
                    809:                        ** prototype offsets.  Note that this difference
                    810:                        ** can be different in standard and summer time;
                    811:                        ** the prototype probably has a 1-hour difference
                    812:                        ** between standard and summer time, but a different
                    813:                        ** difference can be specified in TZ.
                    814:                        */
                    815:                        isdst = FALSE;  /* we start in standard time */
                    816:                        for (i = 0; i < sp->timecnt; ++i) {
                    817:                                register const struct ttinfo *  ttisp;
                    818: 
                    819:                                /*
                    820:                                ** If summer time is in effect, and the
                    821:                                ** transition time was not specified as
                    822:                                ** standard time, add the summer time
                    823:                                ** offset to the transition time;
                    824:                                ** otherwise, add the standard time offset
                    825:                                ** to the transition time.
                    826:                                */
                    827:                                ttisp = &sp->ttis[sp->types[i]];
                    828:                                sp->ats[i] +=
                    829:                                        (isdst && !ttisp->tt_ttisstd) ?
                    830:                                                dstfix : stdfix;
                    831:                                isdst = ttisp->tt_isdst;
                    832:                        }
                    833:                }
                    834:        } else {
                    835:                dstlen = 0;
                    836:                sp->typecnt = 1;                /* only standard time */
                    837:                sp->timecnt = 0;
                    838:                sp->ttis[0].tt_gmtoff = -stdoffset;
                    839:                sp->ttis[0].tt_isdst = 0;
                    840:                sp->ttis[0].tt_abbrind = 0;
                    841:        }
                    842:        sp->charcnt = stdlen + 1;
                    843:        if (dstlen != 0)
                    844:                sp->charcnt += dstlen + 1;
                    845:        if (sp->charcnt > sizeof sp->chars)
                    846:                return -1;
                    847:        cp = sp->chars;
                    848:        (void) strncpy(cp, stdname, stdlen);
                    849:        cp += stdlen;
                    850:        *cp++ = '\0';
                    851:        if (dstlen != 0) {
                    852:                (void) strncpy(cp, dstname, dstlen);
                    853:                *(cp + dstlen) = '\0';
                    854:        }
                    855:        return 0;
                    856: }
                    857: 
                    858: static void
                    859: gmtload(sp)
                    860: struct state * const   sp;
                    861: {
                    862:        if (tzload(GMT, sp) != 0)
                    863:                (void) tzparse(GMT, sp, TRUE);
                    864: }
                    865: 
                    866: void
                    867: tzset()
                    868: {
                    869:        register const char *   name;
                    870:        void tzsetwall();
                    871: 
                    872:        name = getenv("TZ");
                    873:        if (name == NULL) {
                    874:                tzsetwall();
                    875:                return;
                    876:        }
                    877:        lcl_is_set = TRUE;
                    878: #ifdef ALL_STATE
                    879:        if (lclptr == NULL) {
                    880:                lclptr = (struct state *) malloc(sizeof *lclptr);
                    881:                if (lclptr == NULL) {
                    882:                        settzname();    /* all we can do */
                    883:                        return;
                    884:                }
                    885:        }
                    886: #endif /* defined ALL_STATE */
                    887:        if (*name == '\0') {
                    888:                /*
                    889:                ** User wants it fast rather than right.
                    890:                */
                    891:                lclptr->leapcnt = 0;            /* so, we're off a little */
                    892:                lclptr->timecnt = 0;
                    893:                lclptr->ttis[0].tt_gmtoff = 0;
                    894:                lclptr->ttis[0].tt_abbrind = 0;
                    895:                (void) strcpy(lclptr->chars, GMT);
                    896:        } else if (tzload(name, lclptr) != 0)
                    897:                if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
                    898:                        (void) gmtload(lclptr);
                    899:        settzname();
                    900: }
                    901: 
                    902: void
                    903: tzsetwall()
                    904: {
                    905:        lcl_is_set = TRUE;
                    906: #ifdef ALL_STATE
                    907:        if (lclptr == NULL) {
                    908:                lclptr = (struct state *) malloc(sizeof *lclptr);
                    909:                if (lclptr == NULL) {
                    910:                        settzname();    /* all we can do */
                    911:                        return;
                    912:                }
                    913:        }
                    914: #endif /* defined ALL_STATE */
                    915:        if (tzload((char *) NULL, lclptr) != 0)
                    916:                gmtload(lclptr);
                    917:        settzname();
                    918: }
                    919: 
                    920: /*
                    921: ** The easy way to behave "as if no library function calls" localtime
                    922: ** is to not call it--so we drop its guts into "localsub", which can be
                    923: ** freely called.  (And no, the PANS doesn't require the above behavior--
                    924: ** but it *is* desirable.)
                    925: **
                    926: ** The unused offset argument is for the benefit of mktime variants.
                    927: */
                    928: 
                    929: /*ARGSUSED*/
                    930: static void
                    931: localsub(timep, offset, tmp)
                    932: const time_t * const   timep;
                    933: const long             offset;
                    934: struct tm * const      tmp;
                    935: {
                    936:        register const struct state *   sp;
                    937:        register const struct ttinfo *  ttisp;
                    938:        register int                    i;
                    939:        const time_t                    t = *timep;
                    940: 
                    941:        if (!lcl_is_set)
                    942:                tzset();
                    943:        sp = lclptr;
                    944: #ifdef ALL_STATE
                    945:        if (sp == NULL) {
                    946:                gmtsub(timep, offset, tmp);
                    947:                return;
                    948:        }
                    949: #endif /* defined ALL_STATE */
                    950:        if (sp->timecnt == 0 || t < sp->ats[0]) {
                    951:                i = 0;
                    952:                while (sp->ttis[i].tt_isdst)
                    953:                        if (++i >= sp->typecnt) {
                    954:                                i = 0;
                    955:                                break;
                    956:                        }
                    957:        } else {
                    958:                for (i = 1; i < sp->timecnt; ++i)
                    959:                        if (t < sp->ats[i])
                    960:                                break;
                    961:                i = sp->types[i - 1];
                    962:        }
                    963:        ttisp = &sp->ttis[i];
                    964:        /*
                    965:        ** To get (wrong) behavior that's compatible with System V Release 2.0
                    966:        ** you'd replace the statement below with
                    967:        **      t += ttisp->tt_gmtoff;
                    968:        **      timesub(&t, 0L, sp, tmp);
                    969:        */
                    970:        timesub(&t, ttisp->tt_gmtoff, sp, tmp);
                    971:        tmp->tm_isdst = ttisp->tt_isdst;
                    972:        tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
                    973:        tmp->tm_zone = &sp->chars[ttisp->tt_abbrind];
                    974: }
                    975: 
                    976: struct tm *
                    977: localtime(timep)
                    978: const time_t * const   timep;
                    979: {
                    980:        static struct tm        tm;
                    981: 
                    982:        localsub(timep, 0L, &tm);
                    983:        return &tm;
                    984: }
                    985: 
                    986: /*
                    987: ** gmtsub is to gmtime as localsub is to localtime.
                    988: */
                    989: 
                    990: static void
                    991: gmtsub(timep, offset, tmp)
                    992: const time_t * const   timep;
                    993: const long             offset;
                    994: struct tm * const      tmp;
                    995: {
                    996:        if (!gmt_is_set) {
                    997:                gmt_is_set = TRUE;
                    998: #ifdef ALL_STATE
                    999:                gmtptr = (struct state *) malloc(sizeof *gmtptr);
                   1000:                if (gmtptr != NULL)
                   1001: #endif /* defined ALL_STATE */
                   1002:                        gmtload(gmtptr);
                   1003:        }
                   1004:        timesub(timep, offset, gmtptr, tmp);
                   1005:        /*
                   1006:        ** Could get fancy here and deliver something such as
                   1007:        ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
                   1008:        ** but this is no time for a treasure hunt.
                   1009:        */
                   1010:        if (offset != 0)
                   1011:                tmp->tm_zone = WILDABBR;
                   1012:        else {
                   1013: #ifdef ALL_STATE
                   1014:                if (gmtptr == NULL)
                   1015:                        tmp->TM_ZONE = GMT;
                   1016:                else    tmp->TM_ZONE = gmtptr->chars;
                   1017: #endif /* defined ALL_STATE */
                   1018: #ifndef ALL_STATE
                   1019:                tmp->tm_zone = gmtptr->chars;
                   1020: #endif /* State Farm */
                   1021:        }
                   1022: }
                   1023: 
                   1024: struct tm *
                   1025: gmtime(timep)
                   1026: const time_t * const   timep;
                   1027: {
                   1028:        static struct tm        tm;
                   1029: 
                   1030:        gmtsub(timep, 0L, &tm);
                   1031:        return &tm;
                   1032: }
                   1033: 
                   1034: static void
                   1035: timesub(timep, offset, sp, tmp)
                   1036: const time_t * const                   timep;
                   1037: const long                             offset;
                   1038: register const struct state * const    sp;
                   1039: register struct tm * const             tmp;
                   1040: {
                   1041:        register const struct lsinfo *  lp;
                   1042:        register long                   days;
                   1043:        register long                   rem;
                   1044:        register int                    y;
                   1045:        register int                    yleap;
                   1046:        register const int *            ip;
                   1047:        register long                   corr;
                   1048:        register int                    hit;
                   1049:        register int                    i;
                   1050: 
                   1051:        corr = 0;
                   1052:        hit = FALSE;
                   1053: #ifdef ALL_STATE
                   1054:        i = (sp == NULL) ? 0 : sp->leapcnt;
                   1055: #endif /* defined ALL_STATE */
                   1056: #ifndef ALL_STATE
                   1057:        i = sp->leapcnt;
                   1058: #endif /* State Farm */
                   1059:        while (--i >= 0) {
                   1060:                lp = &sp->lsis[i];
                   1061:                if (*timep >= lp->ls_trans) {
                   1062:                        if (*timep == lp->ls_trans)
                   1063:                                hit = ((i == 0 && lp->ls_corr > 0) ||
                   1064:                                        lp->ls_corr > sp->lsis[i - 1].ls_corr);
                   1065:                        corr = lp->ls_corr;
                   1066:                        break;
                   1067:                }
                   1068:        }
                   1069:        days = *timep / SECSPERDAY;
                   1070:        rem = *timep % SECSPERDAY;
                   1071: #ifdef mc68k
                   1072:        if (*timep == 0x80000000) {
                   1073:                /*
                   1074:                ** A 3B1 muffs the division on the most negative number.
                   1075:                */
                   1076:                days = -24855;
                   1077:                rem = -11648;
                   1078:        }
                   1079: #endif /* mc68k */
                   1080:        rem += (offset - corr);
                   1081:        while (rem < 0) {
                   1082:                rem += SECSPERDAY;
                   1083:                --days;
                   1084:        }
                   1085:        while (rem >= SECSPERDAY) {
                   1086:                rem -= SECSPERDAY;
                   1087:                ++days;
                   1088:        }
                   1089:        tmp->tm_hour = (int) (rem / SECSPERHOUR);
                   1090:        rem = rem % SECSPERHOUR;
                   1091:        tmp->tm_min = (int) (rem / SECSPERMIN);
                   1092:        tmp->tm_sec = (int) (rem % SECSPERMIN);
                   1093:        if (hit)
                   1094:                /*
                   1095:                ** A positive leap second requires a special
                   1096:                ** representation.  This uses "... ??:59:60".
                   1097:                */
                   1098:                ++(tmp->tm_sec);
                   1099:        tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
                   1100:        if (tmp->tm_wday < 0)
                   1101:                tmp->tm_wday += DAYSPERWEEK;
                   1102:        y = EPOCH_YEAR;
                   1103:        if (days >= 0)
                   1104:                for ( ; ; ) {
                   1105:                        yleap = isleap(y);
                   1106:                        if (days < (long) year_lengths[yleap])
                   1107:                                break;
                   1108:                        ++y;
                   1109:                        days = days - (long) year_lengths[yleap];
                   1110:                }
                   1111:        else do {
                   1112:                --y;
                   1113:                yleap = isleap(y);
                   1114:                days = days + (long) year_lengths[yleap];
                   1115:        } while (days < 0);
                   1116:        tmp->tm_year = y - TM_YEAR_BASE;
                   1117:        tmp->tm_yday = (int) days;
                   1118:        ip = mon_lengths[yleap];
                   1119:        for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
                   1120:                days = days - (long) ip[tmp->tm_mon];
                   1121:        tmp->tm_mday = (int) (days + 1);
                   1122:        tmp->tm_isdst = 0;
                   1123:        tmp->tm_gmtoff = offset;
                   1124: }
                   1125: 
                   1126: /*
                   1127: ** A la X3J11
                   1128: */
                   1129: 
                   1130: char *
                   1131: asctime(timeptr)
                   1132: register const struct tm *     timeptr;
                   1133: {
                   1134:        static const char       wday_name[DAYSPERWEEK][3] = {
                   1135:                "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
                   1136:        };
                   1137:        static const char       mon_name[MONSPERYEAR][3] = {
                   1138:                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                   1139:                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
                   1140:        };
                   1141:        static char     result[26];
                   1142: 
                   1143:        (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
                   1144:                wday_name[timeptr->tm_wday],
                   1145:                mon_name[timeptr->tm_mon],
                   1146:                timeptr->tm_mday, timeptr->tm_hour,
                   1147:                timeptr->tm_min, timeptr->tm_sec,
                   1148:                TM_YEAR_BASE + timeptr->tm_year);
                   1149:        return result;
                   1150: }
                   1151: 
                   1152: char *
                   1153: ctime(timep)
                   1154: const time_t * const   timep;
                   1155: {
                   1156:        return asctime(localtime(timep));
                   1157: }
                   1158: 
                   1159: /*
                   1160: ** Adapted from code provided by Robert Elz, who writes:
                   1161: **     The "best" way to do mktime I think is based on an idea of Bob
                   1162: **     Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
                   1163: **     It does a binary search of the time_t space.  Since time_t's are
                   1164: **     just 32 bits, its a max of 32 iterations (even at 64 bits it
                   1165: **     would still be very reasonable).
                   1166: */
                   1167: 
                   1168: #ifndef WRONG
                   1169: #define WRONG  (-1)
                   1170: #endif /* !defined WRONG */
                   1171: 
                   1172: static void
                   1173: normalize(tensptr, unitsptr, base)
                   1174: int * const    tensptr;
                   1175: int * const    unitsptr;
                   1176: const int      base;
                   1177: {
                   1178:        if (*unitsptr >= base) {
                   1179:                *tensptr += *unitsptr / base;
                   1180:                *unitsptr %= base;
                   1181:        } else if (*unitsptr < 0) {
                   1182:                --*tensptr;
                   1183:                *unitsptr += base;
                   1184:                if (*unitsptr < 0) {
                   1185:                        *tensptr -= 1 + (-*unitsptr) / base;
                   1186:                        *unitsptr = base - (-*unitsptr) % base;
                   1187:                }
                   1188:        }
                   1189: }
                   1190: 
                   1191: static int
                   1192: tmcomp(atmp, btmp)
                   1193: register const struct tm * const atmp;
                   1194: register const struct tm * const btmp;
                   1195: {
                   1196:        register int    result;
                   1197: 
                   1198:        if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
                   1199:                (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
                   1200:                (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
                   1201:                (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
                   1202:                (result = (atmp->tm_min - btmp->tm_min)) == 0)
                   1203:                        result = atmp->tm_sec - btmp->tm_sec;
                   1204:        return result;
                   1205: }
                   1206: 
                   1207: static time_t
                   1208: time2(tmp, funcp, offset, okayp)
                   1209: struct tm * const      tmp;
                   1210: void (* const          funcp)();
                   1211: const long             offset;
                   1212: int * const            okayp;
                   1213: {
                   1214:        register const struct state *   sp;
                   1215:        register int                    dir;
                   1216:        register int                    bits;
                   1217:        register int                    i, j ;
                   1218:        register int                    saved_seconds;
                   1219:        time_t                          newt;
                   1220:        time_t                          t;
                   1221:        struct tm                       yourtm, mytm;
                   1222: 
                   1223:        *okayp = FALSE;
                   1224:        yourtm = *tmp;
                   1225:        if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
                   1226:                normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
                   1227:        normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
                   1228:        normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
                   1229:        normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
                   1230:        while (yourtm.tm_mday <= 0) {
                   1231:                --yourtm.tm_year;
                   1232:                yourtm.tm_mday +=
                   1233:                        year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
                   1234:        }
                   1235:        for ( ; ; ) {
                   1236:                i = mon_lengths[isleap(yourtm.tm_year +
                   1237:                        TM_YEAR_BASE)][yourtm.tm_mon];
                   1238:                if (yourtm.tm_mday <= i)
                   1239:                        break;
                   1240:                yourtm.tm_mday -= i;
                   1241:                if (++yourtm.tm_mon >= MONSPERYEAR) {
                   1242:                        yourtm.tm_mon = 0;
                   1243:                        ++yourtm.tm_year;
                   1244:                }
                   1245:        }
                   1246:        saved_seconds = yourtm.tm_sec;
                   1247:        yourtm.tm_sec = 0;
                   1248:        /*
                   1249:        ** Calculate the number of magnitude bits in a time_t
                   1250:        ** (this works regardless of whether time_t is
                   1251:        ** signed or unsigned, though lint complains if unsigned).
                   1252:        */
                   1253:        for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
                   1254:                ;
                   1255:        /*
                   1256:        ** If time_t is signed, then 0 is the median value,
                   1257:        ** if time_t is unsigned, then 1 << bits is median.
                   1258:        */
                   1259:        t = (t < 0) ? 0 : ((time_t) 1 << bits);
                   1260:        for ( ; ; ) {
                   1261:                (*funcp)(&t, offset, &mytm);
                   1262:                dir = tmcomp(&mytm, &yourtm);
                   1263:                if (dir != 0) {
                   1264:                        if (bits-- < 0)
                   1265:                                return WRONG;
                   1266:                        if (bits < 0)
                   1267:                                --t;
                   1268:                        else if (dir > 0)
                   1269:                                t -= (time_t) 1 << bits;
                   1270:                        else    t += (time_t) 1 << bits;
                   1271:                        continue;
                   1272:                }
                   1273:                if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
                   1274:                        break;
                   1275:                /*
                   1276:                ** Right time, wrong type.
                   1277:                ** Hunt for right time, right type.
                   1278:                ** It's okay to guess wrong since the guess
                   1279:                ** gets checked.
                   1280:                */
                   1281:                sp = (const struct state *)
                   1282:                        ((funcp == localsub) ? lclptr : gmtptr);
                   1283: #ifdef ALL_STATE
                   1284:                if (sp == NULL)
                   1285:                        return WRONG;
                   1286: #endif /* defined ALL_STATE */
                   1287:                for (i = 0; i < sp->typecnt; ++i) {
                   1288:                        if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
                   1289:                                continue;
                   1290:                        for (j = 0; j < sp->typecnt; ++j) {
                   1291:                                if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
                   1292:                                        continue;
                   1293:                                newt = t + sp->ttis[j].tt_gmtoff -
                   1294:                                        sp->ttis[i].tt_gmtoff;
                   1295:                                (*funcp)(&newt, offset, &mytm);
                   1296:                                if (tmcomp(&mytm, &yourtm) != 0)
                   1297:                                        continue;
                   1298:                                if (mytm.tm_isdst != yourtm.tm_isdst)
                   1299:                                        continue;
                   1300:                                /*
                   1301:                                ** We have a match.
                   1302:                                */
                   1303:                                t = newt;
                   1304:                                goto label;
                   1305:                        }
                   1306:                }
                   1307:                return WRONG;
                   1308:        }
                   1309: label:
                   1310:        t += saved_seconds;
                   1311:        (*funcp)(&t, offset, tmp);
                   1312:        *okayp = TRUE;
                   1313:        return t;
                   1314: }
                   1315: 
                   1316: static time_t
                   1317: time1(tmp, funcp, offset)
                   1318: struct tm * const      tmp;
                   1319: void (* const          funcp)();
                   1320: const long             offset;
                   1321: {
                   1322:        register time_t                 t;
                   1323:        register const struct state *   sp;
                   1324:        register int                    samei, otheri;
                   1325:        int                             okay;
                   1326: 
                   1327:        if (tmp->tm_isdst > 1)
                   1328:                tmp->tm_isdst = 1;
                   1329:        t = time2(tmp, funcp, offset, &okay);
                   1330:        if (okay || tmp->tm_isdst < 0)
                   1331:                return t;
                   1332:        /*
                   1333:        ** We're supposed to assume that somebody took a time of one type
                   1334:        ** and did some math on it that yielded a "struct tm" that's bad.
                   1335:        ** We try to divine the type they started from and adjust to the
                   1336:        ** type they need.
                   1337:        */
                   1338:        sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
                   1339: #ifdef ALL_STATE
                   1340:        if (sp == NULL)
                   1341:                return WRONG;
                   1342: #endif /* defined ALL_STATE */
                   1343:        for (samei = 0; samei < sp->typecnt; ++samei) {
                   1344:                if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
                   1345:                        continue;
                   1346:                for (otheri = 0; otheri < sp->typecnt; ++otheri) {
                   1347:                        if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
                   1348:                                continue;
                   1349:                        tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
                   1350:                                        sp->ttis[samei].tt_gmtoff;
                   1351:                        tmp->tm_isdst = !tmp->tm_isdst;
                   1352:                        t = time2(tmp, funcp, offset, &okay);
                   1353:                        if (okay)
                   1354:                                return t;
                   1355:                        tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
                   1356:                                        sp->ttis[samei].tt_gmtoff;
                   1357:                        tmp->tm_isdst = !tmp->tm_isdst;
                   1358:                }
                   1359:        }
                   1360:        return WRONG;
                   1361: }
                   1362: 
                   1363: time_t
                   1364: mktime(tmp)
                   1365: struct tm * const      tmp;
                   1366: {
                   1367:        return time1(tmp, localsub, 0L);
                   1368: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.