Logo Search packages:      
Sourcecode: ksh version File versions  Download package

tminit.c

/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*          Copyright (c) 1985-2008 AT&T Intellectual Property          *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                    by AT&T Intellectual Property                     *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                  David Korn <dgk@research.att.com>                   *
*                   Phong Vo <kpv@research.att.com>                    *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * time conversion support
 */

#include <tm.h>
#include <ctype.h>
#include <namval.h>

#include "FEATURE/tmlib"

#ifndef tzname
#     if defined(__DYNAMIC__)
#           define      tzname            __DYNAMIC__(tzname)
#     else
#           if !_dat_tzname
#                 if _dat__tzname
#                       undef _dat_tzname
#                       define _dat_tzname      1
#                       define tzname           _tzname
#                 endif
#           endif
#     endif
#     if _dat_tzname
            extern char*            tzname[];
#     endif
#endif

#define TM_type         (-1)

static const Namval_t         options[] =
{
      "adjust",   TM_ADJUST,
      "format",   TM_DEFAULT,
      "leap",           TM_LEAP,
      "subsecond",      TM_SUBSECOND,
      "type",           TM_type,
      "utc",            TM_UTC,
      0,          0
};

/*
 * 2007-03-19 move tm_info from _tm_info_ to (*_tm_infop_)
 *          to allow future Tm_info_t growth
 *            by 2009 _tm_info_ can be static
 */

#if _BLD_ast && defined(__EXPORT__)
#define extern          extern __EXPORT__
#endif

extern Tm_info_t  _tm_info_;

#undef      extern

Tm_info_t         _tm_info_ = { 0 };

__EXTERN__(Tm_info_t, _tm_info_);

__EXTERN__(Tm_info_t*, _tm_infop_);

Tm_info_t*        _tm_infop_ = &_tm_info_;

#if _tzset_environ

static char TZ[256];
static char*      TE[2];

struct tm*
_tm_localtime(const time_t* t)
{
      struct tm*  r;
      char*       e;

      if (TZ[0])
      {
            if (!environ || !*environ)
                  environ = TE;
            else
                  e = environ[0];
            environ[0] = TZ;
      }
      r = localtime(t);
      if (TZ[0])
      {
            if (environ == TE)
                  environ = 0;
            else
                  environ[0] = e;
      }
      return r;
}

#endif

/*
 * return minutes west of GMT for local time clock
 *
 * isdst will point to non-zero if DST is in effect
 * this routine also kicks in the local initialization
 */

static int
tzwest(time_t* clock, int* isdst)
{
      register struct tm*     tp;
      register int            n;
      register int            m;
      int               h;
      time_t                  epoch;

      /*
       * convert to GMT assuming local time
       */

      if (!(tp = gmtime(clock)))
      {
            /*
             * some systems return 0 for negative time_t
             */

            epoch = 0;
            clock = &epoch;
            tp = gmtime(clock);
      }
      n = tp->tm_yday;
      h = tp->tm_hour;
      m = tp->tm_min;

      /*
       * tmlocaltime() handles DST and GMT offset
       */

      tp = tmlocaltime(clock);
      if (n = tp->tm_yday - n)
      {
            if (n > 1)
                  n = -1;
            else if (n < -1)
                  n = 1;
      }
      *isdst = tp->tm_isdst;
      return (h - tp->tm_hour - n * 24) * 60 + m - tp->tm_min;
}

/*
 * stropt() option handler
 */

static int
tmopt(void* a, const void* p, int n, const char* v)
{
      Tm_zone_t*  zp;

      NoP(a);
      if (p)
            switch (((Namval_t*)p)->value)
            {
            case TM_DEFAULT:
                  tm_info.deformat = (n && (n = strlen(v)) > 0 && (n < 2 || v[n-2] != '%' || v[n-1] != '?')) ? strdup(v) : tm_info.format[TM_DEFAULT];
                  break;
            case TM_type:
                  tm_info.local->type = (n && *v) ? ((zp = tmtype(v, NiL)) ? zp->type : strdup(v)) : 0;
                  break;
            default:
                  if (n)
                        tm_info.flags |= ((Namval_t*)p)->value;
                  else
                        tm_info.flags &= ~((Namval_t*)p)->value;
                  break;
            }
      return 0;
}

/*
 * initialize the local timezone
 */

