@@ -125,13 +125,14 @@ static void warning(const char *string,...) pg_attribute_printf(1, 2);
125
125
static void usage (FILE * stream , int status ) pg_attribute_noreturn ();
126
126
static void addtt (zic_t starttime , int type );
127
127
static 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 );
129
129
static void adjleap (void );
130
130
static void associate (void );
131
131
static void dolink (const char * , const char * , bool );
132
132
static char * * getfields (char * buf );
133
133
static zic_t gethms (const char * string , const char * errstring );
134
134
static zic_t getsave (char * , bool * );
135
+ static void inexpires (char * * , int );
135
136
static void infile (const char * filename );
136
137
static void inleap (char * * fields , int nfields );
137
138
static void inlink (char * * fields , int nfields );
@@ -202,6 +203,7 @@ static int typecnt;
202
203
#define LC_ZONE 1
203
204
#define LC_LINK 2
204
205
#define LC_LEAP 3
206
+ #define LC_EXPIRES 4
205
207
206
208
/*
207
209
* Which fields are which on a Zone line.
@@ -267,6 +269,9 @@ static int typecnt;
267
269
#define LP_ROLL 6
268
270
#define LEAP_FIELDS 7
269
271
272
+ /* Expires lines are like Leap lines, except without CORR and ROLL fields. */
273
+ #define EXPIRES_FIELDS 5
274
+
270
275
/*
271
276
* Year synonyms.
272
277
*/
@@ -312,6 +317,7 @@ static struct lookup const zi_line_codes[] = {
312
317
};
313
318
static struct lookup const leap_line_codes [] = {
314
319
{"Leap" , LC_LEAP },
320
+ {"Expires" , LC_EXPIRES },
315
321
{NULL , 0 }
316
322
};
317
323
@@ -584,6 +590,12 @@ static zic_t const max_time = MAXVAL(zic_t, TIME_T_BITS_IN_FILE);
584
590
static zic_t lo_time = MINVAL (zic_t , TIME_T_BITS_IN_FILE );
585
591
static zic_t hi_time = MAXVAL (zic_t , TIME_T_BITS_IN_FILE );
586
592
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
+
587
599
/* Set the time range of the output to TIMERANGE.
588
600
Return true if successful. */
589
601
static bool
@@ -1279,7 +1291,8 @@ infile(const char *name)
1279
1291
}
1280
1292
if (nfields == 0 )
1281
1293
{
1282
- /* nothing to do */
1294
+ if (name == leapsec && * buf == '#' )
1295
+ sscanf (buf , "#expires " INT64_FORMAT , & comment_leapexpires );
1283
1296
}
1284
1297
else if (wantcont )
1285
1298
{
@@ -1311,6 +1324,10 @@ infile(const char *name)
1311
1324
inleap (fields , nfields );
1312
1325
wantcont = false;
1313
1326
break ;
1327
+ case LC_EXPIRES :
1328
+ inexpires (fields , nfields );
1329
+ wantcont = false;
1330
+ break ;
1314
1331
default : /* "cannot happen" */
1315
1332
fprintf (stderr ,
1316
1333
_ ("%s: panic: Invalid l_value %d\n" ),
@@ -1634,8 +1651,8 @@ inzsub(char **fields, int nfields, bool iscont)
1634
1651
return hasuntil ;
1635
1652
}
1636
1653
1637
- static void
1638
- inleap (char * * fields , int nfields )
1654
+ static zic_t
1655
+ getleapdatetime (char * * fields , int nfields , bool expire_line )
1639
1656
{
1640
1657
const char * cp ;
1641
1658
const struct lookup * lp ;
@@ -1651,11 +1668,6 @@ inleap(char **fields, int nfields)
1651
1668
zic_t t ;
1652
1669
char xs ;
1653
1670
1654
- if (nfields != LEAP_FIELDS )
1655
- {
1656
- error (_ ("wrong number of fields on Leap line" ));
1657
- return ;
1658
- }
1659
1671
dayoff = 0 ;
1660
1672
cp = fields [LP_YEAR ];
1661
1673
if (sscanf (cp , "%d%c" , & year , & xs ) != 1 )
@@ -1664,13 +1676,16 @@ inleap(char **fields, int nfields)
1664
1676
* Leapin' Lizards!
1665
1677
*/
1666
1678
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;
1668
1688
}
1669
- if (!leapseen || leapmaxyear < year )
1670
- leapmaxyear = year ;
1671
- if (!leapseen || leapminyear > year )
1672
- leapminyear = year ;
1673
- leapseen = true;
1674
1689
j = EPOCH_YEAR ;
1675
1690
while (j != year )
1676
1691
{
@@ -1689,7 +1704,7 @@ inleap(char **fields, int nfields)
1689
1704
if ((lp = byword (fields [LP_MONTH ], mon_names )) == NULL )
1690
1705
{
1691
1706
error (_ ("invalid month name" ));
1692
- return ;
1707
+ return -1 ;
1693
1708
}
1694
1709
month = lp -> l_value ;
1695
1710
j = TM_JANUARY ;
@@ -1704,56 +1719,70 @@ inleap(char **fields, int nfields)
1704
1719
day <= 0 || day > len_months [isleap (year )][month ])
1705
1720
{
1706
1721
error (_ ("invalid day of month" ));
1707
- return ;
1722
+ return -1 ;
1708
1723
}
1709
1724
dayoff = oadd (dayoff , day - 1 );
1710
1725
if (dayoff < min_time / SECSPERDAY )
1711
1726
{
1712
1727
error (_ ("time too small" ));
1713
- return ;
1728
+ return -1 ;
1714
1729
}
1715
1730
if (dayoff > max_time / SECSPERDAY )
1716
1731
{
1717
1732
error (_ ("time too large" ));
1718
- return ;
1733
+ return -1 ;
1719
1734
}
1720
1735
t = dayoff * SECSPERDAY ;
1721
1736
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
1723
1749
{
1724
- bool positive ;
1725
- int count ;
1750
+ zic_t t = getleapdatetime (fields , nfields , false);
1726
1751
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 )
1733
1753
{
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
+ }
1752
1771
}
1753
- leapadd (t , positive , lp -> l_value , count );
1754
1772
}
1755
1773
}
1756
1774
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
+
1757
1786
static void
1758
1787
inlink (char * * fields , int nfields )
1759
1788
{
@@ -3369,32 +3398,25 @@ addtype(zic_t utoff, char const *abbr, bool isdst, bool ttisstd, bool ttisut)
3369
3398
}
3370
3399
3371
3400
static void
3372
- leapadd (zic_t t , bool positive , int rolling , int count )
3401
+ leapadd (zic_t t , int correction , int rolling )
3373
3402
{
3374
- int i ,
3375
- j ;
3403
+ int i ;
3376
3404
3377
- if (leapcnt + ( positive ? count : 1 ) > TZ_MAX_LEAPS )
3405
+ if (TZ_MAX_LEAPS <= leapcnt )
3378
3406
{
3379
3407
error (_ ("too many leap seconds" ));
3380
3408
exit (EXIT_FAILURE );
3381
3409
}
3382
3410
for (i = 0 ; i < leapcnt ; ++ i )
3383
3411
if (t <= trans [i ])
3384
3412
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 ;
3398
3420
}
3399
3421
3400
3422
static void
@@ -3418,6 +3440,25 @@ adjleap(void)
3418
3440
trans [i ] = tadd (trans [i ], last );
3419
3441
last = corr [i ] += last ;
3420
3442
}
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
+ }
3421
3462
}
3422
3463
3423
3464
static char *
0 commit comments