Proposed time zone abbreviation changes

Arthur David Olson olsona at lecserver.nci.nih.gov
Thu May 26 19:20:36 UTC 2005


Here are changes (relative to what's currently available via ftp) to deal with time zone
abbreviation issues.

1.	The use of "??" as an abbreviation in the solar* files is eliminated.
2.	The zic command warns about non-POSIX abbreviations.
3.	The zdump command warns about non-POSIX abbreviations if its "-v" flag is used.
4.	localtime.c is changed to restrict characters in abbreviations to [a-zA-Z0-9 :+-]
	(replacing other characters with 'X'), and to restrict abbreviation lengths to 16
	(truncating longer abbreviations).

Both zic.c and localtime.c have the long Factory "abbreviation" grandparented in.

				--ado

diff -r -c old/Makefile new/Makefile
*** old/Makefile	Mon Apr  4 11:24:31 2005
--- new/Makefile	Thu May 26 12:42:13 2005
***************
*** 1,4 ****
! # @(#)Makefile	7.108
  
  # Change the line below for your time zone (after finding the zone you want in
  # the time zone files, or adding it to a time zone file).
--- 1,4 ----
! # @(#)Makefile	7.109
  
  # Change the line below for your time zone (after finding the zone you want in
  # the time zone files, or adding it to a time zone file).
***************
*** 111,117 ****
  #  -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU=1
  #	if you do not want run time warnings about formats that may cause
  #	year 2000 grief
! #
  GCC_DEBUG_FLAGS = -Dlint -g -O -fno-common \
  	-Wall -Wcast-qual -Wconversion -Wmissing-prototypes \
  	-Wnested-externs -Wpointer-arith -Wshadow \
--- 111,119 ----
  #  -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU=1
  #	if you do not want run time warnings about formats that may cause
  #	year 2000 grief
! #  -DZIC_MAX_ABBR_LEN_WO_WARN=3
! #	(or some other number) to set the maximum time zone abbreviation length
! #	that zic will accept without a warning (the default is 6)
  GCC_DEBUG_FLAGS = -Dlint -g -O -fno-common \
  	-Wall -Wcast-qual -Wconversion -Wmissing-prototypes \
  	-Wnested-externs -Wpointer-arith -Wshadow \
diff -r -c old/localtime.c new/localtime.c
*** old/localtime.c	Mon Apr  4 11:24:32 2005
--- new/localtime.c	Thu May 26 15:02:36 2005
***************
*** 5,11 ****
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.91";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
--- 5,11 ----
  
  #ifndef lint
  #ifndef NOID
! static char	elsieid[] = "@(#)localtime.c	7.93";
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
***************
*** 22,27 ****
--- 22,40 ----
  #include "fcntl.h"
  #include "float.h"	/* for FLT_MAX and DBL_MAX */
  
+ #ifndef TZ_ABBR_MAX_LEN
+ #define TZ_ABBR_MAX_LEN	16
+ #endif /* !defined TZ_ABBR_MAX_LEN */
+ 
+ #ifndef TZ_ABBR_CHAR_SET
+ #define TZ_ABBR_CHAR_SET \
+ 	"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-"
+ #endif /* !defined TZ_ABBR_CHAR_SET */
+ 
+ #ifndef TZ_ABBR_ERR_CHAR
+ #define TZ_ABBR_ERR_CHAR	'X'
+ #endif /* !defined TZ_ABBR_ERR_CHAR */
+ 
  /*
  ** SunOS 4.1.1 headers lack O_BINARY.
  */
***************
*** 124,129 ****
--- 137,143 ----
  
  static long		detzcode P((const char * codep));
  static const char *	getzname P((const char * strp));
+ static const char *	getqzname P((const char * strp, const char delim));
  static const char *	getnum P((const char * strp, int * nump, int min,
  				int max));
  static const char *	getsecs P((const char * strp, long * secsp));
***************
*** 269,274 ****
--- 283,306 ----
  		tzname[ttisp->tt_isdst] =
  			&sp->chars[ttisp->tt_abbrind];
  	}