static void
tmlocal(void)
{
      register Tm_zone_t*     zp;
      register int            n;
      register char*          s;
      register char*          e;
      int               i;
      int               m;
      int               isdst;
      char*             t;
      struct tm*        tp;
      time_t                  now;
      char              buf[16];

      static Tm_zone_t  local;

#if _lib_tzset
#if _tzset_environ
      if (s = getenv("TZ"))
      {
            sfsprintf(TZ, sizeof(TZ), "TZ=%s", s);
            if (!environ || !*environ)
                  environ = TE;
            else
                  e = environ[0];
            environ[0] = TZ;
      }
      else
      {
            TZ[0] = 0;
            e = 0;
      }
#endif
      tzset();
#if _tzset_environ
      if (environ == TE)
            environ = 0;
      else if (e)
            environ[0] = e;
#endif
#endif
#if _dat_tzname
      local.standard = strdup(tzname[0]);
      local.daylight = strdup(tzname[1]);
#endif
      tmlocale();

      /*
       * tm_info.local
       */

      tm_info.zone = tm_info.local = &local;
      time(&now);
      n = tzwest(&now, &isdst);

      /*
       * compute local DST offset by roaming
       * through the last 12 months until tzwest() changes
       */

      for (i = 0; i < 12; i++)
      {
            now -= 31 * 24 * 60 * 60;
            if ((m = tzwest(&now, &isdst)) != n)
            {
                  if (!isdst)
                  {
                        isdst = n;
                        n = m;
                        m = isdst;
                  }
                  m -= n;
                  break;
            }
      }
      local.west = n;
      local.dst = m;

      /*
       * now get the time zone names
       */

#if _dat_tzname
      if (tzname[0])
      {
            /*
             * POSIX
             */

            if (!local.standard)
                  local.standard = strdup(tzname[0]);
            if (!local.daylight)
                  local.daylight = strdup(tzname[1]);
      }
      else
#endif
      if ((s = getenv("TZNAME")) && *s && (s = strdup(s)))
      {
            /*
             * BSD
             */

            local.standard = s;
            if (s = strchr(s, ','))
                  *s++ = 0;
            else
                  s = "";
            local.daylight = s;
      }
      else if ((s = getenv("TZ")) && *s && *s != ':' && (s = strdup(s)))
      {
            /*
             * POSIX style but skipped by tmlocaltime()
             */

            local.standard = s;
            if (*++s && *++s && *++s)
            {
                  *s++ = 0;
                  tmgoff(s, &t, 0);
                  for (s = t; isalpha(*t); t++);
                  *t = 0;
            }
            else
                  s = "";
            local.daylight = s;
      }
      else
      {
            /*
             * tm_data.zone table lookup
             */

            t = 0;
            for (zp = tm_data.zone; zp->standard; zp++)
            {
                  if (zp->type)
                        t = zp->type;
                  if (zp->west == n && zp->dst == m)
                  {
                        local.type = t;
                        local.standard = zp->standard;
                        if (!(s = zp->daylight))
                        {
                              e = (s = buf) + sizeof(buf);
                              s = tmpoff(s, e - s, zp->standard, 0, 0);
                              if (s < e - 1)
                              {
                                    *s++ = ' ';
                                    tmpoff(s, e - s, tm_info.format[TM_DT], m, TM_DST);
                              }
                              s = strdup(buf);
                        }
                        local.daylight = s;
                        break;
                  }
            }
            if (!zp->standard)
            {
                  /*
                   * not in the table
                   */

                  e = (s = buf) + sizeof(buf);
                  s = tmpoff(s, e - s, tm_info.format[TM_UT], n, 0);
                  local.standard = strdup(buf);
                  if (s < e - 1)
                  {
                        *s++ = ' ';
                        tmpoff(s, e - s, tm_info.format[TM_UT], m, TM_DST);
                        local.daylight = strdup(buf);
                  }
            }
      }

      /*
       * set the options
       */

      stropt(getenv("TM_OPTIONS"), options, sizeof(*options), tmopt, NiL);

      /*
       * the time zone type is probably related to the locale
       */

      if (!local.type)
      {
            s = local.standard;
            t = 0;
            for (zp = tm_data.zone; zp->standard; zp++)
            {
                  if (zp->type)
                        t = zp->type;
                  if (tmword(s, NiL, zp->standard, NiL, 0))
                  {
                        local.type = t;
                        break;
                  }
            }
      }

      /*
       * tm_info.flags
       */

      if (!(tm_info.flags & TM_ADJUST))
      {
            now = (time_t)78811200;       /* Jun 30 1972 23:59:60 */
            tp = tmlocaltime(&now);
            if (tp->tm_sec != 60)
                  tm_info.flags |= TM_ADJUST;
      }
      if (!(tm_info.flags & TM_UTC))
      {
            s = local.standard;
            zp = tm_data.zone;
            if (local.daylight)
                  zp++;
            for (; !zp->type && zp->standard; zp++)
                  if (tmword(s, NiL, zp->standard, NiL, 0))
                  {
                        tm_info.flags |= TM_UTC;
                        break;
                  }
      }
}

/*
 * initialize tm data
 */

void
tminit(register Tm_zone_t* zp)
{
      static uint32_t         serial = ~(uint32_t)0;

      if (serial != ast.env_serial)
      {
            serial = ast.env_serial;
            if (tm_info.local)
            {
                  memset(tm_info.local, 0, sizeof(*tm_info.local));
                  tm_info.local = 0;
            }
      }
      if (!tm_info.local)
            tmlocal();
      if (!zp)
            zp = tm_info.local;
      tm_info.zone = zp;
}

Generated by  Doxygen 1.6.0   Back to index