home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume18 / localtime3 / part02 < prev    next >
Encoding:
Internet Message Format  |  1989-04-19  |  41.6 KB

  1. Subject:  v18i112:  Table-driven ctime/time/localtime/date package, Part02/07
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by:  ado@ncifcrf.gov
  7. Posting-number: Volume 18, Issue 112
  8. Archive-name: localtime3/part02
  9.  
  10. : To unbundle, sh this file
  11. echo file 'tzfile.h' >&2
  12. cat >'tzfile.h' <<'End of tzfile.h'
  13. #ifndef TZFILE_H
  14.  
  15. #define TZFILE_H
  16.  
  17. /*
  18. ** This header is for use ONLY with the time conversion code.
  19. ** There is no guarantee that it will remain unchanged,
  20. ** or that it will remain at all.
  21. ** Do NOT copy it to any system include directory.
  22. ** Thank you!
  23. */
  24.  
  25. /*
  26. ** ID
  27. */
  28.  
  29. #ifndef lint
  30. #ifndef NOID
  31. static char    tzfilehid[] = "@(#)tzfile.h    7.1";
  32. #endif /* !defined NOID */
  33. #endif /* !defined lint */
  34.  
  35. /*
  36. ** Information about time zone files.
  37. */
  38.  
  39. #ifndef TZDIR
  40. #define TZDIR    "/usr/local/etc/zoneinfo" /* Time zone object file directory */
  41. #endif /* !defined TZDIR */
  42.  
  43. #ifndef TZDEFAULT
  44. #define TZDEFAULT    "localtime"
  45. #endif /* !defined TZDEFAULT */
  46.  
  47. #ifndef TZDEFRULES
  48. #define TZDEFRULES    "posixrules"
  49. #endif /* !defined TZDEFRULES */
  50.  
  51. /*
  52. ** Each file begins with. . .
  53. */
  54.  
  55. struct tzhead {
  56.     char    tzh_reserved[24];    /* reserved for future use */
  57.     char    tzh_ttisstdcnt[4];    /* coded number of trans. time flags */
  58.     char    tzh_leapcnt[4];        /* coded number of leap seconds */
  59.     char    tzh_timecnt[4];        /* coded number of transition times */
  60.     char    tzh_typecnt[4];        /* coded number of local time types */
  61.     char    tzh_charcnt[4];        /* coded number of abbr. chars */
  62. };
  63.  
  64. /*
  65. ** . . .followed by. . .
  66. **
  67. **    tzh_timecnt (char [4])s        coded transition times a la time(2)
  68. **    tzh_timecnt (unsigned char)s    types of local time starting at above
  69. **    tzh_typecnt repetitions of
  70. **        one (char [4])        coded GMT offset in seconds
  71. **        one (unsigned char)    used to set tm_isdst
  72. **        one (unsigned char)    that's an abbreviation list index
  73. **    tzh_charcnt (char)s        '\0'-terminated zone abbreviations
  74. **    tzh_leapcnt repetitions of
  75. **        one (char [4])        coded leap second transition times
  76. **        one (char [4])        total correction after above
  77. **    tzh_ttisstdcnt (char)s        indexed by type; if TRUE, transition
  78. **                    time is standard time, if FALSE,
  79. **                    transition time is wall clock time
  80. **                    if absent, transition times are
  81. **                    assumed to be wall clock time
  82. */
  83.  
  84. /*
  85. ** In the current implementation, "tzset()" refuses to deal with files that
  86. ** exceed any of the limits below.
  87. */
  88.  
  89. #ifndef TZ_MAX_TIMES
  90. /*
  91. ** The TZ_MAX_TIMES value below is enough to handle a bit more than a
  92. ** year's worth of solar time (corrected daily to the nearest second) or
  93. ** 138 years of Pacific Presidential Election time
  94. ** (where there are three time zone transitions every fourth year).
  95. */
  96. #define TZ_MAX_TIMES    370
  97. #endif /* !defined TZ_MAX_TIMES */
  98.  
  99. #ifndef TZ_MAX_TYPES
  100. #ifndef NOSOLAR
  101. #define TZ_MAX_TYPES    256    /* Limited by what (unsigned char)'s can hold */
  102. #else /* !defined NOSOLAR */
  103. #define TZ_MAX_TYPES    10    /* Maximum number of local time types */
  104. #endif /* !defined NOSOLAR */
  105. #endif /* !defined TZ_MAX_TYPES */
  106.  
  107. #ifndef TZ_MAX_CHARS
  108. #define TZ_MAX_CHARS    50    /* Maximum number of abbreviation characters */
  109. #endif /* !defined TZ_MAX_CHARS */
  110.  
  111. #ifndef TZ_MAX_LEAPS
  112. #define    TZ_MAX_LEAPS    50    /* Maximum number of leap second corrections */
  113. #endif /* !defined TZ_MAX_LEAPS */
  114.  
  115. #define SECSPERMIN    60
  116. #define MINSPERHOUR    60
  117. #define HOURSPERDAY    24
  118. #define DAYSPERWEEK    7
  119. #define DAYSPERNYEAR    365
  120. #define DAYSPERLYEAR    366
  121. #define SECSPERHOUR    (SECSPERMIN * MINSPERHOUR)
  122. #define SECSPERDAY    ((long) SECSPERHOUR * HOURSPERDAY)
  123. #define MONSPERYEAR    12
  124.  
  125. #define TM_SUNDAY    0
  126. #define TM_MONDAY    1
  127. #define TM_TUESDAY    2
  128. #define TM_WEDNESDAY    3
  129. #define TM_THURSDAY    4
  130. #define TM_FRIDAY    5
  131. #define TM_SATURDAY    6
  132.  
  133. #define TM_JANUARY    0
  134. #define TM_FEBRUARY    1
  135. #define TM_MARCH    2
  136. #define TM_APRIL    3
  137. #define TM_MAY        4
  138. #define TM_JUNE        5
  139. #define TM_JULY        6
  140. #define TM_AUGUST    7
  141. #define TM_SEPTEMBER    8
  142. #define TM_OCTOBER    9
  143. #define TM_NOVEMBER    10
  144. #define TM_DECEMBER    11
  145.  
  146. #define TM_YEAR_BASE    1900
  147.  
  148. #define EPOCH_YEAR    1970
  149. #define EPOCH_WDAY    TM_THURSDAY
  150.  
  151. /*
  152. ** Accurate only for the past couple of centuries;
  153. ** that will probably do.
  154. */
  155.  
  156. #define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
  157.  
  158. #ifndef USG
  159.  
  160. /*
  161. ** Use of the underscored variants may cause problems if you move your code to
  162. ** certain System-V-based systems; for maximum portability, use the
  163. ** underscore-free variants.  The underscored variants are provided for
  164. ** backward compatibility only; they may disappear from future versions of
  165. ** this file.
  166. */
  167.  
  168. #define SECS_PER_MIN    SECSPERMIN
  169. #define MINS_PER_HOUR    MINSPERHOUR
  170. #define HOURS_PER_DAY    HOURSPERDAY
  171. #define DAYS_PER_WEEK    DAYSPERWEEK
  172. #define DAYS_PER_NYEAR    DAYSPERNYEAR
  173. #define DAYS_PER_LYEAR    DAYSPERLYEAR
  174. #define SECS_PER_HOUR    SECSPERHOUR
  175. #define SECS_PER_DAY    SECSPERDAY
  176. #define MONS_PER_YEAR    MONSPERYEAR
  177.  
  178. #endif /* !defined USG */
  179.  
  180. #endif /* !defined TZFILE_H */
  181. End of tzfile.h
  182. echo file 'private.h' >&2
  183. cat >'private.h' <<'End of private.h'
  184. #ifndef PRIVATE_H
  185.  
  186. #define PRIVATE_H
  187.  
  188. /*
  189. ** This header is for use ONLY with the time conversion code.
  190. ** There is no guarantee that it will remain unchanged,
  191. ** or that it will remain at all.
  192. ** Do NOT copy it to any system include directory.
  193. ** Thank you!
  194. */
  195.  
  196. /*
  197. ** ID
  198. */
  199.  
  200. #ifndef lint
  201. #ifndef NOID
  202. static char    privatehid[] = "@(#)private.h    7.1";
  203. #endif /* !defined NOID */
  204. #endif /* !defined lint */
  205.  
  206. /*
  207. ** const
  208. */
  209.  
  210. #ifndef const
  211. #ifndef __STDC__
  212. #define const
  213. #endif /* !defined __STDC__ */
  214. #endif /* !defined const */
  215.  
  216. /*
  217. ** void
  218. */
  219.  
  220. #ifndef void
  221. #ifndef __STDC__
  222. #ifndef vax
  223. #ifndef sun
  224. #define void    char
  225. #endif /* !defined sun */
  226. #endif /* !defined vax */
  227. #endif /* !defined __STDC__ */
  228. #endif /* !defined void */
  229.  
  230. /*
  231. ** P((args))
  232. */
  233.  
  234. #ifndef P
  235. #ifdef __STDC__
  236. #define P(x)    x
  237. #else /* !defined __STDC__ */
  238. #define ASTERISK    *
  239. #define P(x)    ( /ASTERISK x ASTERISK/ )
  240. #endif /* !defined __STDC__ */
  241. #endif /* !defined P */
  242.  
  243. /*
  244. ** genericptr_t
  245. */
  246.  
  247. #ifdef __STDC__
  248. typedef void *        genericptr_t;
  249. #else /* !defined __STDC__ */
  250. typedef char *        genericptr_t;
  251. #endif /* !defined __STDC__ */
  252.  
  253. #include "sys/types.h"    /* for time_t */
  254. #include "stdio.h"
  255. #include "ctype.h"
  256. #include "errno.h"
  257. #include "string.h"
  258. #ifndef _TIME_
  259. #include "time.h"
  260. #endif /* !defined _TIME_ */
  261.  
  262. #ifndef remove
  263. extern int    unlink P((const char * filename));
  264. #define remove    unlink
  265. #endif /* !defined remove */
  266.  
  267. #ifndef FILENAME_MAX
  268.  
  269. #ifndef MAXPATHLEN
  270. #ifdef unix
  271. #include "sys/param.h"
  272. #endif /* defined unix */
  273. #endif /* !defined MAXPATHLEN */
  274.  
  275. #ifdef MAXPATHLEN
  276. #define FILENAME_MAX    MAXPATHLEN
  277. #else /* !defined MAXPATHLEN */
  278. #define FILENAME_MAX    1024        /* Pure guesswork */
  279. #endif /* !defined MAXPATHLEN */
  280.  
  281. #endif /* !defined FILENAME_MAX */
  282.  
  283. #ifndef EXIT_SUCCESS
  284. #define EXIT_SUCCESS    0
  285. #endif /* !defined EXIT_SUCCESS */
  286.  
  287. #ifndef EXIT_FAILURE
  288. #define EXIT_FAILURE    1
  289. #endif /* !defined EXIT_FAILURE */
  290.  
  291. #ifdef __STDC__
  292.  
  293. #define alloc_size_t    size_t
  294. #define qsort_size_t    size_t
  295. #define fwrite_size_t    size_t
  296.  
  297. #else /* !defined __STDC__ */
  298.  
  299. #ifndef alloc_size_t
  300. #define alloc_size_t    unsigned
  301. #endif /* !defined alloc_size_t */
  302.  
  303. #ifndef qsort_size_t
  304. #ifdef USG
  305. #define qsort_size_t    unsigned
  306. #else /* !defined USG */
  307. #define qsort_size_t    int
  308. #endif /* !defined USG */
  309. #endif /* !defined qsort_size_t */
  310.  
  311. #ifndef fwrite_size_t
  312. #define fwrite_size_t    int
  313. #endif /* !defined fwrite_size_t */
  314.  
  315. #ifndef USG
  316. extern char *        sprintf P((char * buf, const char * format, ...));
  317. #endif /* !defined USG */
  318.  
  319. #endif /* !defined __STDC__ */
  320.  
  321. /*
  322. ** Ensure that these are declared--redundantly declaring them shouldn't hurt.
  323. */
  324.  
  325. extern char *        getenv P((const char * name));
  326. extern genericptr_t    malloc P((alloc_size_t size));
  327. extern genericptr_t    calloc P((alloc_size_t nelem, alloc_size_t elsize));
  328. extern genericptr_t    realloc P((genericptr_t oldptr, alloc_size_t newsize));
  329.  
  330. #ifdef USG
  331. extern void        exit P((int s));
  332. extern void        qsort P((genericptr_t base, qsort_size_t nelem,
  333.                 qsort_size_t elsize, int (*comp)()));
  334. extern void        perror P((const char * string));
  335. extern void        free P((char * buf));
  336. #endif /* defined USG */
  337.  
  338. #ifndef TRUE
  339. #define TRUE    1
  340. #endif /* !defined TRUE */
  341.  
  342. #ifndef FALSE
  343. #define FALSE    0
  344. #endif /* !defined FALSE */
  345.  
  346. /*
  347. ** UNIX is a registered trademark of AT&T.
  348. ** VAX is a trademark of Digital Equipment Corporation.
  349. */
  350.  
  351. #endif /* !defined PRIVATE_H */
  352. End of private.h
  353. echo file 'localtime.c' >&2
  354. cat >'localtime.c' <<'End of localtime.c'
  355. #ifndef lint
  356. #ifndef NOID
  357. static char    elsieid[] = "@(#)localtime.c    7.1";
  358. #endif /* !defined NOID */
  359. #endif /* !defined lint */
  360.  
  361. /*
  362. ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
  363. ** POSIX-style TZ environment variable handling from Guy Harris
  364. ** (guy@auspex.com).
  365. */
  366.  
  367. /*LINTLIBRARY*/
  368.  
  369. #include "private.h"
  370. #include "tzfile.h"
  371. #include "fcntl.h"
  372.  
  373. #define ACCESS_MODE    O_RDONLY
  374.  
  375. #ifdef O_BINARY
  376. #define OPEN_MODE    (O_RDONLY | O_BINARY)
  377. #else /* !defined O_BINARY */
  378. #define OPEN_MODE    O_RDONLY
  379. #endif /* !defined O_BINARY */
  380.  
  381. #ifndef WILDABBR
  382. /*
  383. ** Someone might make incorrect use of a time zone abbreviation:
  384. **    1.    They might reference tzname[0] before calling tzset (explicitly
  385. **         or implicitly).
  386. **    2.    They might reference tzname[1] before calling tzset (explicitly
  387. **         or implicitly).
  388. **    3.    They might reference tzname[1] after setting to a time zone
  389. **        in which Daylight Saving Time is never observed.
  390. **    4.    They might reference tzname[0] after setting to a time zone
  391. **        in which Standard Time is never observed.
  392. **    5.    They might reference tm.TM_ZONE after calling offtime.
  393. ** What's best to do in the above cases is open to debate;
  394. ** for now, we just set things up so that in any of the five cases
  395. ** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
  396. ** string "tzname[0] used before set", and similarly for the other cases.
  397. ** And another:  initialize tzname[0] to "ERA", with an explanation in the
  398. ** manual page of what this "time zone abbreviation" means (doing this so
  399. ** that tzname[0] has the "normal" length of three characters).
  400. */
  401. #define WILDABBR    "   "
  402. #endif /* !defined WILDABBR */
  403.  
  404. static const char GMT[] = "GMT";
  405.  
  406. struct ttinfo {                /* time type information */
  407.     long        tt_gmtoff;    /* GMT offset in seconds */
  408.     int        tt_isdst;    /* used to set tm_isdst */
  409.     int        tt_abbrind;    /* abbreviation list index */
  410.     int        tt_ttisstd;    /* TRUE if transition is std time */
  411. };
  412.  
  413. struct lsinfo {                /* leap second information */
  414.     time_t        ls_trans;    /* transition time */
  415.     long        ls_corr;    /* correction to apply */
  416. };
  417.  
  418. struct state {
  419.     int        leapcnt;
  420.     int        timecnt;
  421.     int        typecnt;
  422.     int        charcnt;
  423.     time_t        ats[TZ_MAX_TIMES];
  424.     unsigned char    types[TZ_MAX_TIMES];
  425.     struct ttinfo    ttis[TZ_MAX_TYPES];
  426.     char        chars[(TZ_MAX_CHARS + 1 > sizeof GMT) ?
  427.                 TZ_MAX_CHARS + 1 : sizeof GMT];
  428.     struct lsinfo    lsis[TZ_MAX_LEAPS];
  429. };
  430.  
  431. struct rule {
  432.     int        r_type;        /* type of rule--see below */
  433.     int        r_day;        /* day number of rule */
  434.     int        r_week;        /* week number of rule */
  435.     int        r_mon;        /* month number of rule */
  436.     long        r_time;        /* transition time of rule */
  437. };
  438.  
  439. #define    JULIAN_DAY        0    /* Jn - Julian day */
  440. #define    DAY_OF_YEAR        1    /* n - day of year */
  441. #define    MONTH_NTH_DAY_OF_WEEK    2    /* Mm.n.d - month, week, day of week */
  442.  
  443. /*
  444. ** Prototypes for static functions.
  445. */
  446.  
  447. static long        detzcode P((const char * codep));
  448. static const char *    getzname P((const char * strp));
  449. static const char *    getnum P((const char * strp, int * nump, int min,
  450.                 int max));
  451. static const char *    getsecs P((const char * strp, long * secsp));
  452. static const char *    getoffset P((const char * strp, long * offsetp));
  453. static const char *    getrule P((const char * strp, struct rule * rulep));
  454. static void        gmtload P((struct state * sp));
  455. static void        gmtsub P((const time_t * timep, long offset,
  456.                 struct tm * tmp));
  457. static void        localsub P((const time_t * timep, long offset,
  458.                 struct tm * tmp));
  459. static void        normalize P((int * tensptr, int * unitsptr, int base));
  460. static void        settzname P((void));
  461. static time_t        time1 P((struct tm * tmp, void (* funcp)(),
  462.                 long offset));
  463. static time_t        time2 P((struct tm *tmp, void (* funcp)(),
  464.                 long offset, int * okayp));
  465. static void        timesub P((const time_t * timep, long offset,
  466.                 const struct state * sp, struct tm * tmp));
  467. static int        tmcomp P((const struct tm * atmp,
  468.                 const struct tm * btmp));
  469. static time_t        transtime P((time_t janfirst, int year,
  470.                 const struct rule * rulep, long offset));
  471. static int        tzload P((const char * name, struct state * sp));
  472. static int        tzparse P((const char * name, struct state * sp,
  473.                 int lastditch));
  474.  
  475. #ifdef ALL_STATE
  476. static struct state *    lclptr;
  477. static struct state *    gmtptr;
  478. #endif /* defined ALL_STATE */
  479.  
  480. #ifndef ALL_STATE
  481. static struct state    lclmem;
  482. static struct state    gmtmem;
  483. #define lclptr        (&lclmem)
  484. #define gmtptr        (&gmtmem)
  485. #endif /* State Farm */
  486.  
  487. static int        lcl_is_set;
  488. static int        gmt_is_set;
  489.  
  490. char *            tzname[2] = {
  491.     WILDABBR,
  492.     WILDABBR
  493. };
  494.  
  495. #ifdef USG_COMPAT
  496. time_t            timezone = 0;
  497. int            daylight = 0;
  498. #endif /* defined USG_COMPAT */
  499.  
  500. #ifdef ALTZONE
  501. time_t            altzone = 0;
  502. #endif /* defined ALTZONE */
  503.  
  504. static long
  505. detzcode(codep)
  506. const char * const    codep;
  507. {
  508.     register long    result;
  509.     register int    i;
  510.  
  511.     result = 0;
  512.     for (i = 0; i < 4; ++i)
  513.         result = (result << 8) | (codep[i] & 0xff);
  514.     return result;
  515. }
  516.  
  517. static void
  518. settzname()
  519. {
  520.     register const struct state * const    sp = lclptr;
  521.     register int                i;
  522.  
  523.     tzname[0] = WILDABBR;
  524.     tzname[1] = WILDABBR;
  525. #ifdef USG_COMPAT
  526.     daylight = 0;
  527.     timezone = 0;
  528. #endif /* defined USG_COMPAT */
  529. #ifdef ALTZONE
  530.     altzone = 0;
  531. #endif /* defined ALTZONE */
  532. #ifdef ALL_STATE
  533.     if (sp == NULL) {
  534.         tzname[0] = tzname[1] = GMT;
  535.         return;
  536.     }
  537. #endif /* defined ALL_STATE */
  538.     for (i = 0; i < sp->typecnt; ++i) {
  539.         register const struct ttinfo * const    ttisp = &sp->ttis[i];
  540.  
  541.         tzname[ttisp->tt_isdst] =
  542.             (char *) &sp->chars[ttisp->tt_abbrind];
  543. #ifdef USG_COMPAT
  544.         if (ttisp->tt_isdst)
  545.             daylight = 1;
  546.         if (i == 0 || !ttisp->tt_isdst)
  547.             timezone = -(ttisp->tt_gmtoff);
  548. #endif /* defined USG_COMPAT */
  549. #ifdef ALTZONE
  550.         if (i == 0 || ttisp->tt_isdst)
  551.             altzone = -(ttisp->tt_gmtoff);
  552. #endif /* defined ALTZONE */
  553.     }
  554.     /*
  555.     ** And to get the latest zone names into tzname. . .
  556.     */
  557.     for (i = 0; i < sp->timecnt; ++i) {
  558.         register const struct ttinfo * const    ttisp =
  559.                             &sp->ttis[sp->types[i]];
  560.  
  561.         tzname[ttisp->tt_isdst] =
  562.             (char *) &sp->chars[ttisp->tt_abbrind];
  563.     }
  564. }
  565.  
  566. static int
  567. tzload(name, sp)
  568. register const char *        name;
  569. register struct state * const    sp;
  570. {
  571.     register const char *    p;
  572.     register int        i;
  573.     register int        fid;
  574.  
  575.     if (name == NULL && (name = TZDEFAULT) == NULL)
  576.         return -1;
  577.     {
  578.         register int     doaccess;
  579.         char        fullname[FILENAME_MAX + 1];
  580.  
  581.         if (name[0] == ':')
  582.             ++name;
  583.         doaccess = name[0] == '/';
  584.         if (!doaccess) {
  585.             if ((p = TZDIR) == NULL)
  586.                 return -1;
  587.             if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
  588.                 return -1;
  589.             (void) strcpy(fullname, p);
  590.             (void) strcat(fullname, "/");
  591.             (void) strcat(fullname, name);
  592.             /*
  593.             ** Set doaccess if '.' (as in "../") shows up in name.
  594.             */
  595.             if (strchr(name, '.') != NULL)
  596.                 doaccess = TRUE;
  597.             name = fullname;
  598.         }
  599.         if (doaccess && access(name, ACCESS_MODE) != 0)
  600.             return -1;
  601.         if ((fid = open(name, OPEN_MODE)) == -1)
  602.             return -1;
  603.     }
  604.     {
  605.         register const struct tzhead *    tzhp;
  606.         char                buf[sizeof *sp + sizeof *tzhp];
  607.         int                ttisstdcnt;
  608.  
  609.         i = read(fid, buf, sizeof buf);
  610.         if (close(fid) != 0 || i < sizeof *tzhp)
  611.             return -1;
  612.         tzhp = (struct tzhead *) buf;
  613.         ttisstdcnt = (int) detzcode(tzhp->tzh_ttisstdcnt);
  614.         sp->leapcnt = (int) detzcode(tzhp->tzh_leapcnt);
  615.         sp->timecnt = (int) detzcode(tzhp->tzh_timecnt);
  616.         sp->typecnt = (int) detzcode(tzhp->tzh_typecnt);
  617.         sp->charcnt = (int) detzcode(tzhp->tzh_charcnt);
  618.         if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
  619.             sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
  620.             sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
  621.             sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
  622.             (ttisstdcnt != sp->typecnt && ttisstdcnt != 0))
  623.                 return -1;
  624.         if (i < sizeof *tzhp +
  625.             sp->timecnt * (4 + sizeof (char)) +
  626.             sp->typecnt * (4 + 2 * sizeof (char)) +
  627.             sp->charcnt * sizeof (char) +
  628.             sp->leapcnt * 2 * 4 +
  629.             ttisstdcnt * sizeof (char))
  630.                 return -1;
  631.         p = buf + sizeof *tzhp;
  632.         for (i = 0; i < sp->timecnt; ++i) {
  633.             sp->ats[i] = detzcode(p);
  634.             p += 4;
  635.         }
  636.         for (i = 0; i < sp->timecnt; ++i) {
  637.             sp->types[i] = (unsigned char) *p++;
  638.             if (sp->types[i] >= sp->typecnt)
  639.                 return -1;
  640.         }
  641.         for (i = 0; i < sp->typecnt; ++i) {
  642.             register struct ttinfo *    ttisp;
  643.  
  644.             ttisp = &sp->ttis[i];
  645.             ttisp->tt_gmtoff = detzcode(p);
  646.             p += 4;
  647.             ttisp->tt_isdst = (unsigned char) *p++;
  648.             if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
  649.                 return -1;
  650.             ttisp->tt_abbrind = (unsigned char) *p++;
  651.             if (ttisp->tt_abbrind < 0 ||
  652.                 ttisp->tt_abbrind > sp->charcnt)
  653.                     return -1;
  654.         }
  655.         for (i = 0; i < sp->charcnt; ++i)
  656.             sp->chars[i] = *p++;
  657.         sp->chars[i] = '\0';    /* ensure '\0' at end */
  658.         for (i = 0; i < sp->leapcnt; ++i) {
  659.             register struct lsinfo *    lsisp;
  660.  
  661.             lsisp = &sp->lsis[i];
  662.             lsisp->ls_trans = detzcode(p);
  663.             p += 4;
  664.             lsisp->ls_corr = detzcode(p);
  665.             p += 4;
  666.         }
  667.         for (i = 0; i < sp->typecnt; ++i) {
  668.             register struct ttinfo *    ttisp;
  669.  
  670.             ttisp = &sp->ttis[i];
  671.             if (ttisstdcnt == 0)
  672.                 ttisp->tt_ttisstd = FALSE;
  673.             else {
  674.                 ttisp->tt_ttisstd = *p++;
  675.                 if (ttisp->tt_ttisstd != TRUE &&
  676.                     ttisp->tt_ttisstd != FALSE)
  677.                         return -1;
  678.             }
  679.         }
  680.     }
  681.     return 0;
  682. }
  683.  
  684. static const int    mon_lengths[2][MONSPERYEAR] = {
  685.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  686.     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  687. };
  688.  
  689. static const int    year_lengths[2] = {
  690.     DAYSPERNYEAR, DAYSPERLYEAR
  691. };
  692.  
  693. /*
  694. ** Given a pointer into a time zone string, scan until a character that is not
  695. ** a valid character in a zone name is found.  Return a pointer to that
  696. ** character.
  697. */
  698.  
  699. static const char *
  700. getzname(strp)
  701. register const char *    strp;
  702. {
  703.     register char    c;
  704.  
  705.     while ((c = *strp) != '\0' && !isdigit(c) && c != ',' && c != '-' &&
  706.         c != '+')
  707.             ++strp;
  708.     return strp;
  709. }
  710.  
  711. /*
  712. ** Given a pointer into a time zone string, extract a number from that string.
  713. ** Check that the number is within a specified range; if it is not, return
  714. ** NULL.
  715. ** Otherwise, return a pointer to the first character not part of the number.
  716. */
  717.  
  718. static const char *
  719. getnum(strp, nump, min, max)
  720. register const char *    strp;
  721. int * const        nump;
  722. const int        min;
  723. const int        max;
  724. {
  725.     register char    c;
  726.     register int    num;
  727.  
  728.     if (strp == NULL || !isdigit(*strp))
  729.         return NULL;
  730.     num = 0;
  731.     while ((c = *strp) != '\0' && isdigit(c)) {
  732.         num = num * 10 + (c - '0');
  733.         if (num > max)
  734.             return NULL;    /* illegal value */
  735.         ++strp;
  736.     }
  737.     if (num < min)
  738.         return NULL;        /* illegal value */
  739.     *nump = num;
  740.     return strp;
  741. }
  742.  
  743. /*
  744. ** Given a pointer into a time zone string, extract a number of seconds,
  745. ** in hh[:mm[:ss]] form, from the string.
  746. ** If any error occurs, return NULL.
  747. ** Otherwise, return a pointer to the first character not part of the number
  748. ** of seconds.
  749. */
  750.  
  751. static const char *
  752. getsecs(strp, secsp)
  753. register const char *    strp;
  754. long * const        secsp;
  755. {
  756.     int    num;
  757.  
  758.     strp = getnum(strp, &num, 0, HOURSPERDAY);
  759.     if (strp == NULL)
  760.         return NULL;
  761.     *secsp = num * SECSPERHOUR;
  762.     if (*strp == ':') {
  763.         ++strp;
  764.         strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
  765.         if (strp == NULL)
  766.             return NULL;
  767.         *secsp += num * SECSPERMIN;
  768.         if (*strp == ':') {
  769.             ++strp;
  770.             strp = getnum(strp, &num, 0, SECSPERMIN - 1);
  771.             if (strp == NULL)
  772.                 return NULL;
  773.             *secsp += num;
  774.         }
  775.     }
  776.     return strp;
  777. }
  778.  
  779. /*
  780. ** Given a pointer into a time zone string, extract an offset, in
  781. ** [+-]hh[:mm[:ss]] form, from the string.
  782. ** If any error occurs, return NULL.
  783. ** Otherwise, return a pointer to the first character not part of the time.
  784. */
  785.  
  786. static const char *
  787. getoffset(strp, offsetp)
  788. register const char *    strp;
  789. long * const        offsetp;
  790. {
  791.     register int    neg;
  792.  
  793.     if (*strp == '-') {
  794.         neg = 1;
  795.         ++strp;
  796.     } else if (isdigit(*strp) || *strp++ == '+')
  797.         neg = 0;
  798.     else    return NULL;        /* illegal offset */
  799.     strp = getsecs(strp, offsetp);
  800.     if (strp == NULL)
  801.         return NULL;        /* illegal time */
  802.     if (neg)
  803.         *offsetp = -*offsetp;
  804.     return strp;
  805. }
  806.  
  807. /*
  808. ** Given a pointer into a time zone string, extract a rule in the form
  809. ** date[/time].  See POSIX section 8 for the format of "date" and "time".
  810. ** If a valid rule is not found, return NULL.
  811. ** Otherwise, return a pointer to the first character not part of the rule.
  812. */
  813.  
  814. static const char *
  815. getrule(strp, rulep)
  816. const char *            strp;
  817. register struct rule * const    rulep;
  818. {
  819.     if (*strp == 'J') {
  820.         /*
  821.         ** Julian day.
  822.         */
  823.         rulep->r_type = JULIAN_DAY;
  824.         ++strp;
  825.         strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
  826.     } else if (*strp == 'M') {
  827.         /*
  828.         ** Month, week, day.
  829.         */
  830.         rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
  831.         ++strp;
  832.         strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
  833.         if (strp == NULL)
  834.             return NULL;
  835.         if (*strp++ != '.')
  836.             return NULL;
  837.         strp = getnum(strp, &rulep->r_week, 1, 5);
  838.         if (strp == NULL)
  839.             return NULL;
  840.         if (*strp++ != '.')
  841.             return NULL;
  842.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
  843.     } else if (isdigit(*strp)) {
  844.         /*
  845.         ** Day of year.
  846.         */
  847.         rulep->r_type = DAY_OF_YEAR;
  848.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
  849.     } else    return NULL;        /* invalid format */
  850.     if (strp == NULL)
  851.         return NULL;
  852.     if (*strp == '/') {
  853.         /*
  854.         ** Time specified.
  855.         */
  856.         ++strp;
  857.         strp = getsecs(strp, &rulep->r_time);
  858.     } else    rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
  859.     return strp;
  860. }
  861.  
  862. /*
  863. ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
  864. ** year, a rule, and the offset from GMT at the time that rule takes effect,
  865. ** calculate the Epoch-relative time that rule takes effect.
  866. */
  867.  
  868. static time_t
  869. transtime(janfirst, year, rulep, offset)
  870. const time_t                janfirst;
  871. const int                year;
  872. register const struct rule * const    rulep;
  873. const long                offset;
  874. {
  875.     register int    leapyear;
  876.     register time_t    value;
  877.     register int    i;
  878.     int        d, m1, yy0, yy1, yy2, dow;
  879.  
  880.     leapyear = isleap(year);
  881.     switch (rulep->r_type) {
  882.  
  883.     case JULIAN_DAY:
  884.         /*
  885.         ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
  886.         ** years.
  887.         ** In non-leap years, or if the day number is 59 or less, just
  888.         ** add SECSPERDAY times the day number-1 to the time of
  889.         ** January 1, midnight, to get the day.
  890.         */
  891.         value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
  892.         if (leapyear && rulep->r_day >= 60)
  893.             value += SECSPERDAY;
  894.         break;
  895.  
  896.     case DAY_OF_YEAR:
  897.         /*
  898.         ** n - day of year.
  899.         ** Just add SECSPERDAY times the day number to the time of
  900.         ** January 1, midnight, to get the day.
  901.         */
  902.         value = janfirst + rulep->r_day * SECSPERDAY;
  903.         break;
  904.  
  905.     case MONTH_NTH_DAY_OF_WEEK:
  906.         /*
  907.         ** Mm.n.d - nth "dth day" of month m.
  908.         */
  909.         value = janfirst;
  910.         for (i = 0; i < rulep->r_mon - 1; ++i)
  911.             value += mon_lengths[leapyear][i] * SECSPERDAY;
  912.  
  913.         /*
  914.         ** Use Zeller's Congruence to get day-of-week of first day of
  915.         ** month.
  916.         */
  917.         m1 = (rulep->r_mon + 9) % 12 + 1;
  918.         yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
  919.         yy1 = yy0 / 100;
  920.         yy2 = yy0 % 100;
  921.         dow = ((26 * m1 - 2) / 10 +
  922.             1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
  923.         if (dow < 0)
  924.             dow += DAYSPERWEEK;
  925.  
  926.         /*
  927.         ** "dow" is the day-of-week of the first day of the month.  Get
  928.         ** the day-of-month (zero-origin) of the first "dow" day of the
  929.         ** month.
  930.         */
  931.         d = rulep->r_day - dow;
  932.         if (d < 0)
  933.             d += DAYSPERWEEK;
  934.         for (i = 1; i < rulep->r_week; ++i) {
  935.             if (d + DAYSPERWEEK >=
  936.                 mon_lengths[leapyear][rulep->r_mon - 1])
  937.                     break;
  938.             d += DAYSPERWEEK;
  939.         }
  940.  
  941.         /*
  942.         ** "d" is the day-of-month (zero-origin) of the day we want.
  943.         */
  944.         value += d * SECSPERDAY;
  945.         break;
  946.     }
  947.  
  948.     /*
  949.     ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
  950.     ** question.  To get the Epoch-relative time of the specified local
  951.     ** time on that day, add the transition time and the current offset
  952.     ** from GMT.
  953.     */
  954.     return value + rulep->r_time + offset;
  955. }
  956.  
  957. /*
  958. ** Given a POSIX section 8-style TZ string, fill in the rule tables as
  959. ** appropriate.
  960. */
  961.  
  962. static int
  963. tzparse(name, sp, lastditch)
  964. const char *            name;
  965. register struct state * const    sp;
  966. const int            lastditch;
  967. {
  968.     const char *            stdname;
  969.     const char *            dstname;
  970.     int                stdlen;
  971.     int                dstlen;
  972.     long                stdoffset;
  973.     long                dstoffset;
  974.     register time_t *        atp;
  975.     register unsigned char *    typep;
  976.     register char *            cp;
  977.     register int            load_result;
  978.  
  979.     stdname = name;
  980.     if (lastditch) {
  981.         stdlen = strlen(name);    /* length of standard zone name */
  982.         name += stdlen;
  983.         if (stdlen >= sizeof sp->chars)
  984.             stdlen = (sizeof sp->chars) - 1;
  985.     } else {
  986.         name = getzname(name);
  987.         stdlen = name - stdname;
  988.         if (stdlen < 3)
  989.             return -1;
  990.     }
  991.     if (*name == '\0')
  992.         stdoffset = 0;
  993.     else {
  994.         name = getoffset(name, &stdoffset);
  995.         if (name == NULL)
  996.             return -1;
  997.     }
  998.     load_result = tzload(TZDEFRULES, sp);
  999.     if (load_result != 0)
  1000.         sp->leapcnt = 0;        /* so, we're off a little */
  1001.     if (*name != '\0') {
  1002.         dstname = name;
  1003.         name = getzname(name);
  1004.         dstlen = name - dstname;    /* length of DST zone name */
  1005.         if (dstlen < 3)
  1006.             return -1;
  1007.         if (*name != '\0' && *name != ',' && *name != ';') {
  1008.             name = getoffset(name, &dstoffset);
  1009.             if (name == NULL)
  1010.                 return -1;
  1011.         } else    dstoffset = stdoffset - SECSPERHOUR;
  1012.         if (*name == ',' || *name == ';') {
  1013.             struct rule    start;
  1014.             struct rule    end;
  1015.             register int    year;
  1016.             register time_t    janfirst;
  1017.             time_t        starttime;
  1018.             time_t        endtime;
  1019.  
  1020.             ++name;
  1021.             if ((name = getrule(name, &start)) == NULL)
  1022.                 return -1;
  1023.             if (*name++ != ',')
  1024.                 return -1;
  1025.             if ((name = getrule(name, &end)) == NULL)
  1026.                 return -1;
  1027.             if (*name != '\0')
  1028.                 return -1;
  1029.             sp->typecnt = 2;    /* standard time and DST */
  1030.             /*
  1031.             ** Two transitions per year, from EPOCH_YEAR to 2037.
  1032.             */
  1033.             sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
  1034.             if (sp->timecnt > TZ_MAX_TIMES)
  1035.                 return -1;
  1036.             sp->ttis[0].tt_gmtoff = -dstoffset;
  1037.             sp->ttis[0].tt_isdst = 1;
  1038.             sp->ttis[0].tt_abbrind = stdlen + 1;
  1039.             sp->ttis[1].tt_gmtoff = -stdoffset;
  1040.             sp->ttis[1].tt_isdst = 0;
  1041.             sp->ttis[1].tt_abbrind = 0;
  1042.             atp = sp->ats;
  1043.             typep = sp->types;
  1044.             janfirst = 0;
  1045.             for (year = EPOCH_YEAR; year <= 2037; ++year) {
  1046.                 starttime = transtime(janfirst, year, &start,
  1047.                     stdoffset);
  1048.                 endtime = transtime(janfirst, year, &end,
  1049.                     dstoffset);
  1050.                 if (starttime > endtime) {
  1051.                     *atp++ = endtime;
  1052.                     *typep++ = 1;    /* DST ends */
  1053.                     *atp++ = starttime;
  1054.                     *typep++ = 0;    /* DST begins */
  1055.                 } else {
  1056.                     *atp++ = starttime;
  1057.                     *typep++ = 0;    /* DST begins */
  1058.                     *atp++ = endtime;
  1059.                     *typep++ = 1;    /* DST ends */
  1060.                 }
  1061.                 janfirst +=
  1062.                     year_lengths[isleap(year)] * SECSPERDAY;
  1063.             }
  1064.         } else {
  1065.             int        sawstd;
  1066.             int        sawdst;
  1067.             long        stdfix;
  1068.             long        dstfix;
  1069.             long        oldfix;
  1070.             int        isdst;
  1071.             register int    i;
  1072.  
  1073.             if (*name != '\0')
  1074.                 return -1;
  1075.             if (load_result != 0)
  1076.                 return -1;
  1077.             /*
  1078.             ** Compute the difference between the real and
  1079.             ** prototype standard and summer time offsets
  1080.             ** from GMT, and put the real standard and summer
  1081.             ** time offsets into the rules in place of the
  1082.             ** prototype offsets.
  1083.             */
  1084.             sawstd = FALSE;
  1085.             sawdst = FALSE;
  1086.             stdfix = 0;
  1087.             dstfix = 0;
  1088.             for (i = 0; i < sp->typecnt; ++i) {
  1089.                 if (sp->ttis[i].tt_isdst) {
  1090.                     oldfix = dstfix;
  1091.                     dstfix =
  1092.                         sp->ttis[i].tt_gmtoff + dstoffset;
  1093.                     if (sawdst && (oldfix != dstfix))
  1094.                         return -1;
  1095.                     sp->ttis[i].tt_gmtoff = -dstoffset;
  1096.                     sp->ttis[i].tt_abbrind = stdlen + 1;
  1097.                     sawdst = TRUE;
  1098.                 } else {
  1099.                     oldfix = stdfix;
  1100.                     stdfix =
  1101.                         sp->ttis[i].tt_gmtoff + stdoffset;
  1102.                     if (sawstd && (oldfix != stdfix))
  1103.                         return -1;
  1104.                     sp->ttis[i].tt_gmtoff = -stdoffset;
  1105.                     sp->ttis[i].tt_abbrind = 0;
  1106.                     sawstd = TRUE;
  1107.                 }
  1108.             }
  1109.             /*
  1110.             ** Make sure we have both standard and summer time.
  1111.             */
  1112.             if (!sawdst || !sawstd)
  1113.                 return -1;
  1114.             /*
  1115.             ** Now correct the transition times by shifting
  1116.             ** them by the difference between the real and
  1117.             ** prototype offsets.  Note that this difference
  1118.             ** can be different in standard and summer time;
  1119.             ** the prototype probably has a 1-hour difference
  1120.             ** between standard and summer time, but a different
  1121.             ** difference can be specified in TZ.
  1122.             */
  1123.             isdst = FALSE;    /* we start in standard time */
  1124.             for (i = 0; i < sp->timecnt; ++i) {
  1125.                 register const struct ttinfo *    ttisp;
  1126.  
  1127.                 /*
  1128.                 ** If summer time is in effect, and the
  1129.                 ** transition time was not specified as
  1130.                 ** standard time, add the summer time
  1131.                 ** offset to the transition time;
  1132.                 ** otherwise, add the standard time offset
  1133.                 ** to the transition time.
  1134.                 */
  1135.                 ttisp = &sp->ttis[sp->types[i]];
  1136.                 sp->ats[i] +=
  1137.                     (isdst && !ttisp->tt_ttisstd) ?
  1138.                         dstfix : stdfix;
  1139.                 isdst = ttisp->tt_isdst;
  1140.             }
  1141.         }
  1142.     } else {
  1143.         dstlen = 0;
  1144.         sp->typecnt = 1;        /* only standard time */
  1145.         sp->timecnt = 0;
  1146.         sp->ttis[0].tt_gmtoff = -stdoffset;
  1147.         sp->ttis[0].tt_isdst = 0;
  1148.         sp->ttis[0].tt_abbrind = 0;
  1149.     }
  1150.     sp->charcnt = stdlen + 1;
  1151.     if (dstlen != 0)
  1152.         sp->charcnt += dstlen + 1;
  1153.     if (sp->charcnt > sizeof sp->chars)
  1154.         return -1;
  1155.     cp = sp->chars;
  1156.     (void) strncpy(cp, stdname, stdlen);
  1157.     cp += stdlen;
  1158.     *cp++ = '\0';
  1159.     if (dstlen != 0) {
  1160.         (void) strncpy(cp, dstname, dstlen);
  1161.         *(cp + dstlen) = '\0';
  1162.     }
  1163.     return 0;
  1164. }
  1165.  
  1166. static void
  1167. gmtload(sp)
  1168. struct state * const    sp;
  1169. {
  1170.     if (tzload(GMT, sp) != 0)
  1171.         (void) tzparse(GMT, sp, TRUE);
  1172. }
  1173.  
  1174. #ifndef STD_INSPIRED
  1175. static
  1176. #endif /* !defined STD_INSPIRED */
  1177. void
  1178. tzsetwall()
  1179. {
  1180.     lcl_is_set = TRUE;
  1181. #ifdef ALL_STATE
  1182.     if (lclptr == NULL) {
  1183.         lclptr = (struct state *) malloc(sizeof *lclptr);
  1184.         if (lclptr == NULL) {
  1185.             settzname();    /* all we can do */
  1186.             return;
  1187.         }
  1188.     }
  1189. #endif /* defined ALL_STATE */
  1190.     if (tzload((char *) NULL, lclptr) != 0)
  1191.         gmtload(lclptr);
  1192.     settzname();
  1193. }
  1194.  
  1195. void
  1196. tzset()
  1197. {
  1198.     register const char *    name;
  1199.  
  1200.     name = getenv("TZ");
  1201.     if (name == NULL) {
  1202.         tzsetwall();
  1203.         return;
  1204.     }
  1205.     lcl_is_set = TRUE;
  1206. #ifdef ALL_STATE
  1207.     if (lclptr == NULL) {
  1208.         lclptr = (struct state *) malloc(sizeof *lclptr);
  1209.         if (lclptr == NULL) {
  1210.             settzname();    /* all we can do */
  1211.             return;
  1212.         }
  1213.     }
  1214. #endif /* defined ALL_STATE */
  1215.     if (*name == '\0') {
  1216.         /*
  1217.         ** User wants it fast rather than right.
  1218.         */
  1219.         lclptr->leapcnt = 0;        /* so, we're off a little */
  1220.         lclptr->timecnt = 0;
  1221.         lclptr->ttis[0].tt_gmtoff = 0;
  1222.         lclptr->ttis[0].tt_abbrind = 0;
  1223.         (void) strcpy(lclptr->chars, GMT);
  1224.     } else if (tzload(name, lclptr) != 0)
  1225.         if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
  1226.             (void) tzparse(name, lclptr, TRUE);
  1227.     settzname();
  1228. }
  1229.  
  1230. /*
  1231. ** The easy way to behave "as if no library function calls" localtime
  1232. ** is to not call it--so we drop its guts into "localsub", which can be
  1233. ** freely called.  (And no, the PANS doesn't require the above behavior--
  1234. ** but it *is* desirable.)
  1235. **
  1236. ** The unused offset argument is for the benefit of mktime variants.
  1237. */
  1238.  
  1239. /*ARGSUSED*/
  1240. static void
  1241. localsub(timep, offset, tmp)
  1242. const time_t * const    timep;
  1243. const long        offset;
  1244. struct tm * const    tmp;
  1245. {
  1246.     register const struct state *    sp;
  1247.     register const struct ttinfo *    ttisp;
  1248.     register int            i;
  1249.     const time_t            t = *timep;
  1250.  
  1251.     if (!lcl_is_set)
  1252.         tzset();
  1253.     sp = lclptr;
  1254. #ifdef ALL_STATE
  1255.     if (sp == NULL) {
  1256.         gmtsub(timep, offset, tmp);
  1257.         return;
  1258.     }
  1259. #endif /* defined ALL_STATE */
  1260.     if (sp->timecnt == 0 || t < sp->ats[0]) {
  1261.         i = 0;
  1262.         while (sp->ttis[i].tt_isdst)
  1263.             if (++i >= sp->typecnt) {
  1264.                 i = 0;
  1265.                 break;
  1266.             }
  1267.     } else {
  1268.         for (i = 1; i < sp->timecnt; ++i)
  1269.             if (t < sp->ats[i])
  1270.                 break;
  1271.         i = sp->types[i - 1];
  1272.     }
  1273.     ttisp = &sp->ttis[i];
  1274.     /*
  1275.     ** To get (wrong) behavior that's compatible with System V Release 2.0
  1276.     ** you'd replace the statement below with
  1277.     **    t += ttisp->tt_gmtoff;
  1278.     **    timesub(&t, 0L, sp, tmp);
  1279.     */
  1280.     timesub(&t, ttisp->tt_gmtoff, sp, tmp);
  1281.     tmp->tm_isdst = ttisp->tt_isdst;
  1282.     tzname[tmp->tm_isdst] = (char *) &sp->chars[ttisp->tt_abbrind];
  1283. #ifdef TM_ZONE
  1284.     tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
  1285. #endif /* defined TM_ZONE */
  1286. }
  1287.  
  1288. struct tm *
  1289. localtime(timep)
  1290. const time_t * const    timep;
  1291. {
  1292.     static struct tm    tm;
  1293.  
  1294.     localsub(timep, 0L, &tm);
  1295.     return &tm;
  1296. }
  1297.  
  1298. /*
  1299. ** gmtsub is to gmtime as localsub is to localtime.
  1300. */
  1301.  
  1302. static void
  1303. gmtsub(timep, offset, tmp)
  1304. const time_t * const    timep;
  1305. const long        offset;
  1306. struct tm * const    tmp;
  1307. {
  1308.     if (!gmt_is_set) {
  1309.         gmt_is_set = TRUE;
  1310. #ifdef ALL_STATE
  1311.         gmtptr = (struct state *) malloc(sizeof *gmtptr);
  1312.         if (gmtptr != NULL)
  1313. #endif /* defined ALL_STATE */
  1314.             gmtload(gmtptr);
  1315.     }
  1316.     timesub(timep, offset, gmtptr, tmp);
  1317. #ifdef TM_ZONE
  1318.     /*
  1319.     ** Could get fancy here and deliver something such as
  1320.     ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
  1321.     ** but this is no time for a treasure hunt.
  1322.     */
  1323.     if (offset != 0)
  1324.         tmp->TM_ZONE = WILDABBR;
  1325.     else {
  1326. #ifdef ALL_STATE
  1327.         if (gmtptr == NULL)
  1328.             tmp->TM_ZONE = GMT;
  1329.         else    tmp->TM_ZONE = gmtptr->chars;
  1330. #endif /* defined ALL_STATE */
  1331. #ifndef ALL_STATE
  1332.         tmp->TM_ZONE = gmtptr->chars;
  1333. #endif /* State Farm */
  1334.     }
  1335. #endif /* defined TM_ZONE */
  1336. }
  1337.  
  1338. struct tm *
  1339. gmtime(timep)
  1340. const time_t * const    timep;
  1341. {
  1342.     static struct tm    tm;
  1343.  
  1344.     gmtsub(timep, 0L, &tm);
  1345.     return &tm;
  1346. }
  1347.  
  1348. #ifdef STD_INSPIRED
  1349.  
  1350. struct tm *
  1351. offtime(timep, offset)
  1352. const time_t * const    timep;
  1353. const long        offset;
  1354. {
  1355.     static struct tm    tm;
  1356.  
  1357.     gmtsub(timep, offset, &tm);
  1358.     return &tm;
  1359. }
  1360.  
  1361. #endif /* defined STD_INSPIRED */
  1362.  
  1363. static void
  1364. timesub(timep, offset, sp, tmp)
  1365. const time_t * const            timep;
  1366. const long                offset;
  1367. register const struct state * const    sp;
  1368. register struct tm * const        tmp;
  1369. {
  1370.     register const struct lsinfo *    lp;
  1371.     register long            days;
  1372.     register long            rem;
  1373.     register int            y;
  1374.     register int            yleap;
  1375.     register const int *        ip;
  1376.     register long            corr;
  1377.     register int            hit;
  1378.     register int            i;
  1379.  
  1380.     corr = 0;
  1381.     hit = FALSE;
  1382. #ifdef ALL_STATE
  1383.     i = (sp == NULL) ? 0 : sp->leapcnt;
  1384. #endif /* defined ALL_STATE */
  1385. #ifndef ALL_STATE
  1386.     i = sp->leapcnt;
  1387. #endif /* State Farm */
  1388.     while (--i >= 0) {
  1389.         lp = &sp->lsis[i];
  1390.         if (*timep >= lp->ls_trans) {
  1391.             if (*timep == lp->ls_trans)
  1392.                 hit = ((i == 0 && lp->ls_corr > 0) ||
  1393.                     lp->ls_corr > sp->lsis[i - 1].ls_corr);
  1394.             corr = lp->ls_corr;
  1395.             break;
  1396.         }
  1397.     }
  1398.     days = *timep / SECSPERDAY;
  1399.     rem = *timep % SECSPERDAY;
  1400. #ifdef mc68k
  1401.     if (*timep == 0x80000000) {
  1402.         /*
  1403.         ** A 3B1 muffs the division on the most negative number.
  1404.         */
  1405.         days = -24855;
  1406.         rem = -11648;
  1407.     }
  1408. #endif /* mc68k */
  1409.     rem += (offset - corr);
  1410.     while (rem < 0) {
  1411.         rem += SECSPERDAY;
  1412.         --days;
  1413.     }
  1414.     while (rem >= SECSPERDAY) {
  1415.         rem -= SECSPERDAY;
  1416.         ++days;
  1417.     }
  1418.     tmp->tm_hour = (int) (rem / SECSPERHOUR);
  1419.     rem = rem % SECSPERHOUR;
  1420.     tmp->tm_min = (int) (rem / SECSPERMIN);
  1421.     tmp->tm_sec = (int) (rem % SECSPERMIN);
  1422.     if (hit)
  1423.         /*
  1424.         ** A positive leap second requires a special
  1425.         ** representation.  This uses "... ??:59:60".
  1426.         */
  1427.         ++(tmp->tm_sec);
  1428.     tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
  1429.     if (tmp->tm_wday < 0)
  1430.         tmp->tm_wday += DAYSPERWEEK;
  1431.     y = EPOCH_YEAR;
  1432.     if (days >= 0)
  1433.         for ( ; ; ) {
  1434.             yleap = isleap(y);
  1435.             if (days < (long) year_lengths[yleap])
  1436.                 break;
  1437.             ++y;
  1438.             days = days - (long) year_lengths[yleap];
  1439.         }
  1440.     else do {
  1441.         --y;
  1442.         yleap = isleap(y);
  1443.         days = days + (long) year_lengths[yleap];
  1444.     } while (days < 0);
  1445.     tmp->tm_year = y - TM_YEAR_BASE;
  1446.     tmp->tm_yday = (int) days;
  1447.     ip = mon_lengths[yleap];
  1448.     for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
  1449.         days = days - (long) ip[tmp->tm_mon];
  1450.     tmp->tm_mday = (int) (days + 1);
  1451.     tmp->tm_isdst = 0;
  1452. #ifdef TM_GMTOFF
  1453.     tmp->TM_GMTOFF = offset;
  1454. #endif /* defined TM_GMTOFF */
  1455. }
  1456.  
  1457. char *
  1458. ctime(timep)
  1459. const time_t * const    timep;
  1460. {
  1461.     return asctime(localtime(timep));
  1462. }
  1463.  
  1464. /*
  1465. ** Adapted from code provided by Robert Elz, who writes:
  1466. **    The "best" way to do mktime I think is based on an idea of Bob
  1467. **    Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
  1468. **    It does a binary search of the time_t space.  Since time_t's are
  1469. **    just 32 bits, its a max of 32 iterations (even at 64 bits it
  1470. **    would still be very reasonable).
  1471. */
  1472.  
  1473. #ifndef WRONG
  1474. #define WRONG    (-1)
  1475. #endif /* !defined WRONG */
  1476.  
  1477. static void
  1478. normalize(tensptr, unitsptr, base)
  1479. int * const    tensptr;
  1480. int * const    unitsptr;
  1481. const int    base;
  1482. {
  1483.     if (*unitsptr >= base) {
  1484.         *tensptr += *unitsptr / base;
  1485.         *unitsptr %= base;
  1486.     } else if (*unitsptr < 0) {
  1487.         --*tensptr;
  1488.         *unitsptr += base;
  1489.         if (*unitsptr < 0) {
  1490.             *tensptr -= 1 + (-*unitsptr) / base;
  1491.             *unitsptr = base - (-*unitsptr) % base;
  1492.         }
  1493.     }
  1494. }
  1495.  
  1496. static int
  1497. tmcomp(atmp, btmp)
  1498. register const struct tm * const atmp;
  1499. register const struct tm * const btmp;
  1500. {
  1501.     register int    result;
  1502.  
  1503.     if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
  1504.         (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
  1505.         (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
  1506.         (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
  1507.         (result = (atmp->tm_min - btmp->tm_min)) == 0)
  1508.             result = atmp->tm_sec - btmp->tm_sec;
  1509.     return result;
  1510. }
  1511.  
  1512. static time_t
  1513. time2(tmp, funcp, offset, okayp)
  1514. struct tm * const    tmp;
  1515. void (* const        funcp)();
  1516. const long        offset;
  1517. int * const        okayp;
  1518. {
  1519.     register const struct state *    sp;
  1520.     register int            dir;
  1521.     register int            bits;
  1522.     register int            i, j ;
  1523.     register int            saved_seconds;
  1524.     time_t                newt;
  1525.     time_t                t;
  1526.     struct tm            yourtm, mytm;
  1527.  
  1528.     *okayp = FALSE;
  1529.     yourtm = *tmp;
  1530.     if (yourtm.tm_sec >= SECSPERMIN + 2 || yourtm.tm_sec < 0)
  1531.         normalize(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN);
  1532.     normalize(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR);
  1533.     normalize(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY);
  1534.     normalize(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR);
  1535.     while (yourtm.tm_mday <= 0) {
  1536.         --yourtm.tm_year;
  1537.         yourtm.tm_mday +=
  1538.             year_lengths[isleap(yourtm.tm_year + TM_YEAR_BASE)];
  1539.     }
  1540.     for ( ; ; ) {
  1541.         i = mon_lengths[isleap(yourtm.tm_year +
  1542.             TM_YEAR_BASE)][yourtm.tm_mon];
  1543.         if (yourtm.tm_mday <= i)
  1544.             break;
  1545.         yourtm.tm_mday -= i;
  1546.         if (++yourtm.tm_mon >= MONSPERYEAR) {
  1547.             yourtm.tm_mon = 0;
  1548.             ++yourtm.tm_year;
  1549.         }
  1550.     }
  1551.     saved_seconds = yourtm.tm_sec;
  1552.     yourtm.tm_sec = 0;
  1553.     /*
  1554.     ** Calculate the number of magnitude bits in a time_t
  1555.     ** (this works regardless of whether time_t is
  1556.     ** signed or unsigned, though lint complains if unsigned).
  1557.     */
  1558.     for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
  1559.         ;
  1560.     /*
  1561.     ** If time_t is signed, then 0 is the median value,
  1562.     ** if time_t is unsigned, then 1 << bits is median.
  1563.     */
  1564.     t = (t < 0) ? 0 : ((time_t) 1 << bits);
  1565.     for ( ; ; ) {
  1566.         (*funcp)(&t, offset, &mytm);
  1567.         dir = tmcomp(&mytm, &yourtm);
  1568.         if (dir != 0) {
  1569.             if (bits-- < 0)
  1570.                 return WRONG;
  1571.             if (bits < 0)
  1572.                 --t;
  1573.             else if (dir > 0)
  1574.                 t -= (time_t) 1 << bits;
  1575.             else    t += (time_t) 1 << bits;
  1576.             continue;
  1577.         }
  1578.         if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
  1579.             break;
  1580.         /*
  1581.         ** Right time, wrong type.
  1582.         ** Hunt for right time, right type.
  1583.         ** It's okay to guess wrong since the guess
  1584.         ** gets checked.
  1585.         */
  1586.         sp = (const struct state *)
  1587.             ((funcp == localsub) ? lclptr : gmtptr);
  1588. #ifdef ALL_STATE
  1589.         if (sp == NULL)
  1590.             return WRONG;
  1591. #endif /* defined ALL_STATE */
  1592.         for (i = 0; i < sp->typecnt; ++i) {
  1593.             if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
  1594.                 continue;
  1595.             for (j = 0; j < sp->typecnt; ++j) {
  1596.                 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
  1597.                     continue;
  1598.                 newt = t + sp->ttis[j].tt_gmtoff -
  1599.                     sp->ttis[i].tt_gmtoff;
  1600.                 (*funcp)(&newt, offset, &mytm);
  1601.                 if (tmcomp(&mytm, &yourtm) != 0)
  1602.                     continue;
  1603.                 if (mytm.tm_isdst != yourtm.tm_isdst)
  1604.                     continue;
  1605.                 /*
  1606.                 ** We have a match.
  1607.                 */
  1608.                 t = newt;
  1609.                 goto label;
  1610.             }
  1611.         }
  1612.         return WRONG;
  1613.     }
  1614. label:
  1615.     t += saved_seconds;
  1616.     (*funcp)(&t, offset, tmp);
  1617.     *okayp = TRUE;
  1618.     return t;
  1619. }
  1620.  
  1621. static time_t
  1622. time1(tmp, funcp, offset)
  1623. struct tm * const    tmp;
  1624. void (* const        funcp)();
  1625. const long        offset;
  1626. {
  1627.     register time_t            t;
  1628.     register const struct state *    sp;
  1629.     register int            samei, otheri;
  1630.     int                okay;
  1631.  
  1632.     if (tmp->tm_isdst > 1)
  1633.         return WRONG;
  1634.     t = time2(tmp, funcp, offset, &okay);
  1635.     if (okay || tmp->tm_isdst < 0)
  1636.         return t;
  1637.     /*
  1638.     ** We're supposed to assume that somebody took a time of one type
  1639.     ** and did some math on it that yielded a "struct tm" that's bad.
  1640.     ** We try to divine the type they started from and adjust to the
  1641.     ** type they need.
  1642.     */
  1643.     sp = (const struct state *) ((funcp == localsub) ? lclptr : gmtptr);
  1644. #ifdef ALL_STATE
  1645.     if (sp == NULL)
  1646.         return WRONG;
  1647. #endif /* defined ALL_STATE */
  1648.     for (samei = 0; samei < sp->typecnt; ++samei) {
  1649.         if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
  1650.             continue;
  1651.         for (otheri = 0; otheri < sp->typecnt; ++otheri) {
  1652.             if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
  1653.                 continue;
  1654.             tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
  1655.                     sp->ttis[samei].tt_gmtoff;
  1656.             tmp->tm_isdst = !tmp->tm_isdst;
  1657.             t = time2(tmp, funcp, offset, &okay);
  1658.             if (okay)
  1659.                 return t;
  1660.             tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
  1661.                     sp->ttis[samei].tt_gmtoff;
  1662.             tmp->tm_isdst = !tmp->tm_isdst;
  1663.         }
  1664.     }
  1665.     return WRONG;
  1666. }
  1667.  
  1668. time_t
  1669. mktime(tmp)
  1670. struct tm * const    tmp;
  1671. {
  1672.     return time1(tmp, localsub, 0L);
  1673. }
  1674.  
  1675. #ifdef STD_INSPIRED
  1676.  
  1677. time_t
  1678. timelocal(tmp)
  1679. struct tm * const    tmp;
  1680. {
  1681.     return mktime(tmp);
  1682. }
  1683.  
  1684. time_t
  1685. timegm(tmp)
  1686. struct tm * const    tmp;
  1687. {
  1688.     return time1(tmp, gmtsub, 0L);
  1689. }
  1690.  
  1691. time_t
  1692. timeoff(tmp, offset)
  1693. struct tm * const    tmp;
  1694. const long        offset;
  1695. {
  1696.  
  1697.     return time1(tmp, gmtsub, offset);
  1698. }
  1699.  
  1700. #endif /* defined STD_INSPIRED */
  1701.  
  1702. #ifdef CMUCS
  1703.  
  1704. /*
  1705. ** The following is supplied for compatibility with
  1706. ** previous versions of the CMUCS runtime library.
  1707. */
  1708.  
  1709. long
  1710. gtime(tmp)
  1711. struct tm * const    tmp;
  1712. {
  1713.     const time_t    t = mktime(tmp);
  1714.  
  1715.     if (t == WRONG)
  1716.         return -1;
  1717.     return t;
  1718. }
  1719.  
  1720. #endif /* defined CMUCS */
  1721. End of localtime.c
  1722. echo file 'asctime.c' >&2
  1723. cat >'asctime.c' <<'End of asctime.c'
  1724. #ifndef lint
  1725. #ifndef NOID
  1726. static char    elsieid[] = "@(#)asctime.c    7.1";
  1727. #endif /* !defined NOID */
  1728. #endif /* !defined lint */
  1729.  
  1730. /*LINTLIBRARY*/
  1731.  
  1732. #include "private.h"
  1733. #include "tzfile.h"
  1734.  
  1735. /*
  1736. ** A la X3J11, with core dump avoidance.
  1737. */
  1738.  
  1739. char *
  1740. asctime(timeptr)
  1741. register const struct tm *    timeptr;
  1742. {
  1743.     static const char    wday_name[DAYSPERWEEK][3] = {
  1744.         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  1745.     };
  1746.     static const char    mon_name[MONSPERYEAR][3] = {
  1747.         "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  1748.         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1749.     };
  1750.     static char        result[26];
  1751.     register const char *    wn;
  1752.     register const char *    mn;
  1753.  
  1754.     if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK)
  1755.         wn = "???";
  1756.     else    wn = wday_name[timeptr->tm_wday];
  1757.     if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR)
  1758.         mn = "???";
  1759.     else    mn = mon_name[timeptr->tm_mon];
  1760.     (void) sprintf(result, "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n",
  1761.         wn, mn,
  1762.         timeptr->tm_mday, timeptr->tm_hour,
  1763.         timeptr->tm_min, timeptr->tm_sec,
  1764.         TM_YEAR_BASE + timeptr->tm_year);
  1765.     return result;
  1766. }
  1767. End of asctime.c
  1768. echo file 'difftime.c' >&2
  1769. cat >'difftime.c' <<'End of difftime.c'
  1770. #ifndef lint
  1771. #ifndef NOID
  1772. static char    elsieid[] = "@(#)difftime.c    7.1";
  1773. #endif /* !defined NOID */
  1774. #endif /* !defined lint */
  1775.  
  1776. /*LINTLIBRARY*/
  1777.  
  1778. #include "private.h"
  1779.  
  1780. double
  1781. difftime(time1, time0)
  1782. const time_t    time1;
  1783. const time_t    time0;
  1784. {
  1785.     return time1 - time0;
  1786. }
  1787. End of difftime.c
  1788. exit
  1789.