@@ -125,13 +125,14 @@ static void warning(const char *string,...) pg_attribute_printf(1, 2);
125125static void usage (FILE * stream , int status ) pg_attribute_noreturn ();
126126static void addtt (zic_t starttime , int type );
127127static int addtype (zic_t , char const * , bool , bool , bool );
128- static void leapadd (zic_t , bool , int , int );
128+ static void leapadd (zic_t , int , int );
129129static void adjleap (void );
130130static void associate (void );
131131static void dolink (const char * , const char * , bool );
132132static char * * getfields (char * buf );
133133static zic_t gethms (const char * string , const char * errstring );
134134static zic_t getsave (char * , bool * );
135+ static void inexpires (char * * , int );
135136static void infile (const char * filename );
136137static void inleap (char * * fields , int nfields );
137138static void inlink (char * * fields , int nfields );
@@ -202,6 +203,7 @@ static int typecnt;
202203#define LC_ZONE 1
203204#define LC_LINK 2
204205#define LC_LEAP 3
206+ #define LC_EXPIRES 4
205207
206208/*
207209 * Which fields are which on a Zone line.
@@ -267,6 +269,9 @@ static int typecnt;
267269#define LP_ROLL 6
268270#define LEAP_FIELDS 7
269271
272+ /* Expires lines are like Leap lines, except without CORR and ROLL fields. */
273+ #define EXPIRES_FIELDS 5
274+
270275/*
271276 * Year synonyms.
272277 */
@@ -312,6 +317,7 @@ static struct lookup const zi_line_codes[] = {
312317};
313318static struct lookup const leap_line_codes [] = {
314319 {"Leap" , LC_LEAP },
320+ {"Expires" , LC_EXPIRES },
315321 {NULL , 0 }
316322};
317323
@@ -584,6 +590,12 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
584590static zic_t lo_time = MINVAL (zic_t , TIME_T_BITS_IN_FILE );
585591static zic_t hi_time = MAXVAL (zic_t , TIME_T_BITS_IN_FILE );
586592
593+ /* The time specified by an Expires line, or negative if no such line. */
594+ static zic_t leapexpires = -1 ;
595+
596+ /* The time specified by an #expires comment, or negative if no such line. */
597+ static zic_t comment_leapexpires = -1 ;
598+
587599/* Set the time range of the output to TIMERANGE.
588600 Return true if successful. */
589601static bool
@@ -1279,7 +1291,8 @@ infile(const char *name)
12791291 }
12801292 if (nfields == 0 )
12811293 {
1282- /* nothing to do */
1294+ if (name == leapsec && * buf == '#' )
1295+ sscanf (buf , "#expires " INT64_FORMAT , & comment_leapexpires );
12831296 }
12841297 else if (wantcont )
12851298 {
@@ -1311,6 +1324,10 @@ infile(const char *name)
13111324 inleap (fields , nfields );
13121325 wantcont = false;
13131326 break ;
1327+ case LC_EXPIRES :
1328+ inexpires (fields , nfields );
1329+ wantcont = false;
1330+ break ;
13141331 default : /* "cannot happen" */
13151332 fprintf (stderr ,
13161333 _ ("%s: panic: Invalid l_value %d\n" ),
@@ -1634,8 +1651,8 @@ inzsub(char **fields, int nfields, bool iscont)
16341651 return hasuntil ;
16351652}
16361653
1637- static void
1638- inleap (char * * fields , int nfields )
1654+ static zic_t
1655+ getleapdatetime (char * * fields , int nfields , bool expire_line )
16391656{
16401657 const char * cp ;
16411658 const struct lookup * lp ;
@@ -1651,11 +1668,6 @@ inleap(char **fields, int nfields)
16511668 zic_t t ;
16521669 char xs ;
16531670
1654- if (nfields != LEAP_FIELDS )
1655- {
1656- error (_ ("wrong number of fields on Leap line" ));
1657- return ;
1658- }
16591671 dayoff = 0 ;
16601672 cp = fields [LP_YEAR ];
16611673 if (sscanf (cp , "%d%c" , & year , & xs ) != 1 )
@@ -1664,13 +1676,16 @@ inleap(char **fields, int nfields)
16641676 * Leapin' Lizards!
16651677 */
16661678 error (_ ("invalid leaping year" ));
1667- return ;
1679+ return -1 ;
1680+ }
1681+ if (!expire_line )
1682+ {
1683+ if (!leapseen || leapmaxyear < year )
1684+ leapmaxyear = year ;
1685+ if (!leapseen || leapminyear > year )
1686+ leapminyear = year ;
1687+ leapseen = true;
16681688 }
1669- if (!leapseen || leapmaxyear < year )
1670- leapmaxyear = year ;
1671- if (!leapseen || leapminyear > year )
1672- leapminyear = year ;
1673- leapseen = true;
16741689 j = EPOCH_YEAR ;
16751690 while (j != year )
16761691 {
@@ -1689,7 +1704,7 @@ inleap(char **fields, int nfields)
16891704 if ((lp = byword (fields [LP_MONTH ], mon_names )) == NULL )
16901705 {
16911706 error (_ ("invalid month name" ));
1692- return ;
1707+ return -1 ;
16931708 }
16941709 month = lp -> l_value ;
16951710 j = TM_JANUARY ;
@@ -1704,56 +1719,70 @@ inleap(char **fields, int nfields)
17041719 day <= 0 || day > len_months [isleap (year )][month ])
17051720 {
17061721 error (_ ("invalid day of month" ));
1707- return ;
1722+ return -1 ;
17081723 }
17091724 dayoff = oadd (dayoff , day - 1 );
17101725 if (dayoff < min_time / SECSPERDAY )
17111726 {
17121727 error (_ ("time too small" ));
1713- return ;
1728+ return -1 ;
17141729 }
17151730 if (dayoff > max_time / SECSPERDAY )
17161731 {
17171732 error (_ ("time too large" ));
1718- return ;
1733+ return -1 ;
17191734 }
17201735 t = dayoff * SECSPERDAY ;
17211736 tod = gethms (fields [LP_TIME ], _ ("invalid time of day" ));
1722- cp = fields [LP_CORR ];
1737+ t = tadd (t , tod );
1738+ if (t < 0 )
1739+ error (_ ("leap second precedes Epoch" ));
1740+ return t ;
1741+ }
1742+
1743+ static void
1744+ inleap (char * * fields , int nfields )
1745+ {
1746+ if (nfields != LEAP_FIELDS )
1747+ error (_ ("wrong number of fields on Leap line" ));
1748+ else
17231749 {
1724- bool positive ;
1725- int count ;
1750+ zic_t t = getleapdatetime (fields , nfields , false);
17261751
1727- if (strcmp (cp , "" ) == 0 )
1728- { /* infile() turns "-" into "" */
1729- positive = false;
1730- count = 1 ;
1731- }
1732- else if (strcmp (cp , "+" ) == 0 )
1752+ if (0 <= t )
17331753 {
1734- positive = true;
1735- count = 1 ;
1736- }
1737- else
1738- {
1739- error (_ ("illegal CORRECTION field on Leap line" ));
1740- return ;
1741- }
1742- if ((lp = byword (fields [LP_ROLL ], leap_types )) == NULL )
1743- {
1744- error (_ ("illegal Rolling/Stationary field on Leap line" ));
1745- return ;
1746- }
1747- t = tadd (t , tod );
1748- if (t < 0 )
1749- {
1750- error (_ ("leap second precedes Epoch" ));
1751- return ;
1754+ struct lookup const * lp = byword (fields [LP_ROLL ], leap_types );
1755+
1756+ if (!lp )
1757+ error (_ ("invalid Rolling/Stationary field on Leap line" ));
1758+ else
1759+ {
1760+ int correction = 0 ;
1761+
1762+ if (!fields [LP_CORR ][0 ]) /* infile() turns "-" into "". */
1763+ correction = -1 ;
1764+ else if (strcmp (fields [LP_CORR ], "+" ) == 0 )
1765+ correction = 1 ;
1766+ else
1767+ error (_ ("invalid CORRECTION field on Leap line" ));
1768+ if (correction )
1769+ leapadd (t , correction , lp -> l_value );
1770+ }
17521771 }
1753- leapadd (t , positive , lp -> l_value , count );
17541772 }
17551773}
17561774
1775+ static void
1776+ inexpires (char * * fields , int nfields )
1777+ {
1778+ if (nfields != EXPIRES_FIELDS )
1779+ error (_ ("wrong number of fields on Expires line" ));
1780+ else if (0 <= leapexpires )
1781+ error (_ ("multiple Expires lines" ));
1782+ else
1783+ leapexpires = getleapdatetime (fields , nfields , true);
1784+ }
1785+
17571786static void
17581787inlink (char * * fields , int nfields )
17591788{
@@ -3369,32 +3398,25 @@ addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
33693398}
33703399
33713400static void
3372- leapadd (zic_t t , bool positive , int rolling , int count )
3401+ leapadd (zic_t t , int correction , int rolling )
33733402{
3374- int i ,
3375- j ;
3403+ int i ;
33763404
3377- if (leapcnt + ( positive ? count : 1 ) > TZ_MAX_LEAPS )
3405+ if (TZ_MAX_LEAPS <= leapcnt )
33783406 {
33793407 error (_ ("too many leap seconds" ));
33803408 exit (EXIT_FAILURE );
33813409 }
33823410 for (i = 0 ; i < leapcnt ; ++ i )
33833411 if (t <= trans [i ])
33843412 break ;
3385- do
3386- {
3387- for (j = leapcnt ; j > i ; -- j )
3388- {
3389- trans [j ] = trans [j - 1 ];
3390- corr [j ] = corr [j - 1 ];
3391- roll [j ] = roll [j - 1 ];
3392- }
3393- trans [i ] = t ;
3394- corr [i ] = positive ? 1 : - count ;
3395- roll [i ] = rolling ;
3396- ++ leapcnt ;
3397- } while (positive && -- count != 0 );
3413+ memmove (& trans [i + 1 ], & trans [i ], (leapcnt - i ) * sizeof * trans );
3414+ memmove (& corr [i + 1 ], & corr [i ], (leapcnt - i ) * sizeof * corr );
3415+ memmove (& roll [i + 1 ], & roll [i ], (leapcnt - i ) * sizeof * roll );
3416+ trans [i ] = t ;
3417+ corr [i ] = correction ;
3418+ roll [i ] = rolling ;
3419+ ++ leapcnt ;
33983420}
33993421
34003422static void
@@ -3418,6 +3440,25 @@ adjleap(void)
34183440 trans [i ] = tadd (trans [i ], last );
34193441 last = corr [i ] += last ;
34203442 }
3443+
3444+ if (leapexpires < 0 )
3445+ {
3446+ leapexpires = comment_leapexpires ;
3447+ if (0 <= leapexpires )
3448+ warning (_ ("\"#expires\" is obsolescent; use \"Expires\"" ));
3449+ }
3450+
3451+ if (0 <= leapexpires )
3452+ {
3453+ leapexpires = oadd (leapexpires , last );
3454+ if (!(leapcnt == 0 || (trans [leapcnt - 1 ] < leapexpires )))
3455+ {
3456+ error (_ ("last Leap time does not precede Expires time" ));
3457+ exit (EXIT_FAILURE );
3458+ }
3459+ if (leapexpires <= hi_time )
3460+ hi_time = leapexpires - 1 ;
3461+ }
34213462}
34223463
34233464static char *
0 commit comments