<div dir="ltr"><div><div><div><div><div>I'm guessing that a way to minimize breakage is to end the file with:<br></div> the POSIX string<br></div> any name/value pairs<br></div> a repeat of the POSIX string.<br>
</div>That way folks who look for the POSIX string at the very end of the file will find it, and folks who look for it after the 64-bit data will too.<br><br></div> --ado<br></div><div class="gmail_extra"><br><br><div class="gmail_quote">
On Mon, Sep 9, 2013 at 9:04 PM, Paul Eggert <span dir="ltr"><<a href="mailto:eggert@cs.ucla.edu" target="_blank">eggert@cs.ucla.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im">Arthur David Olson wrote:<br>
<br>
> Adding something such as "2013e" wouldn't exhaust the reserved bytes<br>
<br>
</div>Yes, but I anticipate that various distros will want to append<br>
their own information to the version string, and the reserved<br>
space is uncomfortably small for that. And I share Zefram's<br>
leeriness of making this version information so primary; it's<br>
really just auxiliary data that does not affect how timestamps<br>
are represented or interpreted, unlike the version byte.<br>
<br>
So how about this idea instead? As part of tzfile.v3 we allow<br>
name-value pairs at the end of the file. One of them can be<br>
the version, another the zone name, and perhaps we'll think<br>
of others. Here's a proposed patch to do this, which I've<br>
pushed into the experimental version.<br>
<br>
>From d7680ffd3d43c4da6d9ff21ffb93b6783703a301 Mon Sep 17 00:00:00 2001<br>
From: Paul Eggert <<a href="mailto:eggert@cs.ucla.edu">eggert@cs.ucla.edu</a>><br>
Date: Mon, 9 Sep 2013 17:16:37 -0700<br>
Subject: [PATCH] Add optional meta-information to version-3 format.<br>
<br>
* Makefile (ZFLAGS): Add a comment about how to enable meta-info.<br>
* tzfile.5: Describe meta-information.<br>
* zic.8: Document new options -n and -o, which cause zic to<br>
generate meta-info.<br>
* zic.c: Include <stddef.h>, for ptrdiff_t.<br>
(genoption, genoptions, genname): New static vars.<br>
(usage): Summarize new options.<br>
(addgenoption, writevalue): New function.<br>
(main, writezone): Add support for new options.<br>
---<br>
Makefile | 3 +++<br>
tzfile.5 | 13 ++++++++++++<br>
zic.8 | 14 +++++++++++++<br>
zic.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--<br>
4 files changed, 101 insertions(+), 2 deletions(-)<br>
<br>
diff --git a/Makefile b/Makefile<br>
index 41b6ffc..eccb9da 100644<br>
--- a/Makefile<br>
+++ b/Makefile<br>
@@ -250,6 +250,9 @@ LDFLAGS= $(LFLAGS)<br>
zic= ./zic<br>
ZIC= $(zic) $(ZFLAGS)<br>
<br>
+# Uncomment this to put name and version info into zic output files.<br>
+#ZFLAGS= -n -o version='$(VERSION)'<br>
+<br>
# The name of a Posix-compliant `awk' on your system.<br>
AWK= awk<br>
<br>
diff --git a/tzfile.5 b/tzfile.5<br>
index ff1ec63..d609277 100644<br>
--- a/tzfile.5<br>
+++ b/tzfile.5<br>
@@ -154,6 +154,19 @@ First, the hours part of its transition times may be signed and range from<br>
from 0 through 24. Second, DST is in effect all year if it starts<br>
January 1 at 00:00 and ends December 31 at 24:00 plus the difference<br>
between daylight saving and standard time.<br>
+.PP<br>
+Also, for version-3-format time zone files, the version-2 header and<br>
+data are optionally followed by a section containing auxiliary<br>
+meta-information that is not needed to process time stamps. This<br>
+section, if present, consists of the four magic bytes "=TZ\en"<br>
+followed by zero or more newline-terminated byte strings, each<br>
+containing a name-value pair separated by "=". Names consist of ASCII<br>
+letters, digits and underscores, and start with a letter; duplicate<br>
+names are not allowed. Two common names are "name", the Zone name for<br>
+the data, and "version", the version number. Values consist of any<br>
+bytes except NUL, newline, and backslash; however, newline and<br>
+backslash can represented via the two-byte strings "\en" and "\e\e"<br>
+respectively.<br>
.SH SEE ALSO<br>
newctime(3), newtzset(3)<br>
.\" This file is in the public domain, so clarified as of<br>
diff --git a/zic.8 b/zic.8<br>
index 602c3c9..b1d3348 100644<br>
--- a/zic.8<br>
+++ b/zic.8<br>
@@ -15,6 +15,11 @@ zic \- time zone compiler<br>
.B \-l<br>
.I localtime<br>
] [<br>
+.B \-n<br>
+] [<br>
+.B \-o<br>
+.IB name = value<br>
+] [<br>
.B \-p<br>
.I posixrules<br>
] [<br>
@@ -62,6 +67,15 @@ will act as if the input contained a link line of the form<br>
.ti +.5i<br>
Link \fItimezone\fP localtime<br>
.TP<br>
+.B "\-n"<br>
+Store each zone's name into its generated file, as meta-information<br>
+with the name "name" and value the zone's name.<br>
+.TP<br>
+.BI "\-o " name = value<br>
+Store the given name-value pair into the generated file, as<br>
+meta-information. This option can be repeated, once for each distinct<br>
+name.<br>
+.TP<br>
.BI "\-p " timezone<br>
Use the given time zone's rules when handling POSIX-format<br>
time zone environment variables.<br>
diff --git a/zic.c b/zic.c<br>
index 9939195..eefa1fb 100644<br>
--- a/zic.c<br>
+++ b/zic.c<br>
@@ -9,6 +9,7 @@<br>
#include "tzfile.h"<br>
<br>
#include <stdarg.h><br>
+#include <stddef.h><br>
<br>
#define ZIC_VERSION '3'<br>
<br>
@@ -140,6 +141,9 @@ static int yearistype(int year, const char * type);<br>
static int charcnt;<br>
static int errors;<br>
static const char * filename;<br>
+static const char ** genoption;<br>
+static int genoptions;<br>
+static int genname;<br>
static int leapcnt;<br>
static int leapseen;<br>
static zic_t leapminyear;<br>
@@ -432,7 +436,8 @@ static _Noreturn void<br>
usage(FILE *stream, int status)<br>
{<br>
(void) fprintf(stream, _("%s: usage is %s \<br>
-[ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\<br>
+[ --version ] [ --help ] [ -v ] [ -l localtime ]\\\n\<br>
+\t[ -n ] [ -o name=value ]... [ -p posixrules ] \\\n\<br>
\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\<br>
\n\<br>
Report bugs to %s.\n"),<br>
@@ -446,6 +451,31 @@ static const char * directory;<br>
static const char * leapsec;<br>
static const char * yitcommand;<br>
<br>
+static int<br>
+addgenoption(char const *option)<br>
+{<br>
+ register char const *o = option;<br>
+ register ptrdiff_t namelen;<br>
+ register int i;<br>
+ if (! (isascii (*o) && isalpha(*o)))<br>
+ return 0;<br>
+ while (*++o != '=')<br>
+ if (! (isascii (*o) && (isalnum(*o) || *o == '_')))<br>
+ return 0;<br>
+ namelen = o - option;<br>
+ if (INT_MAX < namelen)<br>
+ return 0; /* fprintf won't work. */<br>
+ if (namelen == sizeof "name" - 1<br>
+ && memcmp(option, "name", namelen) == 0)<br>
+ return 0;<br>
+ for (i = 0; i < genoptions; i++)<br>
+ if (strncmp(genoption[i], option, namelen + 1) == 0)<br>
+ return 0;<br>
+ genoption = erealloc(genoption, (genoptions + 1) * sizeof *genoption);<br>
+ genoption[genoptions++] = option;<br>
+ return 1;<br>
+}<br>
+<br>
int<br>
main(int argc, char **argv)<br>
{<br>
@@ -476,7 +506,7 @@ main(int argc, char **argv)<br>
} else if (strcmp(argv[i], "--help") == 0) {<br>
usage(stdout, EXIT_SUCCESS);<br>
}<br>
- while ((c = getopt(argc, argv, "d:l:p:L:vsy:")) != EOF && c != -1)<br>
+ while ((c = getopt(argc, argv, "d:l:p:L:no:vsy:")) != EOF && c != -1)<br>
switch (c) {<br>
default:<br>
usage(stderr, EXIT_FAILURE);<br>
@@ -500,6 +530,17 @@ _("%s: More than one -l option specified\n"),<br>
exit(EXIT_FAILURE);<br>
}<br>
break;<br>
+ case 'n':<br>
+ genname = TRUE;<br>
+ break;<br>
+ case 'o':<br>
+ if (!addgenoption(optarg)) {<br>
+ fprintf(stderr,<br>
+ _("%s: %s: invalid -o option\n"),<br>
+ progname, optarg);<br>
+ exit(EXIT_FAILURE);<br>
+ }<br>
+ break;<br>
case 'p':<br>
if (psxrules == NULL)<br>
psxrules = optarg;<br>
@@ -1386,6 +1427,22 @@ is32(const zic_t x)<br>
}<br>
<br>
static void<br>
+writevalue(FILE *fp, char const *v)<br>
+{<br>
+ fputc('=', fp);<br>
+<br>
+ for (; *v; v++)<br>
+ if (*v == '\n')<br>
+ fprintf(fp, "\\n");<br>
+ else if (*v == '\\')<br>
+ fprintf(fp, "\\\\");<br>
+ else<br>
+ fputc(*v, fp);<br>
+<br>
+ fputc('\n', fp);<br>
+}<br>
+<br>
+static void<br>
writezone(const char *const name, const char *const string)<br>
{<br>
register FILE * fp;<br>
@@ -1708,6 +1765,18 @@ writezone(const char *const name, const char *const string)<br>
(void) putc(ttisgmts[i], fp);<br>
}<br>
(void) fprintf(fp, "\n%s\n", string);<br>
+ if (genname || genoptions)<br>
+ fprintf(fp, "=TZ\n");<br>
+ if (genname) {<br>
+ fprintf(fp, "name");<br>
+ writevalue(fp, name);<br>
+ }<br>
+ for (i = 0; i < genoptions; i++) {<br>
+ register char const *v = genoption[i];<br>
+ register int namelen = strchr(v, '=') - v;<br>
+ fprintf(fp, "%.*s", namelen, v);<br>
+ writevalue(fp, v + namelen + 1);<br>
+ }<br>
if (ferror(fp) || fclose(fp)) {<br>
(void) fprintf(stderr, _("%s: Error writing %s\n"),<br>
progname, fullname);<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.3.1<br>
<br>
<br>
</font></span></blockquote></div><br></div>