Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Defines | Functions

pgtz.h File Reference

#include "tzfile.h"
#include "pgtime.h"
Include dependency graph for pgtz.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ttinfo
struct  lsinfo
struct  state
struct  pg_tz

Defines

#define BIGGEST(a, b)   (((a) > (b)) ? (a) : (b))

Functions

int pg_open_tzfile (const char *name, char *canonname)
int tzload (const char *name, char *canonname, struct state *sp, int doextend)
int tzparse (const char *name, struct state *sp, int lastditch)

Define Documentation

#define BIGGEST (   a,
  b 
)    (((a) > (b)) ? (a) : (b))

Definition at line 23 of file pgtz.h.


Function Documentation

int pg_open_tzfile ( const char *  name,
char *  canonname 
)

Definition at line 64 of file findtimezone.c.

References MAXPGPATH, PG_BINARY, pg_TZDIR(), scan_directory_ci(), strlcpy(), and TZ_STRLEN_MAX.

Referenced by tzload().

{
    char        fullname[MAXPGPATH];

    if (canonname)
        strlcpy(canonname, name, TZ_STRLEN_MAX + 1);

    strcpy(fullname, pg_TZDIR());
    if (strlen(fullname) + 1 + strlen(name) >= MAXPGPATH)
        return -1;              /* not gonna fit */
    strcat(fullname, "/");
    strcat(fullname, name);

    return open(fullname, O_RDONLY | PG_BINARY, 0);
}

int tzload ( const char *  name,
char *  canonname,
struct state sp,
int  doextend 
)

Definition at line 153 of file localtime.c.

References state::ats, buf, state::charcnt, state::chars, close, detzcode(), detzcode64(), differ_by_repeat(), FALSE, state::goahead, state::goback, i, state::leapcnt, lsinfo::ls_corr, lsinfo::ls_trans, state::lsis, NULL, pg_open_tzfile(), read, state::timecnt, TRUE, ttinfo::tt_abbrind, ttinfo::tt_gmtoff, ttinfo::tt_isdst, ttinfo::tt_ttisgmt, ttinfo::tt_ttisstd, state::ttis, TYPE_INTEGRAL, TYPE_SIGNED, state::typecnt, state::types, typesequiv(), TZ_MAX_CHARS, TZ_MAX_LEAPS, TZ_MAX_TIMES, TZ_MAX_TYPES, TZDEFAULT, and tzparse().

Referenced by gmtload(), pg_load_tz(), pg_tzenumerate_next(), pg_tzset(), and tzparse().