+ 	/*
+ 	** Finally, scrub the abbreviations.
+ 	** First, replace bogus characters.
+ 	*/
+ 	for (i = 0; i < sp->charcnt; ++i)
+ 		if (strchr(TZ_ABBR_CHAR_SET, sp->chars[i]) == NULL)
+ 			sp->chars[i] = TZ_ABBR_ERR_CHAR;
+ 	/*
+ 	** Second, truncate long abbreviations.
+ 	*/
+ 	for (i = 0; i < sp->typecnt; ++i) {
+ 		register const struct ttinfo * const	ttisp = &sp->ttis[i];
+ 		register char *				cp = &sp->chars[ttisp->tt_abbrind];
+ 
+ 		if (strlen(cp) > TZ_ABBR_MAX_LEN &&
+ 			strcmp(cp, GRANDPARENTED) != 0)
+ 				*(cp + TZ_ABBR_MAX_LEN) = '\0';
+ 	}
  }
  
  static int
***************
*** 470,475 ****
--- 502,528 ----
  }
  
  /*
+ ** Given a pointer into an extended time zone string, scan until the ending
+ ** delimiter of the zone name is located.   Return a pointer to the delimiter.
+ **
+ ** As with getzname above, the legal character set is actually quite
+ ** restricted, with other characters producing undefined results.
+ ** We choose not to care - allowing almost anything to be in the zone abbrev.
+ */
+ 
+ static const char *
+ getqzname(strp, delim)
+ register const char *	strp;
+ const char		delim;
+ {
+ 	register char	c;
+ 
+ 	while ((c = *strp) != '\0' && c != delim)
+ 		++strp;
+ 	return strp;
+ }
+ 
+ /*
  ** Given a pointer into a time zone string, extract a number from that string.
  ** Check that the number is within a specified range; if it is not, return
  ** NULL.
***************
*** 753,760 ****
  			stdlen = (sizeof sp->chars) - 1;
  		stdoffset = 0;
  	} else {
! 		name = getzname(name);
! 		stdlen = name - stdname;
  		if (stdlen < 3)
  			return -1;
  		if (*name == '\0')
--- 806,823 ----
  			stdlen = (sizeof sp->chars) - 1;
  		stdoffset = 0;
  	} 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 (stdlen < 3)
  			return -1;
  		if (*name == '\0')
***************
*** 767,775 ****
  	if (load_result != 0)
  		sp->leapcnt = 0;		/* so, we're off a little */
  	if (*name != '\0') {
! 		dstname = name;
! 		name = getzname(name);
! 		dstlen = name - dstname;	/* length of DST zone name */
  		if (dstlen < 3)
  			return -1;
  		if (*name != '\0' && *name != ',' && *name != ';') {
--- 830,847 ----
  	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 (dstlen < 3)
  			return -1;
  		if (*name != '\0' && *name != ',' && *name != ';') {
diff -r -c old/private.h new/private.h
*** old/private.h	Mon Apr  4 11:24:32 2005
--- new/private.h	Thu May 26 14:54:07 2005
***************
*** 25,30 ****
--- 25,32 ----
  #endif /* !defined NOID */
  #endif /* !defined lint */
  
+ #define GRANDPARENTED	"Local time zone must be set--see zic manual page"
+ 
  /*
  ** Defaults for preprocessor symbols.
  ** You can override these in your C compiler options, e.g. `-DHAVE_ADJTIME=0'.
diff -r -c old/solar87 new/solar87
*** old/solar87	Thu Apr 21 15:04:16 2005
--- new/solar87	Thu May 26 12:42:35 2005
***************
*** 1,4 ****
! # @(#)solar87	7.3
  
  # So much for footnotes about Saudi Arabia.
  # Apparent noon times below are for Riyadh; your mileage will vary.
--- 1,4 ----
! # @(#)solar87	7.4
  
  # So much for footnotes about Saudi Arabia.
  # Apparent noon times below are for Riyadh; your mileage will vary.
***************
*** 381,388 ****
  # Before and after 1987, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh87	3:07:04	-		??	1987
! 			3:07:04	sol87		??	1988
! 			3:07:04	-		??
  # For backward compatibility...
  Link	Asia/Riyadh87	Mideast/Riyadh87
--- 381,388 ----
  # Before and after 1987, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh87	3:07:04	-		zzz	1987
! 			3:07:04	sol87		zzz	1988
! 			3:07:04	-		zzz
  # For backward compatibility...
  Link	Asia/Riyadh87	Mideast/Riyadh87
diff -r -c old/solar88 new/solar88
*** old/solar88	Thu Apr 21 15:04:16 2005
--- new/solar88	Thu May 26 12:42:35 2005
***************
*** 1,4 ****
! # @(#)solar88	7.3
  
  # Apparent noon times below are for Riyadh; they're a bit off for other places.
  # Times were computed using formulas in the U.S. Naval Observatory's
--- 1,4 ----
! # @(#)solar88	7.4
  
  # Apparent noon times below are for Riyadh; they're a bit off for other places.
  # Times were computed using formulas in the U.S. Naval Observatory's
***************
*** 381,388 ****
  # Before and after 1988, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh88	3:07:04	-		??	1988
! 			3:07:04	sol88		??	1989
! 			3:07:04	-		??
  # For backward compatibility...
  Link	Asia/Riyadh88	Mideast/Riyadh88
--- 381,388 ----
  # Before and after 1988, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh88	3:07:04	-		zzz	1988
! 			3:07:04	sol88		zzz	1989
! 			3:07:04	-		zzz
  # For backward compatibility...
  Link	Asia/Riyadh88	Mideast/Riyadh88
diff -r -c old/solar89 new/solar89
*** old/solar89	Thu Apr 21 15:04:16 2005
--- new/solar89	Thu May 26 12:42:35 2005
***************
*** 1,4 ****
! # @(#)solar89	7.4
  
  # Apparent noon times below are for Riyadh; they're a bit off for other places.
  # Times were computed using a formula provided by the U. S. Naval Observatory:
--- 1,4 ----
! # @(#)solar89	7.5
  
  # Apparent noon times below are for Riyadh; they're a bit off for other places.
  # Times were computed using a formula provided by the U. S. Naval Observatory:
***************
*** 386,393 ****
  # Before and after 1989, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh89	3:07:04	-		??	1989
! 			3:07:04	sol89		??	1990
! 			3:07:04	-		??
  # For backward compatibility...
  Link	Asia/Riyadh89	Mideast/Riyadh89
--- 386,393 ----
  # Before and after 1989, we'll operate on local mean solar time.
  
  # Zone	NAME		GMTOFF	RULES/SAVE	FORMAT	[UNTIL]
! Zone	Asia/Riyadh89	3:07:04	-		zzz	1989
! 			3:07:04	sol89		zzz	1990
! 			3:07:04	-		zzz
  # For backward compatibility...
  Link	Asia/Riyadh89	Mideast/Riyadh89
diff -r -c old/zdump.c new/zdump.c
*** old/zdump.c	Mon Apr  4 11:24:32 2005
--- new/zdump.c	Thu May 26 12:48:56 2005
***************
*** 1,4 ****
! static char	elsieid[] = "@(#)zdump.c	7.64";
  
  /*
  ** This code has been made independent of the rest of the time
--- 1,4 ----
! static char	elsieid[] = "@(#)zdump.c	7.65";
  
  /*
  ** This code has been made independent of the rest of the time
***************
*** 144,151 ****
--- 144,153 ----
  static time_t	absolute_max_time;
  static size_t	longest;
  static char *	progname;
+ static int	warned;
  
  static char *	abbr P((struct tm * tmp));
+ static void	abbrok P((const char * abbr, const char * zone));
  static long	delta P((struct tm * newp, struct tm * oldp));
  static void	dumptime P((const struct tm * tmp));
  static time_t	hunt P((char * name, time_t lot, time_t	hit));
***************
*** 191,196 ****
--- 193,236 ----
  }
  #endif /* !defined TYPECHECK */
  
+ static void
+ abbrok(abbr, zone)
+ const char * const	abbr;
+ const char * const	zone;
+ {
+ 	register int		i;
+ 	register const char *	cp;
+ 	register char *		wp;
+ 
+ 	if (warned)
+ 		return;
+ 	cp = abbr;
+ 	wp = NULL;
+ 	while (isascii(*cp) && isalpha(*cp))
+ 		++cp;
+ 	if (cp - abbr == 0)
+ 		wp = _("lacks alphabetic at start");
+ 	if (cp - abbr < 3)
+ 		wp = _("has fewer than 3 alphabetics");
+ 	if (cp - abbr > 6)
+ 		wp = _("has more than 6 alphabetics");
+ 	if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ 		++cp;
+ 		if (isascii(*cp) && isdigit(*cp))
+ 			if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
+ 				++cp;
+ 	}
+ 	if (*cp != '\0')
+ 		wp = _("differs from POSIX standard");
+ 	if (wp == NULL)
+ 		return;
+ 	(void) fflush(stdout);
+ 	(void) fprintf(stderr,
+ 		"%s: warning: zone \"%s\" abbreviation \"%s\" %s\n",
+ 		progname, zone, abbr, wp);
+ 	warned = TRUE;
+ }
+ 
  int
  main(argc, argv)
  int	argc;
***************
*** 297,302 ****
--- 337,343 ----
  			show(argv[i], now, FALSE);
  			continue;
  		}
+ 		warned = FALSE;
  		t = absolute_min_time;
  		show(argv[i], t, TRUE);
  		t += SECSPERHOUR * HOURSPERDAY;
***************
*** 527,532 ****
--- 568,575 ----
  		}
  	}
  	(void) printf("\n");
