xref: /onnv-gate/usr/src/lib/libast/common/tm/tminit.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * Glenn Fowler
254887Schin  * AT&T Research
264887Schin  *
274887Schin  * time conversion support
284887Schin  */
294887Schin 
304887Schin #include <tm.h>
314887Schin #include <ctype.h>
324887Schin #include <namval.h>
334887Schin 
344887Schin #include "FEATURE/tmlib"
354887Schin 
364887Schin #ifndef tzname
374887Schin #	if defined(__DYNAMIC__)
384887Schin #		define	tzname		__DYNAMIC__(tzname)
394887Schin #	else
404887Schin #		if !_dat_tzname
414887Schin #			if _dat__tzname
424887Schin #				undef	_dat_tzname
434887Schin #				define _dat_tzname	1
444887Schin #				define tzname		_tzname
454887Schin #			endif
464887Schin #		endif
474887Schin #	endif
484887Schin #	if _dat_tzname
494887Schin 		extern char*		tzname[];
504887Schin #	endif
514887Schin #endif
524887Schin 
534887Schin #define TM_type		(-1)
544887Schin 
554887Schin static const Namval_t		options[] =
564887Schin {
574887Schin 	"adjust",	TM_ADJUST,
584887Schin 	"format",	TM_DEFAULT,
594887Schin 	"leap",		TM_LEAP,
604887Schin 	"subsecond",	TM_SUBSECOND,
614887Schin 	"type",		TM_type,
624887Schin 	"utc",		TM_UTC,
634887Schin 	0,		0
644887Schin };
654887Schin 
664887Schin /*
674887Schin  * 2007-03-19 move tm_info from _tm_info_ to (*_tm_infop_)
684887Schin  *	      to allow future Tm_info_t growth
694887Schin  *            by 2009 _tm_info_ can be static
704887Schin  */
714887Schin 
724887Schin #if _BLD_ast && defined(__EXPORT__)
734887Schin #define extern		extern __EXPORT__
744887Schin #endif
754887Schin 
764887Schin extern Tm_info_t	_tm_info_;
774887Schin 
784887Schin #undef	extern
794887Schin 
804887Schin Tm_info_t		_tm_info_ = { 0 };
814887Schin 
824887Schin __EXTERN__(Tm_info_t, _tm_info_);
834887Schin 
844887Schin __EXTERN__(Tm_info_t*, _tm_infop_);
854887Schin 
864887Schin Tm_info_t*		_tm_infop_ = &_tm_info_;
874887Schin 
884887Schin #if _tzset_environ
894887Schin 
904887Schin static char	TZ[256];
914887Schin static char*	TE[2];
924887Schin 
934887Schin struct tm*
_tm_localtime(const time_t * t)944887Schin _tm_localtime(const time_t* t)
954887Schin {
964887Schin 	struct tm*	r;
974887Schin 	char*		e;
98*12068SRoger.Faulkner@Oracle.COM 	char**		v = environ;
994887Schin 
1004887Schin 	if (TZ[0])
1014887Schin 	{
1024887Schin 		if (!environ || !*environ)
1034887Schin 			environ = TE;
1044887Schin 		else
1054887Schin 			e = environ[0];
1064887Schin 		environ[0] = TZ;
1074887Schin 	}
1084887Schin 	r = localtime(t);
1094887Schin 	if (TZ[0])
1104887Schin 	{
111*12068SRoger.Faulkner@Oracle.COM 		if (environ != v)
112*12068SRoger.Faulkner@Oracle.COM 			environ = v;
1134887Schin 		else
1144887Schin 			environ[0] = e;
1154887Schin 	}
1164887Schin 	return r;
1174887Schin }
1184887Schin 
1194887Schin #endif
1204887Schin 
1214887Schin /*
1224887Schin  * return minutes west of GMT for local time clock
1234887Schin  *
1244887Schin  * isdst will point to non-zero if DST is in effect
1254887Schin  * this routine also kicks in the local initialization
1264887Schin  */
1274887Schin 
1284887Schin static int
tzwest(time_t * clock,int * isdst)1294887Schin tzwest(time_t* clock, int* isdst)
1304887Schin {
1314887Schin 	register struct tm*	tp;
1324887Schin 	register int		n;
1334887Schin 	register int		m;
1344887Schin 	int			h;
1354887Schin 	time_t			epoch;
1364887Schin 
1374887Schin 	/*
1384887Schin 	 * convert to GMT assuming local time
1394887Schin 	 */
1404887Schin 
1414887Schin 	if (!(tp = gmtime(clock)))
1424887Schin 	{
1434887Schin 		/*
1444887Schin 		 * some systems return 0 for negative time_t
1454887Schin 		 */
1464887Schin 
1474887Schin 		epoch = 0;
1484887Schin 		clock = &epoch;
1494887Schin 		tp = gmtime(clock);
1504887Schin 	}
1514887Schin 	n = tp->tm_yday;
1524887Schin 	h = tp->tm_hour;
1534887Schin 	m = tp->tm_min;
1544887Schin 
1554887Schin 	/*
1564887Schin 	 * tmlocaltime() handles DST and GMT offset
1574887Schin 	 */
1584887Schin 
1594887Schin 	tp = tmlocaltime(clock);
1604887Schin 	if (n = tp->tm_yday - n)
1614887Schin 	{
1624887Schin 		if (n > 1)
1634887Schin 			n = -1;
1644887Schin 		else if (n < -1)
1654887Schin 			n = 1;
1664887Schin 	}
1674887Schin 	*isdst = tp->tm_isdst;
1684887Schin 	return (h - tp->tm_hour - n * 24) * 60 + m - tp->tm_min;
1694887Schin }
1704887Schin 
1714887Schin /*
1724887Schin  * stropt() option handler
1734887Schin  */
1744887Schin 
1754887Schin static int
tmopt(void * a,const void * p,int n,const char * v)1764887Schin tmopt(void* a, const void* p, int n, const char* v)
1774887Schin {
1784887Schin 	Tm_zone_t*	zp;
1794887Schin 
1804887Schin 	NoP(a);
1814887Schin 	if (p)
1824887Schin 		switch (((Namval_t*)p)->value)
1834887Schin 		{
1844887Schin 		case TM_DEFAULT:
1854887Schin 			tm_info.deformat = (n && (n = strlen(v)) > 0 && (n < 2 || v[n-2] != '%' || v[n-1] != '?')) ? strdup(v) : tm_info.format[TM_DEFAULT];
1864887Schin 			break;
1874887Schin 		case TM_type:
1884887Schin 			tm_info.local->type = (n && *v) ? ((zp = tmtype(v, NiL)) ? zp->type : strdup(v)) : 0;
1894887Schin 			break;
1904887Schin 		default:
1914887Schin 			if (n)
1924887Schin 				tm_info.flags |= ((Namval_t*)p)->value;
1934887Schin 			else
1944887Schin 				tm_info.flags &= ~((Namval_t*)p)->value;
1954887Schin 			break;
1964887Schin 		}
1974887Schin 	return 0;
1984887Schin }
1994887Schin 
2004887Schin /*
2014887Schin  * initialize the local timezone
2024887Schin  */
2034887Schin 
2044887Schin static void
tmlocal(void)2054887Schin tmlocal(void)
2064887Schin {
2074887Schin 	register Tm_zone_t*	zp;
2084887Schin 	register int		n;
2094887Schin 	register char*		s;
2104887Schin 	register char*		e;
2114887Schin 	int			i;
2124887Schin 	int			m;
2134887Schin 	int			isdst;
2144887Schin 	char*			t;
2154887Schin 	struct tm*		tp;
2164887Schin 	time_t			now;
2174887Schin 	char			buf[16];
2184887Schin 
2194887Schin 	static Tm_zone_t	local;
2204887Schin 
2214887Schin #if _tzset_environ
2224887Schin 	{
223*12068SRoger.Faulkner@Oracle.COM 		char**	v = environ;
224*12068SRoger.Faulkner@Oracle.COM 
225*12068SRoger.Faulkner@Oracle.COM 		if (s = getenv("TZ"))
226*12068SRoger.Faulkner@Oracle.COM 		{
227*12068SRoger.Faulkner@Oracle.COM 			sfsprintf(TZ, sizeof(TZ), "TZ=%s", s);
228*12068SRoger.Faulkner@Oracle.COM 			if (!environ || !*environ)
229*12068SRoger.Faulkner@Oracle.COM 				environ = TE;
230*12068SRoger.Faulkner@Oracle.COM 			else
231*12068SRoger.Faulkner@Oracle.COM 				e = environ[0];
232*12068SRoger.Faulkner@Oracle.COM 			environ[0] = TZ;
233*12068SRoger.Faulkner@Oracle.COM 		}
2344887Schin 		else
235*12068SRoger.Faulkner@Oracle.COM 		{
236*12068SRoger.Faulkner@Oracle.COM 			TZ[0] = 0;
237*12068SRoger.Faulkner@Oracle.COM 			e = 0;
238*12068SRoger.Faulkner@Oracle.COM 		}
239*12068SRoger.Faulkner@Oracle.COM #endif
240*12068SRoger.Faulkner@Oracle.COM #if _lib_tzset
241*12068SRoger.Faulkner@Oracle.COM 		tzset();
242*12068SRoger.Faulkner@Oracle.COM #endif
243*12068SRoger.Faulkner@Oracle.COM #if _tzset_environ
244*12068SRoger.Faulkner@Oracle.COM 		if (environ != v)
245*12068SRoger.Faulkner@Oracle.COM 			environ = v;
246*12068SRoger.Faulkner@Oracle.COM 		else if (e)
247*12068SRoger.Faulkner@Oracle.COM 			environ[0] = e;
2484887Schin 	}
2494887Schin #endif
2504887Schin #if _dat_tzname
2514887Schin 	local.standard = strdup(tzname[0]);
2524887Schin 	local.daylight = strdup(tzname[1]);
2534887Schin #endif
2544887Schin 	tmlocale();
2554887Schin 
2564887Schin 	/*
2574887Schin 	 * tm_info.local
2584887Schin 	 */
2594887Schin 
2604887Schin 	tm_info.zone = tm_info.local = &local;
2614887Schin 	time(&now);
2624887Schin 	n = tzwest(&now, &isdst);
2634887Schin 
2644887Schin 	/*
2654887Schin 	 * compute local DST offset by roaming
2664887Schin 	 * through the last 12 months until tzwest() changes
2674887Schin 	 */
2684887Schin 
2694887Schin 	for (i = 0; i < 12; i++)
2704887Schin 	{
2714887Schin 		now -= 31 * 24 * 60 * 60;
2724887Schin 		if ((m = tzwest(&now, &isdst)) != n)
2734887Schin 		{
2744887Schin 			if (!isdst)
2754887Schin 			{
2764887Schin 				isdst = n;
2774887Schin 				n = m;
2784887Schin 				m = isdst;
2794887Schin 			}
2804887Schin 			m -= n;
2814887Schin 			break;
2824887Schin 		}
2834887Schin 	}
2844887Schin 	local.west = n;
2854887Schin 	local.dst = m;
2864887Schin 
2874887Schin 	/*
2884887Schin 	 * now get the time zone names
2894887Schin 	 */
2904887Schin 
2914887Schin #if _dat_tzname
2924887Schin 	if (tzname[0])
2934887Schin 	{
2944887Schin 		/*
2954887Schin 		 * POSIX
2964887Schin 		 */
2974887Schin 
2984887Schin 		if (!local.standard)
2994887Schin 			local.standard = strdup(tzname[0]);
3004887Schin 		if (!local.daylight)
3014887Schin 			local.daylight = strdup(tzname[1]);
3024887Schin 	}
3034887Schin 	else
3044887Schin #endif
3054887Schin 	if ((s = getenv("TZNAME")) && *s && (s = strdup(s)))
3064887Schin 	{
3074887Schin 		/*
3084887Schin 		 * BSD
3094887Schin 		 */
3104887Schin 
3114887Schin 		local.standard = s;
3124887Schin 		if (s = strchr(s, ','))
3134887Schin 			*s++ = 0;
3144887Schin 		else
3154887Schin 			s = "";
3164887Schin 		local.daylight = s;
3174887Schin 	}
3184887Schin 	else if ((s = getenv("TZ")) && *s && *s != ':' && (s = strdup(s)))
3194887Schin 	{
3204887Schin 		/*
3214887Schin 		 * POSIX style but skipped by tmlocaltime()
3224887Schin 		 */
3234887Schin 
3244887Schin 		local.standard = s;
3254887Schin 		if (*++s && *++s && *++s)
3264887Schin 		{
3274887Schin 			*s++ = 0;
3284887Schin 			tmgoff(s, &t, 0);
3294887Schin 			for (s = t; isalpha(*t); t++);
3304887Schin 			*t = 0;
3314887Schin 		}
3324887Schin 		else
3334887Schin 			s = "";
3344887Schin 		local.daylight = s;
3354887Schin 	}
3364887Schin 	else
3374887Schin 	{
3384887Schin 		/*
3394887Schin 		 * tm_data.zone table lookup
3404887Schin 		 */
3414887Schin 
3424887Schin 		t = 0;
3434887Schin 		for (zp = tm_data.zone; zp->standard; zp++)
3444887Schin 		{
3454887Schin 			if (zp->type)
3464887Schin 				t = zp->type;
3474887Schin 			if (zp->west == n && zp->dst == m)
3484887Schin 			{
3494887Schin 				local.type = t;
3504887Schin 				local.standard = zp->standard;
3514887Schin 				if (!(s = zp->daylight))
3524887Schin 				{
3534887Schin 					e = (s = buf) + sizeof(buf);
3544887Schin 					s = tmpoff(s, e - s, zp->standard, 0, 0);
3554887Schin 					if (s < e - 1)
3564887Schin 					{
3574887Schin 						*s++ = ' ';
3584887Schin 						tmpoff(s, e - s, tm_info.format[TM_DT], m, TM_DST);
3594887Schin 					}
3604887Schin 					s = strdup(buf);
3614887Schin 				}
3624887Schin 				local.daylight = s;
3634887Schin 				break;
3644887Schin 			}
3654887Schin 		}
3664887Schin 		if (!zp->standard)
3674887Schin 		{
3684887Schin 			/*
3694887Schin 			 * not in the table
3704887Schin 			 */
3714887Schin 
3724887Schin 			e = (s = buf) + sizeof(buf);
3734887Schin 			s = tmpoff(s, e - s, tm_info.format[TM_UT], n, 0);
3744887Schin 			local.standard = strdup(buf);
3754887Schin 			if (s < e - 1)
3764887Schin 			{
3774887Schin 				*s++ = ' ';
3784887Schin 				tmpoff(s, e - s, tm_info.format[TM_UT], m, TM_DST);
3794887Schin 				local.daylight = strdup(buf);
3804887Schin 			}
3814887Schin 		}
3824887Schin 	}
3834887Schin 
3844887Schin 	/*
3854887Schin 	 * set the options
3864887Schin 	 */
3874887Schin 
3884887Schin 	stropt(getenv("TM_OPTIONS"), options, sizeof(*options), tmopt, NiL);
3894887Schin 
3904887Schin 	/*
3914887Schin 	 * the time zone type is probably related to the locale
3924887Schin 	 */
3934887Schin 
3944887Schin 	if (!local.type)
3954887Schin 	{
3964887Schin 		s = local.standard;
3974887Schin 		t = 0;
3984887Schin 		for (zp = tm_data.zone; zp->standard; zp++)
3994887Schin 		{
4004887Schin 			if (zp->type)
4014887Schin 				t = zp->type;
4024887Schin 			if (tmword(s, NiL, zp->standard, NiL, 0))
4034887Schin 			{
4044887Schin 				local.type = t;
4054887Schin 				break;
4064887Schin 			}
4074887Schin 		}
4084887Schin 	}
4094887Schin 
4104887Schin 	/*
4114887Schin 	 * tm_info.flags
4124887Schin 	 */
4134887Schin 
4144887Schin 	if (!(tm_info.flags & TM_ADJUST))
4154887Schin 	{
4164887Schin 		now = (time_t)78811200;		/* Jun 30 1972 23:59:60 */
4174887Schin 		tp = tmlocaltime(&now);
4184887Schin 		if (tp->tm_sec != 60)
4194887Schin 			tm_info.flags |= TM_ADJUST;
4204887Schin 	}
4214887Schin 	if (!(tm_info.flags & TM_UTC))
4224887Schin 	{
4234887Schin 		s = local.standard;
4244887Schin 		zp = tm_data.zone;
4254887Schin 		if (local.daylight)
4264887Schin 			zp++;
4274887Schin 		for (; !zp->type && zp->standard; zp++)
4284887Schin 			if (tmword(s, NiL, zp->standard, NiL, 0))
4294887Schin 			{
4304887Schin 				tm_info.flags |= TM_UTC;
4314887Schin 				break;
4324887Schin 			}
4334887Schin 	}
4344887Schin }
4354887Schin 
4364887Schin /*
4374887Schin  * initialize tm data
4384887Schin  */
4394887Schin 
4404887Schin void
tminit(register Tm_zone_t * zp)4414887Schin tminit(register Tm_zone_t* zp)
4424887Schin {
4434887Schin 	static uint32_t		serial = ~(uint32_t)0;
4444887Schin 
4454887Schin 	if (serial != ast.env_serial)
4464887Schin 	{
4474887Schin 		serial = ast.env_serial;
4484887Schin 		if (tm_info.local)
4494887Schin 		{
4504887Schin 			memset(tm_info.local, 0, sizeof(*tm_info.local));
4514887Schin 			tm_info.local = 0;
4524887Schin 		}
4534887Schin 	}
4544887Schin 	if (!tm_info.local)
4554887Schin 		tmlocal();
4564887Schin 	if (!zp)
4574887Schin 		zp = tm_info.local;
4584887Schin 	tm_info.zone = zp;
4594887Schin }
460