a patch for zic.c to allow 'follow rules'

Alois Treindl alois at astro.ch
Thu Aug 25 14:32:13 UTC 2011


Dear Arthur,
I have been preparing a small modification for zic.c which will allow it 
to understand a 'follow rule' in zone files, like this:

# experimental table for Geneva, to test the 'follow' mechanism
Zone    Europe/Geneva   0:24:37 -       LMT     1848 Sep 12
                         0:24:37 -       GET     1894 Jun # Geneva MTime
                         0       follow  Europe/Zurich

For test purposes, one can simply insert this zone in the europe file.

The feature is helpful in the extension of tzdata to cover complete 
timezone history. For this purpose, about 1000 additional zone files 
need to be written, and to be maintained.
The process to do so has started in the astrological community, as it 
needs a complete pre-1970 timezone history.
I will not bother you with details.

I intend to help creating and maintaining a set of files like 
'europe_hist', 'asia_hist' etc which contain the additional zones.

The 'follow rule' will allow to keep these extra zone files very small, 
as usually the additional zones will all have a cross-over moment into a 
regular tzdata zone.

I have for the moment called the modified zic source file zicx.c
and prepared a patch file for zic.c to implement the 'follow rule' feature.

I have tried to keep the modification very small.

Please have a look at the patch, and check for the errors I have 
probably made.

Description of the code:
------------------------
The follow rule must be the last line in a zone, and recursion is not 
allowed. It is parsed in inzsub() which reacts on GMTOFF = 0 and the 
word 'follow' in the RULE field.

The zone line is stored in zones[] with a special value z_gmtoff = 
FOLLOW_MARK and the zone_name to follow in field z_rule (which is abused 
for this purpose).
Before the call to outzone() the two sets of zone lines are patched 
together in a temporary array, so that outzone() and all functions 
deeper down() need not be modified.

Patch
-----
--- zic.c       2011-03-09 20:41:27.000000000 +0100
+++ zicx.c      2011-08-25 16:09:04.000000000 +0200
@@ -262,6 +262,17 @@ static int         typecnt;
  #define YR_MAXIMUM     1
  #define YR_ONLY                2

+/*
+** follow rules, added by Alois Treindl August 2011
+** Zones may end with a line: 0  follow  zone_name
+** which the parser will represent with FOLLOW_MARK in z_gmtoff,
+** and the zone name in z_rule.
+** Before the call to outzone() the zone and its follow zone will be
+** patched together, so that outzone() sees a regular zone array.
+** To keep zone files readable, follow rules cannot be used recursively.
+*/
+#define FOLLOW_MARK    999999
+
  static struct rule *   rules;
  static int             nrules; /* number of rules */

@@ -589,7 +600,48 @@ _("%s: More than one -L option specified
                 */
                 for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
                         continue;
-               outzone(&zones[i], j - i);
+               if (zones[j -1].z_gmtoff == FOLLOW_MARK) {
+                 /* copy zone and follow zone into one new array */
+                 int   k,n,m, nrows;
+                  struct zone *xzones, *zp;
+                 nrows = j - i - 1;
+                 zp = &zones[j - 1];   /* line with the follow rule */
+                 xzones = (struct zone *) (void *) emalloc((int) (nrows 
* sizeof *xzones));
+                 for (k = 0; k < nrows; k++)
+                   xzones[k] = zones[i + k];
+                  /* now find the follow zone in array zones[] */
+                 for (m = 0; m < nzones; m++)  {
+                   if (zones[m].z_name != NULL && strcmp(zp->z_rule, 
zones[m].z_name) == 0) break;
+                 }
+                 if (m == nzones) {  /* error, follow zone not found */
+                   char *cp;
+                   cp = emalloc(80 + strlen(zp->z_rule) + 
strlen(zones[i].z_name));;
+                   sprintf(cp, "For zone %s follow zone %s not found, 
no zonefile created.", zones[i].z_name, zp->z_rule);
+                   eat(zp->z_filename, zp->z_linenum);
+                   error(cp);
+                   ifree(cp);
+                   ifree((void *)xzones);
+                 }
+                 /* now find the next date in the follow zone */
+                 for (n = m + 1; n < nzones; n++) {
+                   if (zp->z_untiltime < zones[n].z_untiltime) break;
+                 }
+                 /* missing errorcode for case n == nzones,
+                  * assume we are still in same follow zone.
+                   * The follow zone part we need starts at zones[n].
+                  * Now find where follow zone ends, will be m.
+                  */
+                 for (m = n; m < nzones && zones[m].z_name == NULL; ++m)
+                   continue;
+                 xzones = (struct zone *) (void *) erealloc((char *) 
xzones, (int) ((nrows + m - n) * sizeof *xzones));
+                 for (k = 0; k <  m - n; k++)
+                   xzones[nrows + k] = zones[n + k];
+                  nrows += m - n;
+                 outzone(&xzones[0], nrows);
+                 ifree((void *) xzones);
+               } else {
+                 outzone(&zones[i], j - i);
+               }
         }
         /*
         ** Make links.
@@ -784,7 +836,7 @@ associate(void)
         }
         for (i = 0; i < nzones; ++i) {
                 zp = &zones[i];
-               if (zp->z_nrules == 0) {
+               if (zp->z_nrules == 0 && zp->z_gmtoff != FOLLOW_MARK) {
                         /*
                         ** Maybe we have a local standard time offset.
                         */
@@ -1079,11 +1131,23 @@ const int               iscont;
                         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;
+       /* check for 0 follow zonename
+        ** zonename must contain at least one /, and follow must be
+       * 'follow' or an abbreviation thereof.
+        */
+       if (z.z_gmtoff == 0 && strchr(fields[i_format], '/') != NULL
+       && itsabbr(fields[i_rule], "follow")) {
+               z.z_gmtoff = FOLLOW_MARK;
+               z.z_rule = ecpyalloc(fields[i_format]);
+               z.z_format = "";
+               hasuntil = FALSE;       /* no continue of zone now */
+       } else {
+               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;


-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: zicx.patch
URL: <http://mm.icann.org/pipermail/tz/attachments/20110825/1541f3aa/attachment.ksh>


More information about the tz mailing list