+ 	if (tmp != NULL && *abbr(tmp) != '\0')
+ 		abbrok(abbr(tmp), zone);
  }
  
  static char *
diff -r -c old/zic.c new/zic.c
*** old/zic.c	Mon Apr  4 11:24:32 2005
--- new/zic.c	Thu May 26 14:54:07 2005
***************
*** 1,4 ****
! static char	elsieid[] = "@(#)zic.c	7.122";
  
  /*
  ** Regardless of the type of time_t, we do our work using this type.
--- 1,4 ----
! static char	elsieid[] = "@(#)zic.c	7.124";
  
  /*
  ** Regardless of the type of time_t, we do our work using this type.
***************
*** 10,15 ****
--- 10,19 ----
  #include "locale.h"
  #include "tzfile.h"
  
+ #ifndef ZIC_MAX_ABBR_LEN_WO_WARN
+ #define ZIC_MAX_ABBR_LEN_WO_WARN	6
+ #endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
+ 
  #if HAVE_SYS_STAT_H
  #include "sys/stat.h"
  #endif
***************
*** 2196,2201 ****
--- 2200,2240 ----
  {
  	register int	i;
  
+ 	if (strcmp(string, GRANDPARENTED) != 0) {
+ 		register const char *	cp;
+ 		register char *		wp;
+ 
+ 		/*
+ 		** Want one to ZIC_MAX_ABBR_LEN_WO_WARN alphabetics
+ 		** optionally followed by a + or - and a number from 1 to 14.
+ 		*/
+ 		cp = string;
+ 		wp = NULL;
+ 		while (isascii(*cp) && isalpha(*cp))
+ 			++cp;
+ 		if (cp - string == 0)
+ wp = _("time zone abbreviation lacks alphabetic at start");
+ 		if (noise && cp - string > 3)
+ wp = _("time zone abbreviation has more than 3 alphabetics");
+ 		if (cp - string > ZIC_MAX_ABBR_LEN_WO_WARN)
+ wp = _("time zone abbreviation has too many alphabetics");
+ 		if (wp == NULL && (*cp == '+' || *cp == '-')) {
+ 			++cp;
+ 			if (isascii(*cp) && isdigit(*cp))
+ 				if (*cp++ == '1' && *cp >= '0' && *cp <= '4')
+ 					++cp;
+ 		}
+ 		if (*cp != '\0')
+ wp = _("time zone abbreviation differs from POSIX standard");
+ 		if (wp != NULL) {
+ 			wp = ecpyalloc(wp);
+ 			wp = ecatalloc(wp, " (");
+ 			wp = ecatalloc(wp, string);
+ 			wp = ecatalloc(wp, ")");
+ 			warning(wp);
+ 			ifree(wp);
+ 		}
+ 	}
  	i = strlen(string) + 1;
  	if (charcnt + i > TZ_MAX_CHARS) {
  		error(_("too many, or too long, time zone abbreviations"));



More information about the tz mailing list