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"));