For example, when the context is weekdays, the old, buggy code rejected both "Sa" and "Su" as ambiguous abbreviations. * NEWS: Document this. * zic.c (ciprefix): New function. (byword): Use it to fix bug in abbreviation determination. Warn if an unambiguous abbreviation is not portable to pre-2017c zic. --- NEWS | 7 +++++++ zic.c | 43 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 1af7b69..d22d561 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,13 @@ Unreleased, experimental changes in civil timekeeping. (Thanks to Robert Elz and Bradley White for noticing glitches in the code that uncovered this problem.) + zic now allows unambiguous abbreviations like "Sa" and "Su" for + weekdays; formerly it rejected them due to a bug. Conversely, zic + no longer considers non-prefixes to be abbreviations; for example, + it no longer accepts "lF" as an abbreviation for "lastFriday". + Also, zic warns about the undocumented usage with a "last-" + prefix, e.g., "last-Fri". + 'make BACKWARD=' now suppresses backward-compatibility names like 'US/Pacific' that are defined in the 'backward' and 'pacificnew' files. diff --git a/zic.c b/zic.c index f57d346..c2737e1 100644 --- a/zic.c +++ b/zic.c @@ -2901,6 +2901,19 @@ itsabbr(register const char *abbr, register const char *word) return true; } +/* Return true if ABBR is an initial prefix of WORD, ignoring ASCII case. */ + +static bool +ciprefix(char const *abbr, char const *word) +{ + do + if (!*abbr) + return true; + while (lowerit(*abbr++) == lowerit(*word++)); + + return false; +} + static const struct lookup * byword(const char *word, const struct lookup *table) { @@ -2909,6 +2922,20 @@ byword(const char *word, const struct lookup *table) if (word == NULL || table == NULL) return NULL; + + /* If TABLE is LASTS and the word starts with "last" followed + by a non-'-', skip the "last" and look in WDAY_NAMES instead. + Warn about any usage of the undocumented prefix "last-". */ + if (table == lasts && ciprefix("last", word) && word[4]) { + if (word[4] == '-') + warning(_("\"%s\" is undocumented; use \"last%s\" instead"), + word, word + 5); + else { + word += 4; + table = wday_names; + } + } + /* ** Look for exact match. */ @@ -2920,11 +2947,25 @@ byword(const char *word, const struct lookup *table) */ foundlp = NULL; for (lp = table; lp->l_word != NULL; ++lp) - if (itsabbr(word, lp->l_word)) { + if (ciprefix(word, lp->l_word)) { if (foundlp == NULL) foundlp = lp; else return NULL; /* multiple inexact matches */ } + + /* Warn about any backward-compatibility issue with pre-2017c zic. */ + if (foundlp) { + bool pre_2017c_match = false; + for (lp = table; lp->l_word; lp++) + if (itsabbr(word, lp->l_word)) { + if (pre_2017c_match) { + warning(_("\"%s\" is ambiguous in pre-2017c zic"), word); + break; + } + pre_2017c_match = true; + } + } + return foundlp; } -- 2.9.4