home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume8 / pd-localtime / part02 < prev    next >
Encoding:
Internet Message Format  |  1987-03-01  |  59.9 KB

  1. Path: mirror!adelie!necntc!husc6!seismo!munnari!sources-request
  2. From: sources-request@munnari.oz
  3. Newsgroups: mod.sources
  4. Subject: v08i086:  Public Domain (Table Driven) ``localtime'', Part02/03
  5. Message-ID: <1436@munnari.oz>
  6. Date: 28 Feb 87 11:51:22 GMT
  7. Sender: kre@munnari.oz
  8. Lines: 2786
  9. Approved: kre@munnari.oz.au
  10.  
  11. Submitted by: Arthur David Olson <ado@elsie.UUCP>
  12. Mod.sources: Volume 8, Issue 86
  13. Archive-name: pd-localtime/Part02
  14.  
  15.  
  16.  
  17. echo x - "tzfile.h" 2>&1
  18. sed "s/^X//" >"tzfile.h" <<'!The!End!'
  19. X#ifndef lint
  20. X#ifndef NOID
  21. Xstatic char    tzfilehid[] = "@(#)tzfile.h    3.1";
  22. X#endif /* !NOID */
  23. X#endif /* !lint */
  24. X
  25. X/*
  26. X** Information about time zone files.
  27. X*/
  28. X
  29. X#ifndef TZDIR
  30. X#define TZDIR        "/etc/zoneinfo"    /* Time zone object file directory */
  31. X#endif /* !TZDIR */
  32. X
  33. X#ifndef TZDEFAULT
  34. X#define TZDEFAULT    "localtime"
  35. X#endif /* !TZDEFAULT */
  36. X
  37. X/*
  38. X** Each file begins with. . .
  39. X*/
  40. X
  41. Xstruct tzhead {
  42. X    char    tzh_reserved[32];    /* reserved for future use */
  43. X    char    tzh_timecnt[4];        /* coded number of transition times */
  44. X    char    tzh_typecnt[4];        /* coded number of local time types */
  45. X    char    tzh_charcnt[4];        /* coded number of abbr. chars */
  46. X};
  47. X
  48. X/*
  49. X** . . .followed by. . .
  50. X**
  51. X**    tzh_timecnt (char [4])s        coded transition times a la time(2)
  52. X**    tzh_timecnt (unsigned char)s    types of local time starting at above
  53. X**    tzh_typecnt repetitions of
  54. X**        one (char [4])        coded GMT offset in seconds
  55. X**        one (unsigned char)    used to set tm_isdt
  56. X**        one (unsigned char)    that's an abbreviation list index
  57. X**    tzh_charcnt (char)s        '\0'-terminated zone abbreviaton strings
  58. X*/
  59. X
  60. X/*
  61. X** In the current implementation, "tzset()" refuses to deal with files that
  62. X** exceed any of the limits below.
  63. X*/
  64. X
  65. X#ifndef TZ_MAX_TIMES
  66. X/*
  67. X** The TZ_MAX_TIMES value below is enough to handle a bit more than a
  68. X** year's worth of solar time (corrected daily to the nearest second) or
  69. X** 138 years of Pacific Presidential Election time
  70. X** (where there are three time zone transitions every fourth year).
  71. X*/
  72. X#define TZ_MAX_TIMES    370
  73. X#endif /* !TZ_MAX_TIMES */
  74. X
  75. X#ifndef TZ_MAX_TYPES
  76. X#ifndef NOSOLAR
  77. X#define TZ_MAX_TYPES    256    /* Limited by what (unsigned char)'s can hold */
  78. X#else /* !NOSOLAR */
  79. X#define TZ_MAX_TYPES    10    /* Maximum number of local time types */
  80. X#endif /* !NOSOLAR */
  81. X#endif /* !TZ_MAX_TYPES */
  82. X
  83. X#ifndef TZ_MAX_CHARS
  84. X#define TZ_MAX_CHARS    50    /* Maximum number of abbreviation characters */
  85. X#endif /* !TZ_MAX_CHARS */
  86. X
  87. X#define SECS_PER_MIN    60
  88. X#define MINS_PER_HOUR    60
  89. X#define HOURS_PER_DAY    24
  90. X#define DAYS_PER_WEEK    7
  91. X#define DAYS_PER_NYEAR    365
  92. X#define DAYS_PER_LYEAR    366
  93. X#define SECS_PER_HOUR    (SECS_PER_MIN * MINS_PER_HOUR)
  94. X#define SECS_PER_DAY    ((long) SECS_PER_HOUR * HOURS_PER_DAY)
  95. X#define MONS_PER_YEAR    12
  96. X
  97. X#define TM_SUNDAY    0
  98. X#define TM_MONDAY    1
  99. X#define TM_TUESDAY    2
  100. X#define TM_WEDNESDAY    3
  101. X#define TM_THURSDAY    4
  102. X#define TM_FRIDAY    5
  103. X#define TM_SATURDAY    6
  104. X
  105. X#define TM_JANUARY    0
  106. X#define TM_FEBRUARY    1
  107. X#define TM_MARCH    2
  108. X#define TM_APRIL    3
  109. X#define TM_MAY        4
  110. X#define TM_JUNE        5
  111. X#define TM_JULY        6
  112. X#define TM_AUGUST    7
  113. X#define TM_SEPTEMBER    8
  114. X#define TM_OCTOBER    9
  115. X#define TM_NOVEMBER    10
  116. X#define TM_DECEMBER    11
  117. X#define TM_SUNDAY    0
  118. X
  119. X#define TM_YEAR_BASE    1900
  120. X
  121. X#define EPOCH_YEAR    1970
  122. X#define EPOCH_WDAY    TM_THURSDAY
  123. X
  124. X/*
  125. X** Accurate only for the past couple of centuries;
  126. X** that will probably do.
  127. X*/
  128. X
  129. X#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
  130. !The!End!
  131.  
  132. echo x - "zic.c" 2>&1
  133. sed "s/^X//" >"zic.c" <<'!The!End!'
  134. X#
  135. X
  136. X#include "stdio.h"
  137. X
  138. X#ifndef lint
  139. X#ifndef NOID
  140. Xstatic char    sccsid[] = "@(#)zic.c    3.1";
  141. X#endif /* !NOID */
  142. X#endif /* !lint */
  143. X
  144. X#include "tzfile.h"
  145. X#include "ctype.h"
  146. X#include "sys/types.h"
  147. X#include "sys/stat.h"
  148. X#include "time.h"
  149. X
  150. X#ifndef BUFSIZ
  151. X#define BUFSIZ    1024
  152. X#endif
  153. X
  154. X#ifndef TRUE
  155. X#define TRUE    1
  156. X#define FALSE    0
  157. X#endif
  158. X
  159. Xextern char *    icpyalloc();
  160. Xextern char *    imalloc();
  161. Xextern char *    irealloc();
  162. Xextern char *    optarg;
  163. Xextern int    optind;
  164. Xextern FILE *    popen();
  165. Xextern char *    scheck();
  166. X#ifndef USG
  167. Xextern char *    sprintf();
  168. X#endif /* !USG */
  169. Xextern char *    strcat();
  170. Xextern char *    strchr();
  171. Xextern char *    strcpy();
  172. X
  173. Xstatic        addtt();
  174. Xstatic        addtype();
  175. Xstatic        associate();
  176. Xstatic int    charcnt;
  177. Xstatic        ciequal();
  178. Xstatic long    eitol();
  179. Xstatic int    errors;
  180. Xstatic char *    filename;
  181. Xstatic char **    getfields();
  182. Xstatic long    gethms();
  183. Xstatic        infile();
  184. Xstatic        inlink();
  185. Xstatic        inrule();
  186. Xstatic        inzcont();
  187. Xstatic        inzone();
  188. Xstatic        inzsub();
  189. Xstatic int    linenum;
  190. Xstatic        lowerit();
  191. Xstatic time_t    max_time;
  192. Xstatic int    max_year;
  193. Xstatic time_t    min_time;
  194. Xstatic int    min_year;
  195. Xstatic        mkdirs();
  196. Xstatic        newabbr();
  197. Xstatic int    noise;
  198. Xstatic        nondunlink();
  199. Xstatic long    oadd();
  200. Xstatic        outzone();
  201. Xstatic char *    progname;
  202. Xstatic char *    rfilename;
  203. Xstatic int    rlinenum;
  204. Xstatic time_t    rpytime();
  205. Xstatic        rulesub();
  206. Xstatic        setboundaries();
  207. Xstatic time_t    tadd();
  208. Xstatic int    timecnt;
  209. Xstatic int    tt_signed;
  210. Xstatic int    typecnt;
  211. Xstatic        yearistype();
  212. X
  213. X/*
  214. X** Line codes.
  215. X*/
  216. X
  217. X#define LC_RULE        0
  218. X#define LC_ZONE        1
  219. X#define LC_LINK        2
  220. X
  221. X/*
  222. X** Which fields are which on a Zone line.
  223. X*/
  224. X
  225. X#define ZF_NAME        1
  226. X#define ZF_GMTOFF    2
  227. X#define ZF_RULE        3
  228. X#define ZF_FORMAT    4
  229. X#define ZF_UNTILYEAR    5
  230. X#define ZF_UNTILMONTH    6
  231. X#define ZF_UNTILDAY    7
  232. X#define ZF_UNTILTIME    8
  233. X#define ZONE_MINFIELDS    5
  234. X#define ZONE_MAXFIELDS    9
  235. X
  236. X/*
  237. X** Which fields are which on a Zone continuation line.
  238. X*/
  239. X
  240. X#define ZFC_GMTOFF    0
  241. X#define ZFC_RULE    1
  242. X#define ZFC_FORMAT    2
  243. X#define ZFC_UNTILYEAR    3
  244. X#define ZFC_UNTILMONTH    4
  245. X#define ZFC_UNTILDAY    5
  246. X#define ZFC_UNTILTIME    6
  247. X#define ZONEC_MINFIELDS    3
  248. X#define ZONEC_MAXFIELDS    7
  249. X
  250. X/*
  251. X** Which files are which on a Rule line.
  252. X*/
  253. X
  254. X#define RF_NAME        1
  255. X#define RF_LOYEAR    2
  256. X#define RF_HIYEAR    3
  257. X#define RF_COMMAND    4
  258. X#define RF_MONTH    5
  259. X#define RF_DAY        6
  260. X#define RF_TOD        7
  261. X#define RF_STDOFF    8
  262. X#define RF_ABBRVAR    9
  263. X#define RULE_FIELDS    10
  264. X
  265. X/*
  266. X** Which fields are which on a Link line.
  267. X*/
  268. X
  269. X#define LF_FROM        1
  270. X#define LF_TO        2
  271. X#define LINK_FIELDS    3
  272. X
  273. Xstruct rule {
  274. X    char *    r_filename;
  275. X    int    r_linenum;
  276. X    char *    r_name;
  277. X
  278. X    int    r_loyear;    /* for example, 1986 */
  279. X    int    r_hiyear;    /* for example, 1986 */
  280. X    char *    r_yrtype;
  281. X
  282. X    int    r_month;    /* 0..11 */
  283. X
  284. X    int    r_dycode;    /* see below */
  285. X    int    r_dayofmonth;
  286. X    int    r_wday;
  287. X
  288. X    long    r_tod;        /* time from midnight */
  289. X    int    r_todisstd;    /* above is standard time if TRUE */
  290. X                /* above is wall clock time if FALSE */
  291. X    long    r_stdoff;    /* offset from standard time */
  292. X    char *    r_abbrvar;    /* variable part of time zone abbreviation */
  293. X
  294. X    int    r_todo;        /* a rule to do (used in outzone) */
  295. X    time_t    r_temp;        /* used in outzone */
  296. X};
  297. X
  298. X/*
  299. X**    r_dycode        r_dayofmonth    r_wday
  300. X*/
  301. X#define DC_DOM        0    /* 1..31 */    /* unused */
  302. X#define DC_DOWGEQ    1    /* 1..31 */    /* 0..6 (Sun..Sat) */
  303. X#define DC_DOWLEQ    2    /* 1..31 */    /* 0..6 (Sun..Sat) */
  304. X
  305. X/*
  306. X** Year synonyms.
  307. X*/
  308. X
  309. X#define YR_MINIMUM    0
  310. X#define YR_MAXIMUM    1
  311. X#define YR_ONLY        2
  312. X
  313. Xstatic struct rule *    rules;
  314. Xstatic int        nrules;    /* number of rules */
  315. X
  316. Xstruct zone {
  317. X    char *        z_filename;
  318. X    int        z_linenum;
  319. X
  320. X    char *        z_name;
  321. X    long        z_gmtoff;
  322. X    char *        z_rule;
  323. X    char *        z_format;
  324. X
  325. X    long        z_stdoff;
  326. X
  327. X    struct rule *    z_rules;
  328. X    int        z_nrules;
  329. X
  330. X    struct rule    z_untilrule;
  331. X    time_t        z_untiltime;
  332. X};
  333. X
  334. Xstatic struct zone *    zones;
  335. Xstatic int        nzones;    /* number of zones */
  336. X
  337. Xstruct link {
  338. X    char *        l_filename;
  339. X    int        l_linenum;
  340. X    char *        l_from;
  341. X    char *        l_to;
  342. X};
  343. X
  344. Xstatic struct link *    links;
  345. Xstatic int        nlinks;
  346. X
  347. Xstruct lookup {
  348. X    char *        l_word;
  349. X    int        l_value;
  350. X};
  351. X
  352. Xstatic struct lookup *    byword();
  353. X
  354. Xstatic struct lookup    line_codes[] = {
  355. X    "Rule",        LC_RULE,
  356. X    "Zone",        LC_ZONE,
  357. X    "Link",        LC_LINK,
  358. X    NULL,        0
  359. X};
  360. X
  361. Xstatic struct lookup    mon_names[] = {
  362. X    "January",    TM_JANUARY,
  363. X    "February",    TM_FEBRUARY,
  364. X    "March",    TM_MARCH,
  365. X    "April",    TM_APRIL,
  366. X    "May",        TM_MAY,
  367. X    "June",        TM_JUNE,
  368. X    "July",        TM_JULY,
  369. X    "August",    TM_AUGUST,
  370. X    "September",    TM_SEPTEMBER,
  371. X    "October",    TM_OCTOBER,
  372. X    "November",    TM_NOVEMBER,
  373. X    "December",    TM_DECEMBER,
  374. X    NULL,        0
  375. X};
  376. X
  377. Xstatic struct lookup    wday_names[] = {
  378. X    "Sunday",    TM_SUNDAY,
  379. X    "Monday",    TM_MONDAY,
  380. X    "Tuesday",    TM_TUESDAY,
  381. X    "Wednesday",    TM_WEDNESDAY,
  382. X    "Thursday",    TM_THURSDAY,
  383. X    "Friday",    TM_FRIDAY,
  384. X    "Saturday",    TM_SATURDAY,
  385. X    NULL,        0
  386. X};
  387. X
  388. Xstatic struct lookup    lasts[] = {
  389. X    "last-Sunday",        TM_SUNDAY,
  390. X    "last-Monday",        TM_MONDAY,
  391. X    "last-Tuesday",        TM_TUESDAY,
  392. X    "last-Wednesday",    TM_WEDNESDAY,
  393. X    "last-Thursday",    TM_THURSDAY,
  394. X    "last-Friday",        TM_FRIDAY,
  395. X    "last-Saturday",    TM_SATURDAY,
  396. X    NULL,            0
  397. X};
  398. X
  399. Xstatic struct lookup    begin_years[] = {
  400. X    "minimum",        YR_MINIMUM,
  401. X    "maximum",        YR_MAXIMUM,
  402. X    NULL,            0
  403. X};
  404. X
  405. Xstatic struct lookup    end_years[] = {
  406. X    "minimum",        YR_MINIMUM,
  407. X    "maximum",        YR_MAXIMUM,
  408. X    "only",            YR_ONLY,
  409. X    NULL,            0
  410. X};
  411. X
  412. Xstatic int    len_months[2][MONS_PER_YEAR] = {
  413. X    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  414. X    31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  415. X};
  416. X
  417. Xstatic int    len_years[2] = {
  418. X    DAYS_PER_NYEAR, DAYS_PER_LYEAR
  419. X};
  420. X
  421. Xstatic time_t        ats[TZ_MAX_TIMES];
  422. Xstatic unsigned char    types[TZ_MAX_TIMES];
  423. Xstatic long        gmtoffs[TZ_MAX_TYPES];
  424. Xstatic char        isdsts[TZ_MAX_TYPES];
  425. Xstatic char        abbrinds[TZ_MAX_TYPES];
  426. Xstatic char        chars[TZ_MAX_CHARS];
  427. X
  428. X/*
  429. X** Memory allocation.
  430. X*/
  431. X
  432. Xstatic char *
  433. Xmemcheck(ptr)
  434. Xchar *    ptr;
  435. X{
  436. X    if (ptr == NULL) {
  437. X        perror(progname);
  438. X        exit(1);
  439. X    }
  440. X    return ptr;
  441. X}
  442. X
  443. X#define emalloc(size)        memcheck(imalloc(size))
  444. X#define erealloc(ptr, size)    memcheck(irealloc(ptr, size))
  445. X#define ecpyalloc(ptr)        memcheck(icpyalloc(ptr))
  446. X
  447. X/*
  448. X** Error handling.
  449. X*/
  450. X
  451. Xstatic
  452. Xeats(name, num, rname, rnum)
  453. Xchar *    name;
  454. Xchar *    rname;
  455. X{
  456. X    filename = name;
  457. X    linenum = num;
  458. X    rfilename = rname;
  459. X    rlinenum = rnum;
  460. X}
  461. X
  462. Xstatic
  463. Xeat(name, num)
  464. Xchar *    name;
  465. X{
  466. X    eats(name, num, (char *) NULL, -1);
  467. X}
  468. X
  469. Xstatic
  470. Xerror(string)
  471. Xchar *    string;
  472. X{
  473. X    /*
  474. X    ** Match the format of "cc" to allow sh users to
  475. X    **     zic ... 2>&1 | error -t "*" -v
  476. X    ** on BSD systems.
  477. X    */
  478. X    (void) fprintf(stderr, "\"%s\", line %d: %s",
  479. X        filename, linenum, string);
  480. X    if (rfilename != NULL)
  481. X        (void) fprintf(stderr, " (rule from \"%s\", line %d)",
  482. X            rfilename, rlinenum);
  483. X    (void) fprintf(stderr, "\n");
  484. X    ++errors;
  485. X}
  486. X
  487. Xstatic
  488. Xusage()
  489. X{
  490. X    (void) fprintf(stderr,
  491. X"%s: usage is %s [ -v ] [ -l localtime ] [ -d directory ] [ filename ... ]\n",
  492. X        progname, progname);
  493. X    exit(1);
  494. X}
  495. X
  496. Xstatic char *    lcltime = NULL;
  497. Xstatic char *    directory = NULL;
  498. X
  499. Xmain(argc, argv)
  500. Xint    argc;
  501. Xchar *    argv[];
  502. X{
  503. X    register int    i, j;
  504. X    register int    c;
  505. X
  506. X#ifdef unix
  507. X    umask(umask(022) | 022);
  508. X#endif
  509. X    progname = argv[0];
  510. X    while ((c = getopt(argc, argv, "d:l:v")) != EOF)
  511. X        switch (c) {
  512. X            default:
  513. X                usage();
  514. X            case 'd':
  515. X                if (directory == NULL)
  516. X                    directory = optarg;
  517. X                else {
  518. X                    (void) fprintf(stderr,
  519. X"%s: More than one -d option specified\n",
  520. X                        progname);
  521. X                    exit(1);
  522. X                }
  523. X                break;
  524. X            case 'l':
  525. X                if (lcltime == NULL)
  526. X                    lcltime = optarg;
  527. X                else {
  528. X                    (void) fprintf(stderr,
  529. X"%s: More than one -l option specified\n",
  530. X                        progname);
  531. X                    exit(1);
  532. X                }
  533. X                break;
  534. X            case 'v':
  535. X                noise = TRUE;
  536. X                break;
  537. X        }
  538. X    if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
  539. X        usage();    /* usage message by request */
  540. X    if (directory == NULL)
  541. X        directory = TZDIR;
  542. X
  543. X    setboundaries();
  544. X
  545. X    zones = (struct zone *) emalloc(0);
  546. X    rules = (struct rule *) emalloc(0);
  547. X    links = (struct link *) emalloc(0);
  548. X    for (i = optind; i < argc; ++i)
  549. X        infile(argv[i]);
  550. X    if (errors)
  551. X        exit(1);
  552. X    associate();
  553. X    for (i = 0; i < nzones; i = j) {
  554. X        /*
  555. X         * Find the next non-continuation zone entry.
  556. X         */
  557. X        for (j = i + 1; j < nzones && zones[j].z_name == NULL; ++j)
  558. X            ;
  559. X        outzone(&zones[i], j - i);
  560. X    }
  561. X    /*
  562. X    ** We'll take the easy way out on this last part.
  563. X    */
  564. X    if (chdir(directory) != 0) {
  565. X        (void) fprintf(stderr, "%s: Can't chdir to ", progname);
  566. X        perror(directory);
  567. X        exit(1);
  568. X    }
  569. X    for (i = 0; i < nlinks; ++i) {
  570. X        nondunlink(links[i].l_to);
  571. X        if (link(links[i].l_from, links[i].l_to) != 0) {
  572. X            (void) fprintf(stderr, "%s: Can't link %s to ",
  573. X                progname, links[i].l_from);
  574. X            perror(links[i].l_to);
  575. X            exit(1);
  576. X        }
  577. X    }
  578. X    if (lcltime != NULL) {
  579. X        nondunlink(TZDEFAULT);
  580. X        if (link(lcltime, TZDEFAULT) != 0) {
  581. X            (void) fprintf(stderr, "%s: Can't link %s to ",
  582. X                progname, lcltime);
  583. X            perror(TZDEFAULT);
  584. X            exit(1);
  585. X        }
  586. X    }
  587. X    exit((errors == 0) ? 0 : 1);
  588. X}
  589. X
  590. Xstatic
  591. Xsetboundaries()
  592. X{
  593. X    register time_t     bit;
  594. X
  595. X    for (bit = 1; bit > 0; bit <<= 1)
  596. X        ;
  597. X    if (bit == 0) {        /* time_t is an unsigned type */
  598. X        tt_signed = FALSE;
  599. X        min_time = 0;
  600. X        max_time = ~(time_t) 0;
  601. X    } else {
  602. X        tt_signed = TRUE;
  603. X        min_time = bit;
  604. X        max_time = bit;
  605. X        ++max_time;
  606. X        max_time = -max_time;
  607. X    }
  608. X    min_year = TM_YEAR_BASE + gmtime(&min_time)->tm_year;
  609. X    max_year = TM_YEAR_BASE + gmtime(&max_time)->tm_year;
  610. X}
  611. X
  612. X/*
  613. X** We get to be careful here since there's a fair chance of root running us.
  614. X*/
  615. X
  616. Xstatic
  617. Xnondunlink(name)
  618. Xchar *    name;
  619. X{
  620. X    struct stat    s;
  621. X
  622. X    if (stat(name, &s) != 0)
  623. X        return;
  624. X    if ((s.st_mode & S_IFMT) == S_IFDIR)
  625. X        return;
  626. X    (void) unlink(name);
  627. X}
  628. X
  629. X/*
  630. X** Associate sets of rules with zones.
  631. X*/
  632. X
  633. X/*
  634. X** Sort by rule name.
  635. X*/
  636. X
  637. Xstatic
  638. Xrcomp(cp1, cp2)
  639. Xchar *    cp1;
  640. Xchar *    cp2;
  641. X{
  642. X    return strcmp(((struct rule *) cp1)->r_name,
  643. X        ((struct rule *) cp2)->r_name);
  644. X}
  645. X
  646. Xstatic
  647. Xassociate()
  648. X{
  649. X    register struct zone *    zp;
  650. X    register struct rule *    rp;
  651. X    register int        base, out;
  652. X    register int        i;
  653. X
  654. X    if (nrules != 0)
  655. X        (void) qsort((char *) rules, nrules, sizeof *rules, rcomp);
  656. X    for (i = 0; i < nzones; ++i) {
  657. X        zp = &zones[i];
  658. X        zp->z_rules = NULL;
  659. X        zp->z_nrules = 0;
  660. X    }
  661. X    for (base = 0; base < nrules; base = out) {
  662. X        rp = &rules[base];
  663. X        for (out = base + 1; out < nrules; ++out)
  664. X            if (strcmp(rp->r_name, rules[out].r_name) != 0)
  665. X                break;
  666. X        for (i = 0; i < nzones; ++i) {
  667. X            zp = &zones[i];
  668. X            if (strcmp(zp->z_rule, rp->r_name) != 0)
  669. X                continue;
  670. X            zp->z_rules = rp;
  671. X            zp->z_nrules = out - base;
  672. X        }
  673. X    }
  674. X    for (i = 0; i < nzones; ++i) {
  675. X        zp = &zones[i];
  676. X        if (zp->z_nrules == 0) {
  677. X            /*
  678. X            ** Maybe we have a local standard time offset.
  679. X            */
  680. X            eat(zp->z_filename, zp->z_linenum);
  681. X            zp->z_stdoff = gethms(zp->z_rule, "unruly zone", TRUE);
  682. X            /*
  683. X            ** Note, though, that if there's no rule,
  684. X            ** a '%s' in the format is a bad thing.
  685. X            */
  686. X            if (strchr(zp->z_format, '%') != 0)
  687. X                error("%s in ruleless zone");
  688. X        }
  689. X    }
  690. X    if (errors)
  691. X        exit(1);
  692. X}
  693. X
  694. Xstatic
  695. Xinfile(name)
  696. Xchar *    name;
  697. X{
  698. X    register FILE *            fp;
  699. X    register char **        fields;
  700. X    register char *            cp;
  701. X    register struct lookup *    lp;
  702. X    register int            nfields;
  703. X    register int            wantcont;
  704. X    register int            num;
  705. X    char                buf[BUFSIZ];
  706. X
  707. X    if (strcmp(name, "-") == 0) {
  708. X        name = "standard input";
  709. X        fp = stdin;
  710. X    } else if ((fp = fopen(name, "r")) == NULL) {
  711. X        (void) fprintf(stderr, "%s: Can't open ", progname);
  712. X        perror(name);
  713. X        exit(1);
  714. X    }
  715. X    wantcont = FALSE;
  716. X    for (num = 1; ; ++num) {
  717. X        eat(name, num);
  718. X        if (fgets(buf, sizeof buf, fp) != buf)
  719. X            break;
  720. X        cp = strchr(buf, '\n');
  721. X        if (cp == NULL) {
  722. X            error("line too long");
  723. X            exit(1);
  724. X        }
  725. X        *cp = '\0';
  726. X        fields = getfields(buf);
  727. X        nfields = 0;
  728. X        while (fields[nfields] != NULL) {
  729. X            if (ciequal(fields[nfields], "-"))
  730. X                fields[nfields] = "";
  731. X            ++nfields;
  732. X        }
  733. X        if (nfields == 0) {
  734. X            /* nothing to do */
  735. X        } else if (wantcont) {
  736. X            wantcont = inzcont(fields, nfields);
  737. X        } else {
  738. X            lp = byword(fields[0], line_codes);
  739. X            if (lp == NULL)
  740. X                error("input line of unknown type");
  741. X            else switch ((int) (lp->l_value)) {
  742. X                case LC_RULE:
  743. X                    inrule(fields, nfields);
  744. X                    wantcont = FALSE;
  745. X                    break;
  746. X                case LC_ZONE:
  747. X                    wantcont = inzone(fields, nfields);
  748. X                    break;
  749. X                case LC_LINK:
  750. X                    inlink(fields, nfields);
  751. X                    wantcont = FALSE;
  752. X                    break;
  753. X                default:    /* "cannot happen" */
  754. X                    (void) fprintf(stderr,
  755. X"%s: panic: Invalid l_value %d\n",
  756. X                        progname, lp->l_value);
  757. X                    exit(1);
  758. X            }
  759. X        }
  760. X        free((char *) fields);
  761. X    }
  762. X    if (ferror(fp)) {
  763. X        (void) fprintf(stderr, "%s: Error reading ", progname);
  764. X        perror(filename);
  765. X        exit(1);
  766. X    }
  767. X    if (fp != stdin && fclose(fp)) {
  768. X        (void) fprintf(stderr, "%s: Error closing ", progname);
  769. X        perror(filename);
  770. X        exit(1);
  771. X    }
  772. X    if (wantcont)
  773. X        error("expected continuation line not found");
  774. X}
  775. X
  776. X/*
  777. X** Convert a string of one of the forms
  778. X**    h    -h     hh:mm    -hh:mm    hh:mm:ss    -hh:mm:ss
  779. X** into a number of seconds.
  780. X** A null string maps to zero.
  781. X** Call error with errstring and return zero on errors.
  782. X*/
  783. X
  784. Xstatic long
  785. Xgethms(string, errstring, signable)
  786. Xchar *    string;
  787. Xchar *    errstring;
  788. X{
  789. X    int    hh, mm, ss, sign;
  790. X
  791. X    if (string == NULL || *string == '\0')
  792. X        return 0;
  793. X    if (!signable)
  794. X        sign = 1;
  795. X    else if (*string == '-') {
  796. X        sign = -1;
  797. X        ++string;
  798. X    } else    sign = 1;
  799. X    if (sscanf(string, scheck(string, "%d"), &hh) == 1)
  800. X        mm = ss = 0;
  801. X    else if (sscanf(string, scheck(string, "%d:%d"), &hh, &mm) == 2)
  802. X        ss = 0;
  803. X    else if (sscanf(string, scheck(string, "%d:%d:%d"),
  804. X        &hh, &mm, &ss) != 3) {
  805. X            error(errstring);
  806. X            return 0;
  807. X    }
  808. X    if (hh < 0 || hh >= HOURS_PER_DAY ||
  809. X        mm < 0 || mm >= MINS_PER_HOUR ||
  810. X        ss < 0 || ss >= SECS_PER_MIN) {
  811. X            error(errstring);
  812. X            return 0;
  813. X    }
  814. X    return eitol(sign) *
  815. X        (eitol(hh * MINS_PER_HOUR + mm) *
  816. X        eitol(SECS_PER_MIN) + eitol(ss));
  817. X}
  818. X
  819. Xstatic
  820. Xinrule(fields, nfields)
  821. Xregister char **    fields;
  822. X{
  823. X    struct rule    r;
  824. X
  825. X    if (nfields != RULE_FIELDS) {
  826. X        error("wrong number of fields on Rule line");
  827. X        return;
  828. X    }
  829. X    if (*fields[RF_NAME] == '\0') {
  830. X        error("nameless rule");
  831. X        return;
  832. X    }
  833. X    r.r_filename = filename;
  834. X    r.r_linenum = linenum;
  835. X    r.r_stdoff = gethms(fields[RF_STDOFF], "invalid saved time", TRUE);
  836. X    rulesub(&r, fields[RF_LOYEAR], fields[RF_HIYEAR], fields[RF_COMMAND],
  837. X        fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD]);
  838. X    r.r_name = ecpyalloc(fields[RF_NAME]);
  839. X    r.r_abbrvar = ecpyalloc(fields[RF_ABBRVAR]);
  840. X    rules = (struct rule *) erealloc((char *) rules,
  841. X        (nrules + 1) * sizeof *rules);
  842. X    rules[nrules++] = r;
  843. X}
  844. X
  845. Xstatic
  846. Xinzone(fields, nfields)
  847. Xregister char **    fields;
  848. X{
  849. X    register int    i;
  850. X    char        buf[132];
  851. X
  852. X    if (nfields < ZONE_MINFIELDS || nfields > ZONE_MAXFIELDS) {
  853. X        error("wrong number of fields on Zone line");
  854. X        return FALSE;
  855. X    }
  856. X    if (strcmp(fields[ZF_NAME], TZDEFAULT) == 0 && lcltime != NULL) {
  857. X        (void) sprintf(buf,
  858. X            "\"Zone %s\" line and -l option are mutually exclusive",
  859. X            TZDEFAULT);
  860. X        error(buf);
  861. X        return FALSE;
  862. X    }
  863. X    for (i = 0; i < nzones; ++i)
  864. X        if (zones[i].z_name != NULL &&
  865. X            strcmp(zones[i].z_name, fields[ZF_NAME]) == 0) {
  866. X                (void) sprintf(buf,
  867. X"duplicate zone name %s (file \"%s\", line %d)",
  868. X                    fields[ZF_NAME],
  869. X                    zones[i].z_filename,
  870. X                    zones[i].z_linenum);
  871. X                error(buf);
  872. X                return FALSE;
  873. X        }
  874. X    return inzsub(fields, nfields, FALSE);
  875. X}
  876. X
  877. Xstatic
  878. Xinzcont(fields, nfields)
  879. Xregister char **    fields;
  880. X{
  881. X    if (nfields < ZONEC_MINFIELDS || nfields > ZONEC_MAXFIELDS) {
  882. X        error("wrong number of fields on Zone continuation line");
  883. X        return FALSE;
  884. X    }
  885. X    return inzsub(fields, nfields, TRUE);
  886. X}
  887. X
  888. Xstatic
  889. Xinzsub(fields, nfields, iscont)
  890. Xregister char **    fields;
  891. X{
  892. X    register char *    cp;
  893. X    struct zone    z;
  894. X    register int    i_gmtoff, i_rule, i_format;
  895. X    register int    i_untilyear, i_untilmonth;
  896. X    register int    i_untilday, i_untiltime;
  897. X    register int    hasuntil;
  898. X
  899. X    if (iscont) {
  900. X        i_gmtoff = ZFC_GMTOFF;
  901. X        i_rule = ZFC_RULE;
  902. X        i_format = ZFC_FORMAT;
  903. X        i_untilyear = ZFC_UNTILYEAR;
  904. X        i_untilmonth = ZFC_UNTILMONTH;
  905. X        i_untilday = ZFC_UNTILDAY;
  906. X        i_untiltime = ZFC_UNTILTIME;
  907. X        z.z_name = NULL;
  908. X    } else {
  909. X        i_gmtoff = ZF_GMTOFF;
  910. X        i_rule = ZF_RULE;
  911. X        i_format = ZF_FORMAT;
  912. X        i_untilyear = ZF_UNTILYEAR;
  913. X        i_untilmonth = ZF_UNTILMONTH;
  914. X        i_untilday = ZF_UNTILDAY;
  915. X        i_untiltime = ZF_UNTILTIME;
  916. X        z.z_name = ecpyalloc(fields[ZF_NAME]);
  917. X    }
  918. X    z.z_filename = filename;
  919. X    z.z_linenum = linenum;
  920. X    z.z_gmtoff = gethms(fields[i_gmtoff], "invalid GMT offset", TRUE);
  921. X    if ((cp = strchr(fields[i_format], '%')) != 0) {
  922. X        if (*++cp != 's' || strchr(cp, '%') != 0) {
  923. X            error("invalid abbreviation format");
  924. X            return FALSE;
  925. X        }
  926. X    }
  927. X    z.z_rule = ecpyalloc(fields[i_rule]);
  928. X    z.z_format = ecpyalloc(fields[i_format]);
  929. X    hasuntil = nfields > i_untilyear;
  930. X    if (hasuntil) {
  931. X        z.z_untilrule.r_filename = filename;
  932. X        z.z_untilrule.r_linenum = linenum;
  933. X        rulesub(&z.z_untilrule,
  934. X            fields[i_untilyear],
  935. X            "only",
  936. X            "",
  937. X            (nfields > i_untilmonth) ? fields[i_untilmonth] : "Jan",
  938. X            (nfields > i_untilday) ? fields[i_untilday] : "1",
  939. X            (nfields > i_untiltime) ? fields[i_untiltime] : "0");
  940. X        z.z_untiltime = rpytime(&z.z_untilrule, z.z_untilrule.r_loyear);
  941. X        if (iscont && nzones > 0 && z.z_untiltime < max_time &&
  942. X            z.z_untiltime > min_time &&
  943. X            zones[nzones - 1].z_untiltime >= z.z_untiltime) {
  944. Xerror("Zone continuation line end time is not after end time of previous line");
  945. X            return FALSE;
  946. X        }
  947. X    }
  948. X    zones = (struct zone *) erealloc((char *) zones,
  949. X        (nzones + 1) * sizeof *zones);
  950. X    zones[nzones++] = z;
  951. X    /*
  952. X    ** If there was an UNTIL field on this line,
  953. X    ** there's more information about the zone on the next line.
  954. X    */
  955. X    return hasuntil;
  956. X}
  957. X
  958. Xstatic
  959. Xinlink(fields, nfields)
  960. Xregister char **    fields;
  961. X{
  962. X    struct link    l;
  963. X
  964. X    if (nfields != LINK_FIELDS) {
  965. X        error("wrong number of fields on Link line");
  966. X        return;
  967. X    }
  968. X    if (*fields[LF_FROM] == '\0') {
  969. X        error("blank FROM field on Link line");
  970. X        return;
  971. X    }
  972. X    if (*fields[LF_TO] == '\0') {
  973. X        error("blank TO field on Link line");
  974. X        return;
  975. X    }
  976. X    l.l_filename = filename;
  977. X    l.l_linenum = linenum;
  978. X    l.l_from = ecpyalloc(fields[LF_FROM]);
  979. X    l.l_to = ecpyalloc(fields[LF_TO]);
  980. X    links = (struct link *) erealloc((char *) links,
  981. X        (nlinks + 1) * sizeof *links);
  982. X    links[nlinks++] = l;
  983. X}
  984. X
  985. Xstatic
  986. Xrulesub(rp, loyearp, hiyearp, typep, monthp, dayp, timep)
  987. Xregister struct rule *    rp;
  988. Xchar *            loyearp;
  989. Xchar *            hiyearp;
  990. Xchar *            typep;
  991. Xchar *            monthp;
  992. Xchar *            dayp;
  993. Xchar *            timep;
  994. X{
  995. X    register struct lookup *    lp;
  996. X    register char *            cp;
  997. X
  998. X    if ((lp = byword(monthp, mon_names)) == NULL) {
  999. X        error("invalid month name");
  1000. X        return;
  1001. X    }
  1002. X    rp->r_month = lp->l_value;
  1003. X    rp->r_todisstd = FALSE;
  1004. X    cp = timep;
  1005. X    if (*cp != '\0') {
  1006. X        cp += strlen(cp) - 1;
  1007. X        switch (lowerit(*cp)) {
  1008. X            case 's':
  1009. X                rp->r_todisstd = TRUE;
  1010. X                *cp = '\0';
  1011. X                break;
  1012. X            case 'w':
  1013. X                rp->r_todisstd = FALSE;
  1014. X                *cp = '\0';
  1015. X                break;
  1016. X        }
  1017. X    }
  1018. X    rp->r_tod = gethms(timep, "invalid time of day", FALSE);
  1019. X    /*
  1020. X    ** Year work.
  1021. X    */
  1022. X    cp = loyearp;
  1023. X    if ((lp = byword(cp, begin_years)) != NULL) switch ((int) lp->l_value) {
  1024. X        case YR_MINIMUM:
  1025. X            rp->r_loyear = min_year;
  1026. X            break;
  1027. X        case YR_MAXIMUM:
  1028. X            rp->r_loyear = max_year;
  1029. X            break;
  1030. X        default:    /* "cannot happen" */
  1031. X            (void) fprintf(stderr,
  1032. X                "%s: panic: Invalid l_value %d\n",
  1033. X                progname, lp->l_value);
  1034. X            exit(1);
  1035. X    } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_loyear) != 1 ||
  1036. X        rp->r_loyear < min_year || rp->r_loyear > max_year) {
  1037. X            if (noise)
  1038. X                error("invalid starting year");
  1039. X            if (rp->r_loyear > max_year)
  1040. X                return;
  1041. X    }
  1042. X    cp = hiyearp;
  1043. X    if ((lp = byword(cp, end_years)) != NULL) switch ((int) lp->l_value) {
  1044. X        case YR_MINIMUM:
  1045. X            rp->r_hiyear = min_year;
  1046. X            break;
  1047. X        case YR_MAXIMUM:
  1048. X            rp->r_hiyear = max_year;
  1049. X            break;
  1050. X        case YR_ONLY:
  1051. X            rp->r_hiyear = rp->r_loyear;
  1052. X            break;
  1053. X        default:    /* "cannot happen" */
  1054. X            (void) fprintf(stderr,
  1055. X                "%s: panic: Invalid l_value %d\n",
  1056. X                progname, lp->l_value);
  1057. X            exit(1);
  1058. X    } else if (sscanf(cp, scheck(cp, "%d"), &rp->r_hiyear) != 1 ||
  1059. X        rp->r_hiyear < min_year || rp->r_hiyear > max_year) {
  1060. X            if (noise)
  1061. X                error("invalid ending year");
  1062. X            if (rp->r_hiyear < min_year)
  1063. X                return;
  1064. X    }
  1065. X    if (rp->r_hiyear < min_year)
  1066. X         return;
  1067. X     if (rp->r_loyear < min_year)
  1068. X         rp->r_loyear = min_year;
  1069. X     if (rp->r_hiyear > max_year)
  1070. X         rp->r_hiyear = max_year;
  1071. X    if (rp->r_loyear > rp->r_hiyear) {
  1072. X        error("starting year greater than ending year");
  1073. X        return;
  1074. X    }
  1075. X    if (*typep == '\0')
  1076. X        rp->r_yrtype = NULL;
  1077. X    else {
  1078. X        if (rp->r_loyear == rp->r_hiyear) {
  1079. X            error("typed single year");
  1080. X            return;
  1081. X        }
  1082. X        rp->r_yrtype = ecpyalloc(typep);
  1083. X    }
  1084. X    /*
  1085. X    ** Day work.
  1086. X    ** Accept things such as:
  1087. X    **    1
  1088. X    **    last-Sunday
  1089. X    **    Sun<=20
  1090. X    **    Sun>=7
  1091. X    */
  1092. X    if ((lp = byword(dayp, lasts)) != NULL) {
  1093. X        rp->r_dycode = DC_DOWLEQ;
  1094. X        rp->r_wday = lp->l_value;
  1095. X        rp->r_dayofmonth = len_months[1][rp->r_month];
  1096. X    } else {
  1097. X        if ((cp = strchr(dayp, '<')) != 0)
  1098. X            rp->r_dycode = DC_DOWLEQ;
  1099. X        else if ((cp = strchr(dayp, '>')) != 0)
  1100. X            rp->r_dycode = DC_DOWGEQ;
  1101. X        else {
  1102. X            cp = dayp;
  1103. X            rp->r_dycode = DC_DOM;
  1104. X        }
  1105. X        if (rp->r_dycode != DC_DOM) {
  1106. X            *cp++ = 0;
  1107. X            if (*cp++ != '=') {
  1108. X                error("invalid day of month");
  1109. X                return;
  1110. X            }
  1111. X            if ((lp = byword(dayp, wday_names)) == NULL) {
  1112. X                error("invalid weekday name");
  1113. X                return;
  1114. X            }
  1115. X            rp->r_wday = lp->l_value;
  1116. X        }
  1117. X        if (sscanf(cp, scheck(cp, "%d"), &rp->r_dayofmonth) != 1 ||
  1118. X            rp->r_dayofmonth <= 0 ||
  1119. X            (rp->r_dayofmonth > len_months[1][rp->r_month])) {
  1120. X                error("invalid day of month");
  1121. X                return;
  1122. X        }
  1123. X    }
  1124. X}
  1125. X
  1126. Xstatic
  1127. Xputtzcode(val, fp)
  1128. Xlong    val;
  1129. XFILE *    fp;
  1130. X{
  1131. X    register int    c;
  1132. X    register int    shift;
  1133. X
  1134. X    for (shift = 24; shift >= 0; shift -= 8) {
  1135. X        c = val >> shift;
  1136. X        (void) putc(c, fp);
  1137. X    }
  1138. X}
  1139. X
  1140. Xstatic
  1141. Xwritezone(name)
  1142. Xchar *    name;
  1143. X{
  1144. X    register FILE *        fp;
  1145. X    register int        i;
  1146. X    char            fullname[BUFSIZ];
  1147. X
  1148. X    if (strlen(directory) + 1 + strlen(name) >= sizeof fullname) {
  1149. X        (void) fprintf(stderr,
  1150. X            "%s: File name %s/%s too long\n", progname,
  1151. X            directory, name);
  1152. X        exit(1);
  1153. X    }
  1154. X    (void) sprintf(fullname, "%s/%s", directory, name);
  1155. X    if ((fp = fopen(fullname, "w")) == NULL) {
  1156. X        if (mkdirs(fullname) != 0)
  1157. X            exit(1);
  1158. X        if ((fp = fopen(fullname, "w")) == NULL) {
  1159. X            (void) fprintf(stderr, "%s: Can't create ", progname);
  1160. X            perror(fullname);
  1161. X            exit(1);
  1162. X        }
  1163. X    }
  1164. X    (void) fseek(fp, (long) sizeof ((struct tzhead *) 0)->tzh_reserved, 0);
  1165. X    puttzcode(eitol(timecnt), fp);
  1166. X    puttzcode(eitol(typecnt), fp);
  1167. X    puttzcode(eitol(charcnt), fp);
  1168. X    for (i = 0; i < timecnt; ++i)
  1169. X        puttzcode((long) ats[i], fp);
  1170. X    if (timecnt > 0)
  1171. X        (void) fwrite((char *) types, sizeof types[0],
  1172. X            (int) timecnt, fp);
  1173. X    for (i = 0; i < typecnt; ++i) {
  1174. X        puttzcode((long) gmtoffs[i], fp);
  1175. X        (void) putc(isdsts[i], fp);
  1176. X        (void) putc(abbrinds[i], fp);
  1177. X    }
  1178. X    if (charcnt != 0)
  1179. X        (void) fwrite(chars, sizeof chars[0], (int) charcnt, fp);
  1180. X    if (ferror(fp) || fclose(fp)) {
  1181. X        (void) fprintf(stderr, "%s: Write error on ", progname);
  1182. X        perror(fullname);
  1183. X        exit(1);
  1184. X    }
  1185. X}
  1186. X
  1187. Xstatic
  1188. Xoutzone(zpfirst, zonecount)
  1189. Xstruct zone *    zpfirst;
  1190. X{
  1191. X    register struct zone *        zp;
  1192. X    register struct rule *        rp;
  1193. X    register int            i, j;
  1194. X    register int            usestart, useuntil;
  1195. X    register time_t            starttime, untiltime;
  1196. X    register long            gmtoff;
  1197. X    register long            stdoff;
  1198. X    register int            year;
  1199. X    register long            startoff;
  1200. X    register int            startisdst;
  1201. X    register int            type;
  1202. X    char                startbuf[BUFSIZ];
  1203. X
  1204. X    /*
  1205. X    ** Now. . .finally. . .generate some useful data!
  1206. X    */
  1207. X    timecnt = 0;
  1208. X    typecnt = 0;
  1209. X    charcnt = 0;
  1210. X    /*
  1211. X    ** Two guesses. . .the second may well be corrected later.
  1212. X    */
  1213. X    gmtoff = zpfirst->z_gmtoff;
  1214. X    stdoff = 0;
  1215. X    for (i = 0; i < zonecount; ++i) {
  1216. X        usestart = i > 0;
  1217. X        useuntil = i < (zonecount - 1);
  1218. X        zp = &zpfirst[i];
  1219. X        eat(zp->z_filename, zp->z_linenum);
  1220. X        startisdst = -1;
  1221. X        if (zp->z_nrules == 0) {
  1222. X            type = addtype(oadd(zp->z_gmtoff, zp->z_stdoff),
  1223. X                zp->z_format, zp->z_stdoff != 0);
  1224. X            if (usestart)
  1225. X                addtt(starttime, type);
  1226. X            gmtoff = zp->z_gmtoff;
  1227. X            stdoff = zp->z_stdoff;
  1228. X        } else for (year = min_year; year <= max_year; ++year) {
  1229. X            if (useuntil && year > zp->z_untilrule.r_hiyear)
  1230. X                break;
  1231. X            /*
  1232. X            ** Mark which rules to do in the current year.
  1233. X            ** For those to do, calculate rpytime(rp, year);
  1234. X            */
  1235. X            for (j = 0; j < zp->z_nrules; ++j) {
  1236. X                rp = &zp->z_rules[j];
  1237. X                eats(zp->z_filename, zp->z_linenum,
  1238. X                    rp->r_filename, rp->r_linenum);
  1239. X                rp->r_todo = year >= rp->r_loyear &&
  1240. X                        year <= rp->r_hiyear &&
  1241. X                        yearistype(year, rp->r_yrtype);
  1242. X                if (rp->r_todo)
  1243. X                    rp->r_temp = rpytime(rp, year);
  1244. X            }
  1245. X            for ( ; ; ) {
  1246. X                register int    k;
  1247. X                register time_t    jtime, ktime;
  1248. X                register long    offset;
  1249. X                char        buf[BUFSIZ];
  1250. X
  1251. X                if (useuntil) {
  1252. X                    /*
  1253. X                    ** Turn untiltime into GMT
  1254. X                    ** assuming the current gmtoff and
  1255. X                    ** stdoff values.
  1256. X                    */
  1257. X                    offset = gmtoff;
  1258. X                    if (!zp->z_untilrule.r_todisstd)
  1259. X                        offset = oadd(offset, stdoff);
  1260. X                    untiltime = tadd(zp->z_untiltime,
  1261. X                        -offset);
  1262. X                }
  1263. X                /*
  1264. X                ** Find the rule (of those to do, if any)
  1265. X                ** that takes effect earliest in the year.
  1266. X                */
  1267. X                k = -1;
  1268. X                for (j = 0; j < zp->z_nrules; ++j) {
  1269. X                    rp = &zp->z_rules[j];
  1270. X                    if (!rp->r_todo)
  1271. X                        continue;
  1272. X                    eats(zp->z_filename, zp->z_linenum,
  1273. X                        rp->r_filename, rp->r_linenum);
  1274. X                    offset = gmtoff;
  1275. X                    if (!rp->r_todisstd)
  1276. X                        offset = oadd(offset, stdoff);
  1277. X                    jtime = rp->r_temp;
  1278. X                    if (jtime == min_time ||
  1279. X                        jtime == max_time)
  1280. X                            continue;
  1281. X                    jtime = tadd(jtime, -offset);
  1282. X                    if (k < 0 || jtime < ktime) {
  1283. X                        k = j;
  1284. X                        ktime = jtime;
  1285. X                    }
  1286. X                }
  1287. X                if (k < 0)
  1288. X                    break;    /* go on to next year */
  1289. X                rp = &zp->z_rules[k];
  1290. X                rp->r_todo = FALSE;
  1291. X                if (useuntil && ktime >= untiltime)
  1292. X                    break;
  1293. X                if (usestart) {
  1294. X                    if (ktime < starttime) {
  1295. X                        stdoff = rp->r_stdoff;
  1296. X                        startoff = oadd(zp->z_gmtoff,
  1297. X                            rp->r_stdoff);
  1298. X                        (void) sprintf(startbuf,
  1299. X                            zp->z_format,
  1300. X                            rp->r_abbrvar);
  1301. X                        startisdst =
  1302. X                            rp->r_stdoff != 0;
  1303. X                        continue;
  1304. X                    }
  1305. X                    if (ktime != starttime &&
  1306. X                        startisdst >= 0)
  1307. Xaddtt(starttime, addtype(startoff, startbuf, startisdst));
  1308. X                    usestart = FALSE;
  1309. X                }
  1310. X                eats(zp->z_filename, zp->z_linenum,
  1311. X                    rp->r_filename, rp->r_linenum);
  1312. X                (void) sprintf(buf, zp->z_format,
  1313. X                    rp->r_abbrvar);
  1314. X                offset = oadd(zp->z_gmtoff, rp->r_stdoff);
  1315. X                type = addtype(offset, buf, rp->r_stdoff != 0);
  1316. X                if (timecnt != 0 || rp->r_stdoff != 0)
  1317. X                    addtt(ktime, type);
  1318. X                gmtoff = zp->z_gmtoff;
  1319. X                stdoff = rp->r_stdoff;
  1320. X            }
  1321. X        }
  1322. X        /*
  1323. X        ** Now we may get to set starttime for the next zone line.
  1324. X        */
  1325. X        if (useuntil)
  1326. X            starttime = tadd(zp->z_untiltime,
  1327. X                -gmtoffs[types[timecnt - 1]]);
  1328. X    }
  1329. X    writezone(zpfirst->z_name);
  1330. X}
  1331. X
  1332. Xstatic
  1333. Xaddtt(starttime, type)
  1334. Xtime_t    starttime;
  1335. X{
  1336. X    if (timecnt != 0 && type == types[timecnt - 1])
  1337. X        return;    /* easy enough! */
  1338. X    if (timecnt >= TZ_MAX_TIMES) {
  1339. X        error("too many transitions?!");
  1340. X        exit(1);
  1341. X    }
  1342. X    ats[timecnt] = starttime;
  1343. X    types[timecnt] = type;
  1344. X    ++timecnt;
  1345. X}
  1346. X
  1347. Xstatic
  1348. Xaddtype(gmtoff, abbr, isdst)
  1349. Xlong    gmtoff;
  1350. Xchar *    abbr;
  1351. X{
  1352. X    register int    i, j;
  1353. X
  1354. X    /*
  1355. X    ** See if there's already an entry for this zone type.
  1356. X    ** If so, just return its index.
  1357. X    */
  1358. X    for (i = 0; i < typecnt; ++i) {
  1359. X        if (gmtoff == gmtoffs[i] && isdst == isdsts[i] &&
  1360. X            strcmp(abbr, &chars[abbrinds[i]]) == 0)
  1361. X                return i;
  1362. X    }
  1363. X    /*
  1364. X    ** There isn't one; add a new one, unless there are already too
  1365. X    ** many.
  1366. X    */
  1367. X    if (typecnt >= TZ_MAX_TYPES) {
  1368. X        error("too many local time types");
  1369. X        exit(1);
  1370. X    }
  1371. X    gmtoffs[i] = gmtoff;
  1372. X    isdsts[i] = isdst;
  1373. X
  1374. X    for (j = 0; j < charcnt; ++j)
  1375. X        if (strcmp(&chars[j], abbr) == 0)
  1376. X            break;
  1377. X    if (j == charcnt)
  1378. X        newabbr(abbr);
  1379. X    abbrinds[i] = j;
  1380. X    ++typecnt;
  1381. X    return i;
  1382. X}
  1383. X
  1384. Xstatic
  1385. Xyearistype(year, type)
  1386. Xchar *    type;
  1387. X{
  1388. X    char    buf[BUFSIZ];
  1389. X    int    result;
  1390. X
  1391. X    if (type == NULL || *type == '\0')
  1392. X        return TRUE;
  1393. X    if (strcmp(type, "uspres") == 0)
  1394. X        return (year % 4) == 0;
  1395. X    if (strcmp(type, "nonpres") == 0)
  1396. X        return (year % 4) != 0;
  1397. X    (void) sprintf(buf, "yearistype %d %s", year, type);
  1398. X    result = system(buf);
  1399. X    if (result == 0)
  1400. X        return TRUE;
  1401. X    if (result == 1 << 8)
  1402. X        return FALSE;
  1403. X    error("Wild result from command execution");
  1404. X    (void) fprintf(stderr, "%s: command was '%s', result was %d\n",
  1405. X        progname, buf, result);
  1406. X    for ( ; ; )
  1407. X        exit(1);
  1408. X}
  1409. X
  1410. Xstatic
  1411. Xlowerit(a)
  1412. X{
  1413. X    return (isascii(a) && isupper(a)) ? tolower(a) : a;
  1414. X}
  1415. X
  1416. Xstatic
  1417. Xciequal(ap, bp)        /* case-insensitive equality */
  1418. Xregister char *    ap;
  1419. Xregister char *    bp;
  1420. X{
  1421. X    while (lowerit(*ap) == lowerit(*bp++))
  1422. X        if (*ap++ == '\0')
  1423. X            return TRUE;
  1424. X    return FALSE;
  1425. X}
  1426. X
  1427. Xstatic
  1428. Xisabbr(abbr, word)
  1429. Xregister char *    abbr;
  1430. Xregister char *    word;
  1431. X{
  1432. X    if (lowerit(*abbr) != lowerit(*word))
  1433. X        return FALSE;
  1434. X    ++word;
  1435. X    while (*++abbr != '\0')
  1436. X        do if (*word == '\0')
  1437. X            return FALSE;
  1438. X                while (lowerit(*word++) != lowerit(*abbr));
  1439. X    return TRUE;
  1440. X}
  1441. X
  1442. Xstatic struct lookup *
  1443. Xbyword(word, table)
  1444. Xregister char *            word;
  1445. Xregister struct lookup *    table;
  1446. X{
  1447. X    register struct lookup *    foundlp;
  1448. X    register struct lookup *    lp;
  1449. X
  1450. X    if (word == NULL || table == NULL)
  1451. X        return NULL;
  1452. X    /*
  1453. X    ** Look for exact match.
  1454. X    */
  1455. X    for (lp = table; lp->l_word != NULL; ++lp)
  1456. X        if (ciequal(word, lp->l_word))
  1457. X            return lp;
  1458. X    /*
  1459. X    ** Look for inexact match.
  1460. X    */
  1461. X    foundlp = NULL;
  1462. X    for (lp = table; lp->l_word != NULL; ++lp)
  1463. X        if (isabbr(word, lp->l_word))
  1464. X            if (foundlp == NULL)
  1465. X                foundlp = lp;
  1466. X            else    return NULL;    /* multiple inexact matches */
  1467. X    return foundlp;
  1468. X}
  1469. X
  1470. Xstatic char **
  1471. Xgetfields(cp)
  1472. Xregister char *    cp;
  1473. X{
  1474. X    register char *        dp;
  1475. X    register char **    array;
  1476. X    register int        nsubs;
  1477. X
  1478. X    if (cp == NULL)
  1479. X        return NULL;
  1480. X    array = (char **) emalloc((strlen(cp) + 1) * sizeof *array);
  1481. X    nsubs = 0;
  1482. X    for ( ; ; ) {
  1483. X        while (isascii(*cp) && isspace(*cp))
  1484. X            ++cp;
  1485. X        if (*cp == '\0' || *cp == '#')
  1486. X            break;
  1487. X        array[nsubs++] = dp = cp;
  1488. X        do {
  1489. X            if ((*dp = *cp++) != '"')
  1490. X                ++dp;
  1491. X            else while ((*dp = *cp++) != '"')
  1492. X                if (*dp != '\0')
  1493. X                    ++dp;
  1494. X                else    error("Odd number of quotation marks");
  1495. X        } while (*cp != '\0' && *cp != '#' &&
  1496. X            (!isascii(*cp) || !isspace(*cp)));
  1497. X        if (isascii(*cp) && isspace(*cp))
  1498. X            ++cp;
  1499. X        *dp = '\0';
  1500. X    }
  1501. X    array[nsubs] = NULL;
  1502. X    return array;
  1503. X}
  1504. X
  1505. Xstatic long
  1506. Xoadd(t1, t2)
  1507. Xlong    t1;
  1508. Xlong    t2;
  1509. X{
  1510. X    register long    t;
  1511. X
  1512. X    t = t1 + t2;
  1513. X    if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
  1514. X        error("time overflow");
  1515. X        exit(1);
  1516. X    }
  1517. X    return t;
  1518. X}
  1519. X
  1520. Xstatic time_t
  1521. Xtadd(t1, t2)
  1522. Xtime_t    t1;
  1523. Xlong    t2;
  1524. X{
  1525. X    register time_t    t;
  1526. X
  1527. X    if (t1 == max_time && t2 > 0)
  1528. X        return max_time;
  1529. X    if (t1 == min_time && t2 < 0)
  1530. X        return min_time;
  1531. X    t = t1 + t2;
  1532. X    if (t2 > 0 && t <= t1 || t2 < 0 && t >= t1) {
  1533. X        error("time overflow");
  1534. X        exit(1);
  1535. X    }
  1536. X    return t;
  1537. X}
  1538. X
  1539. X/*
  1540. X** Given a rule, and a year, compute the date - in seconds since January 1,
  1541. X** 1970, 00:00 LOCAL time - in that year that the rule refers to.
  1542. X*/
  1543. X
  1544. Xstatic time_t
  1545. Xrpytime(rp, wantedy)
  1546. Xregister struct rule *    rp;
  1547. Xregister int        wantedy;
  1548. X{
  1549. X    register int    y, m, i;
  1550. X    register long    dayoff;            /* with a nod to Margaret O. */
  1551. X    register time_t    t;
  1552. X
  1553. X    dayoff = 0;
  1554. X    m = TM_JANUARY;
  1555. X    y = EPOCH_YEAR;
  1556. X    while (wantedy != y) {
  1557. X        if (wantedy > y) {
  1558. X            i = len_years[isleap(y)];
  1559. X            ++y;
  1560. X        } else {
  1561. X            --y;
  1562. X            i = -len_years[isleap(y)];
  1563. X        }
  1564. X        dayoff = oadd(dayoff, eitol(i));
  1565. X    }
  1566. X    while (m != rp->r_month) {
  1567. X        i = len_months[isleap(y)][m];
  1568. X        dayoff = oadd(dayoff, eitol(i));
  1569. X        ++m;
  1570. X    }
  1571. X    i = rp->r_dayofmonth;
  1572. X    if (m == TM_FEBRUARY && i == 29 && !isleap(y)) {
  1573. X        if (rp->r_dycode == DC_DOWLEQ)
  1574. X            --i;
  1575. X        else {
  1576. X            error("use of 2/29 in non leap-year");
  1577. X            exit(1);
  1578. X        }
  1579. X    }
  1580. X    --i;
  1581. X    dayoff = oadd(dayoff, eitol(i));
  1582. X    if (rp->r_dycode == DC_DOWGEQ || rp->r_dycode == DC_DOWLEQ) {
  1583. X        register long    wday;
  1584. X
  1585. X#define LDAYS_PER_WEEK    ((long) DAYS_PER_WEEK)
  1586. X        wday = eitol(EPOCH_WDAY);
  1587. X        /*
  1588. X        ** Don't trust mod of negative numbers.
  1589. X        */
  1590. X        if (dayoff >= 0)
  1591. X            wday = (wday + dayoff) % LDAYS_PER_WEEK;
  1592. X        else {
  1593. X            wday -= ((-dayoff) % LDAYS_PER_WEEK);
  1594. X            if (wday < 0)
  1595. X                wday += LDAYS_PER_WEEK;
  1596. X        }
  1597. X        while (wday != eitol(rp->r_wday))
  1598. X            if (rp->r_dycode == DC_DOWGEQ) {
  1599. X                dayoff = oadd(dayoff, (long) 1);
  1600. X                if (++wday >= LDAYS_PER_WEEK)
  1601. X                    wday = 0;
  1602. X                ++i;
  1603. X            } else {
  1604. X                dayoff = oadd(dayoff, (long) -1);
  1605. X                if (--wday < 0)
  1606. X                    wday = LDAYS_PER_WEEK;
  1607. X                --i;
  1608. X            }
  1609. X        if (i < 0 || i >= len_months[isleap(y)][m]) {
  1610. X            error("no day in month matches rule");
  1611. X            exit(1);
  1612. X        }
  1613. X    }
  1614. X    if (dayoff < 0 && !tt_signed) {
  1615. X        if (wantedy == rp->r_loyear)
  1616. X            return min_time;
  1617. X        error("time before zero");
  1618. X        exit(1);
  1619. X    }
  1620. X    t = (time_t) dayoff * SECS_PER_DAY;
  1621. X    /*
  1622. X    ** Cheap overflow check.
  1623. X    */
  1624. X    if (t / SECS_PER_DAY != dayoff) {
  1625. X        if (wantedy == rp->r_hiyear)
  1626. X            return max_time;
  1627. X        if (wantedy == rp->r_loyear)
  1628. X            return min_time;
  1629. X        error("time overflow");
  1630. X        exit(1);
  1631. X    }
  1632. X    return tadd(t, rp->r_tod);
  1633. X}
  1634. X
  1635. Xstatic
  1636. Xnewabbr(string)
  1637. Xchar *    string;
  1638. X{
  1639. X    register int    i;
  1640. X
  1641. X    i = strlen(string) + 1;
  1642. X    if (charcnt + i >= TZ_MAX_CHARS) {
  1643. X        error("too many, or too long, time zone abbreviations");
  1644. X        exit(1);
  1645. X    }
  1646. X    (void) strcpy(&chars[charcnt], string);
  1647. X    charcnt += eitol(i);
  1648. X}
  1649. X
  1650. Xstatic
  1651. Xmkdirs(name)
  1652. Xchar *    name;
  1653. X{
  1654. X    register char *    cp;
  1655. X
  1656. X    if ((cp = name) == NULL || *cp == '\0')
  1657. X        return 0;
  1658. X    while ((cp = strchr(cp + 1, '/')) != 0) {
  1659. X        *cp = '\0';
  1660. X        if (access(name, 0) != 0) {
  1661. X            /*
  1662. X             * It doesn't seem to exist, so we try to create it.
  1663. X             */
  1664. X            if (mkdir(name, 0755) != 0) {
  1665. X                (void) fprintf(stderr,
  1666. X                    "%s: Can't create directory ",
  1667. X                    progname);
  1668. X                perror(name);
  1669. X                return -1;
  1670. X            }
  1671. X        }
  1672. X        *cp = '/';
  1673. X    }
  1674. X    return 0;
  1675. X}
  1676. X
  1677. Xstatic long
  1678. Xeitol(i)
  1679. X{
  1680. X    long    l;
  1681. X
  1682. X    l = i;
  1683. X    if (i < 0 && l >= 0 || i == 0 && l != 0 || i > 0 && l <= 0) {
  1684. X        (void) fprintf(stderr, "%s: %d did not sign extend correctly\n",
  1685. X            progname, i);
  1686. X        exit(1);
  1687. X    }
  1688. X    return l;
  1689. X}
  1690. X
  1691. X/*
  1692. X** UNIX is a registered trademark of AT&T.
  1693. X*/
  1694. !The!End!
  1695.  
  1696. echo x - "zdump.c" 2>&1
  1697. sed "s/^X//" >"zdump.c" <<'!The!End!'
  1698. X#
  1699. X
  1700. X#include "stdio.h"
  1701. X
  1702. X#ifndef lint
  1703. X#ifndef NOID
  1704. Xstatic char    sccsid[] = "@(#)zdump.c    3.1";
  1705. X#endif /* !NOID */
  1706. X#endif /* !lint */
  1707. X
  1708. X#include "sys/types.h"
  1709. X#include "time.h"
  1710. X#include "tzfile.h"
  1711. X
  1712. X#ifndef TRUE
  1713. X#define TRUE        1
  1714. X#define FALSE        0
  1715. X#endif
  1716. X
  1717. Xextern char *        asctime();
  1718. Xextern char **        environ;
  1719. Xextern struct tm *    gmtime();
  1720. Xextern char *        imalloc();
  1721. Xextern char *        optarg;
  1722. Xextern int        optind;
  1723. X#ifndef USG
  1724. Xextern char *        sprintf();
  1725. X#endif /* !USG */
  1726. Xextern long        time();
  1727. Xextern char *        tzname[2];
  1728. Xextern void        tzset();
  1729. X
  1730. X/*
  1731. X** For the benefit of cyntax...
  1732. X*/
  1733. X
  1734. Xstatic long        tzdecode();
  1735. Xstatic            readerr();
  1736. Xstatic            show();
  1737. X
  1738. Xstatic int        longest;
  1739. X
  1740. Xstatic long
  1741. Xtzdecode(codep)
  1742. Xchar *    codep;
  1743. X{
  1744. X    register int    i;
  1745. X    register long    result;
  1746. X
  1747. X    result = 0;
  1748. X    for (i = 0; i < 4; ++i)
  1749. X        result = (result << 8) | (codep[i] & 0xff);
  1750. X    return result;
  1751. X}
  1752. X
  1753. Xmain(argc, argv)
  1754. Xint    argc;
  1755. Xchar *    argv[];
  1756. X{
  1757. X    register FILE *    fp;
  1758. X    register int    i, j, c;
  1759. X    register int    vflag;
  1760. X    register char *    cutoff;
  1761. X    register int    cutyear;
  1762. X    register long    cuttime;
  1763. X    time_t        now;
  1764. X    time_t        t;
  1765. X    long        timecnt;
  1766. X    char        buf[BUFSIZ];
  1767. X
  1768. X    vflag = 0;
  1769. X    cutoff = NULL;
  1770. X    while ((c = getopt(argc, argv, "c:v")) == 'c' || c == 'v')
  1771. X        if (c == 'v')
  1772. X            vflag = 1;
  1773. X        else    cutoff = optarg;
  1774. X    if (c != EOF || optind == argc - 1 && strcmp(argv[optind], "=") == 0) {
  1775. X        (void) fprintf(stderr, "%s: usage is %s [ -v ] zonename ...\n",
  1776. X            argv[0], argv[0]);
  1777. X        exit(1);
  1778. X    }
  1779. X    if (cutoff != NULL)
  1780. X        cutyear = atoi(cutoff);
  1781. X    /*
  1782. X    ** VERY approximate.
  1783. X    */
  1784. X    cuttime = (long) (cutyear - EPOCH_YEAR) *
  1785. X        SECS_PER_HOUR * HOURS_PER_DAY * DAYS_PER_NYEAR;
  1786. X    (void) time(&now);
  1787. X    longest = 0;
  1788. X    for (i = optind; i < argc; ++i)
  1789. X        if (strlen(argv[i]) > longest)
  1790. X            longest = strlen(argv[i]);
  1791. X    for (i = optind; i < argc; ++i) {
  1792. X        register char **    saveenv;
  1793. X        char *            tzequals;
  1794. X        char *            fakeenv[2];
  1795. X
  1796. X        tzequals = imalloc(strlen(argv[i]) + 4);
  1797. X        if (tzequals == NULL) {
  1798. X            (void) fprintf(stderr, "%s: can't allocate memory\n",
  1799. X                argv[0]);
  1800. X            exit(1);
  1801. X        }
  1802. X        (void) sprintf(tzequals, "TZ=%s", argv[i]);
  1803. X        fakeenv[0] = tzequals;
  1804. X        fakeenv[1] = NULL;
  1805. X        saveenv = environ;
  1806. X        environ = fakeenv;
  1807. X        (void) tzset();
  1808. X        environ = saveenv;
  1809. X        show(argv[i], now, FALSE);
  1810. X        if (!vflag)
  1811. X            continue;
  1812. X        if (argv[i][0] == '/')
  1813. X            fp = fopen(argv[i], "r");
  1814. X        else {
  1815. X            j = strlen(TZDIR) + 1 + strlen(argv[i]) + 1;
  1816. X            if (j > sizeof buf) {
  1817. X                (void) fprintf(stderr,
  1818. X                    "%s: timezone name %s/%s is too long\n",
  1819. X                    argv[0], TZDIR, argv[i]);
  1820. X                exit(1);
  1821. X            }
  1822. X            (void) sprintf(buf, "%s/%s", TZDIR, argv[i]);
  1823. X            fp = fopen(buf, "r");
  1824. X        }
  1825. X        if (fp == NULL) {
  1826. X            (void) fprintf(stderr, "%s: Can't open ", argv[0]);
  1827. X            perror(argv[i]);
  1828. X            exit(1);
  1829. X        }
  1830. X        {
  1831. X            char        code[4];
  1832. X
  1833. X(void) fseek(fp, (long) sizeof ((struct tzhead *) 0)->tzh_reserved, 0);
  1834. X            if (fread((char *) code, sizeof code, 1, fp) != 1)
  1835. X                readerr(fp, argv[0], argv[i]);
  1836. X            timecnt = tzdecode(code);
  1837. X            (void) fseek(fp, (long) (2 * sizeof code), 1);
  1838. X        }
  1839. X        t = 0x80000000;
  1840. X        if (t > 0)        /* time_t is unsigned */
  1841. X            t = 0;
  1842. X        show(argv[i], t, TRUE);
  1843. X        t += SECS_PER_HOUR * HOURS_PER_DAY;
  1844. X        show(argv[i], t, TRUE);
  1845. X        while (timecnt-- > 0) {
  1846. X            char    code[4];
  1847. X
  1848. X            if (fread((char *) code, sizeof code, 1, fp) != 1)
  1849. X                readerr(fp, argv[0], argv[i]);
  1850. X            t = tzdecode(code);
  1851. X            if (cutoff != NULL && t > cuttime)
  1852. X                break;
  1853. X            show(argv[i], t - 1, TRUE);
  1854. X            show(argv[i], t, TRUE);
  1855. X        }
  1856. X        if (fclose(fp)) {
  1857. X            (void) fprintf(stderr, "%s: Error closing ", argv[0]);
  1858. X            perror(argv[i]);
  1859. X            exit(1);
  1860. X        }
  1861. X        t = 0xffffffff;
  1862. X        if (t < 0)        /* time_t is signed */
  1863. X            t = 0x7fffffff ;
  1864. X        t -= SECS_PER_HOUR * HOURS_PER_DAY;
  1865. X        show(argv[i], t, TRUE);
  1866. X        t += SECS_PER_HOUR * HOURS_PER_DAY;
  1867. X        show(argv[i], t, TRUE);
  1868. X        free(tzequals);
  1869. X    }
  1870. X    if (fflush(stdout) || ferror(stdout)) {
  1871. X        (void) fprintf(stderr, "%s: Error writing standard output ",
  1872. X            argv[0]);
  1873. X        perror("standard output");
  1874. X        exit(1);
  1875. X    }
  1876. X    return 0;
  1877. X}
  1878. X
  1879. Xstatic
  1880. Xshow(zone, t, v)
  1881. Xchar *    zone;
  1882. Xtime_t    t;
  1883. X{
  1884. X    struct tm *        tmp;
  1885. X    extern struct tm *    localtime();
  1886. X
  1887. X    (void) printf("%-*s  ", longest, zone);
  1888. X    if (v)
  1889. X        (void) printf("%.24s GMT = ", asctime(gmtime(&t)));
  1890. X    tmp = localtime(&t);
  1891. X    (void) printf("%.24s", asctime(tmp));
  1892. X    if (*tzname[tmp->tm_isdst] != '\0')
  1893. X        (void) printf(" %s", tzname[tmp->tm_isdst]);
  1894. X    if (v) {
  1895. X        (void) printf(" isdst=%d", tmp->tm_isdst);
  1896. X#ifdef KRE_COMPAT
  1897. X        (void) printf(" gmtoff=%ld", tmp->tm_gmtoff);
  1898. X#endif /* KRE_COMPAT */
  1899. X    }
  1900. X    (void) printf("\n");
  1901. X}
  1902. X
  1903. Xstatic
  1904. Xreaderr(fp, progname, filename)
  1905. XFILE *    fp;
  1906. Xchar *    progname;
  1907. Xchar *    filename;
  1908. X{
  1909. X    (void) fprintf(stderr, "%s: Error reading ", progname);
  1910. X    if (ferror(fp))
  1911. X        perror(filename);
  1912. X    else    (void) fprintf(stderr, "%s: Premature EOF\n", filename);
  1913. X    exit(1);
  1914. X}
  1915. !The!End!
  1916.  
  1917. echo x - "localtime.c" 2>&1
  1918. sed "s/^X//" >"localtime.c" <<'!The!End!'
  1919. X#
  1920. X
  1921. X/*LINTLIBRARY*/
  1922. X
  1923. X/*
  1924. X** sys/types.h is included to get time_t.
  1925. X*/
  1926. X
  1927. X#include "sys/types.h"
  1928. X#include "tzfile.h"
  1929. X#include "time.h"
  1930. X
  1931. X#ifndef MAXPATHLEN
  1932. X#include "sys/param.h"
  1933. X#ifndef MAXPATHLEN
  1934. X#define MAXPATHLEN    1024
  1935. X#endif /* !MAXPATHLEN */
  1936. X#endif /* !MAXPATHLEN */
  1937. X
  1938. X#ifndef lint
  1939. X#ifndef NOID
  1940. Xstatic char    sccsid[] = "@(#)localtime.c    3.1";
  1941. X#endif /* !NOID */
  1942. X#endif /* !lint */
  1943. X
  1944. X#ifndef TRUE
  1945. X#define TRUE        1
  1946. X#define FALSE        0
  1947. X#endif /* !TRUE */
  1948. X
  1949. Xextern char *        getenv();
  1950. Xextern char *        strcpy();
  1951. Xextern char *        strcat();
  1952. X#ifdef STD_INSPIRED
  1953. Xstruct tm *        offtime();
  1954. X#else /* !STD_INSPIRED */
  1955. Xstatic struct tm *    offtime();
  1956. X#endif /* !STD_INSPIRED */
  1957. X
  1958. Xstruct ttinfo {                /* time type information */
  1959. X    long        tt_gmtoff;    /* GMT offset in seconds */
  1960. X    int        tt_isdst;    /* used to set tm_isdst */
  1961. X    int        tt_abbrind;    /* abbreviation list index */
  1962. X};
  1963. X
  1964. Xstruct state {
  1965. X    int        timecnt;
  1966. X    int        typecnt;
  1967. X    int        charcnt;
  1968. X    time_t        ats[TZ_MAX_TIMES];
  1969. X    unsigned char    types[TZ_MAX_TIMES];
  1970. X    struct ttinfo    ttis[TZ_MAX_TYPES];
  1971. X    char        chars[TZ_MAX_CHARS + 1];
  1972. X};
  1973. X
  1974. Xstatic struct state    s;
  1975. X
  1976. Xstatic int        tz_is_set;
  1977. X
  1978. Xchar *            tzname[2] = {
  1979. X    "GMT",
  1980. X    "GMT"
  1981. X};
  1982. X
  1983. X#ifdef USG_COMPAT
  1984. Xtime_t            timezone = 0;
  1985. Xint            daylight = 0;
  1986. X#endif /* USG_COMPAT */
  1987. X
  1988. X#ifdef TZA_COMPAT
  1989. Xchar *            tz_abbr;    /* compatibility w/older versions */
  1990. X#endif /* TZA_COMPAT */
  1991. X
  1992. Xstatic long
  1993. Xdetzcode(codep)
  1994. Xchar *    codep;
  1995. X{
  1996. X    register long    result;
  1997. X    register int    i;
  1998. X
  1999. X    result = 0;
  2000. X    for (i = 0; i < 4; ++i)
  2001. X        result = (result << 8) | (codep[i] & 0xff);
  2002. X    return result;
  2003. X}
  2004. X
  2005. Xstatic
  2006. Xtzload(name)
  2007. Xregister char *    name;
  2008. X{
  2009. X    register int    i;
  2010. X    register int    fid;
  2011. X
  2012. X    if (name == 0 && (name = TZDEFAULT) == 0)
  2013. X        return -1;
  2014. X    {
  2015. X        register char *    p;
  2016. X        register int    doaccess;
  2017. X        char        fullname[MAXPATHLEN];
  2018. X
  2019. X        doaccess = name[0] == '/';
  2020. X        if (!doaccess) {
  2021. X            if ((p = TZDIR) == 0)
  2022. X                return -1;
  2023. X            if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
  2024. X                return -1;
  2025. X            (void) strcpy(fullname, p);
  2026. X            (void) strcat(fullname, "/");
  2027. X            (void) strcat(fullname, name);
  2028. X            /*
  2029. X            ** Set doaccess if '.' (as in "../") shows up in name.
  2030. X            */
  2031. X            while (*name != '\0')
  2032. X                if (*name++ == '.')
  2033. X                    doaccess = TRUE;
  2034. X            name = fullname;
  2035. X        }
  2036. X        if (doaccess && access(name, 4) != 0)
  2037. X            return -1;
  2038. X        if ((fid = open(name, 0)) == -1)
  2039. X            return -1;
  2040. X    }
  2041. X    {
  2042. X        register char *            p;
  2043. X        register struct tzhead *    tzhp;
  2044. X        char                buf[sizeof s];
  2045. X
  2046. X        i = read(fid, buf, sizeof buf);
  2047. X        if (close(fid) != 0 || i < sizeof *tzhp)
  2048. X            return -1;
  2049. X        tzhp = (struct tzhead *) buf;
  2050. X        s.timecnt = (int) detzcode(tzhp->tzh_timecnt);
  2051. X        s.typecnt = (int) detzcode(tzhp->tzh_typecnt);
  2052. X        s.charcnt = (int) detzcode(tzhp->tzh_charcnt);
  2053. X        if (s.timecnt > TZ_MAX_TIMES ||
  2054. X            s.typecnt == 0 ||
  2055. X            s.typecnt > TZ_MAX_TYPES ||
  2056. X            s.charcnt > TZ_MAX_CHARS)
  2057. X                return -1;
  2058. X        if (i < sizeof *tzhp +
  2059. X            s.timecnt * (4 + sizeof (char)) +
  2060. X            s.typecnt * (4 + 2 * sizeof (char)) +
  2061. X            s.charcnt * sizeof (char))
  2062. X                return -1;
  2063. X        p = buf + sizeof *tzhp;
  2064. X        for (i = 0; i < s.timecnt; ++i) {
  2065. X            s.ats[i] = detzcode(p);
  2066. X            p += 4;
  2067. X        }
  2068. X        for (i = 0; i < s.timecnt; ++i)
  2069. X            s.types[i] = (unsigned char) *p++;
  2070. X        for (i = 0; i < s.typecnt; ++i) {
  2071. X            register struct ttinfo *    ttisp;
  2072. X
  2073. X            ttisp = &s.ttis[i];
  2074. X            ttisp->tt_gmtoff = detzcode(p);
  2075. X            p += 4;
  2076. X            ttisp->tt_isdst = (unsigned char) *p++;
  2077. X            ttisp->tt_abbrind = (unsigned char) *p++;
  2078. X        }
  2079. X        for (i = 0; i < s.charcnt; ++i)
  2080. X            s.chars[i] = *p++;
  2081. X        s.chars[i] = '\0';    /* ensure '\0' at end */
  2082. X    }
  2083. X    /*
  2084. X    ** Check that all the local time type indices are valid.
  2085. X    */
  2086. X    for (i = 0; i < s.timecnt; ++i)
  2087. X        if (s.types[i] >= s.typecnt)
  2088. X            return -1;
  2089. X    /*
  2090. X    ** Check that all abbreviation indices are valid.
  2091. X    */
  2092. X    for (i = 0; i < s.typecnt; ++i)
  2093. X        if (s.ttis[i].tt_abbrind >= s.charcnt)
  2094. X            return -1;
  2095. X    /*
  2096. X    ** Set tzname elements to initial values.
  2097. X    */
  2098. X    tzname[0] = tzname[1] = &s.chars[0];
  2099. X#ifdef USG_COMPAT
  2100. X    timezone = s.ttis[0].tt_gmtoff;
  2101. X    daylight = 0;
  2102. X#endif /* USG_COMPAT */
  2103. X    for (i = 1; i < s.typecnt; ++i) {
  2104. X        register struct ttinfo *    ttisp;
  2105. X
  2106. X        ttisp = &s.ttis[i];
  2107. X        if (ttisp->tt_isdst) {
  2108. X            tzname[1] = &s.chars[ttisp->tt_abbrind];
  2109. X#ifdef USG_COMPAT
  2110. X            daylight = 1;
  2111. X#endif /* USG_COMPAT */ 
  2112. X        } else {
  2113. X            tzname[0] = &s.chars[ttisp->tt_abbrind];
  2114. X#ifdef USG_COMPAT
  2115. X            timezone = ttisp->tt_gmtoff;
  2116. X#endif /* USG_COMPAT */ 
  2117. X        }
  2118. X    }
  2119. X    return 0;
  2120. X}
  2121. X
  2122. Xstatic
  2123. Xtzsetgmt()
  2124. X{
  2125. X    s.timecnt = 0;
  2126. X    s.ttis[0].tt_gmtoff = 0;
  2127. X    s.ttis[0].tt_abbrind = 0;
  2128. X    (void) strcpy(s.chars, "GMT");
  2129. X    tzname[0] = tzname[1] = s.chars;
  2130. X#ifdef USG_COMPAT
  2131. X    timezone = 0;
  2132. X    daylight = 0;
  2133. X#endif /* USG_COMPAT */
  2134. X}
  2135. X
  2136. Xvoid
  2137. Xtzset()
  2138. X{
  2139. X    register char *    name;
  2140. X
  2141. X    tz_is_set = TRUE;
  2142. X    name = getenv("TZ");
  2143. X    if (name != 0 && *name == '\0')
  2144. X        tzsetgmt();        /* GMT by request */
  2145. X    else if (tzload(name) != 0)
  2146. X        tzsetgmt();
  2147. X}
  2148. X
  2149. Xvoid
  2150. Xtzsetwall()
  2151. X{
  2152. X    tz_is_set = TRUE;
  2153. X    if (tzload((char *) 0) != 0)
  2154. X        tzsetgmt();
  2155. X}
  2156. X
  2157. Xstruct tm *
  2158. Xlocaltime(timep)
  2159. Xtime_t *    timep;
  2160. X{
  2161. X    register struct ttinfo *    ttisp;
  2162. X    register struct tm *        tmp;
  2163. X    register int            i;
  2164. X    time_t                t;
  2165. X
  2166. X    if (!tz_is_set)
  2167. X        (void) tzset();
  2168. X    t = *timep;
  2169. X    if (s.timecnt == 0 || t < s.ats[0]) {
  2170. X        i = 0;
  2171. X        while (s.ttis[i].tt_isdst)
  2172. X            if (++i >= s.timecnt) {
  2173. X                i = 0;
  2174. X                break;
  2175. X            }
  2176. X    } else {
  2177. X        for (i = 1; i < s.timecnt; ++i)
  2178. X            if (t < s.ats[i])
  2179. X                break;
  2180. X        i = s.types[i - 1];
  2181. X    }
  2182. X    ttisp = &s.ttis[i];
  2183. X    /*
  2184. X    ** To get (wrong) behavior that's compatible with System V Release 2.0
  2185. X    ** you'd replace the statement below with
  2186. X    **    tmp = offtime((time_t) (t + ttisp->tt_gmtoff), 0L);
  2187. X    */
  2188. X    tmp = offtime(&t, ttisp->tt_gmtoff);
  2189. X    tmp->tm_isdst = ttisp->tt_isdst;
  2190. X    tzname[tmp->tm_isdst] = &s.chars[ttisp->tt_abbrind];
  2191. X#ifdef KRE_COMPAT
  2192. X    tmp->tm_zone = &s.chars[ttisp->tt_abbrind];
  2193. X#endif /* KRE_COMPAT */
  2194. X#ifdef TZA_COMPAT
  2195. X    tz_abbr = &s.chars[ttisp->tt_abbrind];
  2196. X#endif /* TZA_COMPAT */
  2197. X    return tmp;
  2198. X}
  2199. X
  2200. Xstruct tm *
  2201. Xgmtime(clock)
  2202. Xtime_t *    clock;
  2203. X{
  2204. X    register struct tm *    tmp;
  2205. X
  2206. X    tmp = offtime(clock, 0L);
  2207. X    tzname[0] = "GMT";
  2208. X#ifdef KRE_COMPAT
  2209. X    tmp->tm_zone = "GMT";        /* UCT ? */
  2210. X#endif /* KRE_COMPAT */
  2211. X    return tmp;
  2212. X}
  2213. X
  2214. Xstatic int    mon_lengths[2][MONS_PER_YEAR] = {
  2215. X    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  2216. X    31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  2217. X};
  2218. X
  2219. Xstatic int    year_lengths[2] = {
  2220. X    DAYS_PER_NYEAR, DAYS_PER_LYEAR
  2221. X};
  2222. X
  2223. X#ifdef STD_INSPIRED
  2224. Xstruct tm *
  2225. X#else /* !STD_INSPIRED */
  2226. Xstatic struct tm *
  2227. X#endif /* !STD_INSPIRED */
  2228. Xofftime(clock, offset)
  2229. Xtime_t *    clock;
  2230. Xlong        offset;
  2231. X{
  2232. X    register struct tm *    tmp;
  2233. X    register long        days;
  2234. X    register long        rem;
  2235. X    register int        y;
  2236. X    register int        yleap;
  2237. X    register int *        ip;
  2238. X    static struct tm    tm;
  2239. X
  2240. X    tmp = &tm;
  2241. X    days = *clock / SECS_PER_DAY;
  2242. X    rem = *clock % SECS_PER_DAY;
  2243. X    rem += offset;
  2244. X    while (rem < 0) {
  2245. X        rem += SECS_PER_DAY;
  2246. X        --days;
  2247. X    }
  2248. X    while (rem >= SECS_PER_DAY) {
  2249. X        rem -= SECS_PER_DAY;
  2250. X        ++days;
  2251. X    }
  2252. X    tmp->tm_hour = (int) (rem / SECS_PER_HOUR);
  2253. X    rem = rem % SECS_PER_HOUR;
  2254. X    tmp->tm_min = (int) (rem / SECS_PER_MIN);
  2255. X    tmp->tm_sec = (int) (rem % SECS_PER_MIN);
  2256. X    tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYS_PER_WEEK);
  2257. X    if (tmp->tm_wday < 0)
  2258. X        tmp->tm_wday += DAYS_PER_WEEK;
  2259. X    y = EPOCH_YEAR;
  2260. X    if (days >= 0)
  2261. X        for ( ; ; ) {
  2262. X            yleap = isleap(y);
  2263. X            if (days < (long) year_lengths[yleap])
  2264. X                break;
  2265. X            ++y;
  2266. X            days = days - (long) year_lengths[yleap];
  2267. X        }
  2268. X    else do {
  2269. X        --y;
  2270. X        yleap = isleap(y);
  2271. X        days = days + (long) year_lengths[yleap];
  2272. X    } while (days < 0);
  2273. X    tmp->tm_year = y - TM_YEAR_BASE;
  2274. X    tmp->tm_yday = (int) days;
  2275. X    ip = mon_lengths[yleap];
  2276. X    for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
  2277. X        days = days - (long) ip[tmp->tm_mon];
  2278. X    tmp->tm_mday = (int) (days + 1);
  2279. X    tmp->tm_isdst = 0;
  2280. X#ifdef KRE_COMPAT
  2281. X    tmp->tm_zone = "";
  2282. X    tmp->tm_gmtoff = offset;
  2283. X#endif /* KRE_COMPAT */
  2284. X    return tmp;
  2285. X}
  2286. X
  2287. X#ifdef BSD_COMPAT
  2288. X
  2289. X/*
  2290. X** If ctime and localtime aren't in the same file on 4.3BSD systems,
  2291. X** you can run into compilation problems--take
  2292. X**    cc date.c -lz
  2293. X** (please).
  2294. X*/
  2295. X
  2296. Xchar *
  2297. Xctime(timep)
  2298. Xtime_t *    timep;
  2299. X{
  2300. X    return asctime(localtime(timep));
  2301. X}
  2302. X
  2303. X#endif /* BSD_COMPAT */
  2304. !The!End!
  2305.  
  2306. echo x - "asctime.c" 2>&1
  2307. sed "s/^X//" >"asctime.c" <<'!The!End!'
  2308. X#
  2309. X
  2310. X/*LINTLIBRARY*/
  2311. X
  2312. X#include "stdio.h"
  2313. X
  2314. X#ifndef lint
  2315. X#ifndef NOID
  2316. Xstatic char    sccsid[] = "@(#)asctime.c    3.1";
  2317. X#endif /* !NOID */
  2318. X#endif /* !lint */
  2319. X
  2320. X#include "time.h"
  2321. X#include "tzfile.h"
  2322. X
  2323. X#ifndef USG
  2324. Xextern char *    sprintf();
  2325. X#endif /* !USG */
  2326. X
  2327. X/*
  2328. X** A la X3J11
  2329. X*/
  2330. X
  2331. Xchar *
  2332. Xasctime(timeptr)
  2333. Xregister struct tm *    timeptr;
  2334. X{
  2335. X    static char    wday_name[DAYS_PER_WEEK][3] = {
  2336. X        "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  2337. X    };
  2338. X    static char    mon_name[MONS_PER_YEAR][3] = {
  2339. X        "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  2340. X        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  2341. X    };
  2342. X    static char    result[26];
  2343. X
  2344. X    (void) sprintf(result, "%.3s %.3s%3d %.2d:%.2d:%.2d %d\n",
  2345. X        wday_name[timeptr->tm_wday],
  2346. X        mon_name[timeptr->tm_mon],
  2347. X        timeptr->tm_mday, timeptr->tm_hour,
  2348. X        timeptr->tm_min, timeptr->tm_sec,
  2349. X        TM_YEAR_BASE + timeptr->tm_year);
  2350. X    return result;
  2351. X}
  2352. !The!End!
  2353.  
  2354. echo x - "ctime.c" 2>&1
  2355. sed "s/^X//" >"ctime.c" <<'!The!End!'
  2356. X#
  2357. X
  2358. X/*LINTLIBRARY*/
  2359. X
  2360. X#ifndef lint
  2361. X#ifndef NOID
  2362. Xstatic char    sccsid[] = "@(#)ctime.c    3.1";
  2363. X#endif /* !NOID */
  2364. X#endif /* !lint */
  2365. X
  2366. X#ifndef BSD_COMPAT
  2367. X
  2368. X/*
  2369. X** On non-BSD systems, this can be a separate function (as is proper).
  2370. X*/
  2371. X
  2372. X#include "sys/types.h"
  2373. X#include "time.h"
  2374. X
  2375. Xextern char *        asctime();
  2376. Xextern struct tm *    localtime();
  2377. X
  2378. Xchar *
  2379. Xctime(timep)
  2380. Xtime_t *    timep;
  2381. X{
  2382. X    return asctime(localtime(timep));
  2383. X}
  2384. X
  2385. X#endif /* !BSD_COMPAT */
  2386. !The!End!
  2387.  
  2388. echo x - "dysize.c" 2>&1
  2389. sed "s/^X//" >"dysize.c" <<'!The!End!'
  2390. X#
  2391. X
  2392. X/*LINTLIBRARY*/
  2393. X
  2394. X#ifndef lint
  2395. X#ifndef NOID
  2396. Xstatic char    sccsid[] = "@(#)dysize.c    3.1";
  2397. X#endif /* !NOID */
  2398. X#endif /* !lint */
  2399. X
  2400. X#ifdef BSD_COMPAT
  2401. X
  2402. X#include "tzfile.h"
  2403. X
  2404. Xdysize(y)
  2405. X{
  2406. X    /*
  2407. X    ** The 4.[0123]BSD version of dysize behaves as if the return statement
  2408. X    ** below read
  2409. X    **    return ((y % 4) == 0) ? DAYS_PER_LYEAR : DAYS_PER_NYEAR;
  2410. X    ** but since we'd rather be right than (strictly) compatible. . .
  2411. X    */
  2412. X    return isleap(y) ? DAYS_PER_LYEAR : DAYS_PER_NYEAR;
  2413. X}
  2414. X
  2415. X#endif /* BSD_COMPAT */
  2416. !The!End!
  2417.  
  2418. echo x - "timemk.c" 2>&1
  2419. sed "s/^X//" >"timemk.c" <<'!The!End!'
  2420. X#
  2421. X
  2422. X/*LINTLIBRARY*/
  2423. X
  2424. X#ifndef lint
  2425. X#ifndef NOID
  2426. Xstatic char    sccsid[] = "@(#)timemk.c    3.1";
  2427. X#endif /* !NOID */
  2428. X#endif /* !lint */
  2429. X
  2430. X#ifdef STD_INSPIRED
  2431. X
  2432. X/*
  2433. X** Code provided by Robert Elz, who writes:
  2434. X**    The "best" way to do mktime I think is based on an idea of Bob
  2435. X**    Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
  2436. X**    It does a binary search of the time_t space.  Since time_t's are
  2437. X**    just 32 bits, its a max of 32 iterations (even at 64 bits it
  2438. X**    would still be very reasonable).
  2439. X**
  2440. X** This code does handle "out of bounds" values in the way described
  2441. X** for "mktime" in the October, 1986 draft of the proposed ANSI C Standard;
  2442. X** though this is an accident of the implementation and *cannot* be made to
  2443. X** work correctly for the purposes there described.
  2444. X**
  2445. X** A warning applies if you try to use these functions with a version of
  2446. X** "localtime" that has overflow problems (such as System V Release 2.0
  2447. X** or 4.3 BSD localtime).
  2448. X** If you're not using GMT and feed a value to localtime
  2449. X** that's near the minimum (or maximum) possible time_t value, localtime
  2450. X** may return a struct that represents a time near the maximum (or minimum)
  2451. X** possible time_t value (because of overflow).  If such a returned struct tm
  2452. X** is fed to timelocal, it will not return the value originally feed to
  2453. X** localtime.
  2454. X*/
  2455. X
  2456. X#include "time.h"
  2457. X#include "tzfile.h"
  2458. X#include "sys/types.h"
  2459. X
  2460. X#ifndef WRONG
  2461. X#define WRONG    (-1)
  2462. X#endif /* !WRONG */
  2463. X
  2464. Xextern struct tm *    localtime();
  2465. Xextern struct tm *    gmtime();
  2466. Xextern struct tm *    offtime();
  2467. X
  2468. Xstatic time_t
  2469. Xtimemk(timeptr, funcp, offset)
  2470. Xstruct tm *    timeptr;
  2471. Xstruct tm * (*    funcp)();
  2472. Xlong        offset;
  2473. X{
  2474. X    register int    direction;
  2475. X    register int    bits;
  2476. X    time_t        t;
  2477. X    struct tm    yourtm, mytm;
  2478. X
  2479. X    yourtm = *timeptr;
  2480. X    /*
  2481. X    ** Correct the tm supplied, in case some of its values are
  2482. X    ** out of range.
  2483. X    */
  2484. X    while (yourtm.tm_sec >= SECS_PER_MIN)
  2485. X        ++yourtm.tm_min, yourtm.tm_sec -= SECS_PER_MIN;
  2486. X    while (yourtm.tm_sec < 0)
  2487. X        --yourtm.tm_min, yourtm.tm_sec += SECS_PER_MIN;
  2488. X    while (yourtm.tm_min >= MINS_PER_HOUR)
  2489. X        ++yourtm.tm_hour, yourtm.tm_min -= MINS_PER_HOUR;
  2490. X    while (yourtm.tm_min < 0)
  2491. X        --yourtm.tm_hour, yourtm.tm_min += MINS_PER_HOUR;
  2492. X    while (yourtm.tm_hour >= HOURS_PER_DAY)
  2493. X        ++yourtm.tm_mday, yourtm.tm_hour -= HOURS_PER_DAY;
  2494. X    while (yourtm.tm_hour < 0)
  2495. X        --yourtm.tm_mday, yourtm.tm_hour += HOURS_PER_DAY;
  2496. X    while (yourtm.tm_mday > 31)        /* trust me [kre] */
  2497. X        ++yourtm.tm_mon, yourtm.tm_mday -= 31;
  2498. X    while (yourtm.tm_mday <= 0)
  2499. X        --yourtm.tm_mon, yourtm.tm_mday += 31;
  2500. X    while (yourtm.tm_mon >= MONS_PER_YEAR)
  2501. X        ++yourtm.tm_year, yourtm.tm_mon -= MONS_PER_YEAR;
  2502. X    while (yourtm.tm_mon < 0)
  2503. X        --yourtm.tm_year, yourtm.tm_mon += MONS_PER_YEAR;
  2504. X    /*
  2505. X    ** Calcluate the number of magnitude bits in a time_t
  2506. X    ** (this works regardless of whether time_t is
  2507. X    ** signed or unsigned, though lint complains if unsigned).
  2508. X    */
  2509. X    for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
  2510. X        ;
  2511. X    /*
  2512. X    ** If time_t is signed, then 0 is the median value,
  2513. X    ** if time_t is unsigned, then 1 << bits is median.
  2514. X    */
  2515. X    t = (t < 0) ? 0 : ((time_t) 1 << bits);
  2516. X    for ( ; ; ) {
  2517. X        mytm = (funcp == offtime) ?
  2518. X            *((*funcp)(&t, offset)) : *((*funcp)(&t));
  2519. X        if ((direction = (mytm.tm_year - yourtm.tm_year)) == 0 &&
  2520. X            (direction = (mytm.tm_mon - yourtm.tm_mon)) == 0 &&
  2521. X            (direction = (mytm.tm_mday - yourtm.tm_mday)) == 0 &&
  2522. X            (direction = (mytm.tm_hour - yourtm.tm_hour)) == 0 &&
  2523. X            (direction = (mytm.tm_min - yourtm.tm_min)) == 0)
  2524. X                direction = mytm.tm_sec - yourtm.tm_sec;
  2525. X        if (direction == 0) {
  2526. X            *timeptr = mytm;
  2527. X            return t;
  2528. X        }
  2529. X        if (bits-- < 0) {
  2530. X            *timeptr = yourtm;    /* restore "original" value */
  2531. X            if (yourtm.tm_mday == 31) {
  2532. X                timeptr->tm_mday = 1;
  2533. X                ++(timeptr->tm_mon);
  2534. X                t = timemk(timeptr, funcp);
  2535. X                if (t != WRONG)
  2536. X                    return t;
  2537. X                *timeptr = yourtm;
  2538. X            } else if (yourtm.tm_mon == TM_FEBRUARY &&
  2539. X                yourtm.tm_mday > 28) {
  2540. X                    timeptr->tm_mday -= 28;
  2541. X                    ++(timeptr->tm_mon);
  2542. X                    t = timemk(timeptr, funcp);
  2543. X                    if (t != WRONG)
  2544. X                        return t;
  2545. X                    *timeptr = yourtm;
  2546. X            }
  2547. X            return WRONG;
  2548. X        }
  2549. X        if (bits < 0)
  2550. X            --t;
  2551. X        else if (direction > 0)
  2552. X            t -= (time_t) 1 << bits;
  2553. X        else    t += (time_t) 1 << bits;
  2554. X    }
  2555. X}
  2556. X
  2557. Xtime_t
  2558. Xtimelocal(timeptr)
  2559. Xstruct tm *    timeptr;
  2560. X{
  2561. X    return timemk(timeptr, localtime, 0L);
  2562. X}
  2563. X
  2564. Xtime_t
  2565. Xtimegm(timeptr)
  2566. Xstruct tm *    timeptr;
  2567. X{
  2568. X    return timemk(timeptr, gmtime, 0L);
  2569. X}
  2570. X
  2571. Xtime_t
  2572. Xtimeoff(timeptr, offset)
  2573. Xstruct tm *    timeptr;
  2574. Xlong        offset;
  2575. X{
  2576. X    return timemk(timeptr, offtime, offset);
  2577. X}
  2578. X
  2579. X#endif /* STD_INSPIRED */
  2580. !The!End!
  2581.  
  2582. echo x - "scheck.c" 2>&1
  2583. sed "s/^X//" >"scheck.c" <<'!The!End!'
  2584. X#
  2585. X
  2586. X/*LINTLIBRARY*/
  2587. X
  2588. X#include "stdio.h"
  2589. X
  2590. X#ifndef lint
  2591. X#ifndef NOID
  2592. Xstatic char    sccsid[] = "@(#)scheck.c    7.15";
  2593. X#endif /* !NOID */
  2594. X#endif /* !lint */
  2595. X
  2596. X#include "ctype.h"
  2597. X
  2598. Xextern char *    imalloc();
  2599. X
  2600. Xchar *
  2601. Xscheck(string, format)
  2602. Xchar *    string;
  2603. Xchar *    format;
  2604. X{
  2605. X    register char *    fbuf;
  2606. X    register char *    fp;
  2607. X    register char *    tp;
  2608. X    register int    c;
  2609. X    register char *    result;
  2610. X    char        dummy;
  2611. X
  2612. X    result = "";
  2613. X    if (string == NULL || format == NULL)
  2614. X        return result;
  2615. X    fbuf = imalloc(2 * strlen(format) + 4);
  2616. X    if (fbuf == NULL)
  2617. X        return result;
  2618. X    fp = format;
  2619. X    tp = fbuf;
  2620. X    while ((*tp++ = c = *fp++) != '\0') {
  2621. X        if (c != '%')
  2622. X            continue;
  2623. X        if (*fp == '%') {
  2624. X            *tp++ = *fp++;
  2625. X            continue;
  2626. X        }
  2627. X        *tp++ = '*';
  2628. X        if (*fp == '*')
  2629. X            ++fp;
  2630. X        while (isascii(*fp) && isdigit(*fp))
  2631. X            *tp++ = *fp++;
  2632. X        if (*fp == 'l' || *fp == 'h')
  2633. X            *tp++ = *fp++;
  2634. X        else if (*fp == '[')
  2635. X            do *tp++ = *fp++;
  2636. X                while (*fp != '\0' && *fp != ']');
  2637. X        if ((*tp++ = *fp++) == '\0')
  2638. X            break;
  2639. X    }
  2640. X    *(tp - 1) = '%';
  2641. X    *tp++ = 'c';
  2642. X    *tp = '\0';
  2643. X    if (sscanf(string, fbuf, &dummy) != 1)
  2644. X        result = format;
  2645. X    free(fbuf);
  2646. X    return result;
  2647. X}
  2648. !The!End!
  2649.  
  2650. echo x - "ialloc.c" 2>&1
  2651. sed "s/^X//" >"ialloc.c" <<'!The!End!'
  2652. X#
  2653. X
  2654. X/*LINTLIBRARY*/
  2655. X
  2656. X#include "stdio.h"
  2657. X
  2658. X#ifndef lint
  2659. X#ifndef NOID
  2660. Xstatic char    sccsid[] = "@(#)ialloc.c    7.13";
  2661. X#endif /* !NOID */
  2662. X#endif /* !lint */
  2663. X
  2664. X#ifndef alloc_t
  2665. X#define alloc_t    unsigned
  2666. X#endif /* !alloc_t */
  2667. X
  2668. X#ifdef MAL
  2669. X#define NULLMAL(x)    ((x) == NULL || (x) == MAL)
  2670. X#else /* !MAL */
  2671. X#define NULLMAL(x)    ((x) == NULL)
  2672. X#endif /* !MAL */
  2673. X
  2674. Xextern char *    calloc();
  2675. Xextern char *    malloc();
  2676. Xextern char *    realloc();
  2677. Xextern char *    strcpy();
  2678. X
  2679. Xchar *
  2680. Ximalloc(n)
  2681. X{
  2682. X#ifdef MAL
  2683. X    register char *    result;
  2684. X
  2685. X    if (n == 0)
  2686. X        n = 1;
  2687. X    result = malloc((alloc_t) n);
  2688. X    return (result == MAL) ? NULL : result;
  2689. X#else /* !MAL */
  2690. X    if (n == 0)
  2691. X        n = 1;
  2692. X    return malloc((alloc_t) n);
  2693. X#endif /* !MAL */
  2694. X}
  2695. X
  2696. Xchar *
  2697. Xicalloc(nelem, elsize)
  2698. X{
  2699. X    if (nelem == 0 || elsize == 0)
  2700. X        nelem = elsize = 1;
  2701. X    return calloc((alloc_t) nelem, (alloc_t) elsize);
  2702. X}
  2703. X
  2704. Xchar *
  2705. Xirealloc(pointer, size)
  2706. Xchar *    pointer;
  2707. X{
  2708. X    if (NULLMAL(pointer))
  2709. X        return imalloc(size);
  2710. X    if (size == 0)
  2711. X        size = 1;
  2712. X    return realloc(pointer, (alloc_t) size);
  2713. X}
  2714. X
  2715. Xchar *
  2716. Xicatalloc(old, new)
  2717. Xchar *    old;
  2718. Xchar *    new;
  2719. X{
  2720. X    register char *    result;
  2721. X    register    oldsize, newsize;
  2722. X
  2723. X    oldsize = NULLMAL(old) ? 0 : strlen(old);
  2724. X    newsize = NULLMAL(new) ? 0 : strlen(new);
  2725. X    if ((result = irealloc(old, oldsize + newsize + 1)) != NULL)
  2726. X        if (!NULLMAL(new))
  2727. X            (void) strcpy(result + oldsize, new);
  2728. X    return result;
  2729. X}
  2730. X
  2731. Xchar *
  2732. Xicpyalloc(string)
  2733. Xchar *    string;
  2734. X{
  2735. X    return icatalloc((char *) NULL, string);
  2736. X}
  2737. X
  2738. Xifree(p)
  2739. Xchar *    p;
  2740. X{
  2741. X    if (!NULLMAL(p))
  2742. X        free(p);
  2743. X}
  2744. !The!End!
  2745.  
  2746. echo x - "mkdir.c" 2>&1
  2747. sed "s/^X//" >"mkdir.c" <<'!The!End!'
  2748. X#
  2749. X
  2750. X/*LINTLIBRARY*/
  2751. X
  2752. X#include "stdio.h"
  2753. X
  2754. X#ifndef lint
  2755. X#ifndef NOID
  2756. Xstatic char    sccsid[] = "@(#)mkdir.c    7.5";
  2757. X#endif /* !NOID */
  2758. X#endif /* !lint */
  2759. X
  2760. Xextern FILE *    popen();
  2761. X
  2762. Xstatic
  2763. Xquote(name, fp)
  2764. Xregister char *    name;
  2765. Xregister FILE *    fp;
  2766. X{
  2767. X    register int    c;
  2768. X
  2769. X    (void) fputc('\'', fp);
  2770. X    if (name != NULL)
  2771. X        while ((c = *name++) != '\0')
  2772. X            if (c == '\'')
  2773. X                (void) fprintf(fp, "'\\''");
  2774. X            else    (void) fputc(c, fp);
  2775. X    (void) fputc('\'', fp);
  2776. X}
  2777. X
  2778. Xmkdir(name, mode)
  2779. Xchar *    name;
  2780. X{
  2781. X    register FILE *    fp;
  2782. X    register int    oops;
  2783. X
  2784. X    if ((fp = popen("sh", "w")) == NULL)
  2785. X        return -1;
  2786. X    (void) fprintf(fp, "mkdir 2>&- ");
  2787. X    quote(name, fp);
  2788. X    (void) fprintf(fp, " && chmod 2>&- %o ", mode);
  2789. X    quote(name, fp);
  2790. X    (void) fputc('\n', fp);
  2791. X    (void) fflush(fp);
  2792. X    oops = ferror(fp);
  2793. X    return (pclose(fp) == 0 && !oops) ? 0 : -1;
  2794. X}
  2795. !The!End!
  2796. exit
  2797.