summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/time/scheck.c58
-rw-r--r--lib/libc/time/zdump.863
-rw-r--r--lib/libc/time/zdump.c658
-rw-r--r--lib/libc/time/zic.8450
-rw-r--r--lib/libc/time/zic.c2762
5 files changed, 0 insertions, 3991 deletions
diff --git a/lib/libc/time/scheck.c b/lib/libc/time/scheck.c
deleted file mode 100644
index e4f3b145b6a..00000000000
--- a/lib/libc/time/scheck.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/* $OpenBSD: scheck.c,v 1.11 2015/02/09 11:29:19 tedu Exp $ */
-/*
-** This file is in the public domain, so clarified as of
-** 2006-07-17 by Arthur David Olson.
-*/
-
-/*LINTLIBRARY*/
-
-#include "private.h"
-
-const char *
-scheck(string, format)
-const char * const string;
-const char * const format;
-{
- register char * fbuf;
- register const char * fp;
- register char * tp;
- register int c;
- register const char * result;
- char dummy;
-
- result = "";
- if (string == NULL || format == NULL)
- return result;
- fbuf = malloc((int) (2 * strlen(format) + 4));
- if (fbuf == NULL)
- return result;
- fp = format;
- tp = fbuf;
- while ((*tp++ = c = *fp++) != '\0') {
- if (c != '%')
- continue;
- if (*fp == '%') {
- *tp++ = *fp++;
- continue;
- }
- *tp++ = '*';
- if (*fp == '*')
- ++fp;
- while (is_digit(*fp))
- *tp++ = *fp++;
- if (*fp == 'l' || *fp == 'h')
- *tp++ = *fp++;
- else if (*fp == '[')
- do *tp++ = *fp++;
- while (*fp != '\0' && *fp != ']');
- if ((*tp++ = *fp++) == '\0')
- break;
- }
- *(tp - 1) = '%';
- *tp++ = 'c';
- *tp = '\0';
- if (sscanf(string, fbuf, &dummy) != 1)
- result = (char *) format;
- free(fbuf);
- return result;
-}
diff --git a/lib/libc/time/zdump.8 b/lib/libc/time/zdump.8
deleted file mode 100644
index 7f8644c0904..00000000000
--- a/lib/libc/time/zdump.8
+++ /dev/null
@@ -1,63 +0,0 @@
-.\" $OpenBSD: zdump.8,v 1.16 2012/09/13 11:14:20 millert Exp $
-.Dd $Mdocdate: September 13 2012 $
-.Dt ZDUMP 8
-.Os
-.Sh NAME
-.Nm zdump
-.Nd time zone dumper
-.Sh SYNOPSIS
-.Nm zdump
-.Op Fl v
-.Oo
-.Fl c
-.Oo Ar loyear , Oc Ar hiyear
-.Oc
-.Ar zonename ...
-.Sh DESCRIPTION
-.Nm
-prints the current time in each
-.Ar zonename
-named on the command line.
-.Pp
-These options are available:
-.Bl -tag -width Fl
-.It Xo
-.Fl c
-.Oo Ar loyear , Oc Ar hiyear
-.Xc
-Cut off verbose output near the start of the given year(s).
-By default,
-the program cuts off verbose output near the start of the years -500 and 2500.
-.It Fl v
-For each
-.Ar zonename
-on the command line,
-print the time at the lowest possible time value,
-the time one day after the lowest possible time value,
-the times both one second before and exactly at
-each detected time discontinuity,
-the time at one day less than the highest possible time value,
-and the time at the highest possible time value.
-Each line ends with
-.Dq isdst=1
-if the given time is Daylight Saving Time or
-.Dq isdst=0
-otherwise.
-.El
-.Sh LIMITATIONS
-The
-.Fl v
-option may not be used on systems with floating-point
-.Li time_t
-values that are neither float nor double.
-.Pp
-Time discontinuities are found by sampling the results returned by localtime
-at twelve-hour intervals.
-This works in all real-world cases;
-.\" @(#)zdump.8 8.1
-.Sh SEE ALSO
-.Xr ctime 3 ,
-.Xr tzfile 5 ,
-.Xr zic 8
-.\" This file is in the public domain, so clarified as of
-.\" 2009-05-17 by Arthur David Olson.
diff --git a/lib/libc/time/zdump.c b/lib/libc/time/zdump.c
deleted file mode 100644
index 29036452d7f..00000000000
--- a/lib/libc/time/zdump.c
+++ /dev/null
@@ -1,658 +0,0 @@
-/* $OpenBSD: zdump.c,v 1.24 2015/02/09 10:45:56 tedu Exp $ */
-/*
-** This file is in the public domain, so clarified as of
-** 2009-05-17 by Arthur David Olson.
-*/
-
-/*
-** This code has been made independent of the rest of the time
-** conversion package to increase confidence in the verification it provides.
-** You can use this code to help in verifying other implementations.
-*/
-
-#include "stdio.h" /* for stdout, stderr, perror */
-#include "string.h" /* for strlcpy */
-#include "ctype.h" /* for isascii, isalpha, isdigit */
-#include "sys/types.h" /* for time_t */
-#include "time.h" /* for struct tm */
-#include "stdlib.h" /* for exit, malloc, atoi */
-#include "float.h" /* for FLT_MAX and DBL_MAX */
-#include "ctype.h" /* for isalpha et al. */
-
-#ifndef ZDUMP_LO_YEAR
-#define ZDUMP_LO_YEAR (-500)
-#endif /* !defined ZDUMP_LO_YEAR */
-
-#ifndef ZDUMP_HI_YEAR
-#define ZDUMP_HI_YEAR 2500
-#endif /* !defined ZDUMP_HI_YEAR */
-
-#ifndef MAX_STRING_LENGTH
-#define MAX_STRING_LENGTH 1024
-#endif /* !defined MAX_STRING_LENGTH */
-
-#ifndef TRUE
-#define TRUE 1
-#endif /* !defined TRUE */
-
-#ifndef FALSE
-#define FALSE 0
-#endif /* !defined FALSE */
-
-#ifndef SECSPERMIN
-#define SECSPERMIN 60
-#endif /* !defined SECSPERMIN */
-
-#ifndef MINSPERHOUR
-#define MINSPERHOUR 60
-#endif /* !defined MINSPERHOUR */
-
-#ifndef SECSPERHOUR
-#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
-#endif /* !defined SECSPERHOUR */
-
-#ifndef HOURSPERDAY
-#define HOURSPERDAY 24
-#endif /* !defined HOURSPERDAY */
-
-#ifndef EPOCH_YEAR
-#define EPOCH_YEAR 1970
-#endif /* !defined EPOCH_YEAR */
-
-#ifndef TM_YEAR_BASE
-#define TM_YEAR_BASE 1900
-#endif /* !defined TM_YEAR_BASE */
-
-#ifndef DAYSPERNYEAR
-#define DAYSPERNYEAR 365
-#endif /* !defined DAYSPERNYEAR */
-
-#ifndef isleap
-#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
-#endif /* !defined isleap */
-
-#ifndef isleap_sum
-/*
-** See tzfile.h for details on isleap_sum.
-*/
-#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400)
-#endif /* !defined isleap_sum */
-
-#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
-#define SECSPERNYEAR (SECSPERDAY * DAYSPERNYEAR)
-#define SECSPERLYEAR (SECSPERNYEAR + SECSPERDAY)
-
-#ifndef HAVE_GETTEXT
-#define HAVE_GETTEXT 0
-#endif
-#if HAVE_GETTEXT
-#include "locale.h" /* for setlocale */
-#include "libintl.h"
-#endif /* HAVE_GETTEXT */
-
-#ifndef GNUC_or_lint
-#ifdef lint
-#define GNUC_or_lint
-#else /* !defined lint */
-#ifdef __GNUC__
-#define GNUC_or_lint
-#endif /* defined __GNUC__ */
-#endif /* !defined lint */
-#endif /* !defined GNUC_or_lint */
-
-#ifndef INITIALIZE
-#ifdef GNUC_or_lint
-#define INITIALIZE(x) ((x) = 0)
-#else /* !defined GNUC_or_lint */
-#define INITIALIZE(x)
-#endif /* !defined GNUC_or_lint */
-#endif /* !defined INITIALIZE */
-
-/*
-** For the benefit of GNU folk...
-** `_(MSGID)' uses the current locale's message library string for MSGID.
-** The default is to use gettext if available, and use MSGID otherwise.
-*/
-
-#ifndef _
-#if HAVE_GETTEXT
-#define _(msgid) gettext(msgid)
-#else /* !HAVE_GETTEXT */
-#define _(msgid) msgid
-#endif /* !HAVE_GETTEXT */
-#endif /* !defined _ */
-
-#ifndef TZ_DOMAIN
-#define TZ_DOMAIN "tz"
-#endif /* !defined TZ_DOMAIN */
-
-extern char ** environ;
-extern int getopt(int argc, char * const argv[],
- const char * options);
-extern char * optarg;
-extern int optind;
-extern char * tzname[2];
-
-static time_t absolute_min_time;
-static time_t absolute_max_time;
-static size_t longest;
-static char * progname;
-static int warned;
-
-static char * abbr(struct tm * tmp);
-static void abbrok(const char * abbrp, const char * zone);
-static long delta(struct tm * newp, struct tm * oldp);
-static void dumptime(const struct tm * tmp);
-static time_t hunt(char * name, time_t lot, time_t hit);
-static void setabsolutes(void);
-static void show(char * zone, time_t t, int v);
-static const char * tformat(void);
-static time_t yeartot(long y);
-
-#ifndef TYPECHECK
-#define my_localtime localtime
-#else /* !defined TYPECHECK */
-static struct tm *
-my_localtime(tp)
-time_t * tp;
-{
- register struct tm * tmp;
-
- tmp = localtime(tp);
- if (tp != NULL && tmp != NULL) {
- struct tm tm;
- register time_t t;
-
- tm = *tmp;
- t = mktime(&tm);
- if (t - *tp >= 1 || *tp - t >= 1) {
- (void) fflush(stdout);
- (void) fprintf(stderr, "\n%s: ", progname);
- (void) fprintf(stderr, tformat(), *tp);
- (void) fprintf(stderr, " ->");
- (void) fprintf(stderr, " year=%d", tmp->tm_year);
- (void) fprintf(stderr, " mon=%d", tmp->tm_mon);
- (void) fprintf(stderr, " mday=%d", tmp->tm_mday);
- (void) fprintf(stderr, " hour=%d", tmp->tm_hour);
- (void) fprintf(stderr, " min=%d", tmp->tm_min);
- (void) fprintf(stderr, " sec=%d", tmp->tm_sec);
- (void) fprintf(stderr, " isdst=%d", tmp->tm_isdst);
- (void) fprintf(stderr, " -> ");
- (void) fprintf(stderr, tformat(), t);
- (void) fprintf(stderr, "\n");
- }
- }
- return tmp;
-}
-#endif /* !defined TYPECHECK */
-
-static void
-abbrok(abbrp, zone)
-const char * const abbrp;
-const char * const zone;
-{
- register const char * cp;
- register char * wp;
-
- if (warned)
- return;
- cp = abbrp;
- wp = NULL;
- while (isascii((unsigned char) *cp) && isalpha((unsigned char) *cp))
- ++cp;
- if (cp - abbrp == 0)
- wp = _("lacks alphabetic at start");
- else if (cp - abbrp < 3)
- wp = _("has fewer than 3 alphabetics");
- else if (cp - abbrp > 6)
- wp = _("has more than 6 alphabetics");
- if (wp == NULL && (*cp == '+' || *cp == '-')) {
- ++cp;
- if (isascii((unsigned char) *cp) &&
- isdigit((unsigned char) *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, abbrp, wp);
- warned = TRUE;
-}
-
-static void
-usage(stream, status)
-FILE * const stream;
-const int status;
-{
- (void) fprintf(stream,
-_("usage: %s [-v] [-c [loyear,]hiyear] zonename ...\n"), progname);
- exit(status);
-}
-
-int
-main(argc, argv)
-int argc;
-char * argv[];
-{
- register int i;
- register int c;
- register int vflag;
- register char * cutarg;
- register long cutloyear = ZDUMP_LO_YEAR;
- register long cuthiyear = ZDUMP_HI_YEAR;
- register time_t cutlotime;
- register time_t cuthitime;
- register char ** fakeenv;
- time_t now;
- time_t t;
- time_t newt;
- struct tm tm;
- struct tm newtm;
- register struct tm * tmp;
- register struct tm * newtmp;
-
- INITIALIZE(cutlotime);
- INITIALIZE(cuthitime);
-#if HAVE_GETTEXT
- (void) setlocale(LC_ALL, "");
-#ifdef TZ_DOMAINDIR
- (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
-#endif /* defined TEXTDOMAINDIR */
- (void) textdomain(TZ_DOMAIN);
-#endif /* HAVE_GETTEXT */
- progname = argv[0];
- vflag = 0;
- cutarg = NULL;
- while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
- if (c == 'v')
- vflag = 1;
- else cutarg = optarg;
- if ((c != EOF && c != -1) ||
- (optind == argc - 1 && strcmp(argv[optind], "=") == 0)) {
- usage(stderr, EXIT_FAILURE);
- }
- if (vflag) {
- if (cutarg != NULL) {
- long lo;
- long hi;
- char dummy;
-
- if (sscanf(cutarg, "%ld%c", &hi, &dummy) == 1) {
- cuthiyear = hi;
- } else if (sscanf(cutarg, "%ld,%ld%c",
- &lo, &hi, &dummy) == 2) {
- cutloyear = lo;
- cuthiyear = hi;
- } else {
-(void) fprintf(stderr, _("%s: wild -c argument %s\n"),
- progname, cutarg);
- exit(EXIT_FAILURE);
- }
- }
- setabsolutes();
- cutlotime = yeartot(cutloyear);
- cuthitime = yeartot(cuthiyear);
- }
- (void) time(&now);
- longest = 0;
- for (i = optind; i < argc; ++i)
- if (strlen(argv[i]) > longest)
- longest = strlen(argv[i]);
- {
- register int from;
- register int to;
-
- for (i = 0; environ[i] != NULL; ++i)
- continue;
- fakeenv = (char **) malloc((size_t) ((i + 2) *
- sizeof *fakeenv));
- if (fakeenv == NULL ||
- (fakeenv[0] = (char *) malloc(longest + 4)) == NULL) {
- (void) perror(progname);
- exit(EXIT_FAILURE);
- }
- to = 0;
- strlcpy(fakeenv[to++], "TZ=", longest + 4);
- for (from = 0; environ[from] != NULL; ++from)
- if (strncmp(environ[from], "TZ=", 3) != 0)
- fakeenv[to++] = environ[from];
- fakeenv[to] = NULL;
- environ = fakeenv;
- }
- for (i = optind; i < argc; ++i) {
- static char buf[MAX_STRING_LENGTH];
-
- strlcpy(&fakeenv[0][3], argv[i], longest + 1);
- if (!vflag) {
- show(argv[i], now, FALSE);
- continue;
- }
- warned = FALSE;
- t = absolute_min_time;
- show(argv[i], t, TRUE);
- t += SECSPERHOUR * HOURSPERDAY;
- show(argv[i], t, TRUE);
- if (t < cutlotime)
- t = cutlotime;
- tmp = my_localtime(&t);
- if (tmp != NULL) {
- tm = *tmp;
- strlcpy(buf, abbr(&tm), sizeof buf);
- }
- for ( ; ; ) {
- if (t >= cuthitime || t >= cuthitime - SECSPERHOUR * 12)
- break;
- newt = t + SECSPERHOUR * 12;
- newtmp = localtime(&newt);
- if (newtmp != NULL)
- newtm = *newtmp;
- if ((tmp == NULL || newtmp == NULL) ? (tmp != newtmp) :
- (delta(&newtm, &tm) != (newt - t) ||
- newtm.tm_isdst != tm.tm_isdst ||
- strcmp(abbr(&newtm), buf) != 0)) {
- newt = hunt(argv[i], t, newt);
- newtmp = localtime(&newt);
- if (newtmp != NULL) {
- newtm = *newtmp;
- strlcpy(buf, abbr(&newtm),
- sizeof buf);
- }
- }
- t = newt;
- tm = newtm;
- tmp = newtmp;
- }
- t = absolute_max_time;
- t -= SECSPERHOUR * HOURSPERDAY;
- show(argv[i], t, TRUE);
- t += SECSPERHOUR * HOURSPERDAY;
- show(argv[i], t, TRUE);
- }
- if (fflush(stdout) || ferror(stdout)) {
- (void) fprintf(stderr, "%s: ", progname);
- (void) perror(_("Error writing to standard output"));
- exit(EXIT_FAILURE);
- }
- exit(EXIT_SUCCESS);
- /* If exit fails to exit... */
- return EXIT_FAILURE;
-}
-
-static void
-setabsolutes(void)
-{
- if (0.5 == (time_t) 0.5) {
- /*
- ** time_t is floating.
- */
- if (sizeof (time_t) == sizeof (float)) {
- absolute_min_time = (time_t) -FLT_MAX;
- absolute_max_time = (time_t) FLT_MAX;
- } else if (sizeof (time_t) == sizeof (double)) {
- absolute_min_time = (time_t) -DBL_MAX;
- absolute_max_time = (time_t) DBL_MAX;
- } else {
- (void) fprintf(stderr,
-_("%s: use of -v on system with floating time_t other than float or double\n"),
- progname);
- exit(EXIT_FAILURE);
- }
- } else if (0 > (time_t) -1) {
- /*
- ** time_t is signed. Assume overflow wraps around.
- */
- time_t t = 0;
- time_t t1 = 1;
-
- while (t < t1) {
- t = t1;
- t1 = 2 * t1 + 1;
- }
-
- absolute_max_time = t;
- t = -t;
- absolute_min_time = t - 1;
- if (t < absolute_min_time)
- absolute_min_time = t;
- } else {
- /*
- ** time_t is unsigned.
- */
- absolute_min_time = 0;
- absolute_max_time = absolute_min_time - 1;
- }
-}
-
-static time_t
-yeartot(y)
-const long y;
-{
- register long myy;
- register long seconds;
- register time_t t;
-
- myy = EPOCH_YEAR;
- t = 0;
- while (myy != y) {
- if (myy < y) {
- seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
- ++myy;
- if (t > absolute_max_time - seconds) {
- t = absolute_max_time;
- break;
- }
- t += seconds;
- } else {
- --myy;
- seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR;
- if (t < absolute_min_time + seconds) {
- t = absolute_min_time;
- break;
- }
- t -= seconds;
- }
- }
- return t;
-}
-
-static time_t
-hunt(char *name, time_t lot, time_t hit)
-{
- time_t t;
- long diff;
- struct tm lotm;
- register struct tm * lotmp;
- struct tm tm;
- register struct tm * tmp;
- char loab[MAX_STRING_LENGTH];
-
- lotmp = my_localtime(&lot);
- if (lotmp != NULL) {
- lotm = *lotmp;
- (void) strlcpy(loab, abbr(&lotm), sizeof loab);
- }
- for ( ; ; ) {
- diff = (long) (hit - lot);
- if (diff < 2)
- break;
- t = lot;
- t += diff / 2;
- if (t <= lot)
- ++t;
- else if (t >= hit)
- --t;
- tmp = my_localtime(&t);
- if (tmp != NULL)
- tm = *tmp;
- if ((lotmp == NULL || tmp == NULL) ? (lotmp == tmp) :
- (delta(&tm, &lotm) == (t - lot) &&
- tm.tm_isdst == lotm.tm_isdst &&
- strcmp(abbr(&tm), loab) == 0)) {
- lot = t;
- lotm = tm;
- lotmp = tmp;
- } else hit = t;
- }
- show(name, lot, TRUE);
- show(name, hit, TRUE);
- return hit;
-}
-
-/*
-** Thanks to Paul Eggert for logic used in delta.
-*/
-
-static long
-delta(newp, oldp)
-struct tm * newp;
-struct tm * oldp;
-{
- register long result;
- register int tmy;
-
- if (newp->tm_year < oldp->tm_year)
- return -delta(oldp, newp);
- result = 0;
- for (tmy = oldp->tm_year; tmy < newp->tm_year; ++tmy)
- result += DAYSPERNYEAR + isleap_sum(tmy, TM_YEAR_BASE);
- result += newp->tm_yday - oldp->tm_yday;
- result *= HOURSPERDAY;
- result += newp->tm_hour - oldp->tm_hour;
- result *= MINSPERHOUR;
- result += newp->tm_min - oldp->tm_min;
- result *= SECSPERMIN;
- result += newp->tm_sec - oldp->tm_sec;
- return result;
-}
-
-static void
-show(char *zone, time_t t, int v)
-{
- register struct tm * tmp;
-
- (void) printf("%-*s ", (int) longest, zone);
- if (v) {
- tmp = gmtime(&t);
- if (tmp == NULL) {
- (void) printf(tformat(), t);
- } else {
- dumptime(tmp);
- (void) printf(" UTC");
- }
- (void) printf(" = ");
- }
- tmp = my_localtime(&t);
- dumptime(tmp);
- if (tmp != NULL) {
- if (*abbr(tmp) != '\0')
- (void) printf(" %s", abbr(tmp));
- if (v) {
- (void) printf(" isdst=%d", tmp->tm_isdst);
-#ifdef TM_GMTOFF
- (void) printf(" gmtoff=%ld", tmp->TM_GMTOFF);
-#endif /* defined TM_GMTOFF */
- }
- }
- (void) printf("\n");
- if (tmp != NULL && *abbr(tmp) != '\0')
- abbrok(abbr(tmp), zone);
-}
-
-static char *
-abbr(tmp)
-struct tm * tmp;
-{
- register char * result;
- static char nada;
-
- if (tmp->tm_isdst != 0 && tmp->tm_isdst != 1)
- return &nada;
- result = tzname[tmp->tm_isdst];
- return (result == NULL) ? &nada : result;
-}
-
-/*
-** The code below can fail on certain theoretical systems;
-** it works on all known real-world systems as of 2004-12-30.
-*/
-
-static const char *
-tformat(void)
-{
- if (0.5 == (time_t) 0.5) { /* floating */
- if (sizeof (time_t) > sizeof (double))
- return "%Lg";
- return "%g";
- }
- if (0 > (time_t) -1) { /* signed */
- if (sizeof (time_t) > sizeof (long))
- return "%lld";
- if (sizeof (time_t) > sizeof (int))
- return "%ld";
- return "%d";
- }
- if (sizeof (time_t) > sizeof (unsigned long))
- return "%llu";
- if (sizeof (time_t) > sizeof (unsigned int))
- return "%lu";
- return "%u";
-}
-
-static void
-dumptime(timeptr)
-register const struct tm * timeptr;
-{
- static const char wday_name[][3] = {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
- };
- static const char mon_name[][3] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
- register const char * wn;
- register const char * mn;
- register int lead;
- register int trail;
-
- if (timeptr == NULL) {
- (void) printf("NULL");
- return;
- }
- /*
- ** The packaged versions of localtime and gmtime never put out-of-range
- ** values in tm_wday or tm_mon, but since this code might be compiled
- ** with other (perhaps experimental) versions, paranoia is in order.
- */
- if (timeptr->tm_wday < 0 || timeptr->tm_wday >=
- (int) (sizeof wday_name / sizeof wday_name[0]))
- wn = "???";
- else wn = wday_name[timeptr->tm_wday];
- if (timeptr->tm_mon < 0 || timeptr->tm_mon >=
- (int) (sizeof mon_name / sizeof mon_name[0]))
- mn = "???";
- else mn = mon_name[timeptr->tm_mon];
- (void) printf("%.3s %.3s%3d %.2d:%.2d:%.2d ",
- wn, mn,
- timeptr->tm_mday, timeptr->tm_hour,
- timeptr->tm_min, timeptr->tm_sec);
-#define DIVISOR 10
- trail = timeptr->tm_year % DIVISOR + TM_YEAR_BASE % DIVISOR;
- lead = timeptr->tm_year / DIVISOR + TM_YEAR_BASE / DIVISOR +
- trail / DIVISOR;
- trail %= DIVISOR;
- if (trail < 0 && lead > 0) {
- trail += DIVISOR;
- --lead;
- } else if (lead < 0 && trail > 0) {
- trail -= DIVISOR;
- ++lead;
- }
- if (lead == 0)
- (void) printf("%d", trail);
- else (void) printf("%d%d", lead, ((trail < 0) ? -trail : trail));
-}
diff --git a/lib/libc/time/zic.8 b/lib/libc/time/zic.8
deleted file mode 100644
index f5970554525..00000000000
--- a/lib/libc/time/zic.8
+++ /dev/null
@@ -1,450 +0,0 @@
-.\" $OpenBSD: zic.8,v 1.28 2012/09/13 11:14:20 millert Exp $
-.Dd $Mdocdate: September 13 2012 $
-.Dt ZIC 8
-.Os
-.Sh NAME
-.Nm zic
-.Nd time zone compiler
-.Sh SYNOPSIS
-.Nm zic
-.Bk -words
-.Op Fl v
-.Op Fl d Ar directory
-.Op Fl L Ar leapsecondfilename
-.Op Fl l Ar timezone
-.Op Fl p Ar timezone
-.Op Fl y Ar command
-.Op Ar filename Ar ...
-.Ek
-.Sh DESCRIPTION
-.Nm
-reads text from the file(s) named on the command line
-and creates the time conversion information files specified in this input.
-If a
-.Ar filename
-is
-.Dq Fl ,
-the standard input is read.
-.Pp
-These options are available:
-.Bl -tag -width "-d directory"
-.It Fl d Ar directory
-Create time conversion information files in the named directory rather than
-in the standard directory named below.
-.It Fl L Ar leapsecondfilename
-Read leap second information from the file with the given name.
-If this option is not used,
-no leap second information appears in output files.
-.It Fl l Ar timezone
-Use the given time zone as local time.
-.Nm
-will act as if the input contained a link line of the form
-.Pp
-.Dl Link timezone localtime
-.It Fl p Ar timezone
-Use the given time zone's rules when handling POSIX-format
-time zone environment variables.
-.Nm
-will act as if the input contained a link line of the form
-.Pp
-.Dl Link timezone posixrules
-.It Fl v
-Complain if a year that appears in a data file is outside the range
-of years representable by
-.Xr time 3
-values.
-Also complain if a time of 24:00
-(which cannot be handled by pre-1998 versions of
-.Nm zic )
-appears in the input.
-.It Fl y Ar command
-Use the given
-.Ar command
-rather than
-.Em yearistype
-when checking year types (see below).
-.El
-.Pp
-Input lines are made up of fields.
-Fields are separated from one another by any number of whitespace characters.
-Leading and trailing whitespace on input lines is ignored.
-An unquoted sharp character (#) in the input introduces a comment which extends
-to the end of the line the sharp character appears on.
-White space characters and sharp characters may be enclosed in double quotes
-(") if they're to be used as part of a field.
-Any line that is blank (after comment stripping) is ignored.
-Non-blank lines are expected to be of one of three types:
-rule lines, zone lines, and link lines.
-.Pp
-Names (such as month names) must be in English and are case insensitive.
-Abbreviations, if used, must be unambiguous in context.
-.Pp
-A rule line has the form:
-.Bd -literal -offset indent
-Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-.Ed
-.Pp
-For example:
-.Bd -literal -offset indent
-Rule US 1967 1973 - Apr lastSun 2:00 1:00 D
-.Ed
-.Pp
-The fields that make up a rule line are:
-.Bl -tag -width "LETTER/S"
-.It Cm NAME
-Gives the (arbitrary) name of the set of rules this rule is part of.
-.It Cm FROM
-Gives the first year in which the rule applies.
-Any integer year can be supplied; the Gregorian calendar is assumed.
-The word
-.Em minimum
-(or an abbreviation) means the minimum year representable as an integer.
-The word
-.Em maximum
-(or an abbreviation) means the maximum year representable as an integer.
-Rules can describe times that are not representable as time values,
-with the unrepresentable times ignored; this allows rules to be portable
-among hosts with differing time value types.
-.It Cm TO
-Gives the final year in which the rule applies.
-In addition to
-.Em minimum
-and
-.Em maximum
-(as above),
-the word
-.Em only
-(or an abbreviation)
-may be used to repeat the value of the
-.Em FROM
-field.
-.It Cm TYPE
-Gives the type of year in which the rule applies.
-If
-.Em TYPE
-is
-.Dq Fl
-then the rule applies in all years between
-.Em FROM
-and
-.Em TO
-inclusive.
-If
-.Em TYPE
-is something else, then
-.Nm
-executes the command
-.Pp
-.Dl yearistype Ar year Ar type
-.Pp
-to check the type of a year:
-an exit status of zero is taken to mean that the year is of the given type;
-an exit status of one is taken to mean that the year is not of the given type.
-.It Cm IN
-Names the month in which the rule takes effect.
-Month names may be abbreviated.
-.It Cm ON
-Gives the day on which the rule takes effect.
-Recognized forms include:
-.Pp
-.Bl -tag -width "SunXX25" -compact -offset indent
-.It 5
-the fifth of the month
-.It lastSun
-the last Sunday in the month
-.It lastMon
-the last Monday in the month
-.It Sun\*(Ge8
-first Sunday on or after the eighth
-.It Sun\*(Le25
-last Sunday on or before the 25th
-.El
-.Pp
-Names of days of the week may be abbreviated or spelled out in full.
-Note that there must be no spaces within the
-.Em ON
-field.
-.It Cm AT
-Gives the time of day at which the rule takes effect.
-Recognized forms include:
-.Pp
-.Bl -tag -width "1:28:14" -compact -offset indent
-.It 2
-time in hours
-.It 2:00
-time in hours and minutes
-.It 15:00
-24-hour format time (for times after noon)
-.It 1:28:14
-time in hours, minutes, and seconds
-.It \&-
-equivalent to 0
-.El
-.Pp
-where hour 0 is midnight at the start of the day,
-and hour 24 is midnight at the end of the day.
-Any of these forms may be followed by the letter
-.Em w
-if the given time is local
-.Dq wall clock
-time,
-.Em s
-if the given time is local
-.Dq standard
-time, or
-.Em u
-(or
-.Em g
-or
-.Em z )
-if the given time is universal time;
-in the absence of an indicator,
-wall clock time is assumed.
-.It Cm SAVE
-Gives the amount of time to be added to local standard time when the rule is in
-effect.
-This field has the same format as the
-.Em AT
-field
-(although, of course, the
-.Em w
-and
-.Em s
-suffixes are not used).
-.It Cm LETTER/S
-Gives the
-.Dq variable part
-(for example, the
-.Dq S
-or
-.Dq D
-in
-.Dq EST
-or
-.Dq EDT )
-of time zone abbreviations to be used when this rule is in effect.
-If this field is
-.Dq Fl
-the variable part is null.
-.El
-.Pp
-A zone line has the form:
-.Bd -literal -offset 3n
-Zone NAME GMTOFF RULES/SAVE FORMAT [UNTILYEAR [MONTH [DAY [TIME]]]]
-.Ed
-.Pp
-For example:
-.Bd -literal -offset 3n
-Zone Australia/Adelaide 9:30 Aus CST 1971 Oct 31 2:00
-.Ed
-.Pp
-The fields that make up a zone line are:
-.Bl -tag -width GMTOFF
-.It Cm NAME
-The name of the time zone.
-This is the name used in creating the time conversion information file for the
-zone.
-.It Cm GMTOFF
-The amount of time to add to UTC to get standard time in this zone.
-This field has the same format as the
-.Em AT
-and
-.Em SAVE
-fields of rule lines;
-begin the field with a minus sign if time must be subtracted from UTC.
-.It Cm RULES/SAVE
-The name of the rule(s) that apply in the time zone or,
-alternately, an amount of time to add to local standard time.
-If this field is
-.Dq \-
-then standard time always applies in the time zone.
-.It Cm FORMAT
-The format for time zone abbreviations in this time zone.
-The pair of characters
-.Em %s
-is used to show where the
-.Dq variable part
-of the time zone abbreviation goes.
-Alternately,
-a slash
-.Pq \&/
-separates standard and daylight abbreviations.
-.It Cm UNTILYEAR [MONTH [DAY [TIME]]]
-The time at which the UTC offset or the rule(s) change for a location.
-It is specified as a year, a month, a day, and a time of day.
-If this is specified,
-the time zone information is generated from the given UTC offset
-and rule change until the time specified.
-The month, day, and time of day have the same format as the IN, ON, and AT
-fields of a rule; trailing fields can be omitted, and default to the
-earliest possible value for the missing fields.
-.Pp
-The next line must be a
-.Dq continuation
-line; this has the same form as a zone line except that the
-string
-.Dq Zone
-and the name are omitted, as the continuation line will
-place information starting at the time specified as the
-.Dq until
-information in the previous line in the file used by the previous line.
-Continuation lines may contain
-.Dq until
-information, just as zone lines do, indicating that the next line is a further
-continuation.
-.El
-.Pp
-A link line has the form:
-.Bd -literal -offset indent
-Link LINK-FROM LINK-TO
-.Ed
-.Pp
-For example:
-.Bd -literal -offset indent
-Link Europe/Istanbul Asia/Istanbul
-.Ed
-.Pp
-The
-.Em LINK-FROM
-field should appear as the
-.Em NAME
-field in some zone line;
-the
-.Em LINK-TO
-field is used as an alternate name for that zone.
-.Pp
-Except for continuation lines,
-lines may appear in any order in the input.
-.Pp
-Lines in the file that describes leap seconds have the following form:
-.Bd -literal -offset indent
-Leap YEAR MONTH DAY HH:MM:SS CORR R/S
-.Ed
-.Pp
-For example:
-.Bd -literal -offset indent
-Leap 1974 Dec 31 23:59:60 + S
-.Ed
-.Pp
-The
-.Em YEAR ,
-.Em MONTH ,
-.Em DAY ,
-and
-.Em HH:MM:SS
-fields tell when the leap second happened.
-The
-.Em CORR
-field
-should be
-.Dq +
-if a second was added
-or
-.Dq -
-if a second was skipped.
-.\" There's no need to document the following, since it's impossible for more
-.\" than one leap second to be inserted or deleted at a time.
-.\" The C Standard is in error in suggesting the possibility.
-.\" See Terry J Quinn, The BIPM and the accurate measure of time,
-.\" Proc IEEE 79, 7 (July 1991), 894-905.
-.\" or
-.\" .q ++
-.\" if two seconds were added
-.\" or
-.\" .q --
-.\" if two seconds were skipped.
-The
-.Em R/S
-field should be (an abbreviation of)
-.Dq Stationary
-if the leap second time given by the other fields should be interpreted as UTC
-or (an abbreviation of)
-.Dq Rolling
-if the leap second time given by the other fields should be interpreted as
-local wall clock time.
-.Sh EXTENDED EXAMPLE
-Here is an extended example of
-.Nm
-input, intended to illustrate many of its features.
-.Bd -literal
-# Rule NAME FROM TO TYPE IN ON AT SAVE LETTER/S
-Rule Swiss 1940 only - Nov 2 0:00 1:00 S
-Rule Swiss 1940 only - Dec 31 0:00 0 -
-Rule Swiss 1941 1942 - May Sun\*(Ge1 2:00 1:00 S
-Rule Swiss 1941 1942 - Oct Sun\*(Ge1 0:00 0
-
-Rule EU 1977 1980 - Apr Sun\*(Ge1 1:00u 1:00 S
-Rule EU 1977 only - Sep lastSun 1:00u 0 -
-Rule EU 1978 only - Oct 1 1:00u 0 -
-Rule EU 1979 1995 - Sep lastSun 1:00u 0 -
-Rule EU 1981 max - Mar lastSun 1:00u 1:00 S
-Rule EU 1996 max - Oct lastSun 1:00u 0 -
-
-# Zone NAME GMTOFF RULES FORMAT UNTIL
-Zone Europe/Zurich 0:34:08 - LMT 1848 Sep 12
- 0:29:44 - BMT 1894 Jun
- 1:00 Swiss CE%sT 1981
- 1:00 EU CE%sT
-
-Link Europe/Zurich Switzerland
-.Ed
-.Pp
-In this example, the zone is named Europe/Zurich
-but it has an alias as Switzerland.
-Zurich was 34 minutes and 8 seconds west of GMT until 1848-09-12 at 00:00,
-when the offset changed to 29 minutes and 44 seconds.
-After 1894-06-01 at 00:00 Swiss daylight saving rules
-(defined with lines beginning with "Rule Swiss") apply,
-and the GMT offset became one hour.
-From 1981 to the present,
-EU daylight saving rules have applied,
-and the UTC offset has remained at one hour.
-.Pp
-In 1940, daylight saving time applied from
-November 2 at 00:00 to December 31 at 00:00.
-In 1941 and 1942, daylight saving time applied
-from the first Sunday in May at 02:00
-to the first Sunday in October at 00:00.
-The pre-1981 EU daylight-saving rules have no effect here,
-but are included for completeness.
-Since 1981,
-daylight saving has begun on the last Sunday in March at 01:00 UTC.
-Until 1995 it ended the last Sunday in September at 01:00 UTC,
-but this changed to the last Sunday in October starting in 1996.
-.Pp
-For purposes of display,
-"LMT" and "BMT" were initially used, respectively.
-Since Swiss rules and later EU rules were applied,
-the display name for the timezone has been CET for standard time
-and CEST for daylight saving time.
-.Sh FILES
-.Bl -tag -width "/usr/share/zoneinfo" -compact
-.It Pa /etc/localtime
-link to local time zone
-.It Pa /usr/share/zoneinfo
-standard directory used for created files
-.El
-.Sh SEE ALSO
-.Xr ctime 3 ,
-.Xr tzfile 5 ,
-.Xr zdump 8
-.Sh CAVEATS
-For areas with more than two types of local time,
-you may need to use local standard time in the
-.Em AT
-field of the earliest transition time's rule to ensure that
-the earliest transition time recorded in the compiled file is correct.
-.Pp
-If,
-for a particular zone,
-a clock advance caused by the start of daylight saving
-coincides with and is equal to
-a clock retreat caused by a change in UTC offset,
-.Nm
-produces a single transition to daylight saving at the new UTC offset
-(without any change in wall clock time).
-To get separate transitions
-use multiple zone continuation lines
-specifying transition instants using universal time.
-.\" This file is in the public domain, so clarified as of
-.\" 2009-05-17 by Arthur David Olson.
diff --git a/lib/libc/time/zic.c b/lib/libc/time/zic.c
deleted file mode 100644
index 903fd5ece0a..00000000000
--- a/lib/libc/time/zic.c
+++ /dev/null
@@ -1,2762 +0,0 @@
-/* $OpenBSD: zic.c,v 1.37 2015/02/09 11:29:19 tedu Exp $ */
-/*
-** This file is in the public domain, so clarified as of
-** 2006-07-17 by Arthur David Olson.
-*/
-
-#include "private.h"
-#include "locale.h"
-#include "tzfile.h"
-
-#define ZIC_VERSION '2'
-
-typedef int_fast64_t zic_t;
-
-#ifndef ZIC_MAX_ABBR_LEN_WO_WARN
-#define ZIC_MAX_ABBR_LEN_WO_WARN 6
-#endif /* !defined ZIC_MAX_ABBR_LEN_WO_WARN */
-
-#include <sys/stat.h>
-#define MKDIR_UMASK (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)
-
-/*
-** On some ancient hosts, predicates like `isspace(C)' are defined
-** only if isascii(C) || C == EOF. Modern hosts obey the C Standard,
-** which says they are defined only if C == ((unsigned char) C) || C == EOF.
-** Neither the C Standard nor Posix require that `isascii' exist.
-** For portability, we check both ancient and modern requirements.
-** If isascii is not defined, the isascii check succeeds trivially.
-*/
-#include "ctype.h"
-
-#define OFFSET_STRLEN_MAXIMUM (7 + INT_STRLEN_MAXIMUM(long))
-#define RULE_STRLEN_MAXIMUM 8 /* "Mdd.dd.d" */
-
-#define end(cp, n) (memchr((cp), '\0', (n)))
-
-struct rule {
- const char * r_filename;
- int r_linenum;
- const char * r_name;
-
- int r_loyear; /* for example, 1986 */
- int r_hiyear; /* for example, 1986 */
- const char * r_yrtype;
- int r_lowasnum;
- int r_hiwasnum;
-
- int r_month; /* 0..11 */
-
- int r_dycode; /* see below */
- int r_dayofmonth;
- int r_wday;
-
- long r_tod; /* time from midnight */
- int r_todisstd; /* above is standard time if TRUE */
- /* or wall clock time if FALSE */
- int r_todisgmt; /* above is GMT if TRUE */
- /* or local time if FALSE */
- long r_stdoff; /* offset from standard time */
- const char * r_abbrvar; /* variable part of abbreviation */
-
- int r_todo; /* a rule to do (used in outzone) */
- zic_t r_temp; /* used in outzone */
-};
-
-/*
-** r_dycode r_dayofmonth r_wday
-*/
-
-#define DC_DOM 0 /* 1..31 */ /* unused */
-#define DC_DOWGEQ 1 /* 1..31 */ /* 0..6 (Sun..Sat) */
-#define DC_DOWLEQ 2 /* 1..31 */ /* 0..6 (Sun..Sat) */
-
-struct zone {
- const char * z_filename;
- int z_linenum;
-
- const char * z_name;
- long z_gmtoff;
- const char * z_rule;
- const char * z_format;
-
- long z_stdoff;
-
- struct rule * z_rules;
- int z_nrules;
-
- struct rule z_untilrule;
- zic_t z_untiltime;
-};
-
-extern int getopt(int argc, char * const argv[],
- const char * options);
-extern int link(const char * fromname, const char * toname);
-extern char * optarg;
-extern int optind;
-
-static void addtt(zic_t starttime, int type);
-static int addtype(long gmtoff, const char * abbr, int isdst,
- int ttisstd, int ttisgmt);
-static void leapadd(zic_t t, int positive, int rolling, int count);
-static void adjleap(void);
-static void associate(void);
-static int ciequal(const char * ap, const char * bp);
-static void convert(long val, char * buf);
-static void convert64(zic_t val, char * buf);
-static void dolink(const char * fromfield, const char * tofield);
-static void doabbr(char * abbr, size_t size, const char * format,
- const char * letters, int isdst, int doquotes);
-static void eat(const char * name, int num);
-static void eats(const char * name, int num,
- const char * rname, int rnum);
-static long eitol(int i);
-static void error(const char * message);
-static char ** getfields(char * buf);
-static long gethms(const char * string, const char * errstrng,
- int signable);
-static void infile(const char * filename);
-static void inleap(char ** fields, int nfields);
-static void inlink(char ** fields, int nfields);
-static void inrule(char ** fields, int nfields);
-static int inzcont(char ** fields, int nfields);
-static int inzone(char ** fields, int nfields);
-static int inzsub(char ** fields, int nfields, int iscont);
-static int is32(zic_t x);
-static int itsabbr(const char * abbr, const char * word);
-static int itsdir(const char * name);
-static int lowerit(int c);
-static char * memcheck(char * tocheck);
-static int mkdirs(char * filename);
-static void newabbr(const char * abbr);
-static long oadd(long t1, long t2);
-static void outzone(const struct zone * zp, int ntzones);
-static void puttzcode(long code, FILE * fp);
-static void puttzcode64(zic_t code, FILE * fp);
-static int rcomp(const void * leftp, const void * rightp);
-static zic_t rpytime(const struct rule * rp, int wantedy);
-static void rulesub(struct rule * rp,
- const char * loyearp, const char * hiyearp,
- const char * typep, const char * monthp,
- const char * dayp, const char * timep);
-static int stringoffset(char * result, size_t size, long offset);
-static int stringrule(char * result, size_t size, const struct rule * rp,
- long dstoff, long gmtoff);
-static void stringzone(char * result, size_t size,
- const struct zone * zp, int ntzones);
-static void setboundaries(void);
-static zic_t tadd(zic_t t1, long t2);
-static void usage(FILE *stream, int status);
-static void writezone(const char * name, const char * string);
-static int yearistype(int year, const char * type);
-
-static int charcnt;
-static int errors;
-static const char * filename;
-static int leapcnt;
-static int leapseen;
-static int leapminyear;
-static int leapmaxyear;
-static int linenum;
-static int max_abbrvar_len;
-static int max_format_len;
-static zic_t max_time;
-static int max_year;
-static zic_t min_time;
-static int min_year;
-static int noise;
-static const char * rfilename;
-static int rlinenum;
-static const char * progname;
-static int timecnt;
-static int typecnt;
-
-/*
-** Line codes.
-*/
-
-#define LC_RULE 0
-#define LC_ZONE 1
-#define LC_LINK 2
-#define LC_LEAP 3
-
-/*
-** Which fields are which on a Zone line.
-*/
-
-#define ZF_NAME 1
-#define ZF_GMTOFF 2
-#define ZF_RULE 3
-#define ZF_FORMAT 4
-#define ZF_TILYEAR 5
-#define ZF_TILMONTH 6
-#define ZF_TILDAY 7
-#define ZF_TILTIME 8
-#define ZONE_MINFIELDS 5
-#define ZONE_MAXFIELDS 9
-
-/*
-** Which fields are which on a Zone continuation line.
-*/
-
-#define ZFC_GMTOFF 0
-#define ZFC_RULE 1
-#define ZFC_FORMAT 2
-#define ZFC_TILYEAR 3
-#define ZFC_TILMONTH 4
-#define ZFC_TILDAY 5
-#define ZFC_TILTIME 6
-#define ZONEC_MINFIELDS 3
-#define ZONEC_MAXFIELDS 7
-
-/*
-** Which files are which on a Rule line.
-*/
-
-#define RF_NAME 1
-#define RF_LOYEAR 2
-#define RF_HIYEAR 3
-#define RF_COMMAND 4
-#define RF_MONTH 5
-#define RF_DAY 6
-#define RF_TOD 7
-#define RF_STDOFF 8
-#define RF_ABBRVAR 9
-#define RULE_FIELDS 10
-
-/*
-** Which fields are which on a Link line.
-*/
-
-#define LF_FROM 1
-#define LF_TO 2
-#define LINK_FIELDS 3
-
-/*
-** Which fields are which on a Leap line.
-*/
-
-#define LP_YEAR 1
-#define LP_MONTH 2
-#define LP_DAY 3
-#define LP_TIME 4
-#define LP_CORR 5
-#define LP_ROLL 6
-#define LEAP_FIELDS 7
-
-/*
-** Year synonyms.
-*/
-
-#define YR_MINIMUM 0
-#define YR_MAXIMUM 1
-#define YR_ONLY 2
-
-static struct rule * rules;
-static int nrules; /* number of rules */
-
-static struct zone * zones;
-static int nzones; /* number of zones */
-
-struct link {
- const char * l_filename;
- int l_linenum;
- const char * l_from;
- const char * l_to;
-};
-
-static struct link * links;
-static int nlinks;
-
-struct lookup {
- const char * l_word;
- const int l_value;
-};
-
-static struct lookup const * byword(const char * string,
- const struct lookup * lp);
-
-static struct lookup const line_codes[] = {
- { "Rule", LC_RULE },
- { "Zone", LC_ZONE },
- { "Link", LC_LINK },
- { "Leap", LC_LEAP },
- { NULL, 0}
-};
-
-static struct lookup const mon_names[] = {
- { "January", TM_JANUARY },
- { "February", TM_FEBRUARY },
- { "March", TM_MARCH },
- { "April", TM_APRIL },
- { "May", TM_MAY },
- { "June", TM_JUNE },
- { "July", TM_JULY },
- { "August", TM_AUGUST },
- { "September", TM_SEPTEMBER },
- { "October", TM_OCTOBER },
- { "November", TM_NOVEMBER },
- { "December", TM_DECEMBER },
- { NULL, 0 }
-};
-
-static struct lookup const wday_names[] = {
- { "Sunday", TM_SUNDAY },
- { "Monday", TM_MONDAY },
- { "Tuesday", TM_TUESDAY },
- { "Wednesday", TM_WEDNESDAY },
- { "Thursday", TM_THURSDAY },
- { "Friday", TM_FRIDAY },
- { "Saturday", TM_SATURDAY },
- { NULL, 0 }
-};
-
-static struct lookup const lasts[] = {
- { "last-Sunday", TM_SUNDAY },
- { "last-Monday", TM_MONDAY },
- { "last-Tuesday", TM_TUESDAY },
- { "last-Wednesday", TM_WEDNESDAY },
- { "last-Thursday", TM_THURSDAY },
- { "last-Friday", TM_FRIDAY },
- { "last-Saturday", TM_SATURDAY },
- { NULL, 0 }
-};
-
-static struct lookup const begin_years[] = {
- { "minimum", YR_MINIMUM },
- { "maximum", YR_MAXIMUM },
- { NULL, 0 }
-};
-
-static struct lookup const end_years[] = {
- { "minimum", YR_MINIMUM },
- { "maximum", YR_MAXIMUM },
- { "only", YR_ONLY },
- { NULL, 0 }
-};
-
-static struct lookup const leap_types[] = {
- { "Rolling", TRUE },
- { "Stationary", FALSE },
- { NULL, 0 }
-};
-
-static const int len_months[2][MONSPERYEAR] = {
- { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
- { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
-};
-
-static const int len_years[2] = {
- DAYSPERNYEAR, DAYSPERLYEAR
-};
-
-static struct attype {
- zic_t at;
- unsigned char type;
-} attypes[TZ_MAX_TIMES];
-static long gmtoffs[TZ_MAX_TYPES];
-static char isdsts[TZ_MAX_TYPES];
-static unsigned char abbrinds[TZ_MAX_TYPES];
-static char ttisstds[TZ_MAX_TYPES];
-static char ttisgmts[TZ_MAX_TYPES];
-static char chars[TZ_MAX_CHARS];
-static zic_t trans[TZ_MAX_LEAPS];
-static long corr[TZ_MAX_LEAPS];
-static char roll[TZ_MAX_LEAPS];
-
-/*
-** Memory allocation.
-*/
-
-static char *
-memcheck(ptr)
-char * const ptr;
-{
- if (ptr == NULL) {
- const char *e = strerror(errno);
-
- (void) fprintf(stderr, _("%s: Memory exhausted: %s\n"),
- progname, e);
- exit(EXIT_FAILURE);
- }
- return ptr;
-}
-
-static char *
-ecatalloc(char *start, const char *tail)
-{
- size_t len;
- char *str;
-
- len = strlen(start) + strlen(tail) + 1;
- str = memcheck(realloc(start, len));
- strlcat(str, tail, len);
- return str;
-}
-
-#define emalloc(size) memcheck(malloc(size))
-#define erealloc(ptr, size) memcheck(realloc((ptr), (size)))
-#define ecpyalloc(ptr) memcheck(strdup(ptr))
-
-/*
-** Error handling.
-*/
-
-static void
-eats(name, num, rname, rnum)
-const char * const name;
-const int num;
-const char * const rname;
-const int rnum;
-{
- filename = name;
- linenum = num;
- rfilename = rname;
- rlinenum = rnum;
-}
-
-static void
-eat(name, num)
-const char * const name;
-const int num;
-{
- eats(name, num, (char *) NULL, -1);
-}
-
-static void
-error(string)
-const char * const string;
-{
- /*
- ** Match the format of "cc" to allow sh users to
- ** zic ... 2>&1 | error -t "*" -v
- ** on BSD systems.
- */
- (void) fprintf(stderr, _("\"%s\", line %d: %s"),
- filename, linenum, string);
- if (rfilename != NULL)
- (void) fprintf(stderr, _(" (rule from \"%s\", line %d)"),
- rfilename, rlinenum);
- (void) fprintf(stderr, "\n");
- ++errors;
-}
-
-static void
-warning(string)
-const char * const string;
-{
- char * cp;
-
- cp = ecpyalloc(_("warning: "));
- cp = ecatalloc(cp, string);
- error(cp);
- free(cp);
- --errors;
-}
-
-static void
-usage(FILE *stream, int status)
-{
- (void) fprintf(stream, _("usage: %s [-v] [-d directory] [-L leapsecondfilename] [-l timezone]\n\t[-p timezone] [-y command] [filename ...]\n"),
- progname);
- exit(status);
-}
-
-static const char * psxrules;
-static const char * lcltime;
-static const char * directory;
-static const char * leapsec;
-static const char * yitcommand;
-
-int
-main(argc, argv)
-int argc;
-char * argv[];
-{
- register int i;
- register int j;
- register int c;
-
- (void) umask(umask(S_IWGRP | S_IWOTH) | (S_IWGRP | S_IWOTH));
-#if HAVE_GETTEXT
- (void) setlocale(LC_ALL, "");
-#ifdef TZ_DOMAINDIR
- (void) bindtextdomain(TZ_DOMAIN, TZ_DOMAINDIR);
-#endif /* defined TEXTDOMAINDIR */
- (void) textdomain(TZ_DOMAIN);
-#endif /* HAVE_GETTEXT */
- progname = argv[0];
- if (TYPE_BIT(zic_t) < 64) {
- (void) fprintf(stderr, "%s: %s\n", progname,
- _("wild compilation-time specification of zic_t"));
- exit(EXIT_FAILURE);
- }
- while ((c = getopt(argc, argv, "d:l:p:L:vy:")) != -1)
- switch (c) {
- default:
- usage(stderr, EXIT_FAILURE);
- case 'd':
- if (directory == NULL)
- directory = optarg;
- else {
- (void) fprintf(stderr,
-_("%s: More than one -d option specified\n"),
- progname);
- exit(EXIT_FAILURE);
- }
- break;
- case 'l':
- if (lcltime == NULL)
- lcltime = optarg;
- else {
- (void) fprintf(stderr,
-_("%s: More than one -l option specified\n"),
- progname);
- exit(EXIT_FAILURE);
- }
- break;
- case 'p':
- if (psxrules == NULL)
- psxrules = optarg;
- else {
- (void) fprintf(stderr,
-_("%s: More than one -p option specified\n"),
- progname);
- exit(EXIT_FAILURE);
- }
- break;
- case 'y':
- if (yitcommand == NULL)
- yitcommand = optarg;
- else {
- (void) fprintf(stderr,
-_("%s: More than one -y option specified\n"),
- progname);
- exit(EXIT_FAILURE);
- }
- break;
- case 'L':
- if (leapsec == NULL)
- leapsec = optarg;
- else {
- (void) fprintf(stderr,
-_("%s: More than one -L option specified\n"),
- progname);
- exit(EXIT_FAILURE);
- }
- break;
- case 'v':
- noise = TRUE;
- break;
- }
- if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
- usage(stderr, EXIT_FAILURE); /* usage message by request */
- if (directory == NULL)
- directory = TZDIR;
- if (yitcommand == NULL)
- yitcommand = "yearistype";
-
- setboundaries();
-
- if (optind < argc && leapsec != NULL) {
- infile(leapsec);
- adjleap();
- }
-
- for (i = optind; i < argc; ++i)
- infile(argv[i]);
- if (errors)
- exit(EXIT_FAILURE);
- associate();
- for (i = 0; i < nzones; i = j) {
- /*
- ** Find the next non-continuation zone entry.
- */
- for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
- continue;
- outzone(&zones[i], j - i);
- }
- /*
- ** Make links.
- */
- for (i = 0; i < nlinks; ++i) {
- eat(links[i].l_filename, links[i].l_linenum);
- dolink(links[i].l_from, links[i].l_to);
- if (noise)
- for (j = 0; j < nlinks; ++j)
- if (strcmp(links[i].l_to,
- links[j].l_from) == 0)
- warning(_("link to link"));
- }
- if (lcltime != NULL) {
- eat("command line", 1);
- dolink(lcltime, TZDEFAULT);
- }
- if (psxrules != NULL) {
- eat("command line", 1);
- dolink(psxrules, TZDEFRULES);
- }
- return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-}
-
-static void
-dolink(fromfield, tofield)
-const char * const fromfield;
-const char * const tofield;
-{
- register char * fromname;
- register char * toname;
-
- if (fromfield[0] == '/')
- fromname = ecpyalloc(fromfield);
- else {
- fromname = ecpyalloc(directory);
- fromname = ecatalloc(fromname, "/");
- fromname = ecatalloc(fromname, fromfield);
- }
- if (tofield[0] == '/')
- toname = ecpyalloc(tofield);
- else {
- toname = ecpyalloc(directory);
- toname = ecatalloc(toname, "/");
- toname = ecatalloc(toname, tofield);
- }
- /*
- ** We get to be careful here since
- ** there's a fair chance of root running us.
- */
- if (!itsdir(toname))
- (void) remove(toname);
- if (link(fromname, toname) != 0) {
- int result;
-
- if (mkdirs(toname) != 0)
- exit(EXIT_FAILURE);
-
- result = link(fromname, toname);
-#if HAVE_SYMLINK
- if (result != 0 && errno == EXDEV)
- result = symlink(fromname, toname);
-#endif /* HAVE_SYMLINK */
- if (result != 0) {
- const char *e = strerror(errno);
-
- (void) fprintf(stderr,
- _("%s: Can't link from %s to %s: %s\n"),
- progname, fromname, toname, e);
- exit(EXIT_FAILURE);
- }
- }
- free(fromname);
- free(toname);
-}
-
-#define TIME_T_BITS_IN_FILE 64
-
-static void
-setboundaries(void)
-{
- register int i;
-
- min_time = -1;
- for (i = 0; i < TIME_T_BITS_IN_FILE - 1; ++i)
- min_time *= 2;
- max_time = -(min_time + 1);
-}
-
-static int
-itsdir(name)
-const char * const name;
-{
- register char * myname;
- register int accres;
-
- myname = ecpyalloc(name);
- myname = ecatalloc(myname, "/.");
- accres = access(myname, F_OK);
- free(myname);
- return accres == 0;
-}
-
-/*
-** Associate sets of rules with zones.
-*/
-
-/*
-** Sort by rule name.
-*/
-
-static int
-rcomp(cp1, cp2)
-const void * cp1;
-const void * cp2;
-{
- return strcmp(((const struct rule *) cp1)->r_name,
- ((const struct rule *) cp2)->r_name);
-}
-
-static void
-associate(void)
-{
- register struct zone * zp;
- register struct rule * rp;
- register int base, out;
- register int i, j;
-
- if (nrules != 0) {
- (void) qsort((void *) rules, (size_t) nrules,
- (size_t) sizeof *rules, rcomp);
- for (i = 0; i < nrules - 1; ++i) {
- if (strcmp(rules[i].r_name,
- rules[i + 1].r_name) != 0)
- continue;
- if (strcmp(rules[i].r_filename,
- rules[i + 1].r_filename) == 0)
- continue;
- eat(rules[i].r_filename, rules[i].r_linenum);
- warning(_("same rule name in multiple files"));
- eat(rules[i + 1].r_filename, rules[i + 1].r_linenum);
- warning(_("same rule name in multiple files"));
- for (j = i + 2; j < nrules; ++j) {
- if (strcmp(rules[i].r_name,
- rules[j].r_name) != 0)
- break;
- if (strcmp(rules[i].r_filename,
- rules[j].r_filename) == 0)
- continue;
- if (strcmp(rules[i + 1].r_filename,
- rules[j].r_filename) == 0)
- continue;
- break;
- }
- i = j - 1;
- }
- }
- for (i = 0; i < nzones; ++i) {
- zp = &zones[i];
- zp->z_rules = NULL;
- zp->z_nrules = 0;
- }
- for (base = 0; base < nrules; base = out) {
- rp = &rules[base];
- for (out = base + 1; out < nrules; ++out)
- if (strcmp(rp->r_name, rules[out].r_name) != 0)
- break;
- for (i = 0; i < nzones; ++i) {
- zp = &zones[i];
- if (strcmp(zp->z_rule, rp->r_name) != 0)
- continue;
- zp->z_rules = rp;
- zp->z_nrules = out - base;
- }
- }
- for (i = 0; i < nzones; ++i) {
- zp = &zones[i];
- if (zp->z_nrules == 0) {
- /*
- ** Maybe we have a local standard time offset.
- */
- eat(zp->z_filename, zp->z_linenum);
- zp->z_stdoff = gethms(zp->z_rule, _("unruly zone"),
- TRUE);
- /*
- ** Note, though, that if there's no rule,
- ** a '%s' in the format is a bad thing.
- */
- if (strchr(zp->z_format, '%') != 0)
- error(_("%s in ruleless zone"));
- }
- }
- if (errors)
- exit(EXIT_FAILURE);
-}
-
-static void
-infile(name)
-const char * name;
-{
- register FILE * fp;
- register char ** fields;
- register char * cp;
- register const struct lookup * lp;
- register int nfields;
- register int wantcont;
- register int num;
- char buf[BUFSIZ];
-
- if (strcmp(name, "-") == 0) {
- name = _("standard input");
- fp = stdin;
- } else if ((fp = fopen(name, "r")) == NULL) {
- const char *e = strerror(errno);
-
- (void) fprintf(stderr, _("%s: Can't open %s: %s\n"),
- progname, name, e);
- exit(EXIT_FAILURE);
- }
- wantcont = FALSE;
- for (num = 1; ; ++num) {
- eat(name, num);
- if (fgets(buf, (int) sizeof buf, fp) != buf)
- break;
- cp = strchr(buf, '\n');
- if (cp == NULL) {
- error(_("line too long"));
- exit(EXIT_FAILURE);
- }
- *cp = '\0';
- fields = getfields(buf);
- nfields = 0;
- while (fields[nfields] != NULL) {
- static char nada;
-
- if (strcmp(fields[nfields], "-") == 0)
- fields[nfields] = &nada;
- ++nfields;
- }
- if (nfields == 0) {
- /* nothing to do */
- } else if (wantcont) {
- wantcont = inzcont(fields, nfields);
- } else {
- lp = byword(fields[0], line_codes);
- if (lp == NULL)
- error(_("input line of unknown type"));
- else switch ((int) (lp->l_value)) {
- case LC_RULE:
- inrule(fields, nfields);
- wantcont = FALSE;
- break;
- case LC_ZONE:
- wantcont = inzone(fields, nfields);
- break;
- case LC_LINK:
- inlink(fields, nfields);
- wantcont = FALSE;
- break;
- case LC_LEAP:
- if (name != leapsec)
- (void) fprintf(stderr,
-_("%s: Leap line in non leap seconds file %s\n"),
- progname, name);
- else inleap(fields, nfields);
- wantcont = FALSE;
- break;
- default: /* "cannot happen" */
- (void) fprintf(stderr,
-_("%s: panic: Invalid l_value %d\n"),
- progname, lp->l_value);
- exit(EXIT_FAILURE);
- }
- }
- free((char *) fields);
- }
- if (ferror(fp)) {
- (void) fprintf(stderr, _("%s: Error reading %s\n"),
- progname, filename);
- exit(EXIT_FAILURE);
- }
- if (fp != stdin && fclose(fp)) {
- const char *e = strerror(errno);
-
- (void) fprintf(stderr, _("%s: Error closing %s: %s\n"),
- progname, filename, e);
- exit(EXIT_FAILURE);
- }
- if (wantcont)
- error(_("expected continuation line not found"));
-}
-
-/*
-** Convert a string of one of the forms
-** h -h hh:mm -hh:mm hh:mm:ss -hh:mm:ss
-** into a number of seconds.
-** A null string maps to zero.
-** Call error with errstring and return zero on errors.
-*/
-
-static long
-gethms(string, errstring, signable)
-const char * string;
-const char * const errstring;
-const int signable;
-{
- long hh;
- int mm, ss, sign;
-
- if (string == NULL || *string == '\0')
- return 0;
- if (!signable)
- sign = 1;
- else if (*string == '-') {
- sign = -1;
- ++string;
- } else sign = 1;
- if (sscanf(string, scheck(string, "%ld"), &hh) == 1)
- mm = ss = 0;
- else if (sscanf(string, scheck(string, "%ld:%d"), &hh, &mm) == 2)
- ss = 0;
- else if (sscanf(string, scheck(string, "%ld:%d:%d"),
- &hh, &mm, &ss) != 3) {
- error(errstring);
- return 0;
- }
- if (hh < 0 ||
- mm < 0 || mm >= MINSPERHOUR ||
- ss < 0 || ss > SECSPERMIN) {
- error(errstring);
- return 0;
- }
- if (LONG_MAX / SECSPERHOUR < hh) {
- error(_("time overflow"));
- return 0;
- }
- if (noise && hh == HOURSPERDAY && mm == 0 && ss == 0)
- warning(_("24:00 not handled by pre-1998 versions of zic"));
- if (noise && (hh > HOURSPERDAY ||
- (hh == HOURSPERDAY && (mm != 0 || ss != 0))))
-warning(_("values over 24 hours not handled by pre-2007 versions of zic"));
- return oadd(eitol(sign) * hh * eitol(SECSPERHOUR),
- eitol(sign) * (eitol(mm) * eitol(SECSPERMIN) + eitol(ss)));
-}
-
-static void
-inrule(fields, nfields)
-register char ** const fields;
-const int nfields;
-{
- static struct rule r;
-
- if (nfields != RULE_FIELDS) {
- error(_("wrong number of fields on Rule line"));
- return;
- }
- if (*fields[RF_NAME] == '\0') {
- error(_("nameless rule"));
- return;
- }
- r.r_filename = filename;
- r.r_linenum = linenum;
- r.r_stdoff = gethms(fields[RF_STDOFF], _("invalid saved time"), TRUE);
- rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
- fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
- r.r_name = ecpyalloc(fields[RF_NAME]);
- r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
- if (max_abbrvar_len < strlen(r.r_abbrvar))
- max_abbrvar_len = strlen(r.r_abbrvar);
- rules = (struct rule *) (void *) erealloc((char *) rules,
- (int) ((nrules + 1) * sizeof *rules));
- rules[nrules++] = r;
-}
-
-static int
-inzone(fields, nfields)
-register char ** const fields;
-const int nfields;
-{
- register int i;
- static char * buf;
- size_t len;
-
- if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
- error(_("wrong number of fields on Zone line"));
- return FALSE;
- }
- if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
- len = 132 + strlen(TZDEFAULT);
- buf = erealloc(buf, len);
- (void) snprintf(buf, len,
-_("\"Zone %s\" line and -l option are mutually exclusive"),
- TZDEFAULT);
- error(buf);
- return FALSE;
- }
- if (strcmp(fields[ZF_NAME], TZDEFRULES) == 0 && psxrules != NULL) {
- len = 132 + strlen(TZDEFRULES);
- buf = erealloc(buf, len);
- (void) snprintf(buf, len,
-_("\"Zone %s\" line and -p option are mutually exclusive"),
- TZDEFRULES);
- error(buf);
- return FALSE;
- }
- for (i = 0; i < nzones; ++i)
- if (zones[i].z_name != NULL &&
- strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
- len = 132 + strlen(fields[ZF_NAME]) +
- strlen(zones[i].z_filename);
- buf = erealloc(buf, len);
- (void) snprintf(buf, len,
-_("duplicate zone name %s (file \"%s\", line %d)"),
- fields[ZF_NAME],
- zones[i].z_filename,
- zones[i].z_linenum);
- error(buf);
- return FALSE;
- }
- return inzsub(fields, nfields, FALSE);
-}
-
-static int
-inzcont(fields, nfields)
-register char ** const fields;
-const int nfields;
-{
- if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
- error(_("wrong number of fields on Zone continuation line"));
- return FALSE;
- }
- return inzsub(fields, nfields, TRUE);
-}
-
-static int
-inzsub(fields, nfields, iscont)
-register char ** const fields;
-const int nfields;
-const int iscont;
-{
- register char * cp;
- static struct zone z;
- register int i_gmtoff, i_rule, i_format;
- register int i_untilyear, i_untilmonth;
- register int i_untilday, i_untiltime;
- register int hasuntil;
-
- if (iscont) {
- i_gmtoff = ZFC_GMTOFF;
- i_rule = ZFC_RULE;
- i_format = ZFC_FORMAT;
- i_untilyear = ZFC_TILYEAR;
- i_untilmonth = ZFC_TILMONTH;
- i_untilday = ZFC_TILDAY;
- i_untiltime = ZFC_TILTIME;
- z.z_name = NULL;
- } else {
- i_gmtoff = ZF_GMTOFF;
- i_rule = ZF_RULE;
- i_format = ZF_FORMAT;
- i_untilyear = ZF_TILYEAR;
- i_untilmonth = ZF_TILMONTH;
- i_untilday = ZF_TILDAY;
- i_untiltime = ZF_TILTIME;
- z.z_name = ecpyalloc(fields[ZF_NAME]);
- }
- z.z_filename = filename;
- z.z_linenum = linenum;
- z.z_gmtoff = gethms(fields[i_gmtoff], _("invalid UTC offset"), TRUE);
- if ((cp = strchr(fields[i_format], '%')) != 0) {
- if (*++cp != 's' || strchr(cp, '%') != 0) {
- error(_("invalid abbreviation format"));
- return FALSE;
- }
- }
- z.z_rule = ecpyalloc(fields[i_rule]);
- z.z_format = ecpyalloc(fields[i_format]);
- if (max_format_len < strlen(z.z_format))
- max_format_len = strlen(z.z_format);
- hasuntil = nfields > i_untilyear;
- if (hasuntil) {
- z.z_untilrule.r_filename = filename;
- z.z_untilrule.r_linenum = linenum;
- rulesub(&z.z_untilrule,
- fields[i_untilyear],
- "only",
- "",
- (nfields > i_untilmonth) ?
- fields[i_untilmonth] : "Jan",
- (nfields > i_untilday) ? fields[i_untilday] : "1",
- (nfields > i_untiltime) ? fields[i_untiltime] : "0");
- z.z_untiltime = rpytime(&z.z_untilrule,
- z.z_untilrule.r_loyear);
- if (iscont && nzones > 0 &&
- z.z_untiltime > min_time &&
- z.z_untiltime < max_time &&
- zones[nzones - 1].z_untiltime > min_time &&
- zones[nzones - 1].z_untiltime < max_time &&
- zones[nzones - 1].z_untiltime >= z.z_untiltime) {
- error(_(
-"Zone continuation line end time is not after end time of previous line"
- ));
- return FALSE;
- }
- }
- zones = (struct zone *) (void *) erealloc((char *) zones,
- (int) ((nzones + 1) * sizeof *zones));
- zones[nzones++] = z;
- /*
- ** If there was an UNTIL field on this line,
- ** there's more information about the zone on the next line.
- */
- return hasuntil;
-}
-
-static void
-inleap(fields, nfields)
-register char ** const fields;
-const int nfields;
-{
- register const char * cp;
- register const struct lookup * lp;
- register int i, j;
- int year, month, day;
- long dayoff, tod;
- zic_t t;
-
- if (nfields != LEAP_FIELDS) {
- error(_("wrong number of fields on Leap line"));
- return;
- }
- dayoff = 0;
- cp = fields[LP_YEAR];
- if (sscanf(cp, scheck(cp, "%d"), &year) != 1) {
- /*
- ** Leapin' Lizards!
- */
- error(_("invalid leaping year"));
- return;
- }
- if (!leapseen || leapmaxyear < year)
- leapmaxyear = year;
- if (!leapseen || leapminyear > year)
- leapminyear = year;
- leapseen = TRUE;
- j = EPOCH_YEAR;
- while (j != year) {
- if (year > j) {
- i = len_years[isleap(j)];
- ++j;
- } else {
- --j;
- i = -len_years[isleap(j)];
- }
- dayoff = oadd(dayoff, eitol(i));
- }
- if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
- error(_("invalid month name"));
- return;
- }
- month = lp->l_value;
- j = TM_JANUARY;
- while (j != month) {
- i = len_months[isleap(year)][j];
- dayoff = oadd(dayoff, eitol(i));
- ++j;
- }
- cp = fields[LP_DAY];
- if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
- day <= 0 || day > len_months[isleap(year)][month]) {
- error(_("invalid day of month"));
- return;
- }
- dayoff = oadd(dayoff, eitol(day - 1));
- if (dayoff < 0 && !TYPE_SIGNED(zic_t)) {
- error(_("time before zero"));
- return;
- }
- if (dayoff < min_time / SECSPERDAY) {
- error(_("time too small"));
- return;
- }
- if (dayoff > max_time / SECSPERDAY) {
- error(_("time too large"));
- return;
- }
- t = (zic_t) dayoff * SECSPERDAY;
- tod = gethms(fields[LP_TIME], _("invalid time of day"), FALSE);
- cp = fields[LP_CORR];
- {
- register int positive;
- int count;
-
- if (strcmp(cp, "") == 0) { /* infile() turns "-" into "" */
- positive = FALSE;
- count = 1;
- } else if (strcmp(cp, "--") == 0) {
- positive = FALSE;
- count = 2;
- } else if (strcmp(cp, "+") == 0) {
- positive = TRUE;
- count = 1;
- } else if (strcmp(cp, "++") == 0) {
- positive = TRUE;
- count = 2;
- } else {
- error(_("illegal CORRECTION field on Leap line"));
- return;
- }
- if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
- error(_(
- "illegal Rolling/Stationary field on Leap line"
- ));
- return;
- }
- leapadd(tadd(t, tod), positive, lp->l_value, count);
- }
-}
-
-static void
-inlink(fields, nfields)
-register char ** const fields;
-const int nfields;
-{
- struct link l;
-
- if (nfields != LINK_FIELDS) {
- error(_("wrong number of fields on Link line"));
- return;
- }
- if (*fields[LF_FROM] == '\0') {
- error(_("blank FROM field on Link line"));
- return;
- }
- if (*fields[LF_TO] == '\0') {
- error(_("blank TO field on Link line"));
- return;
- }
- l.l_filename = filename;
- l.l_linenum = linenum;
- l.l_from = ecpyalloc(fields[LF_FROM]);
- l.l_to = ecpyalloc(fields[LF_TO]);
- links = (struct link *) (void *) erealloc((char *) links,
- (int) ((nlinks + 1) * sizeof *links));
- links[nlinks++] = l;
-}
-
-static void
-rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
-register struct rule * const rp;
-const char * const loyearp;
-const char * const hiyearp;
-const char * const typep;
-const char * const monthp;
-const char * const dayp;
-const char * const timep;
-{
- register const struct lookup * lp;
- register const char * cp;
- register char * dp;
- register char * ep;
-
- if ((lp = byword(monthp, mon_names)) == NULL) {
- error(_("invalid month name"));
- return;
- }
- rp->r_month = lp->l_value;
- rp->r_todisstd = FALSE;
- rp->r_todisgmt = FALSE;
- dp = ecpyalloc(timep);
- if (*dp != '\0') {
- ep = dp + strlen(dp) - 1;
- switch (lowerit(*ep)) {
- case 's': /* Standard */
- rp->r_todisstd = TRUE;
- rp->r_todisgmt = FALSE;
- *ep = '\0';
- break;
- case 'w': /* Wall */
- rp->r_todisstd = FALSE;
- rp->r_todisgmt = FALSE;
- *ep = '\0';
- break;
- case 'g': /* Greenwich */
- case 'u': /* Universal */
- case 'z': /* Zulu */
- rp->r_todisstd = TRUE;
- rp->r_todisgmt = TRUE;
- *ep = '\0';
- break;
- }
- }
- rp->r_tod = gethms(dp, _("invalid time of day"), FALSE);
- free(dp);
- /*
- ** Year work.
- */
- cp = loyearp;
- lp = byword(cp, begin_years);
- rp->r_lowasnum = lp == NULL;
- if (!rp->r_lowasnum) switch ((int) lp->l_value) {
- case YR_MINIMUM:
- rp->r_loyear = INT_MIN;
- break;
- case YR_MAXIMUM:
- rp->r_loyear = INT_MAX;
- break;
- default: /* "cannot happen" */
- (void) fprintf(stderr,
- _("%s: panic: Invalid l_value %d\n"),
- progname, lp->l_value);
- exit(EXIT_FAILURE);
- } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1) {
- error(_("invalid starting year"));
- return;
- }
- cp = hiyearp;
- lp = byword(cp, end_years);
- rp->r_hiwasnum = lp == NULL;
- if (!rp->r_hiwasnum) switch ((int) lp->l_value) {
- case YR_MINIMUM:
- rp->r_hiyear = INT_MIN;
- break;
- case YR_MAXIMUM:
- rp->r_hiyear = INT_MAX;
- break;
- case YR_ONLY:
- rp->r_hiyear = rp->r_loyear;
- break;
- default: /* "cannot happen" */
- (void) fprintf(stderr,
- _("%s: panic: Invalid l_value %d\n"),
- progname, lp->l_value);
- exit(EXIT_FAILURE);
- } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1) {
- error(_("invalid ending year"));
- return;
- }
- if (rp->r_loyear > rp->r_hiyear) {
- error(_("starting year greater than ending year"));
- return;
- }
- if (*typep == '\0')
- rp->r_yrtype = NULL;
- else {
- if (rp->r_loyear == rp->r_hiyear) {
- error(_("typed single year"));
- return;
- }
- rp->r_yrtype = ecpyalloc(typep);
- }
- /*
- ** Day work.
- ** Accept things such as:
- ** 1
- ** last-Sunday
- ** Sun<=20
- ** Sun>=7
- */
- dp = ecpyalloc(dayp);
- if ((lp = byword(dp, lasts)) != NULL) {
- rp->r_dycode = DC_DOWLEQ;
- rp->r_wday = lp->l_value;
- rp->r_dayofmonth = len_months[1][rp->r_month];
- } else {
- if ((ep = strchr(dp, '<')) != 0)
- rp->r_dycode = DC_DOWLEQ;
- else if ((ep = strchr(dp, '>')) != 0)
- rp->r_dycode = DC_DOWGEQ;
- else {
- ep = dp;
- rp->r_dycode = DC_DOM;
- }
- if (rp->r_dycode != DC_DOM) {
- *ep++ = 0;
- if (*ep++ != '=') {
- error(_("invalid day of month"));
- free(dp);
- return;
- }
- if ((lp = byword(dp, wday_names)) == NULL) {
- error(_("invalid weekday name"));
- free(dp);
- return;
- }
- rp->r_wday = lp->l_value;
- }
- if (sscanf(ep, scheck(ep, "%d"), &rp->r_dayofmonth) != 1 ||
- rp->r_dayofmonth <= 0 ||
- (rp->r_dayofmonth > len_months[1][rp->r_month])) {
- error(_("invalid day of month"));
- free(dp);
- return;
- }
- }
- free(dp);
-}
-
-static void
-convert(val, buf)
-const long val;
-char * const buf;
-{
- register int i;
- register int shift;
-
- for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
- buf[i] = val >> shift;
-}
-
-static void
-convert64(val, buf)
-const zic_t val;
-char * const buf;
-{
- register int i;
- register int shift;
-
- for (i = 0, shift = 56; i < 8; ++i, shift -= 8)
- buf[i] = val >> shift;
-}
-
-static void
-puttzcode(val, fp)
-const long val;
-FILE * const fp;
-{
- char buf[4];
-
- convert(val, buf);
- (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
-}
-
-static void
-puttzcode64(val, fp)
-const zic_t val;
-FILE * const fp;
-{
- char buf[8];
-
- convert64(val, buf);
- (void) fwrite((void *) buf, (size_t) sizeof buf, (size_t) 1, fp);
-}
-
-static int
-atcomp(avp, bvp)
-const void * avp;
-const void * bvp;
-{
- const zic_t a = ((const struct attype *) avp)->at;
- const zic_t b = ((const struct attype *) bvp)->at;
-
- return (a < b) ? -1 : (a > b);
-}
-
-static int
-is32(x)
-const zic_t x;
-{
- return INT32_MIN <= x && x <= INT32_MAX;
-}
-
-static void
-writezone(name, string)
-const char * const name;
-const char * const string;
-{
- register FILE * fp;
- register int i, j;
- register int leapcnt32, leapi32;
- register int timecnt32, timei32;
- register int pass;
- static char * fullname;
- static const struct tzhead tzh0;
- static struct tzhead tzh;
- zic_t ats[TZ_MAX_TIMES];
- unsigned char types[TZ_MAX_TIMES];
- size_t len;
-
- /*
- ** Sort.
- */
- if (timecnt > 1)
- (void) qsort((void *) attypes, (size_t) timecnt,
- (size_t) sizeof *attypes, atcomp);
- /*
- ** Optimize.
- */
- {
- int fromi;
- int toi;
-
- toi = 0;
- fromi = 0;
- while (fromi < timecnt && attypes[fromi].at < min_time)
- ++fromi;
- if (isdsts[0] == 0)
- while (fromi < timecnt && attypes[fromi].type == 0)
- ++fromi; /* handled by default rule */
- for ( ; fromi < timecnt; ++fromi) {
- if (toi != 0 && ((attypes[fromi].at +
- gmtoffs[attypes[toi - 1].type]) <=
- (attypes[toi - 1].at + gmtoffs[toi == 1 ? 0
- : attypes[toi - 2].type]))) {
- attypes[toi - 1].type =
- attypes[fromi].type;
- continue;
- }
- if (toi == 0 ||
- attypes[toi - 1].type != attypes[fromi].type)
- attypes[toi++] = attypes[fromi];
- }
- timecnt = toi;
- }
- /*
- ** Transfer.
- */
- for (i = 0; i < timecnt; ++i) {
- ats[i] = attypes[i].at;
- types[i] = attypes[i].type;
- }
- /*
- ** Correct for leap seconds.
- */
- for (i = 0; i < timecnt; ++i) {
- j = leapcnt;
- while (--j >= 0)
- if (ats[i] > trans[j] - corr[j]) {
- ats[i] = tadd(ats[i], corr[j]);
- break;
- }
- }
- /*
- ** Figure out 32-bit-limited starts and counts.
- */
- timecnt32 = timecnt;
- timei32 = 0;
- leapcnt32 = leapcnt;
- leapi32 = 0;
- while (timecnt32 > 0 && !is32(ats[timecnt32 - 1]))
- --timecnt32;
- while (timecnt32 > 0 && !is32(ats[timei32])) {
- --timecnt32;
- ++timei32;
- }
- while (leapcnt32 > 0 && !is32(trans[leapcnt32 - 1]))
- --leapcnt32;
- while (leapcnt32 > 0 && !is32(trans[leapi32])) {
- --leapcnt32;
- ++leapi32;
- }
- len = strlen(directory) + 1 + strlen(name) + 1;
- fullname = erealloc(fullname, len);
- (void) snprintf(fullname, len, "%s/%s", directory, name);
- /*
- ** Remove old file, if any, to snap links.
- */
- if (!itsdir(fullname) && remove(fullname) != 0 && errno != ENOENT) {
- const char *e = strerror(errno);
-
- (void) fprintf(stderr, _("%s: Can't remove %s: %s\n"),
- progname, fullname, e);
- exit(EXIT_FAILURE);
- }
- if ((fp = fopen(fullname, "wb")) == NULL) {
- if (mkdirs(fullname) != 0)
- exit(EXIT_FAILURE);
- if ((fp = fopen(fullname, "wb")) == NULL) {
- const char *e = strerror(errno);
-
- (void) fprintf(stderr, _("%s: Can't create %s: %s\n"),
- progname, fullname, e);
- exit(EXIT_FAILURE);
- }
- }
- for (pass = 1; pass <= 2; ++pass) {
- register int thistimei, thistimecnt;
- register int thisleapi, thisleapcnt;
- register int thistimelim, thisleaplim;
- int writetype[TZ_MAX_TIMES];
- int typemap[TZ_MAX_TYPES];
- register int thistypecnt;
- char thischars[TZ_MAX_CHARS];
- char thischarcnt;
- int indmap[TZ_MAX_CHARS];
-
- if (pass == 1) {
- thistimei = timei32;
- thistimecnt = timecnt32;
- thisleapi = leapi32;
- thisleapcnt = leapcnt32;
- } else {
- thistimei = 0;
- thistimecnt = timecnt;
- thisleapi = 0;
- thisleapcnt = leapcnt;
- }
- thistimelim = thistimei + thistimecnt;
- thisleaplim = thisleapi + thisleapcnt;
- for (i = 0; i < typecnt; ++i)
- writetype[i] = thistimecnt == timecnt;
- if (thistimecnt == 0) {
- /*
- ** No transition times fall in the current
- ** (32- or 64-bit) window.
- */
- if (typecnt != 0)
- writetype[typecnt - 1] = TRUE;
- } else {
- for (i = thistimei - 1; i < thistimelim; ++i)
- if (i >= 0)
- writetype[types[i]] = TRUE;
- /*
- ** For America/Godthab and Antarctica/Palmer
- */
- if (thistimei == 0)
- writetype[0] = TRUE;
- }
-#ifndef LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH
- /*
- ** For some pre-2011 systems: if the last-to-be-written
- ** standard (or daylight) type has an offset different from the
- ** most recently used offset,
- ** append an (unused) copy of the most recently used type
- ** (to help get global "altzone" and "timezone" variables
- ** set correctly).
- */
- {
- register int mrudst, mrustd, hidst, histd, type;
-
- hidst = histd = mrudst = mrustd = -1;
- for (i = thistimei; i < thistimelim; ++i)
- if (isdsts[types[i]])
- mrudst = types[i];
- else mrustd = types[i];
- for (i = 0; i < typecnt; ++i)
- if (writetype[i]) {
- if (isdsts[i])
- hidst = i;
- else histd = i;
- }
- if (hidst >= 0 && mrudst >= 0 && hidst != mrudst &&
- gmtoffs[hidst] != gmtoffs[mrudst]) {
- isdsts[mrudst] = -1;
- type = addtype(gmtoffs[mrudst],
- &chars[abbrinds[mrudst]],
- TRUE,
- ttisstds[mrudst],
- ttisgmts[mrudst]);
- isdsts[mrudst] = TRUE;
- writetype[type] = TRUE;
- }
- if (histd >= 0 && mrustd >= 0 && histd != mrustd &&
- gmtoffs[histd] != gmtoffs[mrustd]) {
- isdsts[mrustd] = -1;
- type = addtype(gmtoffs[mrustd],
- &chars[abbrinds[mrustd]],
- FALSE,
- ttisstds[mrustd],
- ttisgmts[mrustd]);
- isdsts[mrustd] = FALSE;
- writetype[type] = TRUE;
- }
- }
-#endif /* !defined LEAVE_SOME_PRE_2011_SYSTEMS_IN_THE_LURCH */
- thistypecnt = 0;
- for (i = 0; i < typecnt; ++i)
- typemap[i] = writetype[i] ? thistypecnt++ : -1;
- for (i = 0; i < sizeof indmap / sizeof indmap[0]; ++i)
- indmap[i] = -1;
- thischarcnt = 0;
- for (i = 0; i < typecnt; ++i) {
- register char * thisabbr;
-
- if (!writetype[i])
- continue;
- if (indmap[abbrinds[i]] >= 0)
- continue;
- thisabbr = &chars[abbrinds[i]];
- for (j = 0; j < thischarcnt; ++j)
- if (strcmp(&thischars[j], thisabbr) == 0)
- break;
- if (j == thischarcnt) {
- (void) strlcpy(&thischars[(int) thischarcnt],
- thisabbr, sizeof(thischars) - thischarcnt);
- thischarcnt += strlen(thisabbr) + 1;
- }
- indmap[abbrinds[i]] = j;
- }
-#define DO(field) (void) fwrite((void *) tzh.field, \
- (size_t) sizeof tzh.field, (size_t) 1, fp)
- tzh = tzh0;
- (void) strncpy(tzh.tzh_magic, TZ_MAGIC, sizeof tzh.tzh_magic);
- tzh.tzh_version[0] = ZIC_VERSION;
- convert(eitol(thistypecnt), tzh.tzh_ttisgmtcnt);
- convert(eitol(thistypecnt), tzh.tzh_ttisstdcnt);
- convert(eitol(thisleapcnt), tzh.tzh_leapcnt);
- convert(eitol(thistimecnt), tzh.tzh_timecnt);
- convert(eitol(thistypecnt), tzh.tzh_typecnt);
- convert(eitol(thischarcnt), tzh.tzh_charcnt);
- DO(tzh_magic);
- DO(tzh_version);
- DO(tzh_reserved);
- DO(tzh_ttisgmtcnt);
- DO(tzh_ttisstdcnt);
- DO(tzh_leapcnt);
- DO(tzh_timecnt);
- DO(tzh_typecnt);
- DO(tzh_charcnt);
-#undef DO
- for (i = thistimei; i < thistimelim; ++i)
- if (pass == 1)
- puttzcode((long) ats[i], fp);
- else puttzcode64(ats[i], fp);
- for (i = thistimei; i < thistimelim; ++i) {
- unsigned char uc;
-
- uc = typemap[types[i]];
- (void) fwrite((void *) &uc,
- (size_t) sizeof uc,
- (size_t) 1,
- fp);
- }
- for (i = 0; i < typecnt; ++i)
- if (writetype[i]) {
- puttzcode(gmtoffs[i], fp);
- (void) putc(isdsts[i], fp);
- (void) putc((unsigned char) indmap[abbrinds[i]], fp);
- }
- if (thischarcnt != 0)
- (void) fwrite((void *) thischars,
- (size_t) sizeof thischars[0],
- (size_t) thischarcnt, fp);
- for (i = thisleapi; i < thisleaplim; ++i) {
- register zic_t todo;
-
- if (roll[i]) {
- if (timecnt == 0 || trans[i] < ats[0]) {
- j = 0;
- while (isdsts[j])
- if (++j >= typecnt) {
- j = 0;
- break;
- }
- } else {
- j = 1;
- while (j < timecnt &&
- trans[i] >= ats[j])
- ++j;
- j = types[j - 1];
- }
- todo = tadd(trans[i], -gmtoffs[j]);
- } else todo = trans[i];
- if (pass == 1)
- puttzcode((long) todo, fp);
- else puttzcode64(todo, fp);
- puttzcode(corr[i], fp);
- }
- for (i = 0; i < typecnt; ++i)
- if (writetype[i])
- (void) putc(ttisstds[i], fp);
- for (i = 0; i < typecnt; ++i)
- if (writetype[i])
- (void) putc(ttisgmts[i], fp);
- }
- (void) fprintf(fp, "\n%s\n", string);
- if (ferror(fp) || fclose(fp)) {
- (void) fprintf(stderr, _("%s: Error writing %s\n"),
- progname, fullname);
- exit(EXIT_FAILURE);
- }
-}
-
-static void
-doabbr(abbr, size, format, letters, isdst, doquotes)
-char * const abbr;
-size_t size;
-const char * const format;
-const char * const letters;
-const int isdst;
-const int doquotes;
-{
- register char * cp;
- register char * slashp;
- register int len;
-
- slashp = strchr(format, '/');
- if (slashp == NULL) {
- if (letters == NULL)
- (void) strlcpy(abbr, format, size);
- else (void) snprintf(abbr, size, format, letters);
- } else if (isdst) {
- (void) strlcpy(abbr, slashp + 1, size);
- } else {
- if (slashp - format + 1 < size)
- size = slashp - format + 1;
- (void) strlcpy(abbr, format, size);
- }
- if (!doquotes)
- return;
- for (cp = abbr; *cp != '\0'; ++cp)
- if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ", *cp) == NULL &&
- strchr("abcdefghijklmnopqrstuvwxyz", *cp) == NULL)
- break;
- len = strlen(abbr);
- if (len > 0 && *cp == '\0')
- return;
- abbr[len + 2] = '\0';
- abbr[len + 1] = '>';
- for ( ; len > 0; --len)
- abbr[len] = abbr[len - 1];
- abbr[0] = '<';
-}
-
-static void
-updateminmax(x)
-const int x;
-{
- if (min_year > x)
- min_year = x;
- if (max_year < x)
- max_year = x;
-}
-
-static int
-stringoffset(result, size, offset)
-char * result;
-size_t size;
-long offset;
-{
- register int hours;
- register int minutes;
- register int seconds;
- register char * ep;
-
- result[0] = '\0';
- if (offset < 0) {
- (void) strlcpy(result, "-", size);
- offset = -offset;
- }
- seconds = offset % SECSPERMIN;
- offset /= SECSPERMIN;
- minutes = offset % MINSPERHOUR;
- offset /= MINSPERHOUR;
- hours = offset;
- if (hours >= HOURSPERDAY) {
- result[0] = '\0';
- return -1;
- }
- ep = end(result, size);
- (void) snprintf(ep, size - (ep - result), "%d", hours);
- if (minutes != 0 || seconds != 0) {
- ep = end(result, size);
- (void) snprintf(ep, size - (ep - result), ":%02d", minutes);
- if (seconds != 0) {
- ep = end(result, size);
- (void) snprintf(ep, size - (ep - result), ":%02d", seconds);
- }
- }
- return 0;
-}
-
-static int
-stringrule(result, size, rp, dstoff, gmtoff)
-char * result;
-size_t size;
-const struct rule * const rp;
-const long dstoff;
-const long gmtoff;
-{
- register long tod;
- register char * ep;
-
- ep = end(result, size);
- size -= ep - result;
- result = ep;
- if (rp->r_dycode == DC_DOM) {
- register int month, total;
-
- if (rp->r_dayofmonth == 29 && rp->r_month == TM_FEBRUARY)
- return -1;
- total = 0;
- for (month = 0; month < rp->r_month; ++month)
- total += len_months[0][month];
- (void) snprintf(result, size, "J%d", total + rp->r_dayofmonth);
- } else {
- register int week;
-
- if (rp->r_dycode == DC_DOWGEQ) {
- if ((rp->r_dayofmonth % DAYSPERWEEK) != 1)
- return -1;
- week = 1 + rp->r_dayofmonth / DAYSPERWEEK;
- } else if (rp->r_dycode == DC_DOWLEQ) {
- if (rp->r_dayofmonth == len_months[1][rp->r_month])
- week = 5;
- else {
- if ((rp->r_dayofmonth % DAYSPERWEEK) != 0)
- return -1;
- week = rp->r_dayofmonth / DAYSPERWEEK;
- }
- } else return -1; /* "cannot happen" */
- (void) snprintf(result, size, "M%d.%d.%d",
- rp->r_month + 1, week, rp->r_wday);
- }
- tod = rp->r_tod;
- if (rp->r_todisgmt)
- tod += gmtoff;
- if (rp->r_todisstd && rp->r_stdoff == 0)
- tod += dstoff;
- if (tod < 0) {
- result[0] = '\0';
- return -1;
- }
- if (tod != 2 * SECSPERMIN * MINSPERHOUR) {
- (void) strlcat(result, "/", size);
- ep = end(result, size);
- if (stringoffset(ep, size - (ep - result), tod) != 0)
- return -1;
- }
- return 0;
-}
-
-static void
-stringzone(result, size, zpfirst, zonecount)
-char * result;
-size_t size;
-const struct zone * const zpfirst;
-const int zonecount;
-{
- register const struct zone * zp;
- register struct rule * rp;
- register struct rule * stdrp;
- register struct rule * dstrp;
- register int i;
- register const char * abbrvar;
- register char * ep;
-
- result[0] = '\0';
- zp = zpfirst + zonecount - 1;
- stdrp = dstrp = NULL;
- for (i = 0; i < zp->z_nrules; ++i) {
- rp = &zp->z_rules[i];
- if (rp->r_hiwasnum || rp->r_hiyear != INT_MAX)
- continue;
- if (rp->r_yrtype != NULL)
- continue;
- if (rp->r_stdoff == 0) {
- if (stdrp == NULL)
- stdrp = rp;
- else return;
- } else {
- if (dstrp == NULL)
- dstrp = rp;
- else return;
- }
- }
- if (stdrp == NULL && dstrp == NULL) {
- /*
- ** There are no rules running through "max".
- ** Let's find the latest rule.
- */
- for (i = 0; i < zp->z_nrules; ++i) {
- rp = &zp->z_rules[i];
- if (stdrp == NULL || rp->r_hiyear > stdrp->r_hiyear ||
- (rp->r_hiyear == stdrp->r_hiyear &&
- rp->r_month > stdrp->r_month))
- stdrp = rp;
- }
- if (stdrp != NULL && stdrp->r_stdoff != 0)
- return; /* We end up in DST (a POSIX no-no). */
- /*
- ** Horrid special case: if year is 2037,
- ** presume this is a zone handled on a year-by-year basis;
- ** do not try to apply a rule to the zone.
- */
- if (stdrp != NULL && stdrp->r_hiyear == 2037)
- return;
- }
- if (stdrp == NULL && (zp->z_nrules != 0 || zp->z_stdoff != 0))
- return;
- abbrvar = (stdrp == NULL) ? "" : stdrp->r_abbrvar;
- doabbr(result, size, zp->z_format, abbrvar, FALSE, TRUE);
- ep = end(result, size);
- if (stringoffset(ep, size - (ep - result), -zp->z_gmtoff) != 0) {
- result[0] = '\0';
- return;
- }
- if (dstrp == NULL)
- return;
- ep = end(result, size);
- doabbr(ep, size - (ep - result), zp->z_format, dstrp->r_abbrvar, TRUE, TRUE);
- if (dstrp->r_stdoff != SECSPERMIN * MINSPERHOUR) {
- ep = end(result, size);
- if (stringoffset(ep, size - (ep - result),
- -(zp->z_gmtoff + dstrp->r_stdoff)) != 0) {
- result[0] = '\0';
- return;
- }
- }
- (void) strlcat(result, ",", size);
- if (stringrule(result, size, dstrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
- result[0] = '\0';
- return;
- }
- (void) strlcat(result, ",", size);
- if (stringrule(result, size, stdrp, dstrp->r_stdoff, zp->z_gmtoff) != 0) {
- result[0] = '\0';
- return;
- }
-}
-
-static void
-outzone(zpfirst, zonecount)
-const struct zone * const zpfirst;
-const int zonecount;
-{
- register const struct zone * zp;
- register struct rule * rp;
- register int i, j;
- register int usestart, useuntil;
- register zic_t starttime, untiltime;
- register long gmtoff;
- register long stdoff;
- register int year;
- register long startoff;
- register int startttisstd;
- register int startttisgmt;
- register int type;
- register char * startbuf;
- register char * ab;
- register char * envvar;
- register int max_abbr_len;
- register int max_envvar_len;
- register int prodstic; /* all rules are min to max */
-
- max_abbr_len = 2 + max_format_len + max_abbrvar_len;
- max_envvar_len = 2 * max_abbr_len + 5 * 9;
- startbuf = emalloc(max_abbr_len + 1);
- ab = emalloc(max_abbr_len + 1);
- envvar = emalloc(max_envvar_len + 1);
- INITIALIZE(untiltime);
- INITIALIZE(starttime);
- /*
- ** Now. . .finally. . .generate some useful data!
- */
- timecnt = 0;
- typecnt = 0;
- charcnt = 0;
- prodstic = zonecount == 1;
- /*
- ** Thanks to Earl Chew
- ** for noting the need to unconditionally initialize startttisstd.
- */
- startttisstd = FALSE;
- startttisgmt = FALSE;
- min_year = max_year = EPOCH_YEAR;
- if (leapseen) {
- updateminmax(leapminyear);
- updateminmax(leapmaxyear + (leapmaxyear < INT_MAX));
- }
- for (i = 0; i < zonecount; ++i) {
- zp = &zpfirst[i];
- if (i < zonecount - 1)
- updateminmax(zp->z_untilrule.r_loyear);
- for (j = 0; j < zp->z_nrules; ++j) {
- rp = &zp->z_rules[j];
- if (rp->r_lowasnum)
- updateminmax(rp->r_loyear);
- if (rp->r_hiwasnum)
- updateminmax(rp->r_hiyear);
- if (rp->r_lowasnum || rp->r_hiwasnum)
- prodstic = FALSE;
- }
- }
- /*
- ** Generate lots of data if a rule can't cover all future times.
- */
- stringzone(envvar, max_envvar_len + 1, zpfirst, zonecount);
- if (noise && envvar[0] == '\0') {
- register char * wp;
-
-wp = ecpyalloc(_("no POSIX environment variable for zone"));
- wp = ecatalloc(wp, " ");
- wp = ecatalloc(wp, zpfirst->z_name);
- warning(wp);
- free(wp);
- }
- if (envvar[0] == '\0') {
- if (min_year >= INT_MIN + YEARSPERREPEAT)
- min_year -= YEARSPERREPEAT;
- else min_year = INT_MIN;
- if (max_year <= INT_MAX - YEARSPERREPEAT)
- max_year += YEARSPERREPEAT;
- else max_year = INT_MAX;
- /*
- ** Regardless of any of the above,
- ** for a "proDSTic" zone which specifies that its rules
- ** always have and always will be in effect,
- ** we only need one cycle to define the zone.
- */
- if (prodstic) {
- min_year = 1900;
- max_year = min_year + YEARSPERREPEAT;
- }
- }
- /*
- ** For the benefit of older systems,
- ** generate data from 1900 through 2037.
- */
- if (min_year > 1900)
- min_year = 1900;
- if (max_year < 2037)
- max_year = 2037;
- for (i = 0; i < zonecount; ++i) {
- /*
- ** A guess that may well be corrected later.
- */
- stdoff = 0;
- zp = &zpfirst[i];
- usestart = i > 0 && (zp - 1)->z_untiltime > min_time;
- useuntil = i < (zonecount - 1);
- if (useuntil && zp->z_untiltime <= min_time)
- continue;
- gmtoff = zp->z_gmtoff;
- eat(zp->z_filename, zp->z_linenum);
- *startbuf = '\0';
- startoff = zp->z_gmtoff;
- if (zp->z_nrules == 0) {
- stdoff = zp->z_stdoff;
- doabbr(startbuf, max_abbr_len + 1, zp->z_format,
- (char *) NULL, stdoff != 0, FALSE);
- type = addtype(oadd(zp->z_gmtoff, stdoff),
- startbuf, stdoff != 0, startttisstd,
- startttisgmt);
- if (usestart) {
- addtt(starttime, type);
- usestart = FALSE;
- } else if (stdoff != 0)
- addtt(min_time, type);
- } else for (year = min_year; year <= max_year; ++year) {
- if (useuntil && year > zp->z_untilrule.r_hiyear)
- break;
- /*
- ** Mark which rules to do in the current year.
- ** For those to do, calculate rpytime(rp, year);
- */
- for (j = 0; j < zp->z_nrules; ++j) {
- rp = &zp->z_rules[j];
- eats(zp->z_filename, zp->z_linenum,
- rp->r_filename, rp->r_linenum);
- rp->r_todo = year >= rp->r_loyear &&
- year <= rp->r_hiyear &&
- yearistype(year, rp->r_yrtype);
- if (rp->r_todo)
- rp->r_temp = rpytime(rp, year);
- }
- for ( ; ; ) {
- register int k;
- register zic_t jtime, ktime;
- register long offset;
-
- INITIALIZE(ktime);
- if (useuntil) {
- /*
- ** Turn untiltime into UTC
- ** assuming the current gmtoff and
- ** stdoff values.
- */
- untiltime = zp->z_untiltime;
- if (!zp->z_untilrule.r_todisgmt)
- untiltime = tadd(untiltime,
- -gmtoff);
- if (!zp->z_untilrule.r_todisstd)
- untiltime = tadd(untiltime,
- -stdoff);
- }
- /*
- ** Find the rule (of those to do, if any)
- ** that takes effect earliest in the year.
- */
- k = -1;
- for (j = 0; j < zp->z_nrules; ++j) {
- rp = &zp->z_rules[j];
- if (!rp->r_todo)
- continue;
- eats(zp->z_filename, zp->z_linenum,
- rp->r_filename, rp->r_linenum);
- offset = rp->r_todisgmt ? 0 : gmtoff;
- if (!rp->r_todisstd)
- offset = oadd(offset, stdoff);
- jtime = rp->r_temp;
- if (jtime == min_time ||
- jtime == max_time)
- continue;
- jtime = tadd(jtime, -offset);
- if (k < 0 || jtime < ktime) {
- k = j;
- ktime = jtime;
- }
- }
- if (k < 0)
- break; /* go on to next year */
- rp = &zp->z_rules[k];
- rp->r_todo = FALSE;
- if (useuntil && ktime >= untiltime)
- break;
- stdoff = rp->r_stdoff;
- if (usestart && ktime == starttime)
- usestart = FALSE;
- if (usestart) {
- if (ktime < starttime) {
- startoff = oadd(zp->z_gmtoff,
- stdoff);
- doabbr(startbuf,
- max_abbr_len + 1,
- zp->z_format,
- rp->r_abbrvar,
- rp->r_stdoff != 0,
- FALSE);
- continue;
- }
- if (*startbuf == '\0' &&
- startoff == oadd(zp->z_gmtoff,
- stdoff)) {
- doabbr(startbuf,
- max_abbr_len + 1,
- zp->z_format,
- rp->r_abbrvar,
- rp->r_stdoff !=
- 0,
- FALSE);
- }
- }
- eats(zp->z_filename, zp->z_linenum,
- rp->r_filename, rp->r_linenum);
- doabbr(ab, max_abbr_len + 1, zp->z_format,
- rp->r_abbrvar,
- rp->r_stdoff != 0, FALSE);
- offset = oadd(zp->z_gmtoff, rp->r_stdoff);
- type = addtype(offset, ab, rp->r_stdoff != 0,
- rp->r_todisstd, rp->r_todisgmt);
- addtt(ktime, type);
- }
- }
- if (usestart) {
- if (*startbuf == '\0' &&
- zp->z_format != NULL &&
- strchr(zp->z_format, '%') == NULL &&
- strchr(zp->z_format, '/') == NULL)
- (void) strlcpy(startbuf, zp->z_format,
- max_abbr_len + 1);
- eat(zp->z_filename, zp->z_linenum);
- if (*startbuf == '\0')
-error(_("can't determine time zone abbreviation to use just after until time"));
- else addtt(starttime,
- addtype(startoff, startbuf,
- startoff != zp->z_gmtoff,
- startttisstd,
- startttisgmt));
- }
- /*
- ** Now we may get to set starttime for the next zone line.
- */
- if (useuntil) {
- startttisstd = zp->z_untilrule.r_todisstd;
- startttisgmt = zp->z_untilrule.r_todisgmt;
- starttime = zp->z_untiltime;
- if (!startttisstd)
- starttime = tadd(starttime, -stdoff);
- if (!startttisgmt)
- starttime = tadd(starttime, -gmtoff);
- }
- }
- writezone(zpfirst->z_name, envvar);
- free(startbuf);
- free(ab);
- free(envvar);
-}
-
-static void
-addtt(starttime, type)
-const zic_t starttime;
-int type;
-{
- size_t len;
-
- if (starttime <= min_time ||
- (timecnt == 1 && attypes[0].at < min_time)) {
- gmtoffs[0] = gmtoffs[type];
- isdsts[0] = isdsts[type];
- ttisstds[0] = ttisstds[type];
- ttisgmts[0] = ttisgmts[type];
- if (abbrinds[type] != 0) {
- len = strlen(&chars[abbrinds[type]]) + 1;
- (void) memmove(chars, &chars[abbrinds[type]], len);
- }
- abbrinds[0] = 0;
- charcnt = strlen(chars) + 1;
- typecnt = 1;
- timecnt = 0;
- type = 0;
- }
- if (timecnt >= TZ_MAX_TIMES) {
- error(_("too many transitions?!"));
- exit(EXIT_FAILURE);
- }
- attypes[timecnt].at = starttime;
- attypes[timecnt].type = type;
- ++timecnt;
-}
-
-static int
-addtype(gmtoff, abbr, isdst, ttisstd, ttisgmt)
-const long gmtoff;
-const char * const abbr;
-const int isdst;
-const int ttisstd;
-const int ttisgmt;
-{
- register int i, j;
-
- if (isdst != TRUE && isdst != FALSE) {
- error(_("internal error - addtype called with bad isdst"));
- exit(EXIT_FAILURE);
- }
- if (ttisstd != TRUE && ttisstd != FALSE) {
- error(_("internal error - addtype called with bad ttisstd"));
- exit(EXIT_FAILURE);
- }
- if (ttisgmt != TRUE && ttisgmt != FALSE) {
- error(_("internal error - addtype called with bad ttisgmt"));
- exit(EXIT_FAILURE);
- }
- /*
- ** See if there's already an entry for this zone type.
- ** If so, just return its index.
- */
- for (i = 0; i < typecnt; ++i) {
- if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
- strcmp(abbr, &chars[abbrinds[i]]) == 0 &&
- ttisstd == ttisstds[i] &&
- ttisgmt == ttisgmts[i])
- return i;
- }
- /*
- ** There isn't one; add a new one, unless there are already too
- ** many.
- */
- if (typecnt >= TZ_MAX_TYPES) {
- error(_("too many local time types"));
- exit(EXIT_FAILURE);
- }
- if (! (-1L - 2147483647L <= gmtoff && gmtoff <= 2147483647L)) {
- error(_("UTC offset out of range"));
- exit(EXIT_FAILURE);
- }
- gmtoffs[i] = gmtoff;
- isdsts[i] = isdst;
- ttisstds[i] = ttisstd;
- ttisgmts[i] = ttisgmt;
-
- for (j = 0; j < charcnt; ++j)
- if (strcmp(&chars[j], abbr) == 0)
- break;
- if (j == charcnt)
- newabbr(abbr);
- abbrinds[i] = j;
- ++typecnt;
- return i;
-}
-
-static void
-leapadd(t, positive, rolling, count)
-const zic_t t;
-const int positive;
-const int rolling;
-int count;
-{
- register int i, j;
-
- if (leapcnt + (positive ? count : 1) > TZ_MAX_LEAPS) {
- error(_("too many leap seconds"));
- exit(EXIT_FAILURE);
- }
- for (i = 0; i < leapcnt; ++i)
- if (t <= trans[i]) {
- if (t == trans[i]) {
- error(_("repeated leap second moment"));
- exit(EXIT_FAILURE);
- }
- break;
- }
- do {
- for (j = leapcnt; j > i; --j) {
- trans[j] = trans[j - 1];
- corr[j] = corr[j - 1];
- roll[j] = roll[j - 1];
- }
- trans[i] = t;
- corr[i] = positive ? 1L : eitol(-count);
- roll[i] = rolling;
- ++leapcnt;
- } while (positive && --count != 0);
-}
-
-static void
-adjleap(void)
-{
- register int i;
- register long last = 0;
-
- /*
- ** propagate leap seconds forward
- */
- for (i = 0; i < leapcnt; ++i) {
- trans[i] = tadd(trans[i], last);
- last = corr[i] += last;
- }
-}
-
-static int
-yearistype(year, type)
-const int year;
-const char * const type;
-{
- static char * buf;
- int result;
- size_t len;
-
- if (type == NULL || *type == '\0')
- return TRUE;
- len = 132 + strlen(yitcommand) + strlen(type);
- buf = erealloc(buf, len);
- (void) snprintf(buf, len, "%s %d %s", yitcommand, year, type);
- result = system(buf);
- if (WIFEXITED(result)) switch (WEXITSTATUS(result)) {
- case 0:
- return TRUE;
- case 1:
- return FALSE;
- }
- error(_("Wild result from command execution"));
- (void) fprintf(stderr, _("%s: command was '%s', result was %d\n"),
- progname, buf, result);
- for ( ; ; )
- exit(EXIT_FAILURE);
-}
-
-static int
-lowerit(a)
-int a;
-{
- a = (unsigned char) a;
- return (isascii(a) && isupper(a)) ? tolower(a) : a;
-}
-
-static int
-ciequal(ap, bp) /* case-insensitive equality */
-register const char * ap;
-register const char * bp;
-{
- while (lowerit(*ap) == lowerit(*bp++))
- if (*ap++ == '\0')
- return TRUE;
- return FALSE;
-}
-
-static int
-itsabbr(abbr, word)
-register const char * abbr;
-register const char * word;
-{
- if (lowerit(*abbr) != lowerit(*word))
- return FALSE;
- ++word;
- while (*++abbr != '\0')
- do {
- if (*word == '\0')
- return FALSE;
- } while (lowerit(*word++) != lowerit(*abbr));
- return TRUE;
-}
-
-static const struct lookup *
-byword(word, table)
-register const char * const word;
-register const struct lookup * const table;
-{
- register const struct lookup * foundlp;
- register const struct lookup * lp;
-
- if (word == NULL || table == NULL)
- return NULL;
- /*
- ** Look for exact match.
- */
- for (lp = table; lp->l_word != NULL; ++lp)
- if (ciequal(word, lp->l_word))
- return lp;
- /*
- ** Look for inexact match.
- */
- foundlp = NULL;
- for (lp = table; lp->l_word != NULL; ++lp)
- if (itsabbr(word, lp->l_word)) {
- if (foundlp == NULL)
- foundlp = lp;
- else return NULL; /* multiple inexact matches */
- }
- return foundlp;
-}
-
-static char **
-getfields(cp)
-register char * cp;
-{
- register char * dp;
- register char ** array;
- register int nsubs;
-
- if (cp == NULL)
- return NULL;
- array = (char **) (void *)
- emalloc((int) ((strlen(cp) + 1) * sizeof *array));
- nsubs = 0;
- for ( ; ; ) {
- while (isascii((unsigned char) *cp) &&
- isspace((unsigned char) *cp))
- ++cp;
- if (*cp == '\0' || *cp == '#')
- break;
- array[nsubs++] = dp = cp;
- do {
- if ((*dp = *cp++) != '"')
- ++dp;
- else while ((*dp = *cp++) != '"')
- if (*dp != '\0')
- ++dp;
- else {
- error(_(
- "Odd number of quotation marks"
- ));
- exit(1);
- }
- } while (*cp != '\0' && *cp != '#' &&
- (!isascii((unsigned char)*cp) || !isspace((unsigned char) *cp)));
- if (isascii((unsigned char) *cp) && isspace((unsigned char) *cp))
- ++cp;
- *dp = '\0';
- }
- array[nsubs] = NULL;
- return array;
-}
-
-static long
-oadd(t1, t2)
-const long t1;
-const long t2;
-{
- register long t;
-
- t = t1 + t2;
- if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
- error(_("time overflow"));
- exit(EXIT_FAILURE);
- }
- return t;
-}
-
-static zic_t
-tadd(t1, t2)
-const zic_t t1;
-const long t2;
-{
- register zic_t t;
-
- if (t1 == max_time && t2 > 0)
- return max_time;
- if (t1 == min_time && t2 < 0)
- return min_time;
- t = t1 + t2;
- if ((t2 > 0 && t <= t1) || (t2 < 0 && t >= t1)) {
- error(_("time overflow"));
- exit(EXIT_FAILURE);
- }
- return t;
-}
-
-/*
-** Given a rule, and a year, compute the date - in seconds since January 1,
-** 1970, 00:00 LOCAL time - in that year that the rule refers to.
-*/
-
-static zic_t
-rpytime(rp, wantedy)
-register const struct rule * const rp;
-register const int wantedy;
-{
- register int y, m, i;
- register long dayoff; /* with a nod to Margaret O. */
- register zic_t t;
-
- if (wantedy == INT_MIN)
- return min_time;
- if (wantedy == INT_MAX)
- return max_time;
- dayoff = 0;
- m = TM_JANUARY;
- y = EPOCH_YEAR;
- while (wantedy != y) {
- if (wantedy > y) {
- i = len_years[isleap(y)];
- ++y;
- } else {
- --y;
- i = -len_years[isleap(y)];
- }
- dayoff = oadd(dayoff, eitol(i));
- }
- while (m != rp->r_month) {
- i = len_months[isleap(y)][m];
- dayoff = oadd(dayoff, eitol(i));
- ++m;
- }
- i = rp->r_dayofmonth;
- if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
- if (rp->r_dycode == DC_DOWLEQ)
- --i;
- else {
- error(_("use of 2/29 in non leap-year"));
- exit(EXIT_FAILURE);
- }
- }
- --i;
- dayoff = oadd(dayoff, eitol(i));
- if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
- register long wday;
-
-#define LDAYSPERWEEK ((long) DAYSPERWEEK)
- wday = eitol(EPOCH_WDAY);
- /*
- ** Don't trust mod of negative numbers.
- */
- if (dayoff >= 0)
- wday = (wday + dayoff) % LDAYSPERWEEK;
- else {
- wday -= ((-dayoff) % LDAYSPERWEEK);
- if (wday < 0)
- wday += LDAYSPERWEEK;
- }
- while (wday != eitol(rp->r_wday))
- if (rp->r_dycode == DC_DOWGEQ) {
- dayoff = oadd(dayoff, (long) 1);
- if (++wday >= LDAYSPERWEEK)
- wday = 0;
- ++i;
- } else {
- dayoff = oadd(dayoff, (long) -1);
- if (--wday < 0)
- wday = LDAYSPERWEEK - 1;
- --i;
- }
- if (i < 0 || i >= len_months[isleap(y)][m]) {
- if (noise)
- warning(_("rule goes past start/end of month--\
-will not work with pre-2004 versions of zic"));
- }
- }
- if (dayoff < min_time / SECSPERDAY)
- return min_time;
- if (dayoff > max_time / SECSPERDAY)
- return max_time;
- t = (zic_t) dayoff * SECSPERDAY;
- return tadd(t, rp->r_tod);
-}
-
-static void
-newabbr(string)
-const char * const string;
-{
- 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((unsigned char) *cp) &&
- isalpha((unsigned char) *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((unsigned char) *cp) &&
- isdigit((unsigned char) *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);
- free(wp);
- }
- }
- i = strlen(string) + 1;
- if (charcnt + i > TZ_MAX_CHARS) {
- error(_("too many, or too long, time zone abbreviations"));
- exit(EXIT_FAILURE);
- }
- (void) strlcpy(&chars[charcnt], string, sizeof(chars) - charcnt);
- charcnt += eitol(i);
-}
-
-static int
-mkdirs(argname)
-char * argname;
-{
- register char * name;
- register char * cp;
-
- if (argname == NULL || *argname == '\0')
- return 0;
- cp = name = ecpyalloc(argname);
- while ((cp = strchr(cp + 1, '/')) != 0) {
- *cp = '\0';
- if (!itsdir(name)) {
- /*
- ** It doesn't seem to exist, so we try to create it.
- ** Creation may fail because of the directory being
- ** created by some other multiprocessor, so we get
- ** to do extra checking.
- */
- if (mkdir(name, MKDIR_UMASK) != 0) {
- const char *e = strerror(errno);
-
- if (errno != EEXIST || !itsdir(name)) {
- (void) fprintf(stderr,
-_("%s: Can't create directory %s: %s\n"),
- progname, name, e);
- free(name);
- return -1;
- }
- }
- }
- *cp = '/';
- }
- free(name);
- return 0;
-}
-
-static long
-eitol(i)
-const int i;
-{
- long l;
-
- l = i;
- if ((i < 0 && l >= 0) || (i == 0 && l != 0) || (i > 0 && l <= 0)) {
- (void) fprintf(stderr,
- _("%s: %d did not sign extend correctly\n"),
- progname, i);
- exit(EXIT_FAILURE);
- }
- return l;
-}
-
-/*
-** UNIX was a registered trademark of The Open Group in 2003.
-*/