static char rcsid[] = "@(#)$Id: get_tz.c,v 1.13 2006/04/09 07:37:05 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.13 $   $State: Exp $
 *
 *  Modified by: Kari Hurtta <hurtta+elm@posti.FMI.FI>
 *                           (was hurtta+elm@ozone.FMI.FI)
 ******************************************************************************
 *  The Elm Mail System 
 *
 * 			Copyright (c) 1992, 1993 USENET Community Trust
 *****************************************************************************/

#include "headers.h"

#ifdef _CONFIGURE
/*
 * The "Configure" program will try to determine the proper setting to make
 * "get_tz_name()" work.  It will compile the program with _CONFIGURE enabled.
 * We do not want to build "get_tz_mins()" when doing the config tests.
 */
#define get_tz_mins(XX) 0
main()
{
	puts(get_tz_name((struct tm *)0));
	exit(0);
}
#endif


#ifndef _CONFIGURE /*{*/
/*
 * get_tz_mins() - Return the local timezone offset in minutes west of GMT.
 *
 * WARNING -- This routine will step on the static data returned by
 * localtime() and gmtime().  Precautions must be taken in the calling
 * routine to avoid trouncing the time information being used.
 *
 * An earlier version of Elm had a more complicated routine of the same
 * name.  This implementation is more limited in that it calculates only
 * the local TZ offset.  The old routine was able to calculate any TZ
 * offset given a (struct tm *).
 */
int get_tz_mins(tval)
     time_t tval;
{
	struct tm *tm;
	long t2, t1;

	tm = localtime(&tval);
	t1 = make_gmttime(1900+tm->tm_year, 1+tm->tm_mon, tm->tm_mday,
		tm->tm_hour, tm->tm_min, tm->tm_sec);

	tm = gmtime(&tval);
	t2 = make_gmttime(1900+tm->tm_year, 1+tm->tm_mon, tm->tm_mday,
		tm->tm_hour, tm->tm_min, tm->tm_sec);

	return (int) ((t2-t1)/60);
}
#endif /*}!_CONFIGURE*/


/*
 * get_tz_name(tm) - Return timezone name.
 *
 * Try to return the timezone name associated with the time specified by
 * "tm", or the local timezone name if "tm" is NULL.  On some systems, you
 * will get the local timezone name regardless of the "tm" value.
 *
 * Exactly one of the following definitions must be enabled to indicate
 * the system-specific method for timezone name handling.
 *
 *	TZNAME_USE_TM_NAME     use (struct tm *)->tm_name
 *	TZNAME_USE_TM_ZONE     use (struct tm *)->tm_zone
 *	TZNAME_USE_TZNAME      use "tzname[]" external
 *	TZNAME_USE_TIMEZONE    use timezone() function
 *
 * The TZNAME_HANDLING definition is just used to verify the configurations
 * was setup correctly.  It will force a compiler warning or error if there
 * is a configuration problem.
 */

CONST char *get_tz_name(tm)
     struct tm *tm;
{

	if (tm == 0) {
		time_t t;
		(void) time(&t);
		tm = localtime(&t);
	}

#ifdef TZNAME_USE_TM_NAME
#define TZNAME_HANDLING 1
	/*
	 * This system maintains the timezone name in the (struct tm).
	 */
	return tm->tm_name;
#endif

#ifdef TZNAME_USE_TM_ZONE
#define TZNAME_HANDLING 2
	/*
	 * This system maintains the timezone name in the (struct tm).
	 */
	return tm->tm_zone;
#endif

#ifdef TZNAME_USE_TZNAME
#define TZNAME_HANDLING 3
	/*
	 * This system maintains a global array that contains two timezone
	 * names, one for when DST is in effect and one for when it is not.
	 * We simply need to pick the right one.
	 */
	{
		extern char *tzname[];
		return tzname[tm->tm_isdst];
	}
#endif

#ifdef TZNAME_USE_TIMEZONE
#define TZNAME_HANDLING 4
	/*
	 * This system provides a timezone() procedure to get a timezone
	 * name.  Be careful -- some systems have this procedure but
	 * depreciate its use, and in some cases it is outright broke.
	 * WARNING!!!  The "get_tz_mins()" routine is destructive
	 * to any (struct tm *) value that was obtained by gmtime() or
	 * localtime().
	 */
	{
		extern char *timezone();
		int isdst = tm->tm_isdst;
		return timezone(get_tz_mins(0), isdst);
	}
#endif

#ifndef TZNAME_HANDLING
	/* Force a compile error if the timezone config is wrong. */
	no_tzname_handling_defined(TZNAME_HANDLING);
#endif
}


#ifdef _TEST

/*
 * This routine tests the timezone procedures by forcing a TZ value
 * and checking the results.  This test routine is *not* portable.  It
 * will work only on systems that (1) use the TZ environment parameter,
 * (2) have a putenv() procedure, and (3) putenv() takes a single argument.
 */

int debug = 1;

struct {
	char *tz_setting;
	char *expected_ans;
} trytable[] = {
	{ "",			"local timezone setting" },
	{ "TZ=GMT",		"always GMT/0" },
	{ "TZ=CST6CDT",		"either CDT/300 or CST/360" },
	{ "TZ=EST5EDT",		"either EDT/240 or EST/300" },
	{ "TZ=EST5EDT;0,364",	"always EDT/240" },
	{ "TZ=EST5EDT;0,0",	"always EST/300" },
	{ NULL,			NULL }
};

main()
{
	time_t t;
	int i;
	extern char *getenv();

	puts("Notes:");
	puts("\"get_tz_name(gmtime)\" trial should always show GMT.");
	puts("\"get_tz_name(NULL)\" should match \"get_tz_name(localtime)\".");
	puts("Results marked \"either/or\" depend whether DST in effect now.");

	for (i = 0 ; trytable[i].tz_setting != NULL ; ++i) {
		if (trytable[i].tz_setting[0] != '\0')
			putenv(trytable[i].tz_setting);
		putchar('\n');
		printf("expected result: %s\n", trytable[i].expected_ans);
		printf("getenv(\"TZ\") = \"%s\"\n", getenv("TZ"));
		(void) time(&t);
		printf("get_tz_mins(%d) = %d\n",t,get_tz_mins(t));
		printf("get_tz_name(NULL) = \"%s\"\n",
			get_tz_name((struct tm *)0));
		printf("get_tz_name(localtime) = \"%s\"\n",
			get_tz_name(localtime(&t)));
		printf("get_tz_name(gmtime) = \"%s\"\n",
			get_tz_name(gmtime(&t)));
	}
	exit(0);
}

#endif /*_TEST*/

/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1