2010-05-27 Tristan Gingold <gingold@adacore.com>
authorTristan Gingold <gingold@adacore.com>
Thu, 27 May 2010 13:43:44 +0000 (13:43 +0000)
committerTristan Gingold <gingold@adacore.com>
Thu, 27 May 2010 13:43:44 +0000 (13:43 +0000)
* vms-misc.c: Define __NEW_STARLET.  Remove trailing spaces.
(VMS_TIME_FACTOR, VMS_TIME_OFFSET): New macros.
(vms_time_to_time_t): Use them instead of local const.
(vms_time_t_to_vms_time): New function.
(vms_get_time): Likewise.
(vms_raw_get_time): Likewise.
* vms.h (vms_time_t_to_vms_time): New declaration.
(vms_get_time): Likewise.
(vms_raw_get_time): Likewise.

bfd/ChangeLog
bfd/vms-misc.c
bfd/vms.h

index 471d1f31f3ef7c3e1c8f184ac945135132788dbd..05a1656324107e15303a70b3b1748bab160120ba 100644 (file)
@@ -1,3 +1,15 @@
+2010-05-27  Tristan Gingold  <gingold@adacore.com>
+
+       * vms-misc.c: Define __NEW_STARLET.  Remove trailing spaces.
+       (VMS_TIME_FACTOR, VMS_TIME_OFFSET): New macros.
+       (vms_time_to_time_t): Use them instead of local const.
+       (vms_time_t_to_vms_time): New function.
+       (vms_get_time): Likewise.
+       (vms_raw_get_time): Likewise.
+       * vms.h (vms_time_t_to_vms_time): New declaration.
+       (vms_get_time): Likewise.
+       (vms_raw_get_time): Likewise.
+
 2010-05-26  Tristan Gingold  <gingold@adacore.com>
 
        * vms-alpha.c: Update comments.
index be6d5094b17541f235489d8c7ee1d051196c8108..c7bd346837098a69421ebbf50f45b8b356e0fe36 100644 (file)
 #include "safe-ctype.h"
 
 #ifdef VMS
-#if defined(__GNUC__) && !defined(globalref)
-#define globalref extern
-#endif
+#define __NEW_STARLET
 #include <rms.h>
 #include <unixlib.h>
+#include <gen64def.h>
 #include <starlet.h>
 #define RME$C_SETRFM 0x00000001
 #include <unistd.h>
@@ -497,19 +496,19 @@ vms_get_module_name (const char *filename, bfd_boolean upcase)
     fout++;
   else
     fout = filename;
-      
+
   /* Strip UNIX path.  */
   fptr = strrchr (fout, '/');
   if (fptr != NULL)
     fout = fptr + 1;
-  
+
   fname = strdup (fout);
 
   /* Strip suffix.  */
   fptr = strrchr (fname, '.');
   if (fptr != 0)
     *fptr = 0;
-  
+
   /* Convert to upper case and truncate at 31 characters.
      (VMS object file format restricts module name length to 31).  */
   fptr = fname;
@@ -526,36 +525,109 @@ vms_get_module_name (const char *filename, bfd_boolean upcase)
   return fname;
 }
 
