home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / libz / localtime.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-09-10  |  7.6 KB  |  386 lines

  1. #
  2.  
  3. /*LINTLIBRARY*/
  4.  
  5. /*
  6. ** sys/types.h is included to get time_t.
  7. */
  8.  
  9. #include "sys/types.h"
  10. #include "tzfile.h"
  11. #include "time.h"
  12.  
  13. #ifndef MAXPATHLEN
  14. #include "sys/param.h"
  15. #ifndef MAXPATHLEN
  16. #define MAXPATHLEN    1024
  17. #endif /* !MAXPATHLEN */
  18. #endif /* !MAXPATHLEN */
  19.  
  20. #ifndef lint
  21. #ifndef NOID
  22. static char    sccsid[] = "@(#)localtime.c    3.2";
  23. #endif /* !NOID */
  24. #endif /* !lint */
  25.  
  26. #ifndef TRUE
  27. #define TRUE        1
  28. #define FALSE        0
  29. #endif /* !TRUE */
  30.  
  31. extern char *        getenv();
  32. extern char *        strcpy();
  33. extern char *        strcat();
  34. #ifdef STD_INSPIRED
  35. struct tm *        offtime();
  36. #else /* !STD_INSPIRED */
  37. static struct tm *    offtime();
  38. #endif /* !STD_INSPIRED */
  39.  
  40. struct ttinfo {                /* time type information */
  41.     long        tt_gmtoff;    /* GMT offset in seconds */
  42.     int        tt_isdst;    /* used to set tm_isdst */
  43.     int        tt_abbrind;    /* abbreviation list index */
  44. };
  45.  
  46. struct state {
  47.     int        timecnt;
  48.     int        typecnt;
  49.     int        charcnt;
  50.     time_t        ats[TZ_MAX_TIMES];
  51.     unsigned char    types[TZ_MAX_TIMES];
  52.     struct ttinfo    ttis[TZ_MAX_TYPES];
  53.     char        chars[TZ_MAX_CHARS + 1];
  54. };
  55.  
  56. static struct state    s;
  57.  
  58. static int        tz_is_set;
  59.  
  60. char *            tzname[2] = {
  61.     "GMT",
  62.     "GMT"
  63. };
  64.  
  65. #ifdef USG_COMPAT
  66. time_t            timezone = 0;
  67. int            daylight = 0;
  68. #endif /* USG_COMPAT */
  69.  
  70. #ifdef TZA_COMPAT
  71. char *            tz_abbr;    /* compatibility w/older versions */
  72. #endif /* TZA_COMPAT */
  73.  
  74. static long
  75. detzcode(codep)
  76. char *    codep;
  77. {
  78.     register long    result;
  79.     register int    i;
  80.  
  81.     result = 0;
  82.     for (i = 0; i < 4; ++i)
  83.         result = (result << 8) | (codep[i] & 0xff);
  84.     return result;
  85. }
  86.  
  87. static
  88. tzload(name)
  89. register char *    name;
  90. {
  91.     register int    i;
  92.     register int    fid;
  93.  
  94.     if (name == 0 && (name = TZDEFAULT) == 0)
  95.         return -1;
  96.     {
  97.         register char *    p;
  98.         register int    doaccess;
  99.         char        fullname[MAXPATHLEN];
  100.  
  101.         doaccess = name[0] == '/';
  102.         if (!doaccess) {
  103.             if ((p = TZDIR) == 0)
  104.                 return -1;
  105.             if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
  106.                 return -1;
  107.             (void) strcpy(fullname, p);
  108.             (void) strcat(fullname, "/");
  109.             (void) strcat(fullname, name);
  110.             /*
  111.             ** Set doaccess if '.' (as in "../") shows up in name.
  112.             */
  113.             while (*name != '\0')
  114.                 if (*name++ == '.')
  115.                     doaccess = TRUE;
  116.             name = fullname;
  117.         }
  118.         if (doaccess && access(name, 4) != 0)
  119.             return -1;
  120.         if ((fid = open(name, 0)) == -1)
  121.             return -1;
  122.     }
  123.     {
  124.         register char *            p;
  125.         register struct tzhead *    tzhp;
  126.         char                buf[sizeof s];
  127.  
  128.         i = read(fid, buf, sizeof buf);
  129.         if (close(fid) != 0 || i < sizeof *tzhp)
  130.             return -1;
  131.         tzhp = (struct tzhead *) buf;
  132.         s.timecnt = (int) detzcode(tzhp->tzh_timecnt);
  133.         s.typecnt = (int) detzcode(tzhp->tzh_typecnt);
  134.         s.charcnt = (int) detzcode(tzhp->tzh_charcnt);
  135.         if (s.timecnt > TZ_MAX_TIMES ||
  136.             s.typecnt == 0 ||
  137.             s.typecnt > TZ_MAX_TYPES ||
  138.             s.charcnt > TZ_MAX_CHARS)
  139.                 return -1;
  140.         if (i < sizeof *tzhp +
  141.             s.timecnt * (4 + sizeof (char)) +
  142.             s.typecnt * (4 + 2 * sizeof (char)) +
  143.             s.charcnt * sizeof (char))
  144.                 return -1;
  145.         p = buf + sizeof *tzhp;
  146.         for (i = 0; i < s.timecnt; ++i) {
  147.             s.ats[i] = detzcode(p);
  148.             p += 4;
  149.         }
  150.         for (i = 0; i < s.timecnt; ++i)
  151.             s.types[i] = (unsigned char) *p++;
  152.         for (i = 0; i < s.typecnt; ++i) {
  153.             register struct ttinfo *    ttisp;
  154.  
  155.             ttisp = &s.ttis[i];
  156.             ttisp->tt_gmtoff = detzcode(p);
  157.             p += 4;
  158.             ttisp->tt_isdst = (unsigned char) *p++;
  159.             ttisp->tt_abbrind = (unsigned char) *p++;
  160.         }
  161.         for (i = 0; i < s.charcnt; ++i)
  162.             s.chars[i] = *p++;
  163.         s.chars[i] = '\0';    /* ensure '\0' at end */
  164.     }
  165.     /*
  166.     ** Check that all the local time type indices are valid.
  167.     */
  168.     for (i = 0; i < s.timecnt; ++i)
  169.         if (s.types[i] >= s.typecnt)
  170.             return -1;
  171.     /*
  172.     ** Check that all abbreviation indices are valid.
  173.     */
  174.     for (i = 0; i < s.typecnt; ++i)
  175.         if (s.ttis[i].tt_abbrind >= s.charcnt)
  176.             return -1;
  177.     /*
  178.     ** Set tzname elements to initial values.
  179.     */
  180.     tzname[0] = tzname[1] = &s.chars[0];
  181. #ifdef USG_COMPAT
  182.     timezone = -s.ttis[0].tt_gmtoff;
  183.     daylight = 0;
  184. #endif /* USG_COMPAT */
  185.     for (i = 1; i < s.typecnt; ++i) {
  186.         register struct ttinfo *    ttisp;
  187.  
  188.         ttisp = &s.ttis[i];
  189.         if (ttisp->tt_isdst) {
  190.             tzname[1] = &s.chars[ttisp->tt_abbrind];
  191. #ifdef USG_COMPAT
  192.             daylight = 1;
  193. #endif /* USG_COMPAT */ 
  194.         } else {
  195.             tzname[0] = &s.chars[ttisp->tt_abbrind];
  196. #ifdef USG_COMPAT
  197.             timezone = -ttisp->tt_gmtoff;
  198. #endif /* USG_COMPAT */ 
  199.         }
  200.     }
  201.     return 0;
  202. }
  203.  
  204. static
  205. tzsetgmt()
  206. {
  207.     s.timecnt = 0;
  208.     s.ttis[0].tt_gmtoff = 0;
  209.     s.ttis[0].tt_abbrind = 0;
  210.     (void) strcpy(s.chars, "GMT");
  211.     tzname[0] = tzname[1] = s.chars;
  212. #ifdef USG_COMPAT
  213.     timezone = 0;
  214.     daylight = 0;
  215. #endif /* USG_COMPAT */
  216. }
  217.  
  218. void
  219. tzset()
  220. {
  221.     register char *    name;
  222.  
  223.     tz_is_set = TRUE;
  224.     name = getenv("TZ");
  225.     if (name != 0 && *name == '\0')
  226.         tzsetgmt();        /* GMT by request */
  227.     else if (tzload(name) != 0)
  228.         tzsetgmt();
  229. }
  230.  
  231. void
  232. tzsetwall()
  233. {
  234.     tz_is_set = TRUE;
  235.     if (tzload((char *) 0) != 0)
  236.         tzsetgmt();
  237. }
  238.  
  239. struct tm *
  240. localtime(timep)
  241. time_t *    timep;
  242. {
  243.     register struct ttinfo *    ttisp;
  244.     register struct tm *        tmp;
  245.     register int            i;
  246.     time_t                t;
  247.  
  248.     if (!tz_is_set)
  249.         (void) tzset();
  250.     t = *timep;
  251.     if (s.timecnt == 0 || t < s.ats[0]) {
  252.         i = 0;
  253.         while (s.ttis[i].tt_isdst)
  254.             if (++i >= s.timecnt) {
  255.                 i = 0;
  256.                 break;
  257.             }
  258.     } else {
  259.         for (i = 1; i < s.timecnt; ++i)
  260.             if (t < s.ats[i])
  261.                 break;
  262.         i = s.types[i - 1];
  263.     }
  264.     ttisp = &s.ttis[i];
  265.     /*
  266.     ** To get (wrong) behavior that's compatible with System V Release 2.0
  267.     ** you'd replace the statement below with
  268.     **    tmp = offtime((time_t) (t + ttisp->tt_gmtoff), 0L);
  269.     */
  270.     tmp = offtime(&t, ttisp->tt_gmtoff);
  271.     tmp->tm_isdst = ttisp->tt_isdst;
  272.     tzname[tmp->tm_isdst] = &s.chars[ttisp->tt_abbrind];
  273. #ifdef KRE_COMPAT
  274.     tmp->tm_zone = &s.chars[ttisp->tt_abbrind];
  275. #endif /* KRE_COMPAT */
  276. #ifdef TZA_COMPAT
  277.     tz_abbr = &s.chars[ttisp->tt_abbrind];
  278. #endif /* TZA_COMPAT */
  279.     return tmp;
  280. }
  281.  
  282. struct tm *
  283. gmtime(clock)
  284. time_t *    clock;
  285. {
  286.     register struct tm *    tmp;
  287.  
  288.     tmp = offtime(clock, 0L);
  289.     tzname[0] = "GMT";
  290. #ifdef KRE_COMPAT
  291.     tmp->tm_zone = "GMT";        /* UCT ? */
  292. #endif /* KRE_COMPAT */
  293.     return tmp;
  294. }
  295.  
  296. static int    mon_lengths[2][MONS_PER_YEAR] = {
  297.     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
  298.     31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  299. };
  300.  
  301. static int    year_lengths[2] = {
  302.     DAYS_PER_NYEAR, DAYS_PER_LYEAR
  303. };
  304.  
  305. #ifdef STD_INSPIRED
  306. struct tm *
  307. #else /* !STD_INSPIRED */
  308. static struct tm *
  309. #endif /* !STD_INSPIRED */
  310. offtime(clock, offset)
  311. time_t *    clock;
  312. long        offset;
  313. {
  314.     register struct tm *    tmp;
  315.     register long        days;
  316.     register long        rem;
  317.     register int        y;
  318.     register int        yleap;
  319.     register int *        ip;
  320.     static struct tm    tm;
  321.  
  322.     tmp = &tm;
  323.     days = *clock / SECS_PER_DAY;
  324.     rem = *clock % SECS_PER_DAY;
  325.     rem += offset;
  326.     while (rem < 0) {
  327.         rem += SECS_PER_DAY;
  328.         --days;
  329.     }
  330.     while (rem >= SECS_PER_DAY) {
  331.         rem -= SECS_PER_DAY;
  332.         ++days;
  333.     }
  334.     tmp->tm_hour = (int) (rem / SECS_PER_HOUR);
  335.     rem = rem % SECS_PER_HOUR;
  336.     tmp->tm_min = (int) (rem / SECS_PER_MIN);
  337.     tmp->tm_sec = (int) (rem % SECS_PER_MIN);
  338.     tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYS_PER_WEEK);
  339.     if (tmp->tm_wday < 0)
  340.         tmp->tm_wday += DAYS_PER_WEEK;
  341.     y = EPOCH_YEAR;
  342.     if (days >= 0)
  343.         for ( ; ; ) {
  344.             yleap = isleap(y);
  345.             if (days < (long) year_lengths[yleap])
  346.                 break;
  347.             ++y;
  348.             days = days - (long) year_lengths[yleap];
  349.         }
  350.     else do {
  351.         --y;
  352.         yleap = isleap(y);
  353.         days = days + (long) year_lengths[yleap];
  354.     } while (days < 0);
  355.     tmp->tm_year = y - TM_YEAR_BASE;
  356.     tmp->tm_yday = (int) days;
  357.     ip = mon_lengths[yleap];
  358.     for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
  359.         days = days - (long) ip[tmp->tm_mon];
  360.     tmp->tm_mday = (int) (days + 1);
  361.     tmp->tm_isdst = 0;
  362. #ifdef KRE_COMPAT
  363.     tmp->tm_zone = "";
  364.     tmp->tm_gmtoff = offset;
  365. #endif /* KRE_COMPAT */
  366.     return tmp;
  367. }
  368.  
  369. #ifdef BSD_COMPAT
  370.  
  371. /*
  372. ** If ctime and localtime aren't in the same file on 4.3BSD systems,
  373. ** you can run into compilation problems--take
  374. **    cc date.c -lz
  375. ** (please).
  376. */
  377.  
  378. char *
  379. ctime(timep)
  380. time_t *    timep;
  381. {
  382.     return asctime(localtime(timep));
  383. }
  384.  
  385. #endif /* BSD_COMPAT */
  386.