home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume14 / localtime3 / part02 < prev    next >
Text File  |  1988-03-31  |  79KB  |  3,560 lines

  1. Subject:  v14i031:  Public time (zone) conversion routines, Part02/03
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Arthur David Olson <elsie!ado>
  7. Posting-number: Volume 14, Issue 31
  8. Archive-name: localtime3/part02
  9.  
  10. : To unbundle, sh this file
  11. echo 'tzfile.h' 1>&2
  12. cat >'tzfile.h' <<'End of tzfile.h'
  13. #ifndef lint
  14. #ifndef NOID
  15. #ifndef TZFILE_H
  16. #define TZFILE_H
  17. static char    tzfilehid[] = "@(#)tzfile.h    4.1";
  18. #endif /* !defined TZFILE_H */
  19. #endif /* !defined NOID */
  20. #endif /* !defined lint */
  21.  
  22. /*
  23. ** Information about time zone files.
  24. */
  25.  
  26. #ifndef TZDIR
  27. #define TZDIR        "/etc/zoneinfo"    /* Time zone object file directory */
  28. #endif /* !defined TZDIR */
  29.  
  30. #ifndef TZDEFAULT
  31. #define TZDEFAULT    "localtime"
  32. #endif /* !defined TZDEFAULT */
  33.  
  34. /*
  35. ** Each file begins with. . .
  36. */
  37.  
  38. struct tzhead {
  39.     char    tzh_reserved[28];    /* reserved for future use */
  40.     char    tzh_leapcnt[4];        /* coded number of leap seconds */
  41.     char    tzh_timecnt[4];        /* coded number of transition times */
  42.     char    tzh_typecnt[4];        /* coded number of local time types */
  43.     char    tzh_charcnt[4];        /* coded number of abbr. chars */
  44. };
  45.  
  46. /*
  47. ** . . .followed by. . .
  48. **
  49. **    tzh_timecnt (char [4])s        coded transition times a la time(2)
  50. **    tzh_timecnt (unsigned char)s    types of local time starting at above
  51. **    tzh_typecnt repetitions of
  52. **        one (char [4])        coded GMT offset in seconds
  53. **        one (unsigned char)    used to set tm_isdt
  54. **        one (unsigned char)    that's an abbreviation list index
  55. **    tzh_charcnt (char)s        '\0'-terminated zone abbreviations
  56. **    tzh_leapcnt repetitions of
  57. **        one (char [4])        coded leap second transition times
  58. **        one (char [4])        total correction after above
  59. */
  60.  
  61. /*
  62. ** In the current implementation, "tzset()" refuses to deal with files that
  63. ** exceed any of the limits below.
  64. */
  65.  
  66. #ifndef TZ_MAX_TIMES
  67. /*
  68. ** The TZ_MAX_TIMES value below is enough to handle a bit more than a
  69. ** year's worth of solar time (corrected daily to the nearest second) or
  70. ** 138 years of Pacific Presidential Election time
  71. ** (where there are three time zone transitions every fourth year).
  72. */
  73. #define TZ_MAX_TIMES    370
  74. #endif /* !defined TZ_MAX_TIMES */
  75.  
  76. #ifndef TZ_MAX_TYPES
  77. #ifndef NOSOLAR
  78. #define TZ_MAX_TYPES    256    /* Limited by what (unsigned char)'s can hold */
  79. #else /* !defined NOSOLAR */
  80. #define TZ_MAX_TYPES    10    /* Maximum number of local time types */
  81. #endif /* !defined NOSOLAR */
  82. #endif /* !defined TZ_MAX_TYPES */
  83.  
  84. #ifndef TZ_MAX_CHARS
  85. #define TZ_MAX_CHARS    50    /* Maximum number of abbreviation characters */
  86. #endif /* !defined TZ_MAX_CHARS */
  87.  
  88. #ifndef TZ_MAX_LEAPS
  89. #define    TZ_MAX_LEAPS    50    /* Maximum number of leap second corrections */
  90. #endif /* !defined TZ_MAX_LEAPS */
  91.  
  92. #define SECSPERMIN    60
  93. #define MINSPERHOUR    60
  94. #define HOURSPERDAY    24
  95. #define DAYSPERWEEK    7
  96. #define DAYSPERNYEAR    365
  97. #define DAYSPERLYEAR    366
  98. #define SECSPERHOUR    (SECSPERMIN * MINSPERHOUR)
  99. #define SECSPERDAY    ((long) SECSPERHOUR * HOURSPERDAY)
  100. #define MONSPERYEAR    12
  101.  
  102. #define TM_SUNDAY    0
  103. #define TM_MONDAY    1
  104. #define TM_TUESDAY    2
  105. #define TM_WEDNESDAY    3
  106. #define TM_THURSDAY    4
  107. #define TM_FRIDAY    5
  108. #define TM_SATURDAY    6
  109.  
  110. #define TM_JANUARY    0
  111. #define TM_FEBRUARY    1
  112. #define TM_MARCH    2
  113. #define TM_APRIL    3
  114. #define TM_MAY        4
  115. #define TM_JUNE        5
  116. #define TM_JULY        6
  117. #define TM_AUGUST    7
  118. #define TM_SEPTEMBER    8
  119. #define TM_OCTOBER    9
  120. #define TM_NOVEMBER    10
  121. #define TM_DECEMBER    11
  122. #define TM_SUNDAY    0
  123.  
  124. #define TM_YEAR_BASE    1900
  125.  
  126. #define EPOCH_YEAR    1970
  127. #define EPOCH_WDAY    TM_THURSDAY
  128.  
  129. /*
  130. ** Accurate only for the past couple of centuries;
  131. ** that will probably do.
  132. */
  133.  
  134. #define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
  135. End of tzfile.h
  136. echo 'nonstd.h' 1>&2
  137. cat >'nonstd.h' <<'End of nonstd.h'
  138. #ifndef NONSTD_H
  139.  
  140. #define NONSTD_H
  141.  
  142. #ifndef lint
  143. #ifndef NOID
  144. static char    nonstdhid[] = "@(#)nonstd.h    4.1";
  145. #endif /* !defined NOID */
  146. #endif /* !defined lint */
  147.  
  148. #ifdef __STDC__
  149.  
  150. #define P(s)        s
  151.  
  152. #ifdef __TURBOC__
  153. /*
  154. ** Cover for stupid Turbo C
  155. */
  156. #define genericptr_t    void *
  157. #else /* !defined __TURBOC__ */
  158. typedef void *        genericptr_t;
  159. #endif /* !defined __TURBOC__ */
  160.  
  161. #define alloc_size_t    size_t
  162. #define qsort_size_t    size_t
  163. #define fread_size_t    size_t
  164. #define fwrite_size_t    size_t
  165.  
  166. #else /* !defined __STDC__ */
  167.  
  168. #define ASTERISK    *
  169. #define P(s)        (/ASTERISK s ASTERISK/)
  170.  
  171. #ifndef genericptr_t
  172. typedef char *        genericptr_t;
  173. #endif /* !defined genericptr_t */
  174.  
  175. #ifndef alloc_size_t
  176. typedef unsigned    alloc_size_t;
  177. #endif /* !defined alloc_size_t */
  178.  
  179. #ifndef qsort_size_t
  180. #ifdef unix
  181. #include "sys/param.h"
  182. #endif /* defined unix */
  183. #ifdef BSD
  184. typedef int        qsort_size_t;
  185. #else /* !defined BSD */
  186. typedef unsigned    qsort_size_t;
  187. #endif /* !defined BSD */
  188. #endif /* !defined qsort_size_t */
  189.  
  190. #ifndef fread_size_t
  191. typedef int        fread_size_t;
  192. #endif /* !defined fread_size_t */
  193.  
  194. #ifndef fwrite_size_t
  195. typedef int        fwrite_size_t;
  196. #endif /* !defined fwrite_size_t */
  197.  
  198. #define const
  199. #define noalias
  200. #define volatile
  201.  
  202. #endif /* !defined __STDC__ */
  203.  
  204. #endif /* !defined NONSTD_H */
  205.  
  206. /*
  207. ** UNIX is a registered trademark of AT&T.
  208. */
  209. End of nonstd.h
  210. echo 'stdio.h' 1>&2
  211. cat >'stdio.h' <<'End of stdio.h'
  212. #ifndef lint
  213. #ifndef NOID
  214. #ifndef STDIO_H
  215. #define STDIO_H
  216. static char    stdiohid[] = "@(#)stdio.h    4.1";
  217. #endif /* !defined STDIO_H */
  218. #endif /* !defined NOID */
  219. #endif /* !defined lint */
  220.  
  221. #ifdef STDIO_RECURSING
  222. #include "/usr/include/stdio.h"
  223. #else /* !defined STDIO_RECURSING */
  224. #define STDIO_RECURSING
  225. #include <stdio.h>
  226. #undef STDIO_RECURSING
  227. #endif /* !defined STDIO_RECURSING */
  228.  
  229. #ifndef FILENAME_MAX
  230.  
  231. #ifndef MAXPATHLEN
  232. #ifdef unix
  233. #include <sys/param.h>
  234. #endif /* defined unix */
  235. #endif /* !defined MAXPATHLEN */
  236.  
  237. #ifdef MAXPATHLEN
  238. #define FILENAME_MAX    MAXPATHLEN
  239. #else /* !defined MAXPATHLEN */
  240. #define FILENAME_MAX    1024        /* Pure guesswork */
  241. #endif /* !defined MAXPATHLEN */
  242.  
  243. #endif /* !defined FILENAME_MAX */
  244.  
  245. #ifndef __STDC__
  246. #ifdef unix
  247.  
  248. #include <sys/param.h>
  249. #ifndef BSD
  250. extern void    perror();
  251. #endif /* !defined BSD */
  252.  
  253. #define remove(name)    unlink(name)
  254.  
  255. #endif /* defined unix */
  256. #endif /* !defined __STDC__ */
  257.  
  258. /*
  259. ** UNIX is a registered trademark of AT&T.
  260. */
  261. End of stdio.h
  262. echo 'stdlib.h' 1>&2
  263. cat >'stdlib.h' <<'End of stdlib.h'
  264. #ifndef lint
  265. #ifndef NOID
  266. #ifndef STDLIB_H
  267. #define STDLIB_H
  268. static char    stdlibhid[] = "@(#)stdlib.h    4.1";
  269. #endif /* !defined STDLIB_H */
  270. #endif /* !defined NOID */
  271. #endif /* !defined lint */
  272.  
  273. #ifdef __STDC__
  274.  
  275. #ifdef STDLIB_RECURSING
  276. #include "/usr/include/stdlib.h"
  277. #else /* !defined STDLIB_RECURSING */
  278. #define STDLIB_RECURSING
  279. #include <stdlib.h>
  280. #undef STDLIB_RECURSING
  281. #endif /* !defined STDLIB_RECURSING */
  282.  
  283. #ifndef NULL
  284. /*
  285. ** Stupid Turbo C doesn't define NULL in stdlib.h
  286. */
  287. #include <stdio.h>
  288. #endif /* !defined NULL */
  289.  
  290. #else /* !defined __STDC__ */
  291.  
  292. #ifdef unix
  293. /*
  294. ** Include sys/param.h so we can figure out if we're BSD or USG
  295. */
  296. #include "sys/param.h"
  297. #endif /* defined unix */
  298.  
  299. #ifndef EXIT_SUCCESS
  300. #define EXIT_SUCCESS    0
  301. #endif /* !defined EXIT_SUCCESS */
  302.  
  303. #ifndef EXIT_FAILURE
  304. #define EXIT_FAILURE    0
  305. #endif /* !defined EXIT_FAILURE */
  306.  
  307. #ifndef NULL
  308. #include <stdio.h>
  309. #endif /* !defined NULL */
  310.  
  311. /*
  312. ** String conversion functions
  313. */
  314.  
  315. #include <math.h>
  316.  
  317. /*
  318. ** Memory management funcsions
  319. */
  320.  
  321. extern char *    calloc();
  322. extern char *    malloc();
  323. extern char *    realloc();
  324.  
  325. #ifndef BSD
  326. extern void    free();
  327. #endif /* !defined BSD */
  328.  
  329. /*
  330. ** Communication with the environment
  331. */
  332.  
  333. extern char *    getenv();
  334.  
  335. #ifndef BSD
  336. extern void    exit();
  337. #endif /* !defined BSD */
  338.  
  339. /*
  340. ** Searching and sorting functions
  341. */
  342.  
  343. #ifndef BSD
  344. extern void    qsort();
  345. #endif /* !defined BSD */
  346.  
  347. #endif /* !defined __STDC__ */
  348.  
  349. /*
  350. ** UNIX is a registered trademark of AT&T.
  351. */
  352. End of stdlib.h
  353. echo 'time.h' 1>&2
  354. cat >'time.h' <<'End of time.h'
  355. #ifndef lint
  356. #ifndef NOID
  357. #ifndef TIME_H
  358. #define TIME_H
  359. static char    timehid[] = "@(#)time.h    4.1";
  360. #endif /* !defined TIME_H */
  361. #endif /* !defined NOID */
  362. #endif /* !defined lint */
  363.  
  364. #ifdef TIME_RECURSING
  365. #include "/usr/include/time.h"
  366. #else /* !defined TIME_RECURSING */
  367. #define TIME_RECURSING
  368. #include <time.h>
  369. #undef TIME_RECURSING
  370. #endif /* !defined TIME_RECURSING */
  371.  
  372. #ifndef __STDC__
  373.  
  374. #ifndef time_t
  375. #ifdef unix
  376. #include <sys/types.h>
  377. #else /* !defined unix */
  378. typedef long    time_t;
  379. #endif /* !defined unix */
  380. #endif /* !defined time_t */
  381.  
  382. extern time_t    time();
  383.  
  384. #endif /* !defined __STDC__ */
  385.  
  386. /*
  387. ** UNIX is a registered trademark of AT&T.
  388. */
  389. End of time.h
  390. echo 'zic.c' 1>&2
  391. cat >'zic.c' <<'End of zic.c'
  392. #ifndef lint
  393. #ifndef NOID
  394. static char    elsieid[] = "@(#)zic.c    4.1";
  395. #endif /* !defined NOID */
  396. #endif /* !defined lint */
  397.  
  398. #include "stdio.h"
  399. #include "tzfile.h"
  400. #include "ctype.h"
  401. #include "time.h"
  402. #include "string.h"
  403. #include "stdlib.h"
  404. #include "sys/stat.h"
  405. #include "nonstd.h"
  406.  
  407. #ifndef TRUE
  408. #define TRUE    1
  409. #define FALSE    0
  410. #endif /* !defined TRUE */
  411.  
  412. extern int    emkdir P((const char * name, int mode));
  413. extern int    getopt P((int argc, char * argv[], const char * options));
  414. extern char *    icatalloc P((char * old, const char * new));
  415. extern char *    icpyalloc P((const char * string));
  416. extern void    ifree P((char * p));
  417. extern char *    imalloc P((int n));
  418. extern char *    irealloc P((char * old, int n));
  419. extern int    link P((const char * fromname, const char * toname));
  420. extern char *    optarg;
  421. extern int    optind;
  422. extern char *    scheck P((const char * string, const char * format));
  423.  
  424. static void    addtt P((time_t starttime, int type));
  425. static int    addtype P((long gmtoff, const char * abbr, int isdst));
  426. static void    addleap P((time_t t, int positive, int rolling));
  427. static void    adjleap P((void));
  428. static void    associate P((void));
  429. static int    ciequal P((const char * ap, const char * bp));
  430. static void    convert P((long val, char * buf));
  431. static void    eat P((const char * name, int num));
  432. static void    eats P((const char * name, int num,
  433.             const char * rname, int rnum));
  434. static long    eitol P((int i));
  435. static void    error P((const char * message));
  436. static char **    getfields P((char * buf));
  437. static long    gethms P((const char * string, const char * errstrng,
  438.             int signable));
  439. static void    infile P((const char * filename));
  440. static void    inleap P((char ** fields, int nfields));
  441. static void    inlink P((char ** fields, int nfields));
  442. static void    inrule P((char ** fields, int nfiekds));
  443. static int    inzcont P((char ** fields, int nfields));
  444. static int    inzone P((char ** fields, int nfields));
  445. static int    inzsub P((char ** fields, int nfields, int iscont));
  446. static int    itsabbr P((const char * abbr, const char * word));
  447. static int    itsdir P((char * name));
  448. static int    lowerit P((int c));
  449. static char *    memcheck P((char * tocheck));
  450. static int    mkdirs P((char * filename));
  451. static void    newabbr P((const char * abbr));
  452. static long    oadd P((long t1, long t2));
  453. static void    outzone P((const struct zone * zp, int ntzones));
  454. static void    puttzcode P((long code, FILE * fp));
  455. static int    rcomp P((const genericptr_t leftp, const genericptr_t rightp));
  456. static time_t    rpytime P((const struct rule * rp, int wantedy));
  457. static void    rulesub P((struct rule * rp,
  458.             char * loyearp, char * hiyearp, char * typep,
  459.             char * monthp, char * dayp, char * timep));
  460. static void    setboundaries P((void));
  461. static time_t    tadd P((time_t t1, long t2));
  462. static void    usage P((void));
  463. static void    writezone P((const char * name));
  464. static int    yearistype P((int year, const char * type));
  465.  
  466. static int        charcnt;
  467. static int        errors;
  468. static const char *    filename;
  469. static int        leapcnt;
  470. static int        linenum;
  471. static time_t        max_time;
  472. static int        max_year;
  473. static time_t        min_time;
  474. static int        min_year;
  475. static int        noise;
  476. static const char *    rfilename;
  477. static int        rlinenum;
  478. static const char *    progname;
  479. static int        timecnt;
  480. static int        typecnt;
  481. static int        tt_signed;
  482.  
  483. /*
  484. ** Line codes.
  485. */
  486.  
  487. #define LC_RULE        0
  488. #define LC_ZONE        1
  489. #define LC_LINK        2
  490. #define LC_LEAP        3
  491.  
  492. /*
  493. ** Which fields are which on a Zone line.
  494. */
  495.  
  496. #define ZF_NAME        1
  497. #define ZF_GMTOFF    2
  498. #define ZF_RULE        3
  499. #define ZF_FORMAT    4
  500. #define ZF_TILYEAR    5
  501. #define ZF_TILMONTH    6
  502. #define ZF_TILDAY    7
  503. #define ZF_TILTIME    8
  504. #define ZONE_MINFIELDS    5
  505. #define ZONE_MAXFIELDS    9
  506.  
  507. /*
  508. ** Which fields are which on a Zone continuation line.
  509. */
  510.  
  511. #define ZFC_GMTOFF    0
  512. #define ZFC_RULE    1
  513. #define ZFC_FORMAT    2
  514. #define ZFC_TILYEAR    3
  515. #define ZFC_TILMONTH    4
  516. #define ZFC_TILDAY    5
  517. #define ZFC_TILTIME    6
  518. #define ZONEC_MINFIELDS    3
  519. #define ZONEC_MAXFIELDS    7
  520.  
  521. /*
  522. ** Which files are which on a Rule line.
  523. */
  524.  
  525. #define RF_NAME        1
  526. #define RF_LOYEAR    2
  527. #define RF_HIYEAR    3
  528. #define RF_COMMAND    4
  529. #define RF_MONTH    5
  530. #define RF_DAY        6
  531. #define RF_TOD        7
  532. #define RF_STDOFF    8
  533. #define RF_ABBRVAR    9
  534. #define RULE_FIELDS    10
  535.  
  536. /*
  537. ** Which fields are which on a Link line.
  538. */
  539.  
  540. #define LF_FROM        1
  541. #define LF_TO        2
  542. #define LINK_FIELDS    3
  543.  
  544. /*
  545. ** Which fields are which on a Leap line.
  546. */
  547.  
  548. #define LP_YEAR        1
  549. #define LP_MONTH    2
  550. #define LP_DAY        3
  551. #define LP_TIME        4
  552. #define LP_CORR        5
  553. #define LP_ROLL        6
  554. #define LEAP_FIELDS    7
  555.  
  556. struct rule {
  557.     const char *    r_filename;
  558.     int        r_linenum;
  559.     const char *    r_name;
  560.  
  561.     int        r_loyear;    /* for example, 1986 */
  562.     int        r_hiyear;    /* for example, 1986 */
  563.     const char *    r_yrtype;
  564.  
  565.     int        r_month;    /* 0..11 */
  566.  
  567.     int        r_dycode;    /* see below */
  568.     int        r_dayofmonth;
  569.     int        r_wday;
  570.  
  571.     long        r_tod;        /* time from midnight */
  572.     int        r_todisstd;    /* above is standard time if TRUE */
  573.                     /* or wall clock time if FALSE */
  574.     long        r_stdoff;    /* offset from standard time */
  575.     const char *    r_abbrvar;    /* variable part of abbreviation */
  576.  
  577.     int        r_todo;        /* a rule to do (used in outzone) */
  578.     time_t        r_temp;        /* used in outzone */
  579. };
  580.  
  581. /*
  582. **    r_dycode        r_dayofmonth    r_wday
  583. */
  584.  
  585. #define DC_DOM        0    /* 1..31 */    /* unused */
  586. #define DC_DOWGEQ    1    /* 1..31 */    /* 0..6 (Sun..Sat) */
  587. #define DC_DOWLEQ    2    /* 1..31 */    /* 0..6 (Sun..Sat) */
  588.  
  589. /*
  590. ** Year synonyms.
  591. */
  592.  
  593. #define YR_MINIMUM    0
  594. #define YR_MAXIMUM    1
  595. #define YR_ONLY        2
  596.  
  597. static struct rule *    rules;
  598. static int        nrules;    /* number of rules */
  599.  
  600. struct zone {
  601.     const char *    z_filename;
  602.     int        z_linenum;
  603.  
  604.     const char *    z_name;
  605.     long        z_gmtoff;
  606.     const char *    z_rule;
  607.     const char *    z_format;
  608.  
  609.     long        z_stdoff;
  610.  
  611.     struct rule *    z_rules;
  612.     int        z_nrules;
  613.  
  614.     struct rule    z_untilrule;
  615.     time_t        z_untiltime;
  616. };
  617.  
  618. static struct zone *    zones;
  619. static int        nzones;    /* number of zones */
  620.  
  621. struct link {
  622.     const char *    l_filename;
  623.     int        l_linenum;
  624.     const char *    l_from;
  625.     const char *    l_to;
  626. };
  627.  
  628. static struct link *    links;
  629. static int        nlinks;
  630.  
  631. struct lookup {
  632.     const char *    l_word;
  633.     const int    l_value;
  634. };
  635.  
  636. static struct lookup const *    byword P((const char * string,
  637.                     const struct lookup * lp));
  638.  
  639. static struct lookup const    line_codes[] = {
  640.     "Rule",        LC_RULE,
  641.     "Zone",        LC_ZONE,
  642.     "Link",        LC_LINK,
  643.     "Leap",        LC_LEAP,
  644.     NULL,        0
  645. };
  646.  
  647. static struct lookup const    mon_names[] = {
  648.     "January",    TM_JANUARY,
  649.     "February",    TM_FEBRUARY,
  650.     "March",    TM_MARCH,
  651.     "April",    TM_APRIL,
  652.     "May",        TM_MAY,
  653.     "June",        TM_JUNE,
  654.     "July",        TM_JULY,
  655.     "August",    TM_AUGUST,
  656.     "September",    TM_SEPTEMBER,
  657.     "October",    TM_OCTOBER,
  658.     "November",    TM_NOVEMBER,
  659.     "December",    TM_DECEMBER,
  660.     NULL,        0
  661. };
  662.  
  663. static struct lookup const    wday_names[] = {
  664.     "Sunday",    TM_SUNDAY,
  665.     "Monday",    TM_MONDAY,
  666.     "Tuesday",    TM_TUESDAY,
  667.     "Wednesday",    TM_WEDNESDAY,
  668.     "Thursday",    TM_THURSDAY,
  669.     "Friday",    TM_FRIDAY,
  670.     "Saturday",    TM_SATURDAY,
  671.     NULL,        0
  672. };
  673.  
  674. static struct lookup const    lasts[] = {
  675.     "last-Sunday",        TM_SUNDAY,
  676.     "last-Monday",        TM_MONDAY,
  677.     "last-Tuesday",        TM_TUESDAY,
  678.     "last-Wednesday",    TM_WEDNESDAY,
  679.     "last-Thursday",    TM_THURSDAY,
  680.     "last-Friday",        TM_FRIDAY,
  681.     "last-Saturday",    TM_SATURDAY,
  682.     NULL,            0
  683. };
  684.  
  685. static struct lookup const    begin_years[] = {
  686.     "minimum",        YR_MINIMUM,
  687.     "maximum",        YR_MAXIMUM,
  688.     NULL,            0
  689. };
  690.  
  691. static struct lookup const    end_years[] = {
  692.     "minimum",        YR_MINIMUM,
  693.     "maximum",        YR_MAXIMUM,
  694.     "only",            YR_ONLY,
  695.     NULL,            0
  696. };
  697.  
  698. static struct lookup const    leap_types[] = {
  699.     "Rolling",        TRUE,
  700.     "Stationary",        FALSE,
  701.     NULL,            0
  702. };
  703.  
  704. static const int    len_months[2][MONSPERYEAR] = {
  705.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  706.     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  707. };
  708.  
  709. static const int    len_years[2] = {
  710.     DAYSPERNYEAR, DAYSPERLYEAR
  711. };
  712.  
  713. static time_t        ats[TZ_MAX_TIMES];
  714. static unsigned char    types[TZ_MAX_TIMES];
  715. static long        gmtoffs[TZ_MAX_TYPES];
  716. static char        isdsts[TZ_MAX_TYPES];
  717. static char        abbrinds[TZ_MAX_TYPES];
  718. static char        chars[TZ_MAX_CHARS];
  719. static time_t        trans[TZ_MAX_LEAPS];
  720. static long        corr[TZ_MAX_LEAPS];
  721. static char        roll[TZ_MAX_LEAPS];
  722.  
  723. /*
  724. ** Memory allocation.
  725. */
  726.  
  727. static char *
  728. memcheck(ptr)
  729. char *    ptr;
  730. {
  731.     if (ptr == NULL) {
  732.         (void) perror(progname);
  733.         (void) exit(EXIT_FAILURE);
  734.     }
  735.     return ptr;
  736. }
  737.  
  738. #define emalloc(size)        memcheck(imalloc(size))
  739. #define erealloc(ptr, size)    memcheck(irealloc(ptr, size))
  740. #define ecpyalloc(ptr)        memcheck(icpyalloc(ptr))
  741. #define ecatalloc(oldp, newp)    memcheck(icatalloc(oldp, newp))
  742.  
  743. /*
  744. ** Error handling.
  745. */
  746.  
  747. static void
  748. eats(name, num, rname, rnum)
  749. const char *    name;
  750. const char *    rname;
  751. {
  752.     filename = name;
  753.     linenum = num;
  754.     rfilename = rname;
  755.     rlinenum = rnum;
  756. }
  757.  
  758. static void
  759. eat(name, num)
  760. const char *    name;
  761. {
  762.     eats(name, num, (char *) NULL, -1);
  763. }
  764.  
  765. static void
  766. error(string)
  767. const char *    string;
  768. {
  769.     /*
  770.     ** Match the format of "cc" to allow sh users to
  771.     **     zic ... 2>&1 | error -t "*" -v
  772.     ** on BSD systems.
  773.     */
  774.     (void) fprintf(stderr, "\"%s\", line %d: %s",
  775.         filename, linenum, string);
  776.     if (rfilename != NULL)
  777.         (void) fprintf(stderr, " (rule from \"%s\", line %d)",
  778.             rfilename, rlinenum);
  779.     (void) fprintf(stderr, "\n");
  780.     ++errors;
  781. }
  782.  
  783. static void
  784. usage()
  785. {
  786.     (void) fprintf(stderr,
  787. "%s: usage is %s [ -s ] [ -v ] [ -l localtime ] [ -d directory ]\n\
  788. \t[ -L leapseconds ] [ filename ... ]\n",
  789.         progname, progname);
  790.     (void) exit(EXIT_FAILURE);
  791. }
  792.  
  793. static const char *    lcltime = NULL;
  794. static const char *    directory = NULL;
  795. static const char *    leapsec = NULL;
  796. static int        sflag = FALSE;
  797.  
  798. main(argc, argv)
  799. int    argc;
  800. char *    argv[];
  801. {
  802.     register int    i, j;
  803.     register int    c;
  804.  
  805. #ifdef unix
  806.     (void) umask(umask(022) | 022);
  807. #endif /* defined unix */
  808.     progname = argv[0];
  809.     while ((c = getopt(argc, argv, "d:l:L:vs")) != EOF)
  810.         switch (c) {
  811.             default:
  812.                 usage();
  813.             case 'd':
  814.                 if (directory == NULL)
  815.                     directory = optarg;
  816.                 else {
  817.                     (void) fprintf(stderr,
  818. "%s: More than one -d option specified\n",
  819.                         progname);
  820.                     (void) exit(EXIT_FAILURE);
  821.                 }
  822.                 break;
  823.             case 'l':
  824.                 if (lcltime == NULL)
  825.                     lcltime = optarg;
  826.                 else {
  827.                     (void) fprintf(stderr,
  828. "%s: More than one -l option specified\n",
  829.                         progname);
  830.                     (void) exit(EXIT_FAILURE);
  831.                 }
  832.                 break;
  833.             case 'L':
  834.                 if (leapsec == NULL)
  835.                     leapsec = optarg;
  836.                 else {
  837.                     (void) fprintf(stderr,
  838. "%s: More than one -L option specified\n",
  839.                         progname);
  840.                     (void) exit(EXIT_FAILURE);
  841.                 }
  842.                 break;
  843.             case 'v':
  844.                 noise = TRUE;
  845.                 break;
  846.             case 's':
  847.                 sflag = TRUE;
  848.                 break;
  849.         }
  850.     if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
  851.         usage();    /* usage message by request */
  852.     if (directory == NULL)
  853.         directory = TZDIR;
  854.     if (leapsec == NULL)
  855.         leapsec = "leapseconds";
  856.  
  857.     setboundaries();
  858.  
  859.     if (optind < argc) {
  860.         infile(leapsec);
  861.         adjleap();
  862.     }
  863.  
  864.     zones = (struct zone *) emalloc(0);
  865.     rules = (struct rule *) emalloc(0);
  866.     links = (struct link *) emalloc(0);
  867.     for (i = optind; i < argc; ++i)
  868.         infile(argv[i]);
  869.     if (errors)
  870.         (void) exit(EXIT_FAILURE);
  871.     associate();
  872.     for (i = 0; i < nzones; i = j) {
  873.         /*
  874.          * Find the next non-continuation zone entry.
  875.          */
  876.         for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
  877.             ;
  878.         outzone(&zones[i], j - i);
  879.     }
  880.     /*
  881.     ** Make links.
  882.     */
  883.     for (i = 0; i < nlinks + (lcltime != NULL); ++i) {
  884.         register char *    fromname;
  885.         register char *    toname;
  886.  
  887.         fromname = ecpyalloc(directory);
  888.         fromname = ecatalloc(fromname, "/");
  889.         fromname = ecatalloc(fromname,
  890.             (i == nlinks) ? lcltime : links[i].l_from);
  891.         toname = ecpyalloc(directory);
  892.         toname = ecatalloc(toname, "/");
  893.         toname = ecatalloc(toname,
  894.             (i == nlinks) ? TZDEFAULT : links[i].l_to);
  895.         /*
  896.         ** We get to be careful here since
  897.         ** there's a fair chance of root running us.
  898.         */
  899.         if (!itsdir(toname))
  900.             (void) remove(toname);
  901.         if (link(fromname, toname) != 0) {
  902.             (void) fprintf(stderr, "%s: Can't link from %s to ",
  903.                 progname, fromname);
  904.             (void) perror(toname);
  905.             (void) exit(EXIT_FAILURE);
  906.         }
  907.         ifree(fromname);
  908.         ifree(toname);
  909.     }
  910.     return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  911. }
  912.  
  913. static void
  914. setboundaries()
  915. {
  916.     register time_t    bit;
  917.  
  918.     for (bit = 1; bit > 0; bit <<= 1)
  919.         ;
  920.     if (bit == 0) {        /* time_t is an unsigned type */
  921.         tt_signed = FALSE;
  922.         min_time = 0;
  923.         max_time = ~(time_t) 0;
  924.         if (sflag)
  925.             max_time >>= 1;
  926.     } else {
  927.         tt_signed = TRUE;
  928.         min_time = bit;
  929.         max_time = bit;
  930.         ++max_time;
  931.         max_time = -max_time;
  932.         if (sflag)
  933.             min_time = 0;
  934.     }
  935.     min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
  936.     max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
  937. }
  938.  
  939. static int
  940. itsdir(name)
  941. char *    name;
  942. {
  943.     struct stat    s;
  944.  
  945.     return stat(name, &s) == 0 && (s.st_mode & S_IFMT) == S_IFDIR;
  946. }
  947.  
  948. /*
  949. ** Associate sets of rules with zones.
  950. */
  951.  
  952. /*
  953. ** Sort by rule name.
  954. */
  955.  
  956. static
  957. rcomp(cp1, cp2)
  958. const genericptr_t    cp1;
  959. const genericptr_t    cp2;
  960. {
  961.     return strcmp(((struct rule *) cp1)->r_name,
  962.         ((struct rule *) cp2)->r_name);
  963. }
  964.  
  965. static void
  966. associate()
  967. {
  968.     register struct zone *    zp;
  969.     register struct rule *    rp;
  970.     register int        base, out;
  971.     register int        i;
  972.  
  973.     if (nrules != 0) {
  974.         /*
  975.         ** This only *looks* like an optimization;
  976.         ** it's actually a workaround for a buggy Turbo C 1.5 qsort.
  977.         */
  978.         for (i = 1; i < nrules; ++i)
  979.             if (rcomp((char *) &rules[i - 1],
  980.                 (char *) &rules[i]) > 0)
  981.                     break;
  982.         if (i < nrules)
  983.             (void) qsort((genericptr_t) rules,
  984.                 (qsort_size_t) nrules,
  985.                 (qsort_size_t) sizeof *rules, rcomp);
  986.     }
  987.     for (i = 0; i < nzones; ++i) {
  988.         zp = &zones[i];
  989.         zp->z_rules = NULL;
  990.         zp->z_nrules = 0;
  991.     }
  992.     for (base = 0; base < nrules; base = out) {
  993.         rp = &rules[base];
  994.         for (out = base + 1; out < nrules; ++out)
  995.             if (strcmp(rp->r_name, rules[out].r_name) != 0)
  996.                 break;
  997.         for (i = 0; i < nzones; ++i) {
  998.             zp = &zones[i];
  999.             if (strcmp(zp->z_rule, rp->r_name) != 0)
  1000.                 continue;
  1001.             zp->z_rules = rp;
  1002.             zp->z_nrules = out - base;
  1003.         }
  1004.     }
  1005.     for (i = 0; i < nzones; ++i) {
  1006.         zp = &zones[i];
  1007.         if (zp->z_nrules == 0) {
  1008.             /*
  1009.             ** Maybe we have a local standard time offset.
  1010.             */
  1011.             eat(zp->z_filename, zp->z_linenum);
  1012.             zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE);
  1013.             /*
  1014.             ** Note, though, that if there's no rule,
  1015.             ** a '%s' in the format is a bad thing.
  1016.             */
  1017.             if (strchr(zp->z_format, '%') != 0)
  1018.                 error("%s in ruleless zone");
  1019.         }
  1020.     }
  1021.     if (errors)
  1022.         (void) exit(EXIT_FAILURE);
  1023. }
  1024.  
  1025. static void
  1026. infile(name)
  1027. const char *    name;
  1028. {
  1029.     register FILE *            fp;
  1030.     register char **        fields;
  1031.     register char *            cp;
  1032.     register const struct lookup *    lp;
  1033.     register int            nfields;
  1034.     register int            wantcont;
  1035.     register int            num;
  1036.     char                buf[BUFSIZ];
  1037.  
  1038.     if (strcmp(name, "-") == 0) {
  1039.         name = "standard input";
  1040.         fp = stdin;
  1041.     } else if ((fp = fopen(name, "r")) == NULL) {
  1042.         (void) fprintf(stderr, "%s: Can't open ", progname);
  1043.         (void) perror(name);
  1044.         (void) exit(EXIT_FAILURE);
  1045.     }
  1046.     wantcont = FALSE;
  1047.     for (num = 1; ; ++num) {
  1048.         eat(name, num);
  1049.         if (fgets(buf, (int) sizeof buf, fp) != buf)
  1050.             break;
  1051.         cp = strchr(buf, '\n');
  1052.         if (cp == NULL) {
  1053.             error("line too long");
  1054.             (void) exit(EXIT_FAILURE);
  1055.         }
  1056.         *cp = '\0';
  1057.         fields = getfields(buf);
  1058.         nfields = 0;
  1059.         while (fields[nfields] != NULL) {
  1060.             if (ciequal(fields[nfields], "-"))
  1061.                 fields[nfields] = "";
  1062.             ++nfields;
  1063.         }
  1064.         if (nfields == 0) {
  1065.             /* nothing to do */
  1066.         } else if (wantcont) {
  1067.             wantcont = inzcont(fields, nfields);
  1068.         } else {
  1069.             lp = byword(fields[0], line_codes);
  1070.             if (lp == NULL)
  1071.                 error("input line of unknown type");
  1072.             else switch ((int) (lp->l_value)) {
  1073.                 case LC_RULE:
  1074.                     inrule(fields, nfields);
  1075.                     wantcont = FALSE;
  1076.                     break;
  1077.                 case LC_ZONE:
  1078.                     wantcont = inzone(fields, nfields);
  1079.                     break;
  1080.                 case LC_LINK:
  1081.                     inlink(fields, nfields);
  1082.                     wantcont = FALSE;
  1083.                     break;
  1084.                 case LC_LEAP:
  1085.                     if (name != leapsec)
  1086.                         (void) fprintf(stderr,
  1087. "%s: Leap line in non leap seconds file %s\n",
  1088.                         progname, name);
  1089.                     else
  1090.                         inleap(fields, nfields);
  1091.                     wantcont = FALSE;
  1092.                     break;
  1093.                 default:    /* "cannot happen" */
  1094.                     (void) fprintf(stderr,
  1095. "%s: panic: Invalid l_value %d\n",
  1096.                         progname, lp->l_value);
  1097.                     (void) exit(EXIT_FAILURE);
  1098.             }
  1099.         }
  1100.         ifree((char *) fields);
  1101.     }
  1102.     if (ferror(fp)) {
  1103.         (void) fprintf(stderr, "%s: Error reading ", progname);
  1104.         (void) perror(filename);
  1105.         (void) exit(EXIT_FAILURE);
  1106.     }
  1107.     if (fp != stdin && fclose(fp)) {
  1108.         (void) fprintf(stderr, "%s: Error closing ", progname);
  1109.         (void) perror(filename);
  1110.         (void) exit(EXIT_FAILURE);
  1111.     }
  1112.     if (wantcont)
  1113.         error("expected continuation line not found");
  1114. }
  1115.  
  1116. /*
  1117. ** Convert a string of one of the forms
  1118. **    h    -h     hh:mm    -hh:mm    hh:mm:ss    -hh:mm:ss
  1119. ** into a number of seconds.
  1120. ** A null string maps to zero.
  1121. ** Call error with errstring and return zero on errors.
  1122. */
  1123.  
  1124. static long
  1125. gethms(string, errstring, signable)
  1126. const char *    string;
  1127. const char *    errstring;
  1128. {
  1129.     int    hh, mm, ss, sign;
  1130.  
  1131.     if (string == NULL || *string == '\0')
  1132.         return 0;
  1133.     if (!signable)
  1134.         sign = 1;
  1135.     else if (*string == '-') {
  1136.         sign = -1;
  1137.         ++string;
  1138.     } else    sign = 1;
  1139.     if (sscanf(string, scheck(string, "%d"), &hh) == 1)
  1140.         mm = ss = 0;
  1141.     else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
  1142.         ss = 0;
  1143.     else if (sscanf(string, scheck(string, "%d:%d:%d"),
  1144.         &hh, &mm, &ss) != 3) {
  1145.             error(errstring);
  1146.             return 0;
  1147.     }
  1148.     if (hh < 0 || hh >= HOURSPERDAY ||
  1149.         mm < 0 || mm >= MINSPERHOUR ||
  1150.         ss < 0 || ss > SECSPERMIN) {
  1151.             error(errstring);
  1152.             return 0;
  1153.     }
  1154.     return eitol(sign) *
  1155.         (eitol(hh * MINSPERHOUR + mm) *
  1156.         eitol(SECSPERMIN) + eitol(ss));
  1157. }
  1158.  
  1159. static void
  1160. inrule(fields, nfields)
  1161. register char **    fields;
  1162. {
  1163.     static struct rule    r;
  1164.  
  1165.     if (nfields != RULE_FIELDS) {
  1166.         error("wrong number of fields on Rule line");
  1167.         return;
  1168.     }
  1169.     if (*fields[RF_NAME] == '\0') {
  1170.         error("nameless rule");
  1171.         return;
  1172.     }
  1173.     r.r_filename = filename;
  1174.     r.r_linenum = linenum;
  1175.     r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
  1176.     rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
  1177.         fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
  1178.     r.r_name = ecpyalloc(fields[RF_NAME]);
  1179.     r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
  1180.     rules = (struct rule *) erealloc((char *) rules,
  1181.         (int) ((nrules + 1) * sizeof *rules));
  1182.     rules[nrules++] = r;
  1183. }
  1184.  
  1185. static
  1186. inzone(fields, nfields)
  1187. register char **    fields;
  1188. {
  1189.     register int    i;
  1190.     char        buf[132];
  1191.  
  1192.     if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
  1193.         error("wrong number of fields on Zone line");
  1194.         return FALSE;
  1195.     }
  1196.     if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
  1197.         (void) sprintf(buf,
  1198.             "\"Zone %s\" line and -l option are mutually exclusive",
  1199.             TZDEFAULT);
  1200.         error(buf);
  1201.         return FALSE;
  1202.     }
  1203.     for (i = 0; i < nzones; ++i)
  1204.         if (zones[i].z_name != NULL &&
  1205.             strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
  1206.                 (void) sprintf(buf,
  1207. "duplicate zone name %s (file \"%s\", line %d)",
  1208.                     fields[ZF_NAME],
  1209.                     zones[i].z_filename,
  1210.                     zones[i].z_linenum);
  1211.                 error(buf);
  1212.                 return FALSE;
  1213.         }
  1214.     return inzsub(fields, nfields, FALSE);
  1215. }
  1216.  
  1217. static
  1218. inzcont(fields, nfields)
  1219. register char **    fields;
  1220. {
  1221.     if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
  1222.         error("wrong number of fields on Zone continuation line");
  1223.         return FALSE;
  1224.     }
  1225.     return inzsub(fields, nfields, TRUE);
  1226. }
  1227.  
  1228. static
  1229. inzsub(fields, nfields, iscont)
  1230. register char **    fields;
  1231. {
  1232.     register char *        cp;
  1233.     static struct zone    z;
  1234.     register int        i_gmtoff, i_rule, i_format;
  1235.     register int        i_untilyear, i_untilmonth;
  1236.     register int        i_untilday, i_untiltime;
  1237.     register int        hasuntil;
  1238.  
  1239.     if (iscont) {
  1240.         i_gmtoff = ZFC_GMTOFF;
  1241.         i_rule = ZFC_RULE;
  1242.         i_format = ZFC_FORMAT;
  1243.         i_untilyear = ZFC_TILYEAR;
  1244.         i_untilmonth = ZFC_TILMONTH;
  1245.         i_untilday = ZFC_TILDAY;
  1246.         i_untiltime = ZFC_TILTIME;
  1247.         z.z_name = NULL;
  1248.     } else {
  1249.         i_gmtoff = ZF_GMTOFF;
  1250.         i_rule = ZF_RULE;
  1251.         i_format = ZF_FORMAT;
  1252.         i_untilyear = ZF_TILYEAR;
  1253.         i_untilmonth = ZF_TILMONTH;
  1254.         i_untilday = ZF_TILDAY;
  1255.         i_untiltime = ZF_TILTIME;
  1256.         z.z_name = ecpyalloc(fields[ZF_NAME]);
  1257.     }
  1258.     z.z_filename = filename;
  1259.     z.z_linenum = linenum;
  1260.     z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
  1261.     if ((cp = strchr(fields[i_format], '%')) != 0) {
  1262.         if (*++cp != 's' || strchr(cp, '%') != 0) {
  1263.             error("invalid abbreviation format");
  1264.             return FALSE;
  1265.         }
  1266.     }
  1267.     z.z_rule = ecpyalloc(fields[i_rule]);
  1268.     z.z_format = ecpyalloc(fields[i_format]);
  1269.     hasuntil = nfields > i_untilyear;
  1270.     if (hasuntil) {
  1271.         z.z_untilrule.r_filename = filename;
  1272.         z.z_untilrule.r_linenum = linenum;
  1273.         rulesub(&z.z_untilrule,
  1274.             fields[i_untilyear],
  1275.             "only",
  1276.             "",
  1277.             (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan",
  1278.             (nfields > i_untilday) ? fields[i_untilday] : "1",
  1279.             (nfields > i_untiltime) ? fields[i_untiltime] : "0");
  1280.         z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear);
  1281.         if (iscont && nzones > 0 && z.z_untiltime < max_time &&
  1282.             z.z_untiltime > min_time &&
  1283.             zones[nzones - 1].z_untiltime >= z.z_untiltime) {
  1284. error("Zone continuation line end time is not after end time of previous line");
  1285.             return FALSE;
  1286.         }
  1287.     }
  1288.     zones = (struct zone *) erealloc((char *) zones,
  1289.         (int) ((nzones + 1) * sizeof *zones));
  1290.     zones[nzones++] = z;
  1291.     /*
  1292.     ** If there was an UNTIL field on this line,
  1293.     ** there's more information about the zone on the next line.
  1294.     */
  1295.     return hasuntil;
  1296. }
  1297.  
  1298. static void
  1299. inleap(fields, nfields)
  1300. register char **    fields;
  1301. {
  1302.     register char *            cp;
  1303.     register const struct lookup *    lp;
  1304.     register int            i, j;
  1305.     int                year, month, day;
  1306.     long                dayoff, tod;
  1307.     time_t                t;
  1308.  
  1309.     if (nfields != LEAP_FIELDS) {
  1310.         error("wrong number of fields on Leap line");
  1311.         return;
  1312.     }
  1313.     dayoff = 0;
  1314.     cp = fields[LP_YEAR];
  1315.     if (sscanf(cp, scheck(cp, "%d"), &year) != 1 ||
  1316.         year < min_year || year > max_year) {
  1317.             error("invalid leaping year");
  1318.             return;
  1319.     }
  1320.     j = EPOCH_YEAR;
  1321.     while (j != year) {
  1322.         if (year > j) {
  1323.             i = len_years[isleap(j)];
  1324.             ++j;
  1325.         } else {
  1326.             --j;
  1327.             i = -len_years[isleap(j)];
  1328.         }
  1329.         dayoff = oadd(dayoff, eitol(i));
  1330.     }
  1331.     if ((lp = byword(fields[LP_MONTH], mon_names)) == NULL) {
  1332.         error("invalid month name");
  1333.         return;
  1334.     }
  1335.     month = lp->l_value;
  1336.     j = TM_JANUARY;
  1337.     while (j != month) {
  1338.         i = len_months[isleap(year)][j];
  1339.         dayoff = oadd(dayoff, eitol(i));
  1340.         ++j;
  1341.     }
  1342.     cp = fields[LP_DAY];
  1343.     if (sscanf(cp, scheck(cp, "%d"), &day) != 1 ||
  1344.         day <= 0 || day > len_months[isleap(year)][month]) {
  1345.             error("invalid day of month");
  1346.             return;
  1347.     }
  1348.     dayoff = oadd(dayoff, eitol(day - 1));
  1349.     if (dayoff < 0 && !tt_signed) {
  1350.         error("time before zero");
  1351.         return;
  1352.     }
  1353.     t = (time_t) dayoff * SECSPERDAY;
  1354.     /*
  1355.     ** Cheap overflow check.
  1356.     */
  1357.     if (t / SECSPERDAY != dayoff) {
  1358.         error("time overflow");
  1359.         return;
  1360.     }
  1361.     tod = gethms(fields[LP_TIME], "invalid time of day", FALSE);
  1362.     cp = fields[LP_CORR];
  1363.     if (strcmp(cp, "+") != 0 && strcmp(cp, "") != 0) {
  1364.         /* infile() turned "-" into "" */
  1365.         error("illegal CORRECTION field on Leap line");
  1366.         return;
  1367.     }
  1368.     if ((lp = byword(fields[LP_ROLL], leap_types)) == NULL) {
  1369.         error("illegal Rolling/Stationary field on Leap line");
  1370.         return;
  1371.     }
  1372.     addleap(tadd(t, tod), *cp == '+', lp->l_value);
  1373. }
  1374.  
  1375. static void
  1376. inlink(fields, nfields)
  1377. register char **    fields;
  1378. {
  1379.     struct link    l;
  1380.  
  1381.     if (nfields != LINK_FIELDS) {
  1382.         error("wrong number of fields on Link line");
  1383.         return;
  1384.     }
  1385.     if (*fields[LF_FROM] == '\0') {
  1386.         error("blank FROM field on Link line");
  1387.         return;
  1388.     }
  1389.     if (*fields[LF_TO] == '\0') {
  1390.         error("blank TO field on Link line");
  1391.         return;
  1392.     }
  1393.     l.l_filename = filename;
  1394.     l.l_linenum = linenum;
  1395.     l.l_from = ecpyalloc(fields[LF_FROM]);
  1396.     l.l_to = ecpyalloc(fields[LF_TO]);
  1397.     links = (struct link *) erealloc((char *) links,
  1398.         (int) ((nlinks + 1) * sizeof *links));
  1399.     links[nlinks++] = l;
  1400. }
  1401.  
  1402. static void
  1403. rulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
  1404. register struct rule *    rp;
  1405. char *            loyearp;
  1406. char *            hiyearp;
  1407. char *            typep;
  1408. char *            monthp;
  1409. char *            dayp;
  1410. char *            timep;
  1411. {
  1412.     register struct lookup const *    lp;
  1413.     register char *            cp;
  1414.  
  1415.     if ((lp = byword(monthp, mon_names)) == NULL) {
  1416.         error("invalid month name");
  1417.         return;
  1418.     }
  1419.     rp->r_month = lp->l_value;
  1420.     rp->r_todisstd = FALSE;
  1421.     cp = timep;
  1422.     if (*cp != '\0') {
  1423.         cp += strlen(cp) - 1;
  1424.         switch (lowerit(*cp)) {
  1425.             case 's':
  1426.                 rp->r_todisstd = TRUE;
  1427.                 *cp = '\0';
  1428.                 break;
  1429.             case 'w':
  1430.                 rp->r_todisstd = FALSE;
  1431.                 *cp = '\0';
  1432.                 break;
  1433.         }
  1434.     }
  1435.     rp->r_tod = gethms(timep, "invalid time of day", FALSE);
  1436.     /*
  1437.     ** Year work.
  1438.     */
  1439.     cp = loyearp;
  1440.     if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
  1441.         case YR_MINIMUM:
  1442.             rp->r_loyear = min_year;
  1443.             break;
  1444.         case YR_MAXIMUM:
  1445.             rp->r_loyear = max_year;
  1446.             break;
  1447.         default:    /* "cannot happen" */
  1448.             (void) fprintf(stderr,
  1449.                 "%s: panic: Invalid l_value %d\n",
  1450.                 progname, lp->l_value);
  1451.             (void) exit(EXIT_FAILURE);
  1452.     } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 ||
  1453.         rp->r_loyear < min_year || rp->r_loyear > max_year) {
  1454.             if (noise)
  1455.                 error("invalid starting year");
  1456.             if (rp->r_loyear > max_year)
  1457.                 return;
  1458.     }
  1459.     cp = hiyearp;
  1460.     if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
  1461.         case YR_MINIMUM:
  1462.             rp->r_hiyear = min_year;
  1463.             break;
  1464.         case YR_MAXIMUM:
  1465.             rp->r_hiyear = max_year;
  1466.             break;
  1467.         case YR_ONLY:
  1468.             rp->r_hiyear = rp->r_loyear;
  1469.             break;
  1470.         default:    /* "cannot happen" */
  1471.             (void) fprintf(stderr,
  1472.                 "%s: panic: Invalid l_value %d\n",
  1473.                 progname, lp->l_value);
  1474.             (void) exit(EXIT_FAILURE);
  1475.     } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 ||
  1476.         rp->r_hiyear < min_year || rp->r_hiyear > max_year) {
  1477.             if (noise)
  1478.                 error("invalid ending year");
  1479.             if (rp->r_hiyear < min_year)
  1480.                 return;
  1481.     }
  1482.     if (rp->r_hiyear < min_year)
  1483.          return;
  1484.      if (rp->r_loyear < min_year)
  1485.          rp->r_loyear = min_year;
  1486.      if (rp->r_hiyear > max_year)
  1487.          rp->r_hiyear = max_year;
  1488.     if (rp->r_loyear > rp->r_hiyear) {
  1489.         error("starting year greater than ending year");
  1490.         return;
  1491.     }
  1492.     if (*typep == '\0')
  1493.         rp->r_yrtype = NULL;
  1494.     else {
  1495.         if (rp->r_loyear == rp->r_hiyear) {
  1496.             error("typed single year");
  1497.             return;
  1498.         }
  1499.         rp->r_yrtype = ecpyalloc(typep);
  1500.     }
  1501.     /*
  1502.     ** Day work.
  1503.     ** Accept things such as:
  1504.     **    1
  1505.     **    last-Sunday
  1506.     **    Sun<=20
  1507.     **    Sun>=7
  1508.     */
  1509.     if ((lp = byword(dayp, lasts)) != NULL) {
  1510.         rp->r_dycode = DC_DOWLEQ;
  1511.         rp->r_wday = lp->l_value;
  1512.         rp->r_dayofmonth = len_months[1][rp->r_month];
  1513.     } else {
  1514.         if ((cp = strchr(dayp, '<')) != 0)
  1515.             rp->r_dycode = DC_DOWLEQ;
  1516.         else if ((cp = strchr(dayp, '>')) != 0)
  1517.             rp->r_dycode = DC_DOWGEQ;
  1518.         else {
  1519.             cp = dayp;
  1520.             rp->r_dycode = DC_DOM;
  1521.         }
  1522.         if (rp->r_dycode != DC_DOM) {
  1523.             *cp++ = 0;
  1524.             if (*cp++ != '=') {
  1525.                 error("invalid day of month");
  1526.                 return;
  1527.             }
  1528.             if ((lp = byword(dayp, wday_names)) == NULL) {
  1529.                 error("invalid weekday name");
  1530.                 return;
  1531.             }
  1532.             rp->r_wday = lp->l_value;
  1533.         }
  1534.         if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 ||
  1535.             rp->r_dayofmonth <= 0 ||
  1536.             (rp->r_dayofmonth > len_months[1][rp->r_month])) {
  1537.                 error("invalid day of month");
  1538.                 return;
  1539.         }
  1540.     }
  1541. }
  1542.  
  1543. static void
  1544. convert(val, buf)
  1545. long    val;
  1546. char *    buf;
  1547. {
  1548.     register int    i;
  1549.     register long    shift;
  1550.  
  1551.     for (i = 0, shift = 24; i < 4; ++i, shift -= 8)
  1552.         buf[i] = val >> shift;
  1553. }
  1554.  
  1555. static void
  1556. puttzcode(val, fp)
  1557. long    val;
  1558. FILE *    fp;
  1559. {
  1560.     char    buf[4];
  1561.  
  1562.     convert(val, buf);
  1563.     (void) fwrite((genericptr_t) buf,
  1564.         (fwrite_size_t) sizeof buf,
  1565.         (fwrite_size_t) 1, fp);
  1566. }
  1567.  
  1568. static void
  1569. writezone(name)
  1570. const char *    name;
  1571. {
  1572.     register FILE *        fp;
  1573.     register int        i, j;
  1574.     char            fullname[BUFSIZ];
  1575.     static struct tzhead    tzh;
  1576.  
  1577.     if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) {
  1578.         (void) fprintf(stderr,
  1579.             "%s: File name %s/%s too long\n", progname,
  1580.             directory, name);
  1581.         (void) exit(EXIT_FAILURE);
  1582.     }
  1583.     (void) sprintf(fullname, "%s/%s", directory, name);
  1584.     if ((fp = fopen(fullname, "wb")) == NULL) {
  1585.         if (mkdirs(fullname) != 0)
  1586.             (void) exit(EXIT_FAILURE);
  1587.         if ((fp = fopen(fullname, "wb")) == NULL) {
  1588.             (void) fprintf(stderr, "%s: Can't create ", progname);
  1589.             (void) perror(fullname);
  1590.             (void) exit(EXIT_FAILURE);
  1591.         }
  1592.     }
  1593.     convert(eitol(leapcnt), tzh.tzh_leapcnt);
  1594.     convert(eitol(timecnt), tzh.tzh_timecnt);
  1595.     convert(eitol(typecnt), tzh.tzh_typecnt);
  1596.     convert(eitol(charcnt), tzh.tzh_charcnt);
  1597.     (void) fwrite((genericptr_t) &tzh,
  1598.         (fwrite_size_t) sizeof tzh,
  1599.         (fwrite_size_t) 1, fp);
  1600.     for (i = 0; i < timecnt; ++i) {
  1601.         j = leapcnt;
  1602.         while (--j >= 0)
  1603.             if (ats[i] >= trans[j]) {
  1604.                 ats[i] = tadd(ats[i], corr[j]);
  1605.                 break;
  1606.             }
  1607.         puttzcode((long) ats[i], fp);
  1608.     }
  1609.     if (timecnt > 0)
  1610.         (void) fwrite((genericptr_t) types,
  1611.             (fwrite_size_t) sizeof types[0],
  1612.             (fwrite_size_t) timecnt, fp);
  1613.     for (i = 0; i < typecnt; ++i) {
  1614.         puttzcode((long) gmtoffs[i], fp);
  1615.         (void) putc(isdsts[i], fp);
  1616.         (void) putc(abbrinds[i], fp);
  1617.     }
  1618.     if (charcnt != 0)
  1619.         (void) fwrite((genericptr_t) chars,
  1620.             (fwrite_size_t) sizeof chars[0],
  1621.             (fwrite_size_t) charcnt, fp);
  1622.     for (i = 0; i < leapcnt; ++i) {
  1623.         if (roll[i]) {
  1624.             if (timecnt == 0 || trans[i] < ats[0]) {
  1625.                 j = 0;
  1626.                 while (isdsts[j])
  1627.                     if (++j >= typecnt) {
  1628.                         j = 0;
  1629.                         break;
  1630.                     }
  1631.             } else {
  1632.                 j = 1;
  1633.                 while (j < timecnt && trans[i] >= ats[j])
  1634.                     ++j;
  1635.                 j = types[j - 1];
  1636.             }
  1637.             puttzcode((long) tadd(trans[i], -gmtoffs[j]), fp);
  1638.         } else    puttzcode((long) trans[i], fp);
  1639.         puttzcode((long) corr[i], fp);
  1640.     }
  1641.     if (ferror(fp) || fclose(fp)) {
  1642.         (void) fprintf(stderr, "%s: Write error on ", progname);
  1643.         (void) perror(fullname);
  1644.         (void) exit(EXIT_FAILURE);
  1645.     }
  1646. }
  1647.  
  1648. static void
  1649. outzone(zpfirst, zonecount)
  1650. const struct zone *    zpfirst;
  1651. {
  1652.     register const struct zone *    zp;
  1653.     register struct rule *        rp;
  1654.     register int            i, j;
  1655.     register int            usestart, useuntil;
  1656.     register time_t            starttime, untiltime;
  1657.     register long            gmtoff;
  1658.     register long            stdoff;
  1659.     register int            year;
  1660.     register long            startoff;
  1661.     register int            startisdst;
  1662.     register int            type;
  1663.     char                startbuf[BUFSIZ];
  1664.  
  1665.     /*
  1666.     ** Now. . .finally. . .generate some useful data!
  1667.     */
  1668.     timecnt = 0;
  1669.     typecnt = 0;
  1670.     charcnt = 0;
  1671.     /*
  1672.     ** Two guesses. . .the second may well be corrected later.
  1673.     */
  1674.     gmtoff = zpfirst->z_gmtoff;
  1675.     stdoff = 0;
  1676. #ifdef lint
  1677.     starttime = 0;
  1678. #endif /* defined lint */
  1679. #ifdef __TURBOC__
  1680.     starttime = 0;
  1681. #endif /* defined __TURBOC__ */
  1682.     for (i = 0; i < zonecount; ++i) {
  1683.         usestart = i > 0;
  1684.         useuntil = i < (zonecount - 1);
  1685.         zp = &zpfirst[i];
  1686.         eat(zp->z_filename, zp->z_linenum);
  1687.         startisdst = -1;
  1688.         if (zp->z_nrules == 0) {
  1689.             type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff),
  1690.                 zp->z_format, zp->z_stdoff != 0);
  1691.             if (usestart)
  1692.                 addtt(starttime, type);
  1693.             gmtoff = zp->z_gmtoff;
  1694.             stdoff = zp->z_stdoff;
  1695.         } else for (year = min_year; year <= max_year; ++year) {
  1696.             if (useuntil && year > zp->z_untilrule.r_hiyear)
  1697.                 break;
  1698.             /*
  1699.             ** Mark which rules to do in the current year.
  1700.             ** For those to do, calculate rpytime(rp, year);
  1701.             */
  1702.             for (j = 0; j < zp->z_nrules; ++j) {
  1703.                 rp = &zp->z_rules[j];
  1704.                 eats(zp->z_filename, zp->z_linenum,
  1705.                     rp->r_filename, rp->r_linenum);
  1706.                 rp->r_todo = year >= rp->r_loyear &&
  1707.                         year <= rp->r_hiyear &&
  1708.                         yearistype(year, rp->r_yrtype);
  1709.                 if (rp->r_todo)
  1710.                     rp->r_temp = rpytime(rp, year);
  1711.             }
  1712.             for ( ; ; ) {
  1713.                 register int    k;
  1714.                 register time_t    jtime, ktime;
  1715.                 register long    offset;
  1716.                 char        buf[BUFSIZ];
  1717.  
  1718.                 if (useuntil) {
  1719.                     /*
  1720.                     ** Turn untiltime into GMT
  1721.                     ** assuming the current gmtoff and
  1722.                     ** stdoff values.
  1723.                     */
  1724.                     offset = gmtoff;
  1725.                     if (!zp->z_untilrule.r_todisstd)
  1726.                         offset = oadd(offset, stdoff);
  1727.                     untiltime = tadd(zp->z_untiltime,
  1728.                         -offset);
  1729.                 }
  1730.                 /*
  1731.                 ** Find the rule (of those to do, if any)
  1732.                 ** that takes effect earliest in the year.
  1733.                 */
  1734.                 k = -1;
  1735. #ifdef lint
  1736.                 ktime = 0;
  1737. #endif /* defined lint */
  1738. #ifdef __TURBOC__
  1739.                 ktime = 0;
  1740. #endif /* defined __TURBOC__ */
  1741.                 for (j = 0; j < zp->z_nrules; ++j) {
  1742.                     rp = &zp->z_rules[j];
  1743.                     if (!rp->r_todo)
  1744.                         continue;
  1745.                     eats(zp->z_filename, zp->z_linenum,
  1746.                         rp->r_filename, rp->r_linenum);
  1747.                     offset = gmtoff;
  1748.                     if (!rp->r_todisstd)
  1749.                         offset = oadd(offset, stdoff);
  1750.                     jtime = rp->r_temp;
  1751.                     if (jtime == min_time ||
  1752.                         jtime == max_time)
  1753.                             continue;
  1754.                     jtime = tadd(jtime, -offset);
  1755.                     if (k < 0 || jtime < ktime) {
  1756.                         k = j;
  1757.                         ktime = jtime;
  1758.                     }
  1759.                 }
  1760.                 if (k < 0)
  1761.                     break;    /* go on to next year */
  1762.                 rp = &zp->z_rules[k];
  1763.                 rp->r_todo = FALSE;
  1764.                 if (useuntil && ktime >= untiltime)
  1765.                     break;
  1766.                 if (usestart) {
  1767.                     if (ktime < starttime) {
  1768.                         stdoff = rp->r_stdoff;
  1769.                         startoff = oadd(zp->z_gmtoff,
  1770.                             rp->r_stdoff);
  1771.                         (void) sprintf(startbuf,
  1772.                             zp->z_format,
  1773.                             rp->r_abbrvar);
  1774.                         startisdst =
  1775.                             rp->r_stdoff != 0;
  1776.                         continue;
  1777.                     }
  1778.                     if (ktime != starttime &&
  1779.                         startisdst >= 0)
  1780. addtt(starttime, addtype(startoff, startbuf, startisdst));
  1781.                     usestart = FALSE;
  1782.                 }
  1783.                 eats(zp->z_filename, zp->z_linenum,
  1784.                     rp->r_filename, rp->r_linenum);
  1785.                 (void) sprintf(buf, zp->z_format,
  1786.                     rp->r_abbrvar);
  1787.                 offset = oadd(zp->z_gmtoff, rp->r_stdoff);
  1788.                 type = addtype(offset, buf, rp->r_stdoff != 0);
  1789.                 if (timecnt != 0 || rp->r_stdoff != 0)
  1790.                     addtt(ktime, type);
  1791.                 gmtoff = zp->z_gmtoff;
  1792.                 stdoff = rp->r_stdoff;
  1793.             }
  1794.         }
  1795.         /*
  1796.         ** Now we may get to set starttime for the next zone line.
  1797.         */
  1798.         if (useuntil)
  1799.             starttime = tadd(zp->z_untiltime,
  1800.                 -gmtoffs[types[timecnt - 1]]);
  1801.     }
  1802.     writezone(zpfirst->z_name);
  1803. }
  1804.  
  1805. static void
  1806. addtt(starttime, type)
  1807. time_t    starttime;
  1808. {
  1809.     if (timecnt != 0 && type == types[timecnt - 1])
  1810.         return;    /* easy enough! */
  1811.     if (timecnt >= TZ_MAX_TIMES) {
  1812.         error("too many transitions?!");
  1813.         (void) exit(EXIT_FAILURE);
  1814.     }
  1815.     ats[timecnt] = starttime;
  1816.     types[timecnt] = type;
  1817.     ++timecnt;
  1818. }
  1819.  
  1820. static
  1821. addtype(gmtoff, abbr, isdst)
  1822. long        gmtoff;
  1823. const char *    abbr;
  1824. {
  1825.     register int    i, j;
  1826.  
  1827.     /*
  1828.     ** See if there's already an entry for this zone type.
  1829.     ** If so, just return its index.
  1830.     */
  1831.     for (i = 0; i < typecnt; ++i) {
  1832.         if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
  1833.             strcmp(abbr, &chars[abbrinds[i]]) == 0)
  1834.                 return i;
  1835.     }
  1836.     /*
  1837.     ** There isn't one; add a new one, unless there are already too
  1838.     ** many.
  1839.     */
  1840.     if (typecnt >= TZ_MAX_TYPES) {
  1841.         error("too many local time types");
  1842.         (void) exit(EXIT_FAILURE);
  1843.     }
  1844.     gmtoffs[i] = gmtoff;
  1845.     isdsts[i] = isdst;
  1846.  
  1847.     for (j = 0; j < charcnt; ++j)
  1848.         if (strcmp(&chars[j], abbr) == 0)
  1849.             break;
  1850.     if (j == charcnt)
  1851.         newabbr(abbr);
  1852.     abbrinds[i] = j;
  1853.     ++typecnt;
  1854.     return i;
  1855. }
  1856.  
  1857. static void
  1858. addleap(t, positive, rolling)
  1859. time_t    t;
  1860. {
  1861.     register int    i, j;
  1862.  
  1863.     if (leapcnt >= TZ_MAX_LEAPS) {
  1864.         error("too many leap seconds");
  1865.         (void) exit(EXIT_FAILURE);
  1866.     }
  1867.     for (i = 0; i < leapcnt; ++i)
  1868.         if (t <= trans[i]) {
  1869.             if (t == trans[i]) {
  1870.                 error("repeated leap second moment");
  1871.                 (void) exit(EXIT_FAILURE);
  1872.             }
  1873.             break;
  1874.         }
  1875.     for (j = leapcnt; j > i; --j) {
  1876.         trans[j] = trans[j-1];
  1877.         corr[j] = corr[j-1];
  1878.         roll[j] = roll[j-1];
  1879.     }
  1880.     trans[i] = t;
  1881.     corr[i] = (positive ? 1L : -1L);
  1882.     roll[i] = rolling;
  1883.     ++leapcnt;
  1884. }
  1885.  
  1886. static void
  1887. adjleap()
  1888. {
  1889.     register int    i;
  1890.     register long    last = 0;
  1891.  
  1892.     /*
  1893.     ** propagate leap seconds forward
  1894.     */
  1895.     for (i = 0; i < leapcnt; ++i) {
  1896.         trans[i] = tadd(trans[i], last);
  1897.         last = corr[i] += last;
  1898.     }
  1899. }
  1900.  
  1901. static
  1902. yearistype(year, type)
  1903. const char *    type;
  1904. {
  1905.     char    buf[BUFSIZ];
  1906.     int    result;
  1907.  
  1908.     if (type == NULL || *type == '\0')
  1909.         return TRUE;
  1910.     if (strcmp(type, "uspres") == 0)
  1911.         return (year % 4) == 0;
  1912.     if (strcmp(type, "nonpres") == 0)
  1913.         return (year % 4) != 0;
  1914.     (void) sprintf(buf, "yearistype %d %s", year, type);
  1915.     result = system(buf);
  1916.     if (result == 0)
  1917.         return TRUE;
  1918.     if (result == (1 << 8))
  1919.         return FALSE;
  1920.     error("Wild result from command execution");
  1921.     (void) fprintf(stderr, "%s: command was '%s', result was %d\n",
  1922.         progname, buf, result);
  1923.     for ( ; ; )
  1924.         (void) exit(EXIT_FAILURE);
  1925. }
  1926.  
  1927. static
  1928. lowerit(a)
  1929. {
  1930.     return (isascii(a) && isupper(a)) ? tolower(a) : a;
  1931. }
  1932.  
  1933. static
  1934. ciequal(ap, bp)        /* case-insensitive equality */
  1935. register const char *    ap;
  1936. register const char *    bp;
  1937. {
  1938.     while (lowerit(*ap) == lowerit(*bp++))
  1939.         if (*ap++ == '\0')
  1940.             return TRUE;
  1941.     return FALSE;
  1942. }
  1943.  
  1944. static int
  1945. itsabbr(abbr, word)
  1946. register const char *    abbr;
  1947. register const char *    word;
  1948. {
  1949.     if (lowerit(*abbr) != lowerit(*word))
  1950.         return FALSE;
  1951.     ++word;
  1952.     while (*++abbr != '\0')
  1953.         do if (*word == '\0')
  1954.             return FALSE;
  1955.                 while (lowerit(*word++) != lowerit(*abbr));
  1956.     return TRUE;
  1957. }
  1958.  
  1959. static const struct lookup *
  1960. byword(word, table)
  1961. register const char *        word;
  1962. register const struct lookup *    table;
  1963. {
  1964.     register const struct lookup *    foundlp;
  1965.     register const struct lookup *    lp;
  1966.  
  1967.     if (word == NULL || table == NULL)
  1968.         return NULL;
  1969.     /*
  1970.     ** Look for exact match.
  1971.     */
  1972.     for (lp = table; lp->l_word != NULL; ++lp)
  1973.         if (ciequal(word, lp->l_word))
  1974.             return lp;
  1975.     /*
  1976.     ** Look for inexact match.
  1977.     */
  1978.     foundlp = NULL;
  1979.     for (lp = table; lp->l_word != NULL; ++lp)
  1980.         if (itsabbr(word, lp->l_word))
  1981.             if (foundlp == NULL)
  1982.                 foundlp = lp;
  1983.             else    return NULL;    /* multiple inexact matches */
  1984.     return foundlp;
  1985. }
  1986.  
  1987. static char **
  1988. getfields(cp)
  1989. register char *    cp;
  1990. {
  1991.     register char *        dp;
  1992.     register char **    array;
  1993.     register int        nsubs;
  1994.  
  1995.     if (cp == NULL)
  1996.         return NULL;
  1997.     array = (char **) emalloc((int) ((strlen(cp) + 1) * sizeof *array));
  1998.     nsubs = 0;
  1999.     for ( ; ; ) {
  2000.         while (isascii(*cp) && isspace(*cp))
  2001.             ++cp;
  2002.         if (*cp == '\0' || *cp == '#')
  2003.             break;
  2004.         array[nsubs++] = dp = cp;
  2005.         do {
  2006.             if ((*dp = *cp++) != '"')
  2007.                 ++dp;
  2008.             else while ((*dp = *cp++) != '"')
  2009.                 if (*dp != '\0')
  2010.                     ++dp;
  2011.                 else    error("Odd number of quotation marks");
  2012.         } while (*cp != '\0' && *cp != '#' &&
  2013.             (!isascii(*cp) || !isspace(*cp)));
  2014.         if (isascii(*cp) && isspace(*cp))
  2015.             ++cp;
  2016.         *dp = '\0';
  2017.     }
  2018.     array[nsubs] = NULL;
  2019.     return array;
  2020. }
  2021.  
  2022. static long
  2023. oadd(t1, t2)
  2024. long    t1;
  2025. long    t2;
  2026. {
  2027.     register long    t;
  2028.  
  2029.     t = t1 + t2;
  2030.     if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
  2031.         error("time overflow");
  2032.         (void) exit(EXIT_FAILURE);
  2033.     }
  2034.     return t;
  2035. }
  2036.  
  2037. static time_t
  2038. tadd(t1, t2)
  2039. time_t    t1;
  2040. long    t2;
  2041. {
  2042.     register time_t    t;
  2043.  
  2044.     if (t1 == max_time && t2 > 0)
  2045.         return max_time;
  2046.     if (t1 == min_time && t2 < 0)
  2047.         return min_time;
  2048.     t = t1 + t2;
  2049.     if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
  2050.         error("time overflow");
  2051.         (void) exit(EXIT_FAILURE);
  2052.     }
  2053.     return t;
  2054. }
  2055.  
  2056. /*
  2057. ** Given a rule, and a year, compute the date - in seconds since January 1,
  2058. ** 1970, 00:00 LOCAL time - in that year that the rule refers to.
  2059. */
  2060.  
  2061. static time_t
  2062. rpytime(rp, wantedy)
  2063. register const struct rule *    rp;
  2064. register int            wantedy;
  2065. {
  2066.     register int    y, m, i;
  2067.     register long    dayoff;            /* with a nod to Margaret O. */
  2068.     register time_t    t;
  2069.  
  2070.     dayoff = 0;
  2071.     m = TM_JANUARY;
  2072.     y = EPOCH_YEAR;
  2073.     while (wantedy != y) {
  2074.         if (wantedy > y) {
  2075.             i = len_years[isleap(y)];
  2076.             ++y;
  2077.         } else {
  2078.             --y;
  2079.             i = -len_years[isleap(y)];
  2080.         }
  2081.         dayoff = oadd(dayoff, eitol(i));
  2082.     }
  2083.     while (m != rp->r_month) {
  2084.         i = len_months[isleap(y)][m];
  2085.         dayoff = oadd(dayoff, eitol(i));
  2086.         ++m;
  2087.     }
  2088.     i = rp->r_dayofmonth;
  2089.     if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
  2090.         if (rp->r_dycode == DC_DOWLEQ)
  2091.             --i;
  2092.         else {
  2093.             error("use of 2/29 in non leap-year");
  2094.             (void) exit(EXIT_FAILURE);
  2095.         }
  2096.     }
  2097.     --i;
  2098.     dayoff = oadd(dayoff, eitol(i));
  2099.     if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
  2100.         register long    wday;
  2101.  
  2102. #define LDAYSPERWEEK    ((long) DAYSPERWEEK)
  2103.         wday = eitol(EPOCH_WDAY);
  2104.         /*
  2105.         ** Don't trust mod of negative numbers.
  2106.         */
  2107.         if (dayoff >= 0)
  2108.             wday = (wday + dayoff) % LDAYSPERWEEK;
  2109.         else {
  2110.             wday -= ((-dayoff) % LDAYSPERWEEK);
  2111.             if (wday < 0)
  2112.                 wday += LDAYSPERWEEK;
  2113.         }
  2114.         while (wday != eitol(rp->r_wday))
  2115.             if (rp->r_dycode == DC_DOWGEQ) {
  2116.                 dayoff = oadd(dayoff, (long) 1);
  2117.                 if (++wday >= LDAYSPERWEEK)
  2118.                     wday = 0;
  2119.                 ++i;
  2120.             } else {
  2121.                 dayoff = oadd(dayoff, (long) -1);
  2122.                 if (--wday < 0)
  2123.                     wday = LDAYSPERWEEK;
  2124.                 --i;
  2125.             }
  2126.         if (i < 0 || i >= len_months[isleap(y)][m]) {
  2127.             error("no day in month matches rule");
  2128.             (void) exit(EXIT_FAILURE);
  2129.         }
  2130.     }
  2131.     if (dayoff < 0 && !tt_signed) {
  2132.         if (wantedy == rp->r_loyear)
  2133.             return min_time;
  2134.         error("time before zero");
  2135.         (void) exit(EXIT_FAILURE);
  2136.     }
  2137.     t = (time_t) dayoff * SECSPERDAY;
  2138.     /*
  2139.     ** Cheap overflow check.
  2140.     */
  2141.     if (t / SECSPERDAY != dayoff) {
  2142.         if (wantedy == rp->r_hiyear)
  2143.             return max_time;
  2144.         if (wantedy == rp->r_loyear)
  2145.             return min_time;
  2146.         error("time overflow");
  2147.         (void) exit(EXIT_FAILURE);
  2148.     }
  2149.     return tadd(t, rp->r_tod);
  2150. }
  2151.  
  2152. static void
  2153. newabbr(string)
  2154. const char *    string;
  2155. {
  2156.     register int    i;
  2157.  
  2158.     i = strlen(string) + 1;
  2159.     if (charcnt + i >= TZ_MAX_CHARS) {
  2160.         error("too many, or too long, time zone abbreviations");
  2161.         (void) exit(EXIT_FAILURE);
  2162.     }
  2163.     (void) strcpy(&chars[charcnt], string);
  2164.     charcnt += eitol(i);
  2165. }
  2166.  
  2167. static
  2168. mkdirs(name)
  2169. char *    name;
  2170. {
  2171.     register char *    cp;
  2172.  
  2173.     if ((cp = name) == NULL || *cp == '\0')
  2174.         return 0;
  2175.     while ((cp = strchr(cp + 1, '/')) != 0) {
  2176.         *cp = '\0';
  2177. #ifndef unix
  2178.         /*
  2179.         ** MS-DOS drive specifier?
  2180.         */
  2181.         if (strlen(name) == 2 && isascii(name[0]) &&
  2182.             isalpha(name[0]) && name[1] == ':') {
  2183.                 *cp = '/';
  2184.                 continue;
  2185.         }
  2186. #endif /* !defined unix */
  2187.         if (!itsdir(name)) {
  2188.             /*
  2189.              * It doesn't seem to exist, so we try to create it.
  2190.              */
  2191.             if (emkdir(name, 0755) != 0) {
  2192.                 (void) fprintf(stderr,
  2193.                     "%s: Can't create directory ",
  2194.                     progname);
  2195.                 (void) perror(name);
  2196.                 return -1;
  2197.             }
  2198.         }
  2199.         *cp = '/';
  2200.     }
  2201.     return 0;
  2202. }
  2203.  
  2204. static long
  2205. eitol(i)
  2206. {
  2207.     long    l;
  2208.  
  2209.     l = i;
  2210.     if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) {
  2211.         (void) fprintf(stderr, "%s: %d did not sign extend correctly\n",
  2212.             progname, i);
  2213.         (void) exit(EXIT_FAILURE);
  2214.     }
  2215.     return l;
  2216. }
  2217.  
  2218. /*
  2219. ** UNIX is a registered trademark of AT&T.
  2220. */
  2221. End of zic.c
  2222. echo 'zdump.c' 1>&2
  2223. cat >'zdump.c' <<'End of zdump.c'
  2224. #ifndef lint
  2225. #ifndef NOID
  2226. static char    elsieid[] = "@(#)zdump.c    4.1";
  2227. #endif /* !defined NOID */
  2228. #endif /* !defined lint */
  2229.  
  2230. #include "stdio.h"
  2231. #include "time.h"
  2232. #include "tzfile.h"
  2233. #include "string.h"
  2234. #include "stdlib.h"
  2235. #include "nonstd.h"
  2236.  
  2237. #ifndef TRUE
  2238. #define TRUE        1
  2239. #define FALSE        0
  2240. #endif /* !defined TRUE */
  2241.  
  2242. extern char **    environ;
  2243. extern void    ifree P((char * p));
  2244. extern char *    imalloc P((int n));
  2245. extern int    getopt P((int argc, char * argv[], char * options));
  2246. extern char *    optarg;
  2247. extern int    optind;
  2248. extern char *    tzname[2];
  2249. extern void    tzset P((void));
  2250.  
  2251. static int    longest;
  2252. static void     readerr P((FILE * fp,
  2253.             const char * progname, const char * filename));
  2254. static void    show P((const char * zone, time_t t, int v));
  2255. static long    tzdecode P((const char * buffer));
  2256.  
  2257. static long
  2258. tzdecode(codep)
  2259. const char *    codep;
  2260. {
  2261.     register int    i;
  2262.     register long    result;
  2263.  
  2264.     result = 0;
  2265.     for (i = 0; i < 4; ++i)
  2266.         result = (result << 8) | (codep[i] & 0xff);
  2267.     return result;
  2268. }
  2269.  
  2270. main(argc, argv)
  2271. int    argc;
  2272. char *    argv[];
  2273. {
  2274.     register FILE *        fp;
  2275.     register int        i, j, c;
  2276.     register int        vflag;
  2277.     register const char *    cutoff;
  2278.     register int        cutyear;
  2279.     register long        cuttime, k;
  2280.     time_t            now;
  2281.     time_t            t;
  2282.     long            leapcnt, timecnt;
  2283.     long            typecnt, charcnt;
  2284.     char            buf[FILENAME_MAX + 1];
  2285.  
  2286.     vflag = 0;
  2287.     cutoff = NULL;
  2288.     while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
  2289.         if (c == 'v')
  2290.             vflag = 1;
  2291.         else    cutoff = optarg;
  2292.     if (c != EOF || optind == argc - 1 && strcmp(argv[optind], "=") == 0) {
  2293.         (void) fprintf(stderr, "%s: usage is %s [ -v ] zonename ...\n",
  2294.             argv[0], argv[0]);
  2295.         (void) exit(EXIT_FAILURE);
  2296.     }
  2297.     if (cutoff != NULL)
  2298.         cutyear = atoi(cutoff);
  2299.     /*
  2300.     ** VERY approximate.
  2301.     */
  2302.     cuttime = (long) (cutyear - EPOCH_YEAR) *
  2303.         SECSPERHOUR * HOURSPERDAY * DAYSPERNYEAR;
  2304.     (void) time(&now);
  2305.     longest = 0;
  2306.     for (i = optind; i < argc; ++i)
  2307.         if (strlen(argv[i]) > longest)
  2308.             longest = strlen(argv[i]);
  2309.     for (i = optind; i < argc; ++i) {
  2310.         register char **    saveenv;
  2311.         char *            tzequals;
  2312.         char *            fakeenv[2];
  2313.  
  2314.         tzequals = imalloc(strlen(argv[i]) + 4);
  2315.         if (tzequals == NULL) {
  2316.             (void) fprintf(stderr, "%s: can't allocate memory\n",
  2317.                 argv[0]);
  2318.             (void) exit(EXIT_FAILURE);
  2319.         }
  2320.         (void) sprintf(tzequals, "TZ=%s", argv[i]);
  2321.         fakeenv[0] = tzequals;
  2322.         fakeenv[1] = NULL;
  2323.         saveenv = environ;
  2324.         environ = fakeenv;
  2325.         (void) tzset();
  2326.         environ = saveenv;
  2327.         show(argv[i], now, FALSE);
  2328.         if (!vflag)
  2329.             continue;
  2330.         if (argv[i][0] == '\0') {
  2331.             fp = NULL;
  2332.             timecnt = 0;
  2333.             leapcnt = 0;
  2334.         } else {
  2335.             struct tzhead    tzh;
  2336.  
  2337.             if (argv[i][0] == '/')
  2338.                 fp = fopen(argv[i], "rb");
  2339.             else {
  2340.                 j = strlen(TZDIR) + 1 + strlen(argv[i]) + 1;
  2341.                 if (j > sizeof buf) {
  2342.                     (void) fprintf(stderr,
  2343. "%s: timezone name %s/%s is too long\n",
  2344.                         argv[0], TZDIR, argv[i]);
  2345.                     (void) exit(EXIT_FAILURE);
  2346.                 }
  2347.                 (void) sprintf(buf, "%s/%s", TZDIR, argv[i]);
  2348.                 fp = fopen(buf, "rb");
  2349.             }
  2350.             if (fp == NULL) {
  2351.                 (void) fprintf(stderr, "%s: Can't open ",
  2352.                     argv[0]);
  2353.                 (void) perror(argv[i]);
  2354.                 (void) exit(EXIT_FAILURE);
  2355.             }
  2356.             if (fread((genericptr_t) &tzh,
  2357.                 (fread_size_t) sizeof tzh,
  2358.                 (fread_size_t) 1, fp) != 1)
  2359.                     readerr(fp, argv[0], argv[i]);
  2360.             leapcnt = tzdecode(tzh.tzh_leapcnt);
  2361.             timecnt = tzdecode(tzh.tzh_timecnt);
  2362.             typecnt = tzdecode(tzh.tzh_typecnt);
  2363.             charcnt = tzdecode(tzh.tzh_charcnt);
  2364.         }
  2365.         t = 0x80000000;
  2366.         if (t > 0)        /* time_t is unsigned */
  2367.             t = 0;
  2368.         show(argv[i], t, TRUE);
  2369.         t += SECSPERHOUR * HOURSPERDAY;
  2370.         show(argv[i], t, TRUE);
  2371.         for (k = timecnt; k > 0; --k) {
  2372.             char    code[4];
  2373.  
  2374.             if (fread((genericptr_t) code,
  2375.                 (fread_size_t) sizeof code,
  2376.                 (fread_size_t) 1, fp) != 1)
  2377.                     readerr(fp, argv[0], argv[i]);
  2378.             t = tzdecode(code);
  2379.             if (cutoff != NULL && t > cuttime)
  2380.                 break;
  2381.             show(argv[i], t - 1, TRUE);
  2382.             show(argv[i], t, TRUE);
  2383.         }
  2384.         if (fp != NULL)
  2385.             (void) fseek(fp, (long) sizeof (struct tzhead) +
  2386.                 timecnt * 5 + typecnt * 6 + charcnt, 0);
  2387.         for (k = leapcnt; k > 0; --k) {
  2388.             char    code[4];
  2389.  
  2390.             if (fread((genericptr_t) code,
  2391.                 (fread_size_t) sizeof code,
  2392.                 (fread_size_t) 1, fp) != 1)
  2393.                     readerr(fp, argv[0], argv[i]);
  2394.             (void) fseek(fp, (long) sizeof code, 1);
  2395.             t = tzdecode(code);
  2396.             if (cutoff != NULL && t > cuttime)
  2397.                 break;
  2398.             show(argv[i], t - 1, TRUE);
  2399.             show(argv[i], t, TRUE);
  2400.             show(argv[i], t + 1, TRUE);
  2401.         }
  2402.         if (fp != NULL && fclose(fp)) {
  2403.             (void) fprintf(stderr, "%s: Error closing ", argv[0]);
  2404.             (void) perror(argv[i]);
  2405.             (void) exit(EXIT_FAILURE);
  2406.         }
  2407.         t = 0xffffffff;
  2408.         if (t < 0)        /* time_t is signed */
  2409.             t = 0x7fffffff ;
  2410.         t -= SECSPERHOUR * HOURSPERDAY;
  2411.         show(argv[i], t, TRUE);
  2412.         t += SECSPERHOUR * HOURSPERDAY;
  2413.         show(argv[i], t, TRUE);
  2414.         ifree(tzequals);
  2415.     }
  2416.     if (fflush(stdout) || ferror(stdout)) {
  2417.         (void) fprintf(stderr, "%s: Error writing standard output ",
  2418.             argv[0]);
  2419.         (void) perror("standard output");
  2420.         (void) exit(EXIT_FAILURE);
  2421.     }
  2422.     return 0;
  2423. }
  2424.  
  2425. static void
  2426. show(zone, t, v)
  2427. const char *    zone;
  2428. time_t        t;
  2429. {
  2430.     const struct tm *    tmp;
  2431.     extern struct tm *    localtime();
  2432.  
  2433.     (void) printf("%-*s  ", longest, zone);
  2434.     if (v)
  2435.         (void) printf("%.24s GMT = ", asctime(gmtime(&t)));
  2436.     tmp = localtime(&t);
  2437.     (void) printf("%.24s", asctime(tmp));
  2438.     if (*tzname[tmp->tm_isdst] != '\0')
  2439.         (void) printf(" %s", tzname[tmp->tm_isdst]);
  2440.     if (v) {
  2441.         (void) printf(" isdst=%d", tmp->tm_isdst);
  2442. #ifdef KRE_COMPAT
  2443.         (void) printf(" gmtoff=%ld", tmp->tm_gmtoff);
  2444. #endif /* KRE_COMPAT */
  2445.     }
  2446.     (void) printf("\n");
  2447. }
  2448.  
  2449. static void
  2450. readerr(fp, progname, filename)
  2451. FILE *    fp;
  2452. const char *    progname;
  2453. const char *    filename;
  2454. {
  2455.     (void) fprintf(stderr, "%s: Error reading ", progname);
  2456.     if (ferror(fp))
  2457.         (void) perror(filename);
  2458.     else    (void) fprintf(stderr, "%s: Premature EOF\n", filename);
  2459.     (void) exit(EXIT_FAILURE);
  2460. }
  2461. End of zdump.c
  2462. echo 'localtime.c' 1>&2
  2463. cat >'localtime.c' <<'End of localtime.c'
  2464. #ifndef lint
  2465. #ifndef NOID
  2466. static char    elsieid[] = "@(#)localtime.c    4.1";
  2467. #endif /* !defined NOID */
  2468. #endif /* !defined lint */
  2469.  
  2470. /*LINTLIBRARY*/
  2471.  
  2472. #include "tzfile.h"
  2473. #include "time.h"
  2474. #include "string.h"
  2475. #include "stdlib.h"
  2476. #include "stdio.h"    /* for FILENAME_MAX */
  2477. #include "fcntl.h"    /* for O_RDONLY */
  2478. #include "nonstd.h"
  2479.  
  2480. #ifdef __TURBOC__
  2481. #include "io.h"        /* for open et al. prototypes */
  2482. #endif /* defined __TURBOC__ */
  2483.  
  2484. #define ACCESS_MODE    O_RDONLY
  2485.  
  2486. #ifdef O_BINARY
  2487. #define OPEN_MODE    O_RDONLY | O_BINARY
  2488. #else /* !defined O_BINARY */
  2489. #define OPEN_MODE    O_RDONLY
  2490. #endif /* !defined O_BINARY */
  2491.  
  2492. #ifndef TRUE
  2493. #define TRUE        1
  2494. #define FALSE        0
  2495. #endif /* !defined TRUE */
  2496.  
  2497. static long        detzcode P((const char * codep));
  2498. #ifdef STD_INSPIRED
  2499. struct tm *         offtime P((const time_t * clockp, long offset));
  2500. #endif /* !defined STD_INSPIRED */
  2501. static void        timesub P((const time_t * clockp, long offset,
  2502.                 const struct state * sp, struct tm * tmp));
  2503. static int        tzload P((const char * name, struct state * sp));
  2504. void            tzsetwall P((void));
  2505.  
  2506. struct ttinfo {                /* time type information */
  2507.     long        tt_gmtoff;    /* GMT offset in seconds */
  2508.     int        tt_isdst;    /* used to set tm_isdst */
  2509.     int        tt_abbrind;    /* abbreviation list index */
  2510. };
  2511.  
  2512. struct lsinfo {                /* leap second information */
  2513.     time_t        ls_trans;    /* transition time */
  2514.     long        ls_corr;    /* correction to apply */
  2515. };
  2516.  
  2517. struct state {
  2518.     int        leapcnt;
  2519.     int        timecnt;
  2520.     int        typecnt;
  2521.     int        charcnt;
  2522.     time_t        ats[TZ_MAX_TIMES];
  2523.     unsigned char    types[TZ_MAX_TIMES];
  2524.     struct ttinfo    ttis[TZ_MAX_TYPES];
  2525.     char        chars[TZ_MAX_CHARS + 1];
  2526.     struct lsinfo    lsis[TZ_MAX_LEAPS];
  2527. };
  2528.  
  2529. static struct state    lclstate;
  2530. static struct state    gmtstate;
  2531.  
  2532. static int        lcl_is_set;
  2533. static int        gmt_is_set;
  2534.  
  2535. char *            tzname[2] = {
  2536.     "GMT",
  2537.     "GMT"
  2538. };
  2539.  
  2540. #ifdef USG_COMPAT
  2541. time_t            timezone = 0;
  2542. int            daylight = 0;
  2543. #endif /* defined USG_COMPAT */
  2544.  
  2545. #ifdef TZA_COMPAT
  2546. char *            tz_abbr;    /* compatibility w/older versions */
  2547. #endif /* defined TZA_COMPAT */
  2548.  
  2549. static long
  2550. detzcode(codep)
  2551. const char *    codep;
  2552. {
  2553.     register long    result;
  2554.     register int    i;
  2555.  
  2556.     result = 0;
  2557.     for (i = 0; i < 4; ++i)
  2558.         result = (result << 8) | (codep[i] & 0xff);
  2559.     return result;
  2560. }
  2561.  
  2562. static int
  2563. tzload(name, sp)
  2564. register const char *    name;
  2565. register struct state *    sp;
  2566. {
  2567.     register const char *    p;
  2568.     register int        i;
  2569.     register int        fid;
  2570.  
  2571.     if (name == 0 && (name = TZDEFAULT) == 0)
  2572.         return -1;
  2573.     {
  2574.         register int     doaccess;
  2575.         char        fullname[FILENAME_MAX + 1];
  2576.  
  2577.         doaccess = name[0] == '/';
  2578.         if (!doaccess) {
  2579.             if ((p = TZDIR) == NULL)
  2580.                 return -1;
  2581.             if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
  2582.                 return -1;
  2583.             (void) strcpy(fullname, p);
  2584.             (void) strcat(fullname, "/");
  2585.             (void) strcat(fullname, name);
  2586.             /*
  2587.             ** Set doaccess if '.' (as in "../") shows up in name.
  2588.             */
  2589.             if (strchr(name, '.') != NULL)
  2590.                 doaccess = TRUE;
  2591.             name = fullname;
  2592.         }
  2593.         if (doaccess && access(name, ACCESS_MODE) != 0)
  2594.             return -1;
  2595.         if ((fid = open(name, OPEN_MODE)) == -1)
  2596.             return -1;
  2597.     }
  2598.     {
  2599.         register const struct tzhead *    tzhp;
  2600.         char                buf[sizeof *sp];
  2601.  
  2602.         i = read(fid, buf, sizeof buf);
  2603.         if (close(fid) != 0 || i < sizeof *tzhp)
  2604.             return -1;
  2605.         tzhp = (struct tzhead *) buf;
  2606.         sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
  2607.         sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
  2608.         sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
  2609.         sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
  2610.         if (sp->leapcnt > TZ_MAX_LEAPS ||
  2611.             sp->timecnt > TZ_MAX_TIMES ||
  2612.             sp->typecnt == 0 ||
  2613.             sp->typecnt > TZ_MAX_TYPES ||
  2614.             sp->charcnt > TZ_MAX_CHARS)
  2615.                 return -1;
  2616.         if (i < sizeof *tzhp +
  2617.             sp->timecnt * (4 + sizeof (char)) +
  2618.             sp->typecnt * (4 + 2 * sizeof (char)) +
  2619.             sp->charcnt * sizeof (char) +
  2620.             sp->leapcnt * 2 * 4)
  2621.                 return -1;
  2622.         p = buf + sizeof *tzhp;
  2623.         for (i = 0; i < sp->timecnt; ++i) {
  2624.             sp->ats[i] = detzcode(p);
  2625.             p += 4;
  2626.         }
  2627.         for (i = 0; i < sp->timecnt; ++i)
  2628.             sp->types[i] = (unsigned char) *p++;
  2629.         for (i = 0; i < sp->typecnt; ++i) {
  2630.             register struct ttinfo *    ttisp;
  2631.  
  2632.             ttisp = &sp->ttis[i];
  2633.             ttisp->tt_gmtoff = detzcode(p);
  2634.             p += 4;
  2635.             ttisp->tt_isdst = (unsigned char) *p++;
  2636.             ttisp->tt_abbrind = (unsigned char) *p++;
  2637.         }
  2638.         for (i = 0; i < sp->charcnt; ++i)
  2639.             sp->chars[i] = *p++;
  2640.         sp->chars[i] = '\0';    /* ensure '\0' at end */
  2641.         for (i = 0; i < sp->leapcnt; ++i) {
  2642.             register struct lsinfo *    lsisp;
  2643.  
  2644.             lsisp = &sp->lsis[i];
  2645.             lsisp->ls_trans = detzcode(p);
  2646.             p += 4;
  2647.             lsisp->ls_corr = detzcode(p);
  2648.             p += 4;
  2649.         }
  2650.     }
  2651.     /*
  2652.     ** Check that all the local time type indices are valid.
  2653.     */
  2654.     for (i = 0; i < sp->timecnt; ++i)
  2655.         if (sp->types[i] >= sp->typecnt)
  2656.             return -1;
  2657.     /*
  2658.     ** Check that all abbreviation indices are valid.
  2659.     */
  2660.     for (i = 0; i < sp->typecnt; ++i)
  2661.         if (sp->ttis[i].tt_abbrind >= sp->charcnt)
  2662.             return -1;
  2663.     /*
  2664.     ** Set tzname elements to initial values.
  2665.     */
  2666.     if (sp == &lclstate) {
  2667.         tzname[0] = tzname[1] = &sp->chars[0];
  2668. #ifdef USG_COMPAT
  2669.         timezone = -sp->ttis[0].tt_gmtoff;
  2670.         daylight = 0;
  2671. #endif /* defined USG_COMPAT */
  2672.         for (i = 1; i < sp->typecnt; ++i) {
  2673.             register const struct ttinfo *    ttisp;
  2674.  
  2675.             ttisp = &sp->ttis[i];
  2676.             if (ttisp->tt_isdst) {
  2677.                 tzname[1] = &sp->chars[ttisp->tt_abbrind];
  2678. #ifdef USG_COMPAT
  2679.                 daylight = 1;
  2680. #endif /* defined USG_COMPAT */
  2681.             } else {
  2682.                 tzname[0] = &sp->chars[ttisp->tt_abbrind];
  2683. #ifdef USG_COMPAT
  2684.                 timezone = -ttisp->tt_gmtoff;
  2685. #endif /* defined USG_COMPAT */
  2686.             }
  2687.         }
  2688.     }
  2689.     return 0;
  2690. }
  2691.  
  2692. static void
  2693. tzsetgmt(sp)
  2694. register struct state *    sp;
  2695. {
  2696.     sp->leapcnt = 0;        /* so, we're off a little */
  2697.     sp->timecnt = 0;
  2698.     sp->ttis[0].tt_gmtoff = 0;
  2699.     sp->ttis[0].tt_abbrind = 0;
  2700.     (void) strcpy(sp->chars, "GMT");
  2701.     if (sp == &lclstate) {
  2702.         tzname[0] = tzname[1] = sp->chars;
  2703. #ifdef USG_COMPAT
  2704.         timezone = 0;
  2705.         daylight = 0;
  2706. #endif /* defined USG_COMPAT */
  2707.     }
  2708. }
  2709.  
  2710. void
  2711. tzset()
  2712. {
  2713.     register const char *    name;
  2714.  
  2715.     lcl_is_set = TRUE;
  2716.     name = getenv("TZ");
  2717.     if (name != 0 && *name == '\0')
  2718.         tzsetgmt(&lclstate);        /* GMT by request */
  2719.     else if (tzload(name, &lclstate) != 0)
  2720.         tzsetgmt(&lclstate);
  2721. }
  2722.  
  2723. void
  2724. tzsetwall()
  2725. {
  2726.     lcl_is_set = TRUE;
  2727.     if (tzload((char *) 0, &lclstate) != 0)
  2728.         tzsetgmt(&lclstate);
  2729. }
  2730.  
  2731. struct tm *
  2732. localtime(timep)
  2733. const time_t *    timep;
  2734. {
  2735.     register const struct state *    sp;
  2736.     register const struct ttinfo *    ttisp;
  2737.     register int            i;
  2738.     time_t                t;
  2739.     static struct tm        tm;
  2740.  
  2741.     if (!lcl_is_set)
  2742.         tzset();
  2743.     sp = &lclstate;
  2744.     t = *timep;
  2745.     if (sp->timecnt == 0 || t < sp->ats[0]) {
  2746.         i = 0;
  2747.         while (sp->ttis[i].tt_isdst)
  2748.             if (++i >= sp->typecnt) {
  2749.                 i = 0;
  2750.                 break;
  2751.             }
  2752.     } else {
  2753.         for (i = 1; i < sp->timecnt; ++i)
  2754.             if (t < sp->ats[i])
  2755.                 break;
  2756.         i = sp->types[i - 1];
  2757.     }
  2758.     ttisp = &sp->ttis[i];
  2759.     /*
  2760.     ** To get (wrong) behavior that's compatible with System V Release 2.0
  2761.     ** you'd replace the statement below with
  2762.     **    t += ttisp->tt_gmtoff;
  2763.     **    timesub(&t, 0L, sp, &tm);
  2764.     */
  2765.     timesub(&t, ttisp->tt_gmtoff, sp, &tm);
  2766.     tm.tm_isdst = ttisp->tt_isdst;
  2767.     tzname[tm.tm_isdst] = &sp->chars[ttisp->tt_abbrind];
  2768. #ifdef KRE_COMPAT
  2769.     tm.tm_zone = &sp->chars[ttisp->tt_abbrind];
  2770. #endif /* defined KRE_COMPAT */
  2771. #ifdef TZA_COMPAT
  2772.     tz_abbr = &sp->chars[ttisp->tt_abbrind];
  2773. #endif /* defined TZA_COMPAT */
  2774.     return &tm;
  2775. }
  2776.  
  2777. struct tm *
  2778. gmtime(clock)
  2779. const time_t *    clock;
  2780. {
  2781.     static struct tm    tm;
  2782.  
  2783.     if (!gmt_is_set) {
  2784.         gmt_is_set = TRUE;
  2785.         if (tzload("GMT", &gmtstate) != 0)
  2786.             tzsetgmt(&gmtstate);
  2787.     }
  2788.     timesub(clock, 0L, &gmtstate, &tm);
  2789. #ifdef KRE_COMPAT
  2790.     tm.tm_zone = "GMT";        /* UCT ? */
  2791. #endif /* defined KRE_COMPAT */
  2792.     return &tm;
  2793. }
  2794.  
  2795. #ifdef STD_INSPIRED
  2796.  
  2797. struct tm *
  2798. offtime(clock, offset)
  2799. const time_t *    clock;
  2800. long        offset;
  2801. {
  2802.     static struct tm    tm;
  2803.  
  2804.     if (!gmt_is_set) {
  2805.         gmt_is_set = TRUE;
  2806.         if (tzload("GMT", &gmtstate) != 0)
  2807.             tzsetgmt(&gmtstate);
  2808.     }
  2809.     timesub(clock, offset, &gmtstate, &tm);
  2810.     return &tm;
  2811. }
  2812.  
  2813. #endif /* defined STD_INSPIRED */
  2814.  
  2815. static const int    mon_lengths[2][MONSPERYEAR] = {
  2816.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  2817.     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  2818. };
  2819.  
  2820. static const int    year_lengths[2] = {
  2821.     DAYSPERNYEAR, DAYSPERLYEAR
  2822. };
  2823.  
  2824. static void
  2825. timesub(clock, offset, sp, tmp)
  2826. const time_t *            clock;
  2827. long                offset;
  2828. register const struct state *    sp;
  2829. register struct tm *        tmp;
  2830. {
  2831.     register const struct lsinfo *    lp;
  2832.     register long            days;
  2833.     register long            rem;
  2834.     register int            y;
  2835.     register int            yleap;
  2836.     register const int *        ip;
  2837.     register long            corr;
  2838.     register int            hit;
  2839.  
  2840.     corr = 0;
  2841.     hit = FALSE;
  2842.     y = sp->leapcnt;
  2843.     while (--y >= 0) {
  2844.         lp = &sp->lsis[y];
  2845.         if (*clock >= lp->ls_trans) {
  2846.             if (*clock == lp->ls_trans)
  2847.                 hit = ((y == 0 && lp->ls_corr > 0) ||
  2848.                     lp->ls_corr > sp->lsis[y-1].ls_corr);
  2849.             corr = lp->ls_corr;
  2850.             break;
  2851.         }
  2852.     }
  2853.     days = *clock / SECSPERDAY;
  2854.     rem = *clock % SECSPERDAY;
  2855.     rem += (offset - corr);
  2856.     while (rem < 0) {
  2857.         rem += SECSPERDAY;
  2858.         --days;
  2859.     }
  2860.     while (rem >= SECSPERDAY) {
  2861.         rem -= SECSPERDAY;
  2862.         ++days;
  2863.     }
  2864.     tmp->tm_hour = (int) (rem / SECSPERHOUR);
  2865.     rem = rem % SECSPERHOUR;
  2866.     tmp->tm_min = (int) (rem / SECSPERMIN);
  2867.     tmp->tm_sec = (int) (rem % SECSPERMIN);
  2868.     if (hit)
  2869.         /*
  2870.          * A positive leap second requires a special
  2871.          * representation.  This uses "... ??:59:60".
  2872.          */
  2873.          tmp->tm_sec += 1;
  2874.     tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
  2875.     if (tmp->tm_wday < 0)
  2876.         tmp->tm_wday += DAYSPERWEEK;
  2877.     y = EPOCH_YEAR;
  2878.     if (days >= 0)
  2879.         for ( ; ; ) {
  2880.             yleap = isleap(y);
  2881.             if (days < (long) year_lengths[yleap])
  2882.                 break;
  2883.             ++y;
  2884.             days = days - (long) year_lengths[yleap];
  2885.         }
  2886.     else do {
  2887.         --y;
  2888.         yleap = isleap(y);
  2889.         days = days + (long) year_lengths[yleap];
  2890.     } while (days < 0);
  2891.     tmp->tm_year = y - TM_YEAR_BASE;
  2892.     tmp->tm_yday = (int) days;
  2893.     ip = mon_lengths[yleap];
  2894.     for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
  2895.         days = days - (long) ip[tmp->tm_mon];
  2896.     tmp->tm_mday = (int) (days + 1);
  2897.     tmp->tm_isdst = 0;
  2898. #ifdef KRE_COMPAT
  2899.     tmp->tm_zone = "";
  2900.     tmp->tm_gmtoff = offset;
  2901. #endif /* defined KRE_COMPAT */
  2902. }
  2903.  
  2904. #ifdef BSD_COMPAT
  2905.  
  2906. /*
  2907. ** If ctime and localtime aren't in the same file on 4.3BSD systems,
  2908. ** you can run into compilation problems--take
  2909. **    cc date.c -lz
  2910. ** (please).
  2911. */
  2912.  
  2913. char *
  2914. ctime(timep)
  2915. const time_t *    timep;
  2916. {
  2917.     return asctime(localtime(timep));
  2918. }
  2919.  
  2920. #endif /* defined BSD_COMPAT */
  2921. End of localtime.c
  2922. echo 'asctime.c' 1>&2
  2923. cat >'asctime.c' <<'End of asctime.c'
  2924. #ifndef lint
  2925. #ifndef NOID
  2926. static char    elsieid[] = "@(#)asctime.c    4.1";
  2927. #endif /* !defined NOID */
  2928. #endif /* !defined lint */
  2929.  
  2930. /*LINTLIBRARY*/
  2931.  
  2932. #include "stdio.h"
  2933. #include "time.h"
  2934. #include "tzfile.h"
  2935. #include "nonstd.h"
  2936.  
  2937. /*
  2938. ** A la X3J11
  2939. */
  2940.  
  2941. char *
  2942. asctime(timeptr)
  2943. register const struct tm *    timeptr;
  2944. {
  2945.     static const char    wday_name[DAYSPERWEEK][3] = {
  2946.         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  2947.     };
  2948.     static const char    mon_name[MONSPERYEAR][3] = {
  2949.         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  2950.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  2951.     };
  2952.     static char    result[26];
  2953.  
  2954.     (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
  2955.         wday_name[timeptr->tm_wday],
  2956.         mon_name[timeptr->tm_mon],
  2957.         timeptr->tm_mday, timeptr->tm_hour,
  2958.         timeptr->tm_min, timeptr->tm_sec,
  2959.         TM_YEAR_BASE + timeptr->tm_year);
  2960.     return result;
  2961. }
  2962. End of asctime.c
  2963. echo 'ctime.c' 1>&2
  2964. cat >'ctime.c' <<'End of ctime.c'
  2965. #ifndef lint
  2966. #ifndef NOID
  2967. static char    elsieid[] = "@(#)ctime.c    4.1";
  2968. #endif /* !defined NOID */
  2969. #endif /* !defined lint */
  2970.  
  2971. /*LINTLIBRARY*/
  2972.  
  2973. #ifndef BSD_COMPAT
  2974.  
  2975. /*
  2976. ** On non-BSD systems, this can be a separate function (as is proper).
  2977. */
  2978.  
  2979. #include "time.h"
  2980. #include "nonstd.h"
  2981.  
  2982. char *
  2983. ctime(timep)
  2984. const time_t *    timep;
  2985. {
  2986.     return asctime(localtime(timep));
  2987. }
  2988.  
  2989. #endif /* !defined BSD_COMPAT */
  2990. End of ctime.c
  2991. echo 'dysize.c' 1>&2
  2992. cat >'dysize.c' <<'End of dysize.c'
  2993. #ifndef lint
  2994. #ifndef NOID
  2995. static char    elsieid[] = "@(#)dysize.c    4.1";
  2996. #endif /* !defined NOID */
  2997. #endif /* !defined lint */
  2998.  
  2999. /*LINTLIBRARY*/
  3000.  
  3001. #ifdef BSD_COMPAT
  3002.  
  3003. #include "tzfile.h"
  3004.  
  3005. dysize(y)
  3006. {
  3007.     /*
  3008.     ** The 4.[0123]BSD version of dysize behaves as if the return statement
  3009.     ** below read
  3010.     **    return ((y % 4) == 0) ? DAYSPERLYEAR : DAYSPERNYEAR;
  3011.     ** but since we'd rather be right than (strictly) compatible. . .
  3012.     */
  3013.     return isleap(y) ? DAYSPERLYEAR : DAYSPERNYEAR;
  3014. }
  3015.  
  3016. #endif /* defined BSD_COMPAT */
  3017. End of dysize.c
  3018. echo 'timemk.c' 1>&2
  3019. cat >'timemk.c' <<'End of timemk.c'
  3020. #ifndef lint
  3021. #ifndef NOID
  3022. static char    elsieid[] = "@(#)timemk.c    4.1";
  3023. #endif /* !defined NOID */
  3024. #endif /* !defined lint */
  3025.  
  3026. /*LINTLIBRARY*/
  3027.  
  3028. #ifdef STD_INSPIRED
  3029.  
  3030. /*
  3031. ** Code provided by Robert Elz, who writes:
  3032. **    The "best" way to do mktime I think is based on an idea of Bob
  3033. **    Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
  3034. **    It does a binary search of the time_t space.  Since time_t's are
  3035. **    just 32 bits, its a max of 32 iterations (even at 64 bits it
  3036. **    would still be very reasonable).
  3037. **
  3038. ** This code does handle "out of bounds" values in the way described
  3039. ** for "mktime" in the October, 1986 draft of the proposed ANSI C Standard;
  3040. ** though this is an accident of the implementation and *cannot* be made to
  3041. ** work correctly for the purposes there described.
  3042. **
  3043. ** A warning applies if you try to use these functions with a version of
  3044. ** "localtime" that has overflow problems (such as System V Release 2.0
  3045. ** or 4.3 BSD localtime).
  3046. ** If you're not using GMT and feed a value to localtime
  3047. ** that's near the minimum (or maximum) possible time_t value, localtime
  3048. ** may return a struct that represents a time near the maximum (or minimum)
  3049. ** possible time_t value (because of overflow).  If such a returned struct tm
  3050. ** is fed to timelocal, it will not return the value originally feed to
  3051. ** localtime.
  3052. */
  3053.  
  3054. #include "time.h"
  3055. #include "tzfile.h"
  3056. #include "nonstd.h"
  3057.  
  3058. #ifndef WRONG
  3059. #define WRONG    (-1)
  3060. #endif /* !defined WRONG */
  3061.  
  3062. extern struct tm *    offtime P((const time_t * clock, long offset));
  3063.  
  3064. static time_t
  3065. timemk(timeptr, funcp, offset)
  3066. const struct tm *    timeptr;
  3067. struct tm * (*        funcp)();
  3068. long            offset;
  3069. {
  3070.     register int    direction;
  3071.     register int    bits;
  3072.     time_t        t;
  3073.     struct tm    yourtm, mytm;
  3074.  
  3075.     yourtm = *timeptr;
  3076.     /*
  3077.     ** Correct the tm supplied, in case some of its values are
  3078.     ** out of range.
  3079.     */
  3080.     while (yourtm.tm_sec > SECSPERMIN)    /* could be leap sec */
  3081.         ++yourtm.tm_min, yourtm.tm_sec -= SECSPERMIN;
  3082.     while (yourtm.tm_sec < 0)
  3083.         --yourtm.tm_min, yourtm.tm_sec += SECSPERMIN;
  3084.     while (yourtm.tm_min >= MINSPERHOUR)
  3085.         ++yourtm.tm_hour, yourtm.tm_min -= MINSPERHOUR;
  3086.     while (yourtm.tm_min < 0)
  3087.         --yourtm.tm_hour, yourtm.tm_min += MINSPERHOUR;
  3088.     while (yourtm.tm_hour >= HOURSPERDAY)
  3089.         ++yourtm.tm_mday, yourtm.tm_hour -= HOURSPERDAY;
  3090.     while (yourtm.tm_hour < 0)
  3091.         --yourtm.tm_mday, yourtm.tm_hour += HOURSPERDAY;
  3092.     while (yourtm.tm_mday > 31)        /* trust me [kre] */
  3093.         ++yourtm.tm_mon, yourtm.tm_mday -= 31;
  3094.     while (yourtm.tm_mday <= 0)
  3095.         --yourtm.tm_mon, yourtm.tm_mday += 31;
  3096.     while (yourtm.tm_mon >= MONSPERYEAR)
  3097.         ++yourtm.tm_year, yourtm.tm_mon -= MONSPERYEAR;
  3098.     while (yourtm.tm_mon < 0)
  3099.         --yourtm.tm_year, yourtm.tm_mon += MONSPERYEAR;
  3100.     /*
  3101.     ** Calculate the number of magnitude bits in a time_t
  3102.     ** (this works regardless of whether time_t is
  3103.     ** signed or unsigned, though lint complains if unsigned).
  3104.     */
  3105.     for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
  3106.         ;
  3107.     /*
  3108.     ** If time_t is signed, then 0 is the median value,
  3109.     ** if time_t is unsigned, then 1 << bits is median.
  3110.     */
  3111.     t = (t < 0) ? 0 : ((time_t) 1 << bits);
  3112.     for ( ; ; ) {
  3113.         mytm = (funcp == offtime) ?
  3114.             *((*funcp)(&t, offset)) : *((*funcp)(&t));
  3115.         if ((direction = (mytm.tm_year - yourtm.tm_year)) == 0 &&
  3116.             (direction = (mytm.tm_mon - yourtm.tm_mon)) == 0 &&
  3117.             (direction = (mytm.tm_mday - yourtm.tm_mday)) == 0 &&
  3118.             (direction = (mytm.tm_hour - yourtm.tm_hour)) == 0 &&
  3119.             (direction = (mytm.tm_min - yourtm.tm_min)) == 0)
  3120.                 direction = mytm.tm_sec - yourtm.tm_sec;
  3121.         if (direction == 0) {
  3122.             *timeptr = mytm;
  3123.             return t;
  3124.         }
  3125.         if (bits-- < 0) {
  3126.             *timeptr = yourtm;    /* restore "original" value */
  3127.             if (yourtm.tm_mday == 31) {
  3128.                 timeptr->tm_mday = 1;
  3129.                 ++(timeptr->tm_mon);
  3130.                 t = timemk(timeptr, funcp, offset);
  3131.                 if (t != WRONG)
  3132.                     return t;
  3133.                 *timeptr = yourtm;
  3134.             } else if (yourtm.tm_mon == TM_FEBRUARY &&
  3135.                 yourtm.tm_mday > 28) {
  3136.                     timeptr->tm_mday -= 28;
  3137.                     ++(timeptr->tm_mon);
  3138.                     t = timemk(timeptr, funcp, offset);
  3139.                     if (t != WRONG)
  3140.                         return t;
  3141.                     *timeptr = yourtm;
  3142.             }
  3143.             return WRONG;
  3144.         }
  3145.         if (bits < 0)
  3146.             --t;
  3147.         else if (direction > 0)
  3148.             t -= (time_t) 1 << bits;
  3149.         else    t += (time_t) 1 << bits;
  3150.     }
  3151. }
  3152.  
  3153. time_t
  3154. timelocal(timeptr)
  3155. const struct tm *    timeptr;
  3156. {
  3157.     return timemk(timeptr, localtime, 0L);
  3158. }
  3159.  
  3160. time_t
  3161. timegm(timeptr)
  3162. const struct tm *    timeptr;
  3163. {
  3164.     return timemk(timeptr, gmtime, 0L);
  3165. }
  3166.  
  3167. time_t
  3168. timeoff(timeptr, offset)
  3169. const struct tm *    timeptr;
  3170. long            offset;
  3171. {
  3172.     return timemk(timeptr, offtime, offset);
  3173. }
  3174.  
  3175. #endif /* defined STD_INSPIRED */
  3176. End of timemk.c
  3177. echo 'scheck.c' 1>&2
  3178. cat >'scheck.c' <<'End of scheck.c'
  3179. #ifndef lint
  3180. #ifndef NOID
  3181. static char    elsieid[] = "@(#)scheck.c    8.8";
  3182. #endif /* !defined lint */
  3183. #endif /* !defined NOID */
  3184.  
  3185. /*LINTLIBRARY*/
  3186.  
  3187. #include "stdio.h"
  3188. #include "ctype.h"
  3189. #include "string.h"
  3190. #include "stdlib.h"
  3191. #include "nonstd.h"
  3192.  
  3193. extern char *    imalloc P((int n));
  3194. extern void    ifree P((char * p));
  3195.  
  3196. char *
  3197. scheck(string, format)
  3198. const char *    string;
  3199. char *        format;
  3200. {
  3201.     register char *        fbuf;
  3202.     register const char *    fp;
  3203.     register char *        tp;
  3204.     register int        c;
  3205.     register char *        result;
  3206.     char            dummy;
  3207.  
  3208.     result = "";
  3209.     if (string == NULL || format == NULL)
  3210.         return result;
  3211.     fbuf = imalloc(2 * strlen(format) + 4);
  3212.     if (fbuf == NULL)
  3213.         return result;
  3214.     fp = format;
  3215.     tp = fbuf;
  3216.     while ((*tp++ = c = *fp++) != '\0') {
  3217.         if (c != '%')
  3218.             continue;
  3219.         if (*fp == '%') {
  3220.             *tp++ = *fp++;
  3221.             continue;
  3222.         }
  3223.         *tp++ = '*';
  3224.         if (*fp == '*')
  3225.             ++fp;
  3226.         while (isascii(*fp) && isdigit(*fp))
  3227.             *tp++ = *fp++;
  3228.         if (*fp == 'l' || *fp == 'h')
  3229.             *tp++ = *fp++;
  3230.         else if (*fp == '[')
  3231.             do *tp++ = *fp++;
  3232.                 while (*fp != '\0' && *fp != ']');
  3233.         if ((*tp++ = *fp++) == '\0')
  3234.             break;
  3235.     }
  3236.     *(tp - 1) = '%';
  3237.     *tp++ = 'c';
  3238.     *tp = '\0';
  3239.     if (sscanf(string, fbuf, &dummy) != 1)
  3240.         result = format;
  3241.     ifree(fbuf);
  3242.     return result;
  3243. }
  3244. End of scheck.c
  3245. echo 'ialloc.c' 1>&2
  3246. cat >'ialloc.c' <<'End of ialloc.c'
  3247. #ifndef lint
  3248. #ifndef NOID
  3249. static char    elsieid[] = "@(#)ialloc.c    8.17";
  3250. #endif /* !defined NOID */
  3251. #endif /* !defined lint */
  3252.  
  3253. /*LINTLIBRARY*/
  3254.  
  3255. #include "string.h"
  3256. #include "stdlib.h"
  3257. #include "nonstd.h"
  3258.  
  3259. #ifdef MAL
  3260. #define NULLMAL(x)    ((x) == NULL || (x) == MAL)
  3261. #else /* !defined MAL */
  3262. #define NULLMAL(x)    ((x) == NULL)
  3263. #endif /* !defined MAL */
  3264.  
  3265. #define nonzero(n)    (((n) == 0) ? 1 : (n))
  3266.  
  3267. char *    icalloc P((int nelem, int elsize));
  3268. char *    icatalloc P((char * old, const char * new));
  3269. char *    icpyalloc P((const char * string));
  3270. char *    imalloc P((int n));
  3271. char *    irealloc P((char * pointer, int size));
  3272. void    ifree P((char * pointer));
  3273.  
  3274. char *
  3275. imalloc(n)
  3276. {
  3277. #ifdef MAL
  3278.     register char *    result;
  3279.  
  3280.     result = malloc((alloc_size_t) nonzero(n));
  3281.     return NULLMAL(result) ? NULL : result;
  3282. #else /* !defined MAL */
  3283.     return malloc((alloc_size_t) nonzero(n));
  3284. #endif /* !defined MAL */
  3285. }
  3286.  
  3287. char *
  3288. icalloc(nelem, elsize)
  3289. {
  3290.     if (nelem == 0 || elsize == 0)
  3291.         nelem = elsize = 1;
  3292.     return calloc((alloc_size_t) nelem, (alloc_size_t) elsize);
  3293. }
  3294.  
  3295. char *
  3296. irealloc(pointer, size)
  3297. char *    pointer;
  3298. {
  3299.     if (NULLMAL(pointer))
  3300.         return imalloc(size);
  3301.     return realloc((genericptr_t) pointer, (alloc_size_t) nonzero(size));
  3302. }
  3303.  
  3304. char *
  3305. icatalloc(old, new)
  3306. char *        old;
  3307. const char *    new;
  3308. {
  3309.     register char *    result;
  3310.     register    oldsize, newsize;
  3311.  
  3312.     newsize = NULLMAL(new) ? 0 : strlen(new);
  3313.     if (NULLMAL(old))
  3314.         oldsize = 0;
  3315.     else if (newsize == 0)
  3316.         return old;
  3317.     else    oldsize = strlen(old);
  3318.     if ((result = irealloc(old, oldsize + newsize + 1)) != NULL)
  3319.         if (!NULLMAL(new))
  3320.             (void) strcpy(result + oldsize, new);
  3321.     return result;
  3322. }
  3323.  
  3324. char *
  3325. icpyalloc(string)
  3326. const char *    string;
  3327. {
  3328.     return icatalloc((char *) NULL, string);
  3329. }
  3330.  
  3331. void
  3332. ifree(p)
  3333. char *    p;
  3334. {
  3335.     if (!NULLMAL(p))
  3336.         (void) free(p);
  3337. }
  3338.  
  3339. void
  3340. icfree(p)
  3341. char *    p;
  3342. {
  3343.     if (!NULLMAL(p))
  3344.         (void) free(p);
  3345. }
  3346. End of ialloc.c
  3347. echo 'emkdir.c' 1>&2
  3348. cat >'emkdir.c' <<'End of emkdir.c'
  3349. #ifndef lint
  3350. #ifndef NOID
  3351. static char    elsieid[] = "@(#)emkdir.c    8.15";
  3352. #endif /* !defined NOID */
  3353. #endif /* !defined lint */
  3354.  
  3355. /*LINTLIBRARY*/
  3356.  
  3357. #include "stdio.h"    /* for sprintf prototype */
  3358. #include "stdlib.h"    /* for system prototype */
  3359. #include "nonstd.h"
  3360.  
  3361. extern char *    imalloc P((int n));
  3362. extern void    ifree P((char * p));
  3363.  
  3364. static char *
  3365. quoted(name)
  3366. register const char *    name;
  3367. {
  3368.     register char *    result;
  3369.     register char *    cp;
  3370.     register int    c;
  3371.  
  3372.     if (name == NULL)
  3373.         name = "";
  3374.     result = imalloc(4 * strlen(name) + 3);
  3375.     if (result == NULL)
  3376.         return NULL;
  3377.     cp = result;
  3378. #ifdef unix
  3379.     *cp++ = '\'';
  3380.     while ((c = *name++) != '\0')
  3381.         if (c == '\'') {
  3382.             *cp++ = c;
  3383.             *cp++ = '\\';
  3384.             *cp++ = c;
  3385.             *cp++ = c;
  3386.         } else    *cp++ = c;
  3387.     *cp++ = '\'';
  3388. #else /* !defined unix */
  3389.     while ((c = *name++) != '\0')
  3390.         if (c == '/')
  3391.             *cp++ = '\\';
  3392.         else    *cp++ = c;
  3393. #endif /* !defined unix */
  3394.     *cp = '\0';
  3395.     return result;
  3396. }
  3397.  
  3398. emkdir(name, mode)
  3399. const char *    name;
  3400. {
  3401.     register int        result;
  3402.     register const char *    format;
  3403.     register char *        command;
  3404.     register char *        qname;
  3405.  
  3406.     if ((qname = quoted(name)) == NULL)
  3407.         return -1;
  3408. #ifdef unix
  3409.     format = "mkdir 2>&- %s && chmod 2>&- %o %s";
  3410. #else /* !defined unix */
  3411.     format = "mkdir %s";
  3412. #endif /* !defined unix */
  3413.     command = imalloc(strlen(format) + 2 * strlen(qname) + 20 + 1);
  3414.     if (command == NULL) {
  3415.         ifree(qname);
  3416.         return -1;
  3417.     }
  3418.     (void) sprintf(command, format, qname, mode, qname);
  3419.     ifree(qname);
  3420.     result = system(command);
  3421.     ifree(command);
  3422.     return (result == 0) ? 0 : -1;
  3423. }
  3424.  
  3425. /*
  3426. ** UNIX is a registered trademark of AT&T.
  3427. */
  3428. End of emkdir.c
  3429. echo 'getopt.c' 1>&2
  3430. cat >'getopt.c' <<'End of getopt.c'
  3431. #ifndef lint
  3432. #ifndef NOID
  3433. static char    elsieid[] = "@(#)getopt.c    4.1";
  3434. #endif /* !defined NOID */
  3435. #endif /* !defined lint */
  3436.  
  3437. /*LINTLIBRARY*/
  3438.  
  3439. #include "string.h"
  3440.  
  3441. #ifndef strchr
  3442. #define index    strchr
  3443. #endif /* !defined strchr */
  3444.  
  3445. #include <stdio.h>
  3446.  
  3447. /*
  3448.  * get option letter from argument vector
  3449.  */
  3450. int    opterr = 1,        /* useless, never set or used */
  3451.     optind = 1,        /* index into parent argv vector */
  3452.     optopt;            /* character checked for validity */
  3453. char    *optarg;        /* argument associated with option */
  3454.  
  3455. #define BADCH    (int)'?'
  3456. #define EMSG    ""
  3457. #define tell(s)    fputs(*nargv,stderr);fputs(s,stderr); \
  3458.         fputc(optopt,stderr);fputc('\n',stderr);return(BADCH);
  3459.  
  3460. getopt(nargc,nargv,ostr)
  3461. int    nargc;
  3462. char    **nargv,
  3463.     *ostr;
  3464. {
  3465.     static char    *place = EMSG;    /* option letter processing */
  3466.     register char    *oli;        /* option letter list index */
  3467.     char    *index();
  3468.  
  3469.     if(!*place) {            /* update scanning pointer */
  3470.         if(optind >= nargc || *(place = nargv[optind]) != '-' || !*++place) return(EOF);
  3471.         if (*place == '-') {    /* found "--" */
  3472.             ++optind;
  3473.             return(EOF);
  3474.         }
  3475.     }                /* option letter okay? */
  3476.     if ((optopt = (int)*place++) == (int)':' || !(oli = index(ostr,optopt))) {
  3477.         if(!*place) ++optind;
  3478.         tell(": illegal option -- ");
  3479.     }
  3480.     if (*++oli != ':') {        /* don't need argument */
  3481.         optarg = NULL;
  3482.         if (!*place) ++optind;
  3483.     }
  3484.     else {                /* need an argument */
  3485.         if (*place) optarg = place;    /* no white space */
  3486.         else if (nargc <= ++optind) {    /* no arg */
  3487.             place = EMSG;
  3488.             tell(": option requires an argument -- ");
  3489.         }
  3490.          else optarg = nargv[optind];    /* white space */
  3491.         place = EMSG;
  3492.         ++optind;
  3493.     }
  3494.     return(optopt);            /* dump back option letter */
  3495. }
  3496. End of getopt.c
  3497. echo 'link.c' 1>&2
  3498. cat >'link.c' <<'End of link.c'
  3499. #ifndef lint
  3500. #ifndef NOID
  3501. static char    elsieid[] = "@(#)link.c    4.1";
  3502. #endif /* !defined NOID */
  3503. #endif /* !defined lint */
  3504.  
  3505. /*LINTLIBRARY*/
  3506.  
  3507. #ifndef HAVELINK
  3508. #ifndef WANTLINK
  3509. #ifndef unix
  3510. #define WANTLINK
  3511. #endif /* !defined unix */
  3512. #endif /* !defined WANTLINK */
  3513. #endif /* !defined HAVELINK */
  3514.  
  3515. #ifdef WANTLINK
  3516.  
  3517. /*
  3518. ** Fake link by copying.
  3519. */
  3520.  
  3521. #include "stdio.h"
  3522. #include "nonstd.h"
  3523.  
  3524. link(fromname, toname)
  3525. const char *    fromname;
  3526. const char *    toname;
  3527. {
  3528.     register FILE *    fromfp;
  3529.     register FILE *    tofp;
  3530.     register int    c;
  3531.     register int    ok;
  3532.  
  3533.     if ((fromfp = fopen(fromname, "rb")) == NULL)
  3534.         return -1;
  3535.     if ((tofp = fopen(toname, "wb")) == NULL) {
  3536.         (void) fclose(fromfp);
  3537.         return -1;
  3538.     }
  3539.     while ((c = getc(fromfp)) != EOF) {
  3540.         if (ferror(fromfp))
  3541.             break;
  3542.         (void) putc(c, tofp);
  3543.         if (ferror(tofp))
  3544.             break;
  3545.     }
  3546.     ok = !ferror(fromfp) && feof(fromfp) && !ferror(tofp);
  3547.     ok = fclose(fromfp) == 0 && ok;
  3548.     ok = fclose(tofp) == 0 && ok;
  3549.     return ok ? 0 : -1;
  3550. }
  3551.  
  3552. #endif /* defined WANTLINK */
  3553.  
  3554. /*
  3555. ** UNIX is a registered trademark of AT&T.
  3556. */
  3557. End of link.c
  3558. exit
  3559.  
  3560.