-/* Convert a raw VMS time to a unix time.  */
+/* Compared to usual UNIX time_t, VMS time has less limits:
+   -  64 bit (63 bits in fact as the MSB must be 0)
+   -  100ns granularity
+   -  epoch is Nov 17, 1858.
+   Here has the constants and the routines used to convert VMS from/to UNIX time.
+   The conversion routines don't assume 64 bits arithmetic.  */
+
+/* UNIX time granularity for VMS, ie 1s / 100ns.  */
+#define VMS_TIME_FACTOR 10000000
+
+/* Number of seconds since VMS epoch of the UNIX epoch.  */
+#define VMS_TIME_OFFSET 3506716800U
+
+/* Convert a VMS time to a unix time.  */
 
 time_t
 vms_time_to_time_t (unsigned int hi, unsigned int lo)
 {
-  const unsigned int off = 3506716800U;
-  const unsigned int factor = 10000000;
   unsigned int tmp;
   unsigned int rlo;
   int i;
 
   /* First convert to seconds.  */
-  tmp = hi % factor;
-  hi = hi / factor;
+  tmp = hi % VMS_TIME_FACTOR;
+  hi = hi / VMS_TIME_FACTOR;
   rlo = 0;
   for (i = 0; i < 4; i++)
     {
       tmp = (tmp << 8) | (lo >> 24);
       lo <<= 8;
 
-      rlo = (rlo << 8) | (tmp / factor);
-      tmp %= factor;
+      rlo = (rlo << 8) | (tmp / VMS_TIME_FACTOR);
+      tmp %= VMS_TIME_FACTOR;
     }
   lo = rlo;
 
   /* Return 0 in case of overflow.  */
-  if (lo > off && hi > 1)
+  if (lo > VMS_TIME_OFFSET && hi > 1)
+    return 0;
+
+  /* Return 0 in case of underflow.  */
+  if (lo < VMS_TIME_OFFSET)
     return 0;
 
-  return lo - off;
+  return lo - VMS_TIME_OFFSET;
+}
+
+/* Convert a time_t to a VMS time.  */
+
+void
+vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo)
+{
+  unsigned short val[4];
+  unsigned short tmp[4];
+  unsigned int carry;
+  int i;
+
+  /* Put into val.  */
+  val[0] = ut & 0xffff;
+  val[1] = (ut >> 16) & 0xffff;
+  if (sizeof (ut) > 4)
+    {
+      val[2] = (ut >> 32) & 0xffff;
+      val[3] = (ut >> 48) & 0xffff;
+    }
+  else
+    {
+      val[2] = 0;
+      val[3] = 0;
+    }
+
+  /* Add offset.  */
+  tmp[0] = VMS_TIME_OFFSET & 0xffff;
+  tmp[1] = VMS_TIME_OFFSET >> 16;
+  tmp[2] = 0;
+  tmp[3] = 0;
+  carry = 0;
+  for (i = 0; i < 4; i++)
+    {
+      carry += tmp[i] + val[i];
+      val[i] = carry & 0xffff;
+      carry = carry >> 16;
+    }
+
+  /* Multiply by factor, well first by 10000 and then by 1000.  */
+  carry = 0;
+  for (i = 0; i < 4; i++)
+    {
+      carry += val[i] * 10000;
+      val[i] = carry & 0xffff;
+      carry = carry >> 16;
+    }
+  carry = 0;
+  for (i = 0; i < 4; i++)
+    {
+      carry += val[i] * 1000;
+      val[i] = carry & 0xffff;
+      carry = carry >> 16;
+    }
+
+  /* Write the result.  */
+  *lo = val[0] | (val[1] << 16);
+  *hi = val[2] | (val[3] << 16);
 }
 
 /* Convert a raw (stored in a buffer) VMS time to a unix time.  */
@@ -568,3 +640,32 @@ vms_rawtime_to_time_t (unsigned char *buf)
 
   return vms_time_to_time_t (hi, lo);
 }
+
+void
+vms_get_time (unsigned int *hi, unsigned int *lo)
+{
+#ifdef VMS
+  struct _generic_64 t;
+
+  sys$gettim (&t);
+  *lo = t.gen64$q_quadword;
+  *hi = t.gen64$q_quadword >> 32;
+#else
+  time_t t;
+
+  time (&t);
+  vms_time_t_to_vms_time (t, hi, lo);
+#endif
+}
+
+/* Get the current time into a raw buffer BUF.  */
+
+void
+vms_raw_get_time (unsigned char *buf)
+{
+  unsigned int hi, lo;
+
+  vms_get_time (&hi, &lo);
+  bfd_putl32 (lo, buf + 0);
+  bfd_putl32 (hi, buf + 4);
+}
index 762c8b53984a79c3fbebbfc45d26aad1459626fa..c95487d5d4de90b977d2d9d4fd5d0888248f17f5 100644 (file)
--- a/bfd/vms.h
+++ b/bfd/vms.h
@@ -115,6 +115,9 @@ extern char * vms_get_module_name (const char *, bfd_boolean);
 extern unsigned char *get_vms_time_string (void);
 extern time_t vms_time_to_time_t (unsigned int hi, unsigned int lo);
 extern time_t vms_rawtime_to_time_t (unsigned char *);
+extern void vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo);
+extern void vms_get_time (unsigned int *hi, unsigned int *lo);
+extern void vms_raw_get_time (unsigned char *buf);
 
 extern char * _bfd_vms_save_sized_string (unsigned char *, int);
 extern char * _bfd_vms_save_counted_string (unsigned char *);