--- 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;