{
    const char *p;
    int         i;
    int         fid;
    int         stored;
    int         nread;
    union
    {
        struct tzhead tzhead;
        char        buf[2 * sizeof(struct tzhead) +
                                    2 * sizeof *sp +
                                    4 * TZ_MAX_TIMES];
    }           u;

    sp->goback = sp->goahead = FALSE;
    if (name == NULL && (name = TZDEFAULT) == NULL)
        return -1;
    if (name[0] == ':')
        ++name;
    fid = pg_open_tzfile(name, canonname);
    if (fid < 0)
        return -1;
    nread = read(fid, u.buf, sizeof u.buf);
    if (close(fid) != 0 || nread <= 0)
        return -1;
    for (stored = 4; stored <= 8; stored *= 2)
    {
        int         ttisstdcnt;
        int         ttisgmtcnt;

        ttisstdcnt = (int) detzcode(u.tzhead.tzh_ttisstdcnt);
        ttisgmtcnt = (int) detzcode(u.tzhead.tzh_ttisgmtcnt);
        sp->leapcnt = (int) detzcode(u.tzhead.tzh_leapcnt);
        sp->timecnt = (int) detzcode(u.tzhead.tzh_timecnt);
        sp->typecnt = (int) detzcode(u.tzhead.tzh_typecnt);
        sp->charcnt = (int) detzcode(u.tzhead.tzh_charcnt);
        p = u.tzhead.tzh_charcnt + sizeof u.tzhead.tzh_charcnt;
        if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
            sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
            sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
            sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
            (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
            (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
            return -1;
        if (nread - (p - u.buf) <
            sp->timecnt * stored +      /* ats */
            sp->timecnt +       /* types */
            sp->typecnt * 6 +   /* ttinfos */
            sp->charcnt +       /* chars */
            sp->leapcnt * (stored + 4) +        /* lsinfos */
            ttisstdcnt +        /* ttisstds */
            ttisgmtcnt)         /* ttisgmts */
            return -1;
        for (i = 0; i < sp->timecnt; ++i)
        {
            sp->ats[i] = (stored == 4) ? detzcode(p) : detzcode64(p);
            p += stored;
        }
        for (i = 0; i < sp->timecnt; ++i)
        {
            sp->types[i] = (unsigned char) *p++;
            if (sp->types[i] >= sp->typecnt)
                return -1;
        }
        for (i = 0; i < sp->typecnt; ++i)
        {
            struct ttinfo *ttisp;

            ttisp = &sp->ttis[i];
            ttisp->tt_gmtoff = detzcode(p);
            p += 4;
            ttisp->tt_isdst = (unsigned char) *p++;
            if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
                return -1;
            ttisp->tt_abbrind = (unsigned char) *p++;
            if (ttisp->tt_abbrind < 0 ||
                ttisp->tt_abbrind > sp->charcnt)
                return -1;
        }
        for (i = 0; i < sp->charcnt; ++i)
            sp->chars[i] = *p++;
        sp->chars[i] = '\0';    /* ensure '\0' at end */
        for (i = 0; i < sp->leapcnt; ++i)
        {
            struct lsinfo *lsisp;

            lsisp = &sp->lsis[i];
            lsisp->ls_trans = (stored == 4) ? detzcode(p) : detzcode64(p);
            p += stored;
            lsisp->ls_corr = detzcode(p);
            p += 4;
        }
        for (i = 0; i < sp->typecnt; ++i)
        {
            struct ttinfo *ttisp;

            ttisp = &sp->ttis[i];
            if (ttisstdcnt == 0)
                ttisp->tt_ttisstd = FALSE;
            else
            {
                ttisp->tt_ttisstd = *p++;
                if (ttisp->tt_ttisstd != TRUE &&
                    ttisp->tt_ttisstd != FALSE)
                    return -1;
            }
        }
        for (i = 0; i < sp->typecnt; ++i)
        {
            struct ttinfo *ttisp;

            ttisp = &sp->ttis[i];
            if (ttisgmtcnt == 0)
                ttisp->tt_ttisgmt = FALSE;
            else
            {
                ttisp->tt_ttisgmt = *p++;
                if (ttisp->tt_ttisgmt != TRUE &&
                    ttisp->tt_ttisgmt != FALSE)
                    return -1;
            }
        }

        /*
         * Out-of-sort ats should mean we're running on a signed time_t system
         * but using a data file with unsigned values (or vice versa).
         */
        for (i = 0; i < sp->timecnt - 2; ++i)
            if (sp->ats[i] > sp->ats[i + 1])
            {
                ++i;
                if (TYPE_SIGNED(pg_time_t))
                {
                    /*
                     * Ignore the end (easy).
                     */
                    sp->timecnt = i;
                }
                else
                {
                    /*
                     * Ignore the beginning (harder).
                     */
                    int         j;

                    for (j = 0; j + i < sp->timecnt; ++j)
                    {
                        sp->ats[j] = sp->ats[j + i];
                        sp->types[j] = sp->types[j + i];
                    }
                    sp->timecnt = j;
                }
                break;
            }

        /*
         * If this is an old file, we're done.
         */
        if (u.tzhead.tzh_version[0] == '\0')
            break;
        nread -= p - u.buf;
        for (i = 0; i < nread; ++i)
            u.buf[i] = p[i];

        /*
         * If this is a narrow integer time_t system, we're done.
         */
        if (stored >= (int) sizeof(pg_time_t) && TYPE_INTEGRAL(pg_time_t))
            break;
    }
    if (doextend && nread > 2 &&
        u.buf[0] == '\n' && u.buf[nread - 1] == '\n' &&
        sp->typecnt + 2 <= TZ_MAX_TYPES)
    {
        struct state ts;
        int         result;

        u.buf[nread - 1] = '\0';
        result = tzparse(&u.buf[1], &ts, FALSE);
        if (result == 0 && ts.typecnt == 2 &&
            sp->charcnt + ts.charcnt <= TZ_MAX_CHARS)
        {
            for (i = 0; i < 2; ++i)
                ts.ttis[i].tt_abbrind +=
                    sp->charcnt;
            for (i = 0; i < ts.charcnt; ++i)
                sp->chars[sp->charcnt++] =
                    ts.chars[i];
            i = 0;
            while (i < ts.timecnt &&
                   ts.ats[i] <=
                   sp->ats[sp->timecnt - 1])
                ++i;
            while (i < ts.timecnt &&
                   sp->timecnt < TZ_MAX_TIMES)
            {
                sp->ats[sp->timecnt] =
                    ts.ats[i];
                sp->types[sp->timecnt] =
                    sp->typecnt +
                    ts.types[i];
                ++sp->timecnt;
                ++i;
            }
            sp->ttis[sp->typecnt++] = ts.ttis[0];
            sp->ttis[sp->typecnt++] = ts.ttis[1];
        }
    }
    if (sp->timecnt > 1)
    {
        for (i = 1; i < sp->timecnt; ++i)
            if (typesequiv(sp, sp->types[i], sp->types[0]) &&
                differ_by_repeat(sp->ats[i], sp->ats[0]))
            {
                sp->goback = TRUE;
                break;
            }
        for (i = sp->timecnt - 2; i >= 0; --i)
            if (typesequiv(sp, sp->types[sp->timecnt - 1],
                           sp->types[i]) &&
                differ_by_repeat(sp->ats[sp->timecnt - 1],
                                 sp->ats[i]))
            {
                sp->goahead = TRUE;
                break;
            }
    }
    return 0;
}

int tzparse ( const char *  name,
struct state sp,
int  lastditch 
)

Definition at line 711 of file localtime.c.

References state::ats, state::charcnt, state::chars, EPOCH_YEAR, FALSE, getoffset(), getqzname(), getrule(), getzname(), state::goahead, state::goback, i, isleap, state::leapcnt, NULL, state::timecnt, transtime(), ttinfo::tt_abbrind, ttinfo::tt_gmtoff, ttinfo::tt_isdst, ttinfo::tt_ttisgmt, ttinfo::tt_ttisstd, state::ttis, state::typecnt, state::types, TZDEFRULES, tzload(), and year_lengths.

Referenced by gmtload(), pg_load_tz(), pg_tzset(), and tzload().

{
    const char *stdname;
    const char *dstname = NULL;
    size_t      stdlen;
    size_t      dstlen;
    long        stdoffset;
    long        dstoffset;
    pg_time_t  *atp;
    unsigned char *typep;
    char       *cp;
    int         load_result;

    stdname = name;
    if (lastditch)
    {
        stdlen = strlen(name);  /* length of standard zone name */
        name += stdlen;
        if (stdlen >= sizeof sp->chars)
            stdlen = (sizeof sp->chars) - 1;
        stdoffset = 0;

        /*
         * Unlike the original zic library, do NOT invoke tzload() here; we
         * can't assume pg_open_tzfile() is sane yet, and we don't care about
         * leap seconds anyway.
         */
        sp->goback = sp->goahead = FALSE;
        load_result = -1;
    }
    else
    {
        if (*name == '<')
        {
            name++;
            stdname = name;
            name = getqzname(name, '>');
            if (*name != '>')
                return (-1);
            stdlen = name - stdname;
            name++;
        }
        else
        {
            name = getzname(name);
            stdlen = name - stdname;
        }
        if (*name == '\0')
            return -1;
        name = getoffset(name, &stdoffset);
        if (name == NULL)
            return -1;
        load_result = tzload(TZDEFRULES, NULL, sp, FALSE);
    }
    if (load_result != 0)
        sp->leapcnt = 0;        /* so, we're off a little */
    if (*name != '\0')
    {
        if (*name == '<')
        {
            dstname = ++name;
            name = getqzname(name, '>');
            if (*name != '>')
                return -1;
            dstlen = name - dstname;
            name++;
        }
        else
        {
            dstname = name;
            name = getzname(name);
            dstlen = name - dstname;    /* length of DST zone name */
        }
        if (*name != '\0' && *name != ',' && *name != ';')
        {
            name = getoffset(name, &dstoffset);
            if (name == NULL)
                return -1;
        }
        else
            dstoffset = stdoffset - SECSPERHOUR;
        if (*name == '\0' && load_result != 0)
            name = TZDEFRULESTRING;
        if (*name == ',' || *name == ';')
        {
            struct rule start;
            struct rule end;
            int         year;
            pg_time_t   janfirst;
            pg_time_t   starttime;
            pg_time_t   endtime;

            ++name;
            if ((name = getrule(name, &start)) == NULL)
                return -1;
            if (*name++ != ',')
                return -1;
            if ((name = getrule(name, &end)) == NULL)
                return -1;
            if (*name != '\0')
                return -1;
            sp->typecnt = 2;    /* standard time and DST */

            /*
             * Two transitions per year, from EPOCH_YEAR forward.
             */
            sp->ttis[0].tt_gmtoff = -dstoffset;
            sp->ttis[0].tt_isdst = 1;
            sp->ttis[0].tt_abbrind = stdlen + 1;
            sp->ttis[1].tt_gmtoff = -stdoffset;
            sp->ttis[1].tt_isdst = 0;
            sp->ttis[1].tt_abbrind = 0;
            atp = sp->ats;
            typep = sp->types;
            janfirst = 0;
            sp->timecnt = 0;
            for (year = EPOCH_YEAR;
                 sp->timecnt + 2 <= TZ_MAX_TIMES;
                 ++year)
            {
                pg_time_t   newfirst;

                starttime = transtime(janfirst, year, &start,
                                      stdoffset);
                endtime = transtime(janfirst, year, &end,
                                    dstoffset);
                if (starttime > endtime)
                {
                    *atp++ = endtime;
                    *typep++ = 1;       /* DST ends */
                    *atp++ = starttime;
                    *typep++ = 0;       /* DST begins */
                }
                else
                {
                    *atp++ = starttime;
                    *typep++ = 0;       /* DST begins */
                    *atp++ = endtime;
                    *typep++ = 1;       /* DST ends */
                }
                sp->timecnt += 2;
                newfirst = janfirst;
                newfirst += year_lengths[isleap(year)] *
                    SECSPERDAY;
                if (newfirst <= janfirst)
                    break;
                janfirst = newfirst;
            }
        }
        else
        {
            long        theirstdoffset;
            long        theirdstoffset;
            long        theiroffset;
            int         isdst;
            int         i;
            int         j;

            if (*name != '\0')
                return -1;

            /*
             * Initial values of theirstdoffset and theirdstoffset.
             */
            theirstdoffset = 0;
            for (i = 0; i < sp->timecnt; ++i)
            {
                j = sp->types[i];
                if (!sp->ttis[j].tt_isdst)
                {
                    theirstdoffset =
                        -sp->ttis[j].tt_gmtoff;
                    break;
                }
            }
            theirdstoffset = 0;
            for (i = 0; i < sp->timecnt; ++i)
            {
                j = sp->types[i];
                if (sp->ttis[j].tt_isdst)
                {
                    theirdstoffset =
                        -sp->ttis[j].tt_gmtoff;
                    break;
                }
            }

            /*
             * Initially we're assumed to be in standard time.
             */
            isdst = FALSE;
            theiroffset = theirstdoffset;

            /*
             * Now juggle transition times and types tracking offsets as you
             * do.
             */
            for (i = 0; i < sp->timecnt; ++i)
            {
                j = sp->types[i];
                sp->types[i] = sp->ttis[j].tt_isdst;
                if (sp->ttis[j].tt_ttisgmt)
                {
                    /* No adjustment to transition time */
                }
                else
                {
                    /*
                     * If summer time is in effect, and the transition time
                     * was not specified as standard time, add the summer time
                     * offset to the transition time; otherwise, add the
                     * standard time offset to the transition time.
                     */

                    /*
                     * Transitions from DST to DDST will effectively disappear
                     * since POSIX provides for only one DST offset.
                     */
                    if (isdst && !sp->ttis[j].tt_ttisstd)
                    {
                        sp->ats[i] += dstoffset -
                            theirdstoffset;
                    }
                    else
                    {
                        sp->ats[i] += stdoffset -
                            theirstdoffset;
                    }
                }
                theiroffset = -sp->ttis[j].tt_gmtoff;
                if (sp->ttis[j].tt_isdst)
                    theirdstoffset = theiroffset;
                else
                    theirstdoffset = theiroffset;
            }

            /*
             * Finally, fill in ttis. ttisstd and ttisgmt need not be handled.
             */
            sp->ttis[0].tt_gmtoff = -stdoffset;
            sp->ttis[0].tt_isdst = FALSE;
            sp->ttis[0].tt_abbrind = 0;
            sp->ttis[1].tt_gmtoff = -dstoffset;
            sp->ttis[1].tt_isdst = TRUE;
            sp->ttis[1].tt_abbrind = stdlen + 1;
            sp->typecnt = 2;
        }
    }
    else
    {
        dstlen = 0;
        sp->typecnt = 1;        /* only standard time */
        sp->timecnt = 0;
        sp->ttis[0].tt_gmtoff = -stdoffset;
        sp->ttis[0].tt_isdst = 0;
        sp->ttis[0].tt_abbrind = 0;
    }
    sp->charcnt = stdlen + 1;
    if (dstlen != 0)
        sp->charcnt += dstlen + 1;
    if ((size_t) sp->charcnt > sizeof sp->chars)
        return -1;
    cp = sp->chars;
    (void) strncpy(cp, stdname, stdlen);
    cp += stdlen;
    *cp++ = '\0';
    if (dstlen != 0)
    {
        (void) strncpy(cp, dstname, dstlen);
        *(cp + dstlen) = '\0';
    }
    return 0;
}