home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / e20313sr.zip / emacs / 20.3.1 / src / vmstime.c < prev    next >
C/C++ Source or Header  |  1999-07-31  |  10KB  |  378 lines

  1. /* Time support for VMS.
  2.    Copyright (C) 1993 Free Software Foundation.
  3.  
  4. This file is part of GNU Emacs.
  5.  
  6. GNU Emacs is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. GNU Emacs is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU Emacs; see the file COPYING.  If not, write to
  18. the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19. Boston, MA 02111-1307, USA.  */
  20.  
  21. #include <config.h>
  22. #include "vmstime.h"
  23.  
  24. long timezone=0;
  25. int daylight=0;
  26.  
  27. static char tzname_default[20]="";
  28. static char tzname_dst[20]="";
  29.  
  30. char *tzname[2] = { tzname_default, tzname_dst };
  31.  
  32. static long internal_daylight=0;
  33. static char daylight_set=0;
  34.  
  35. static long read_time(const char *nptr, const char **endptr,
  36.               int sign_allowed_p)
  37. {
  38.   int t;
  39.  
  40.   *endptr = nptr;
  41.  
  42.   /* This routine trusts the user very much, and does no checks!
  43.       The only exception is this: */
  44.   if (!sign_allowed_p && (*nptr == '-' || *nptr == '+'))
  45.     return 0;
  46.  
  47.   t = strtol(*endptr, endptr, 10) * 3600;
  48.   if (**endptr != ':' || **endptr == '+' || **endptr == '-')
  49.     return t;
  50.   (*endptr)++;
  51.  
  52.   t = t + strtol(*endptr, endptr, 10) * 60;
  53.   if (**endptr != ':' || **endptr == '+' || **endptr == '-')
  54.     return t;
  55.   (*endptr)++;
  56.  
  57.   return t + strtol(*endptr, endptr, 10);
  58. }
  59.  
  60. static void read_dst_time(const char *nptr, const char **endptr,
  61.               int *m, int *n, int *d,
  62.               int *leap_p)
  63. {
  64.   time_t bintim = time(0);
  65.   struct tm *lc = localtime(&bintim);
  66.  
  67.   *leap_p = 1;
  68.   *m = 0;            /* When m and n are 0, a Julian */
  69.   *n = 0;            /* date has been inserted in d */
  70.  
  71.   switch(*nptr)
  72.     {
  73.     case 'M':
  74.       {
  75.     /* This routine counts on the user to have specified "Mm.n.d",
  76.        where 1 <= n <= 5, 1 <= m <= 12, 0 <= d <= 6 */
  77.  
  78.     *m = strtol(++nptr, endptr, 10);
  79.     (*endptr)++;        /* Skip the dot */
  80.     *n = strtol(*endptr, endptr, 10);
  81.     (*endptr)++;        /* Skip the dot */
  82.     *d = strtol(*endptr, endptr, 10);
  83.  
  84.     return;
  85.       }
  86.     case 'J':
  87.       *leap_p = 0;        /* Never count with leap years */
  88.     default: /* trust the user to have inserted a number! */
  89.       *d = strtol(++nptr, endptr, 10);
  90.       return;
  91.     }
  92. }
  93.  
  94. struct vms_vectim
  95. {
  96.   short year, month, day, hour, minute, second, centi_second;
  97. };
  98. static void find_dst_time(int m, int n, long d,
  99.               int hour, int minute, int second,
  100.               int leap_p,
  101.               long vms_internal_time[2])
  102. {
  103.   long status = SYS$GETTIM(vms_internal_time);
  104.   struct vms_vectim vms_vectime;
  105.   status = SYS$NUMTIM(&vms_vectime, vms_internal_time);
  106.  
  107.   if (m == 0 && n == 0)
  108.     {
  109.       long tmp_vms_internal_time[2][2];
  110.       long day_of_year;
  111.       long tmp_operation = LIB$K_DAY_OF_YEAR;
  112.  
  113.       status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation, &day_of_year,
  114.                       vms_internal_time);
  115.       
  116.       vms_vectime.month = 2;
  117.       vms_vectime.day = 29;
  118.       status = LIB$CVT_VECTIM(&vms_vectime, tmp_vms_internal_time[0]);
  119.       if (status & 1) /* This is a leap year */
  120.     {
  121.       if (!leap_p && d > 59)
  122.         d ++;        /* If we don't count with 29th Feb,
  123.                    and this is a leap year, count up,
  124.                    to make day 60 really become the
  125.                    1st March. */
  126.     }
  127.       /* 1st January, at midnight */
  128.       vms_vectime.month = 1;
  129.       vms_vectime.day = 1;
  130.       vms_vectime.hour = hour;
  131.       vms_vectime.minute = minute;
  132.       vms_vectime.second = second;
  133.       vms_vectime.centi_second = 0;
  134.       status = LIB$CVT_VECTIM(&vms_vectime, tmp_vms_internal_time[0]);
  135.       tmp_operation = LIB$K_DELTA_DAYS;
  136.       status = LIB$CVT_TO_INTERNAL_TIME(&tmp_operation, &d,
  137.                     tmp_vms_internal_time[1]);
  138.       /* now, tmp_vms_interval_time[0] contains 1st Jan, 00:00:00,
  139.      and  tmp_vms_interval_time[1] contains delta time +d days.
  140.      Let's just add them together */
  141.       status = LIB$ADD_TIMES(tmp_vms_internal_time[0],
  142.                  tmp_vms_internal_time[1],
  143.                  vms_internal_time);
  144.     }
  145.   else
  146.     {
  147.       long tmp_vms_internal_time[2];
  148.       long day_of_week;
  149.       long tmp_operation = LIB$K_DAY_OF_YEAR;
  150.  
  151.       if (d == 0) /* 0 is Sunday, which isn't compatible with VMS,
  152.              where day_of_week is 1 -- 7, and 1 is Monday */
  153.     {
  154.       d = 7; /* So a simple conversion is required */
  155.     }
  156.       vms_vectime.month = m;
  157.       vms_vectime.day = 1;
  158.       vms_vectime.hour = hour;
  159.       vms_vectime.minute = minute;
  160.       vms_vectime.second = second;
  161.       vms_vectime.centi_second = 0;
  162.       status = LIB$CVT_VECTIM(&vms_vectime, tmp_vms_internal_time);
  163.       tmp_operation = LIB$K_DAY_OF_WEEK;
  164.       status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation, &day_of_week,
  165.                       tmp_vms_internal_time);
  166.       d -= day_of_week;
  167.       if (d < 0)
  168.     {
  169.       d += 7;
  170.     }
  171.       vms_vectime.day += (n-1)*7 + d;
  172.       status = LIB$CVT_VECTIM(&vms_vectime, vms_internal_time);
  173.       if (!(status & 1))
  174.     {
  175.       vms_vectime.day -= 7;    /* n was probably 5 */
  176.       status = LIB$CVT_VECTIM(&vms_vectime, vms_internal_time);
  177.     }
  178.     }
  179. }
  180.  
  181. static cmp_vms_internal_times(long vms_internal_time1[2],
  182.                   long vms_internal_time2[2])
  183. {
  184.   if (vms_internal_time1[1] < vms_internal_time2[1])
  185.     return -1;
  186.   else
  187.     if (vms_internal_time1[1] > vms_internal_time2[1])
  188.       return 1;
  189.  
  190.   if (vms_internal_time1[0] < vms_internal_time2[0])
  191.     return -1;
  192.   else
  193.     if (vms_internal_time1[0] > vms_internal_time2[0])
  194.       return 1;
  195.  
  196.   return 0;
  197. }
  198.  
  199. /* -------------------------- Global routines ------------------------------ */
  200.  
  201. #ifdef tzset
  202. #undef tzset
  203. #endif
  204. void sys_tzset()
  205. {
  206.   char *TZ;
  207.   char *p, *q;
  208.  
  209.   if (daylight_set)
  210.     return;
  211.  
  212.   daylight = 0;
  213.  
  214.   if ((TZ = getenv("TZ")) == 0)
  215.     return;
  216.  
  217.   p = TZ;
  218.   q = tzname[0];
  219.  
  220.   while(*p != '\0'
  221.     && (*p <'0' || *p > '9') && *p != '-' && *p != '+' && *p != ',')
  222.     *q++ = *p++;
  223.   *q = '\0';
  224.  
  225.   /* This is special for VMS, so I don't care if it doesn't exist anywhere
  226.      else */
  227.  
  228.   timezone = read_time(p, &p, 1);
  229.  
  230.   q = tzname[1];
  231.  
  232.   while(*p != '\0'
  233.     && (*p <'0' || *p > '9') && *p != '-' && *p != '+' && *p != ',')
  234.     *q++ = *p++;
  235.   *q = '\0';
  236.  
  237.   if (*p != '-' && *p != '+' && !(*p >='0' && *p <= '9'))
  238.     internal_daylight = timezone - 3600;
  239.   else
  240.     internal_daylight = read_time(p, &p, 1);
  241.  
  242.   if (*p == ',')
  243.     {
  244.       int start_m;
  245.       int start_n;
  246.       int start_d;
  247.       int start_leap_p;
  248.       int start_hour=2, start_minute=0, start_second=0;
  249.  
  250.       p++;
  251.       read_dst_time(p, &p, &start_m, &start_n, &start_d, &start_leap_p);
  252.       if (*p == '/')
  253.     {
  254.       long tmp = read_time (++p, &p, 0);
  255.       start_hour = tmp / 3600;
  256.       start_minute = (tmp % 3600) / 60;
  257.       start_second = tmp % 60;
  258.     }
  259.       if (*p == ',')
  260.     {
  261.       int end_m;
  262.       int end_n;
  263.       int end_d;
  264.       int end_leap_p;
  265.       int end_hour=2, end_minute=0, end_second=0;
  266.  
  267.       p++;
  268.       read_dst_time(p, &p, &end_m, &end_n, &end_d, &end_leap_p);
  269.       if (*p == '/')
  270.         {
  271.           long tmp = read_time (++p, &p, 0);
  272.           end_hour = tmp / 3600;
  273.           end_minute = (tmp % 3600) / 60;
  274.           end_second = tmp % 60;
  275.         }
  276.       {
  277.         long vms_internal_time[3][2];
  278.         find_dst_time(start_m, start_n, start_d,
  279.               start_hour, start_minute, start_second,
  280.               start_leap_p,
  281.               vms_internal_time[0]);
  282.         SYS$GETTIM(&vms_internal_time[1]);
  283.         find_dst_time(end_m, end_n, end_d,
  284.               end_hour, end_minute, end_second,
  285.               end_leap_p,
  286.               vms_internal_time[2]);
  287.         if (cmp_vms_internal_times(vms_internal_time[0],
  288.                       vms_internal_time[1]) < 0
  289.         && cmp_vms_internal_times(vms_internal_time[1],
  290.                      vms_internal_time[2]) < 0)
  291.           daylight = 1;
  292.       }
  293.     }
  294.     }
  295. }  
  296.  
  297. #ifdef localtime
  298. #undef localtime
  299. #endif
  300. struct tm *sys_localtime(time_t *clock)
  301. {
  302.   struct tm *tmp = localtime(clock);
  303.  
  304.   sys_tzset();
  305.   tmp->tm_isdst = daylight;
  306.  
  307.   return tmp;
  308. }
  309.  
  310. #ifdef gmtime
  311. #undef gmtime
  312. #endif
  313. struct tm *sys_gmtime(time_t *clock)
  314. {
  315.   static struct tm gmt;
  316.   struct vms_vectim tmp_vectime;
  317.   long vms_internal_time[3][2];
  318.   long tmp_operation = LIB$K_DELTA_SECONDS;
  319.   long status;
  320.   long tmp_offset;
  321.   char tmp_o_sign;
  322.  
  323.   sys_tzset();
  324.   
  325.   if (daylight)
  326.     tmp_offset = internal_daylight;
  327.   else
  328.     tmp_offset = timezone;
  329.  
  330.   if (tmp_offset < 0)
  331.     {
  332.       tmp_o_sign = -1;
  333.       tmp_offset = -tmp_offset;
  334.     }
  335.   else
  336.     tmp_o_sign = 1;
  337.  
  338.   status = LIB$CVT_TO_INTERNAL_TIME(&tmp_operation, &tmp_offset,
  339.                     vms_internal_time[1]);
  340.   status = SYS$GETTIM(vms_internal_time[0]);
  341.   if (tmp_o_sign < 0)
  342.     {
  343.       status = LIB$SUB_TIMES(vms_internal_time[0],
  344.                  vms_internal_time[1],
  345.                  vms_internal_time[2]);
  346.     }
  347.   else
  348.     {
  349.       status = LIB$ADD_TIMES(vms_internal_time[0],
  350.                  vms_internal_time[1],
  351.                  vms_internal_time[2]);
  352.     }
  353.  
  354.   status = SYS$NUMTIM(&tmp_vectime, vms_internal_time[2]);
  355.   gmt.tm_sec = tmp_vectime.second;
  356.   gmt.tm_min = tmp_vectime.minute;
  357.   gmt.tm_hour = tmp_vectime.hour;
  358.   gmt.tm_mday = tmp_vectime.day;
  359.   gmt.tm_mon = tmp_vectime.month - 1;
  360.   gmt.tm_year = tmp_vectime.year - 1900;
  361.  
  362.   tmp_operation = LIB$K_DAY_OF_WEEK;
  363.   status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation,
  364.                       &gmt.tm_wday,
  365.                       vms_internal_time[2]);
  366.   if (gmt.tm_wday == 7) gmt.tm_wday = 0;
  367.  
  368.   tmp_operation = LIB$K_DAY_OF_YEAR;
  369.   status = LIB$CVT_FROM_INTERNAL_TIME(&tmp_operation,
  370.                       &gmt.tm_yday,
  371.                       vms_internal_time[2]);
  372.   gmt.tm_yday--;
  373.   gmt.tm_isdst = daylight;
  374.  
  375.   return &gmt;
  376. }
  377.  
  378.