<div dir="ltr"><div><div><div><div><div>I&#39;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">&lt;<a href="mailto:eggert@cs.ucla.edu" target="_blank">eggert@cs.ucla.edu</a>&gt;</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>
&gt; Adding something such as &quot;2013e&quot; wouldn&#39;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&#39;s<br>
leeriness of making this version information so primary; it&#39;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&#39;ll think<br>
of others.  Here&#39;s a proposed patch to do this, which I&#39;ve<br>
pushed into the experimental version.<br>
<br>
>From d7680ffd3d43c4da6d9ff21ffb93b6783703a301 Mon Sep 17 00:00:00 2001<br>
From: Paul Eggert &lt;<a href="mailto:eggert@cs.ucla.edu">eggert@cs.ucla.edu</a>&gt;<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 &lt;stddef.h&gt;, 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=&#39;$(VERSION)&#39;<br>
+<br>
 # The name of a Posix-compliant `awk&#39; 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 &quot;=TZ\en&quot;<br>
+followed by zero or more newline-terminated byte strings, each<br>
+containing a name-value pair separated by &quot;=&quot;.  Names consist of ASCII<br>
+letters, digits and underscores, and start with a letter; duplicate<br>
+names are not allowed.  Two common names are &quot;name&quot;, the Zone name for<br>
+the data, and &quot;version&quot;, 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 &quot;\en&quot; and &quot;\e\e&quot;<br>
+respectively.<br>
 .SH SEE ALSO<br>
 newctime(3), newtzset(3)<br>
 .\&quot; 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 &quot;\-n&quot;<br>
+Store each zone&#39;s name into its generated file, as meta-information<br>
+with the name &quot;name&quot; and value the zone&#39;s name.<br>
+.TP<br>
+.BI &quot;\-o &quot; 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 &quot;\-p &quot; timezone<br>
 Use the given time zone&#39;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 &quot;tzfile.h&quot;<br>
<br>
 #include &lt;stdarg.h&gt;<br>
+#include &lt;stddef.h&gt;<br>
<br>
 #define        ZIC_VERSION     &#39;3&#39;<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, _(&quot;%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&quot;),<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) &amp;&amp; isalpha(*o)))<br>
+               return 0;<br>
+       while (*++o != &#39;=&#39;)<br>
+               if (! (isascii (*o) &amp;&amp; (isalnum(*o) || *o == &#39;_&#39;)))<br>
+                       return 0;<br>
+       namelen = o - option;<br>
+       if (INT_MAX &lt; namelen)<br>
+               return 0; /* fprintf won&#39;t work.  */<br>
+       if (namelen == sizeof &quot;name&quot; - 1<br>
+           &amp;&amp; memcmp(option, &quot;name&quot;, namelen) == 0)<br>
+               return 0;<br>
+       for (i = 0; i &lt; 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], &quot;--help&quot;) == 0) {<br>
                        usage(stdout, EXIT_SUCCESS);<br>
                }<br>
-       while ((c = getopt(argc, argv, &quot;d:l:p:L:vsy:&quot;)) != EOF &amp;&amp; c != -1)<br>
+       while ((c = getopt(argc, argv, &quot;d:l:p:L:no:vsy:&quot;)) != EOF &amp;&amp; c != -1)<br>
                switch (c) {<br>
                        default:<br>
                                usage(stderr, EXIT_FAILURE);<br>
@@ -500,6 +530,17 @@ _(&quot;%s: More than one -l option specified\n&quot;),<br>
                                        exit(EXIT_FAILURE);<br>
                                }<br>
                                break;<br>
+                       case &#39;n&#39;:<br>
+                               genname = TRUE;<br>
+                               break;<br>
+                       case &#39;o&#39;:<br>
+                               if (!addgenoption(optarg)) {<br>
+                                       fprintf(stderr,<br>
+                                               _(&quot;%s: %s: invalid -o option\n&quot;),<br>
+                                               progname, optarg);<br>
+                                       exit(EXIT_FAILURE);<br>
+                               }<br>
+                               break;<br>
                        case &#39;p&#39;:<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(&#39;=&#39;, fp);<br>
+<br>
+       for (; *v; v++)<br>
+               if (*v == &#39;\n&#39;)<br>
+                       fprintf(fp, &quot;\\n&quot;);<br>
+               else if (*v == &#39;\\&#39;)<br>
+                       fprintf(fp, &quot;\\\\&quot;);<br>
+               else<br>
+                       fputc(*v, fp);<br>
+<br>
+       fputc(&#39;\n&#39;, 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, &quot;\n%s\n&quot;, string);<br>
+       if (genname || genoptions)<br>
+               fprintf(fp, &quot;=TZ\n&quot;);<br>
+       if (genname) {<br>
+               fprintf(fp, &quot;name&quot;);<br>
+               writevalue(fp, name);<br>
+       }<br>
+       for (i = 0; i &lt; genoptions; i++) {<br>
+               register char const *v = genoption[i];<br>
+               register int namelen = strchr(v, &#39;=&#39;) - v;<br>
+               fprintf(fp, &quot;%.*s&quot;, namelen, v);<br>
+               writevalue(fp, v + namelen + 1);<br>
+       }<br>
        if (ferror(fp) || fclose(fp)) {<br>
                (void) fprintf(stderr, _(&quot;%s: Error writing %s\n&quot;),<br>
                        progname, fullname);<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.8.3.1<br>
<br>
<br>
</font></span></blockquote></div><br></div>