Annotation of 43BSDReno/lib/libc/gen/ctime.c, revision 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.