vms-misc.c revision 1.1.1.7 1 1.1 christos /* vms-misc.c -- BFD back-end for VMS/VAX (openVMS/VAX) and
2 1.1 christos EVAX (openVMS/Alpha) files.
3 1.1.1.7 christos Copyright (C) 1996-2020 Free Software Foundation, Inc.
4 1.1 christos
5 1.1 christos Miscellaneous functions.
6 1.1 christos
7 1.1 christos Written by Klaus K"ampf (kkaempf (at) rmi.de)
8 1.1 christos
9 1.1 christos This program is free software; you can redistribute it and/or modify
10 1.1 christos it under the terms of the GNU General Public License as published by
11 1.1 christos the Free Software Foundation; either version 3 of the License, or
12 1.1 christos (at your option) any later version.
13 1.1 christos
14 1.1 christos This program is distributed in the hope that it will be useful,
15 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
16 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 1.1 christos GNU General Public License for more details.
18 1.1 christos
19 1.1 christos You should have received a copy of the GNU General Public License
20 1.1 christos along with this program; if not, write to the Free Software
21 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
22 1.1 christos MA 02110-1301, USA. */
23 1.1 christos
24 1.1 christos #if __STDC__
25 1.1 christos #include <stdarg.h>
26 1.1 christos #endif
27 1.1 christos
28 1.1 christos #include "sysdep.h"
29 1.1 christos #include "bfd.h"
30 1.1 christos #include "bfdlink.h"
31 1.1 christos #include "libbfd.h"
32 1.1 christos #include "safe-ctype.h"
33 1.1 christos
34 1.1 christos #ifdef VMS
35 1.1 christos #define __NEW_STARLET
36 1.1 christos #include <rms.h>
37 1.1 christos #include <unixlib.h>
38 1.1 christos #include <gen64def.h>
39 1.1 christos #include <starlet.h>
40 1.1 christos #define RME$C_SETRFM 0x00000001
41 1.1 christos #include <unistd.h>
42 1.1 christos #endif
43 1.1 christos #include <time.h>
44 1.1 christos
45 1.1 christos #include "vms.h"
46 1.1 christos #include "vms/emh.h"
47 1.1 christos
48 1.1 christos #if VMS_DEBUG
49 1.1 christos /* Debug functions. */
50 1.1 christos
51 1.1 christos /* Debug function for all vms extensions evaluates environment
52 1.1 christos variable VMS_DEBUG for a numerical value on the first call all
53 1.1 christos error levels below this value are printed:
54 1.1 christos
55 1.1 christos Levels:
56 1.1 christos 1 toplevel bfd calls (functions from the bfd vector)
57 1.1 christos 2 functions called by bfd calls
58 1.1 christos ...
59 1.1 christos 9 almost everything
60 1.1 christos
61 1.1 christos Level is also indentation level. Indentation is performed
62 1.1 christos if level > 0. */
63 1.1 christos
64 1.1 christos void
65 1.1 christos _bfd_vms_debug (int level, char *format, ...)
66 1.1 christos {
67 1.1 christos static int min_level = -1;
68 1.1 christos static FILE *output = NULL;
69 1.1 christos char *eptr;
70 1.1 christos va_list args;
71 1.1 christos int abslvl = (level > 0) ? level : - level;
72 1.1 christos
73 1.1 christos if (min_level == -1)
74 1.1 christos {
75 1.1 christos if ((eptr = getenv ("VMS_DEBUG")) != NULL)
76 1.1 christos {
77 1.1 christos min_level = atoi (eptr);
78 1.1 christos output = stderr;
79 1.1 christos }
80 1.1 christos else
81 1.1 christos min_level = 0;
82 1.1 christos }
83 1.1 christos if (output == NULL)
84 1.1 christos return;
85 1.1 christos if (abslvl > min_level)
86 1.1 christos return;
87 1.1 christos
88 1.1 christos while (--level > 0)
89 1.1 christos fprintf (output, " ");
90 1.1 christos va_start (args, format);
91 1.1 christos vfprintf (output, format, args);
92 1.1 christos fflush (output);
93 1.1 christos va_end (args);
94 1.1 christos }
95 1.1 christos
96 1.1 christos /* A debug function
97 1.1 christos hex dump 'size' bytes starting at 'ptr'. */
98 1.1 christos
99 1.1 christos void
100 1.1 christos _bfd_hexdump (int level, unsigned char *ptr, int size, int offset)
101 1.1 christos {
102 1.1 christos unsigned char *lptr = ptr;
103 1.1 christos int count = 0;
104 1.1 christos long start = offset;
105 1.1 christos
106 1.1 christos while (size-- > 0)
107 1.1 christos {
108 1.1 christos if ((count % 16) == 0)
109 1.1 christos vms_debug (level, "%08lx:", start);
110 1.1 christos vms_debug (-level, " %02x", *ptr++);
111 1.1 christos count++;
112 1.1 christos start++;
113 1.1 christos if (size == 0)
114 1.1 christos {
115 1.1 christos while ((count % 16) != 0)
116 1.1 christos {
117 1.1 christos vms_debug (-level, " ");
118 1.1 christos count++;
119 1.1 christos }
120 1.1 christos }
121 1.1 christos if ((count % 16) == 0)
122 1.1 christos {
123 1.1 christos vms_debug (-level, " ");
124 1.1 christos while (lptr < ptr)
125 1.1 christos {
126 1.1 christos vms_debug (-level, "%c", (*lptr < 32) ? '.' : *lptr);
127 1.1 christos lptr++;
128 1.1 christos }
129 1.1 christos vms_debug (-level, "\n");
130 1.1 christos }
131 1.1 christos }
132 1.1 christos if ((count % 16) != 0)
133 1.1 christos vms_debug (-level, "\n");
134 1.1 christos }
135 1.1 christos #endif
136 1.1 christos
137 1.1 christos
139 1.1.1.6 christos /* Copy sized string (string with fixed size) to new allocated area.
140 1.1 christos Size is string size (size of record). */
141 1.1 christos
142 1.1.1.7 christos char *
143 1.1 christos _bfd_vms_save_sized_string (bfd *abfd, unsigned char *str, size_t size)
144 1.1.1.7 christos {
145 1.1 christos char *newstr;
146 1.1.1.7 christos
147 1.1.1.7 christos if (size == (size_t) -1)
148 1.1.1.7 christos {
149 1.1.1.7 christos bfd_set_error (bfd_error_no_memory);
150 1.1.1.7 christos return NULL;
151 1.1.1.7 christos }
152 1.1 christos newstr = bfd_alloc (abfd, size + 1);
153 1.1 christos if (newstr == NULL)
154 1.1.1.7 christos return NULL;
155 1.1 christos memcpy (newstr, str, size);
156 1.1 christos newstr[size] = 0;
157 1.1 christos
158 1.1 christos return newstr;
159 1.1 christos }
160 1.1.1.6 christos
161 1.1.1.6 christos /* Copy counted string (string with size at first byte) to new allocated area.
162 1.1 christos PTR points to size byte on entry. */
163 1.1 christos
164 1.1.1.7 christos char *
165 1.1 christos _bfd_vms_save_counted_string (bfd *abfd, unsigned char *ptr, size_t maxlen)
166 1.1.1.6 christos {
167 1.1 christos unsigned int len = *ptr++;
168 1.1.1.6 christos
169 1.1.1.6 christos if (len > maxlen)
170 1.1.1.7 christos return NULL;
171 1.1 christos return _bfd_vms_save_sized_string (abfd, ptr, len);
172 1.1 christos }
173 1.1 christos
174 1.1 christos /* Object output routines. */
176 1.1 christos
177 1.1 christos /* Begin new record.
178 1.1 christos Write 2 bytes rectype and 2 bytes record length. */
179 1.1 christos
180 1.1 christos void
181 1.1 christos _bfd_vms_output_begin (struct vms_rec_wr *recwr, int rectype)
182 1.1 christos {
183 1.1 christos vms_debug2 ((6, "_bfd_vms_output_begin (type %d)\n", rectype));
184 1.1 christos
185 1.1 christos /* Record must have been closed. */
186 1.1 christos BFD_ASSERT (recwr->size == 0);
187 1.1 christos
188 1.1 christos _bfd_vms_output_short (recwr, (unsigned int) rectype);
189 1.1 christos
190 1.1 christos /* Placeholder for length. */
191 1.1 christos _bfd_vms_output_short (recwr, 0);
192 1.1 christos }
193 1.1 christos
194 1.1 christos /* Begin new sub-record.
195 1.1 christos Write 2 bytes rectype, and 2 bytes record length. */
196 1.1 christos
197 1.1 christos void
198 1.1 christos _bfd_vms_output_begin_subrec (struct vms_rec_wr *recwr, int rectype)
199 1.1 christos {
200 1.1 christos vms_debug2 ((6, "_bfd_vms_output_begin_subrec (type %d)\n", rectype));
201 1.1 christos
202 1.1 christos /* Subrecord must have been closed. */
203 1.1 christos BFD_ASSERT (recwr->subrec_offset == 0);
204 1.1 christos
205 1.1 christos /* Save start of subrecord offset. */
206 1.1 christos recwr->subrec_offset = recwr->size;
207 1.1 christos
208 1.1 christos /* Subrecord type. */
209 1.1 christos _bfd_vms_output_short (recwr, (unsigned int) rectype);
210 1.1 christos
211 1.1 christos /* Placeholder for length. */
212 1.1 christos _bfd_vms_output_short (recwr, 0);
213 1.1 christos }
214 1.1 christos
215 1.1 christos /* Set record/subrecord alignment. */
216 1.1 christos
217 1.1 christos void
218 1.1 christos _bfd_vms_output_alignment (struct vms_rec_wr *recwr, int alignto)
219 1.1 christos {
220 1.1 christos vms_debug2 ((6, "_bfd_vms_output_alignment (%d)\n", alignto));
221 1.1 christos recwr->align = alignto;
222 1.1 christos }
223 1.1 christos
224 1.1 christos /* Align the size of the current record (whose length is LENGTH).
225 1.1 christos Warning: this obviously changes the record (and the possible subrecord)
226 1.1 christos length. */
227 1.1 christos
228 1.1 christos static void
229 1.1 christos _bfd_vms_output_align (struct vms_rec_wr *recwr, unsigned int length)
230 1.1 christos {
231 1.1 christos unsigned int real_size = recwr->size;
232 1.1 christos unsigned int aligncount;
233 1.1 christos
234 1.1 christos /* Pad with 0 if alignment is required. */
235 1.1 christos aligncount = (recwr->align - (length % recwr->align)) % recwr->align;
236 1.1 christos vms_debug2 ((6, "align: adding %d bytes\n", aligncount));
237 1.1 christos while (aligncount-- > 0)
238 1.1 christos recwr->buf[real_size++] = 0;
239 1.1 christos
240 1.1 christos recwr->size = real_size;
241 1.1 christos }
242 1.1 christos
243 1.1 christos /* Ends current sub-record. Set length field. */
244 1.1 christos
245 1.1 christos void
246 1.1 christos _bfd_vms_output_end_subrec (struct vms_rec_wr *recwr)
247 1.1 christos {
248 1.1 christos int real_size = recwr->size;
249 1.1 christos int length;
250 1.1 christos
251 1.1 christos /* Subrecord must be open. */
252 1.1 christos BFD_ASSERT (recwr->subrec_offset != 0);
253 1.1 christos
254 1.1 christos length = real_size - recwr->subrec_offset;
255 1.1 christos
256 1.1 christos if (length == 0)
257 1.1 christos return;
258 1.1 christos
259 1.1 christos _bfd_vms_output_align (recwr, length);
260 1.1 christos
261 1.1.1.6 christos /* Put length to buffer. */
262 1.1 christos bfd_putl16 ((bfd_vma) (recwr->size - recwr->subrec_offset),
263 1.1 christos recwr->buf + recwr->subrec_offset + 2);
264 1.1 christos
265 1.1 christos /* Close the subrecord. */
266 1.1 christos recwr->subrec_offset = 0;
267 1.1 christos }
268 1.1 christos
269 1.1 christos /* Ends current record (and write it). */
270 1.1 christos
271 1.1 christos void
272 1.1 christos _bfd_vms_output_end (bfd *abfd, struct vms_rec_wr *recwr)
273 1.1 christos {
274 1.1 christos vms_debug2 ((6, "_bfd_vms_output_end (size %u)\n", recwr->size));
275 1.1 christos
276 1.1 christos /* Subrecord must have been closed. */
277 1.1 christos BFD_ASSERT (recwr->subrec_offset == 0);
278 1.1 christos
279 1.1 christos if (recwr->size == 0)
280 1.1 christos return;
281 1.1 christos
282 1.1 christos _bfd_vms_output_align (recwr, recwr->size);
283 1.1 christos
284 1.1 christos /* Write the length word. */
285 1.1 christos bfd_putl16 ((bfd_vma) recwr->size, recwr->buf + 2);
286 1.1 christos
287 1.1 christos /* File is open in undefined (UDF) format on VMS, but ultimately will be
288 1.1 christos converted to variable length (VAR) format. VAR format has a length
289 1.1 christos word first which must be explicitly output in UDF format. */
290 1.1 christos /* So, first the length word. */
291 1.1 christos bfd_bwrite (recwr->buf + 2, 2, abfd);
292 1.1 christos
293 1.1 christos /* Align. */
294 1.1 christos if (recwr->size & 1)
295 1.1 christos recwr->buf[recwr->size++] = 0;
296 1.1 christos
297 1.1 christos /* Then the record. */
298 1.1 christos bfd_bwrite (recwr->buf, (size_t) recwr->size, abfd);
299 1.1 christos
300 1.1 christos recwr->size = 0;
301 1.1 christos }
302 1.1 christos
303 1.1 christos /* Check remaining buffer size. Return what's left. */
304 1.1 christos
305 1.1 christos int
306 1.1 christos _bfd_vms_output_check (struct vms_rec_wr *recwr, int size)
307 1.1 christos {
308 1.1 christos vms_debug2 ((6, "_bfd_vms_output_check (%d)\n", size));
309 1.1 christos
310 1.1 christos return (MAX_OUTREC_SIZE - (recwr->size + size + MIN_OUTREC_LUFT));
311 1.1 christos }
312 1.1 christos
313 1.1 christos /* Output byte (8 bit) value. */
314 1.1 christos
315 1.1 christos void
316 1.1 christos _bfd_vms_output_byte (struct vms_rec_wr *recwr, unsigned int value)
317 1.1 christos {
318 1.1 christos vms_debug2 ((6, "_bfd_vms_output_byte (%02x)\n", value));
319 1.1 christos
320 1.1 christos *(recwr->buf + recwr->size) = value;
321 1.1 christos recwr->size += 1;
322 1.1 christos }
323 1.1 christos
324 1.1 christos /* Output short (16 bit) value. */
325 1.1 christos
326 1.1 christos void
327 1.1 christos _bfd_vms_output_short (struct vms_rec_wr *recwr, unsigned int value)
328 1.1 christos {
329 1.1 christos vms_debug2 ((6, "_bfd_vms_output_short (%04x)\n", value));
330 1.1 christos
331 1.1 christos bfd_putl16 ((bfd_vma) value & 0xffff, recwr->buf + recwr->size);
332 1.1 christos recwr->size += 2;
333 1.1 christos }
334 1.1 christos
335 1.1 christos /* Output long (32 bit) value. */
336 1.1 christos
337 1.1 christos void
338 1.1 christos _bfd_vms_output_long (struct vms_rec_wr *recwr, unsigned long value)
339 1.1 christos {
340 1.1 christos vms_debug2 ((6, "_bfd_vms_output_long (%08lx)\n", value));
341 1.1 christos
342 1.1 christos bfd_putl32 ((bfd_vma) value, recwr->buf + recwr->size);
343 1.1 christos recwr->size += 4;
344 1.1 christos }
345 1.1 christos
346 1.1 christos /* Output quad (64 bit) value. */
347 1.1 christos
348 1.1 christos void
349 1.1 christos _bfd_vms_output_quad (struct vms_rec_wr *recwr, bfd_vma value)
350 1.1 christos {
351 1.1 christos vms_debug2 ((6, "_bfd_vms_output_quad (%08lx)\n", (unsigned long)value));
352 1.1 christos
353 1.1 christos bfd_putl64 (value, recwr->buf + recwr->size);
354 1.1 christos recwr->size += 8;
355 1.1 christos }
356 1.1 christos
357 1.1 christos /* Output c-string as counted string. */
358 1.1 christos
359 1.1 christos void
360 1.1 christos _bfd_vms_output_counted (struct vms_rec_wr *recwr, const char *value)
361 1.1 christos {
362 1.1 christos int len;
363 1.1 christos
364 1.1 christos vms_debug2 ((6, "_bfd_vms_output_counted (%s)\n", value));
365 1.1 christos
366 1.1 christos len = strlen (value);
367 1.1.1.5 christos if (len == 0)
368 1.1 christos {
369 1.1 christos _bfd_error_handler (_("_bfd_vms_output_counted called with zero bytes"));
370 1.1 christos return;
371 1.1 christos }
372 1.1.1.5 christos if (len > 255)
373 1.1 christos {
374 1.1 christos _bfd_error_handler (_("_bfd_vms_output_counted called with too many bytes"));
375 1.1 christos return;
376 1.1 christos }
377 1.1 christos _bfd_vms_output_byte (recwr, (unsigned int) len & 0xff);
378 1.1 christos _bfd_vms_output_dump (recwr, (const unsigned char *)value, len);
379 1.1 christos }
380 1.1 christos
381 1.1 christos /* Output character area. */
382 1.1 christos
383 1.1 christos void
384 1.1 christos _bfd_vms_output_dump (struct vms_rec_wr *recwr, const unsigned char *data, int len)
385 1.1 christos {
386 1.1 christos vms_debug2 ((6, "_bfd_vms_output_dump (%d)\n", len));
387 1.1 christos
388 1.1 christos if (len == 0)
389 1.1 christos return;
390 1.1 christos
391 1.1 christos memcpy (recwr->buf + recwr->size, data, (size_t) len);
392 1.1 christos recwr->size += len;
393 1.1 christos }
394 1.1 christos
395 1.1 christos /* Output count bytes of value. */
396 1.1 christos
397 1.1 christos void
398 1.1 christos _bfd_vms_output_fill (struct vms_rec_wr *recwr, int value, int count)
399 1.1 christos {
400 1.1 christos vms_debug2 ((6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count));
401 1.1 christos
402 1.1 christos if (count == 0)
403 1.1 christos return;
404 1.1 christos memset (recwr->buf + recwr->size, value, (size_t) count);
405 1.1 christos recwr->size += count;
406 1.1 christos }
407 1.1 christos
408 1.1 christos #ifdef VMS
409 1.1 christos /* Convert the file to variable record length format. This is done
410 1.1 christos using undocumented system call sys$modify().
411 1.1 christos Pure VMS version. */
412 1.1 christos
413 1.1 christos static void
414 1.1 christos vms_convert_to_var (char * vms_filename)
415 1.1 christos {
416 1.1 christos struct FAB fab = cc$rms_fab;
417 1.1 christos
418 1.1 christos fab.fab$l_fna = vms_filename;
419 1.1 christos fab.fab$b_fns = strlen (vms_filename);
420 1.1 christos fab.fab$b_fac = FAB$M_PUT;
421 1.1 christos fab.fab$l_fop = FAB$M_ESC;
422 1.1 christos fab.fab$l_ctx = RME$C_SETRFM;
423 1.1 christos
424 1.1 christos sys$open (&fab);
425 1.1 christos
426 1.1 christos fab.fab$b_rfm = FAB$C_VAR;
427 1.1 christos
428 1.1 christos sys$modify (&fab);
429 1.1 christos sys$close (&fab);
430 1.1 christos }
431 1.1 christos
432 1.1 christos static int
433 1.1 christos vms_convert_to_var_1 (char *filename, int type)
434 1.1 christos {
435 1.1 christos if (type != DECC$K_FILE)
436 1.1 christos return FALSE;
437 1.1 christos vms_convert_to_var (filename);
438 1.1 christos return TRUE;
439 1.1 christos }
440 1.1 christos
441 1.1 christos /* Convert the file to variable record length format. This is done
442 1.1 christos using undocumented system call sys$modify().
443 1.1 christos Unix filename version. */
444 1.1 christos
445 1.1 christos int
446 1.1 christos _bfd_vms_convert_to_var_unix_filename (const char *unix_filename)
447 1.1 christos {
448 1.1 christos if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1)
449 1.1 christos return FALSE;
450 1.1 christos return TRUE;
451 1.1 christos }
452 1.1 christos #endif /* VMS */
453 1.1 christos
454 1.1 christos /* Manufacture a VMS like time on a unix based system.
455 1.1 christos stolen from obj-vms.c. */
456 1.1 christos
457 1.1 christos unsigned char *
458 1.1 christos get_vms_time_string (void)
459 1.1 christos {
460 1.1 christos static unsigned char tbuf[18];
461 1.1 christos #ifndef VMS
462 1.1 christos char *pnt;
463 1.1 christos time_t timeb;
464 1.1 christos
465 1.1 christos time (& timeb);
466 1.1 christos pnt = ctime (&timeb);
467 1.1 christos pnt[3] = 0;
468 1.1 christos pnt[7] = 0;
469 1.1 christos pnt[10] = 0;
470 1.1 christos pnt[16] = 0;
471 1.1 christos pnt[24] = 0;
472 1.1 christos sprintf ((char *) tbuf, "%2s-%3s-%s %s",
473 1.1 christos pnt + 8, pnt + 4, pnt + 20, pnt + 11);
474 1.1 christos #else
475 1.1 christos struct
476 1.1 christos {
477 1.1 christos int Size;
478 1.1 christos unsigned char *Ptr;
479 1.1 christos } Descriptor;
480 1.1 christos Descriptor.Size = 17;
481 1.1 christos Descriptor.Ptr = tbuf;
482 1.1 christos SYS$ASCTIM (0, &Descriptor, 0, 0);
483 1.1 christos #endif /* not VMS */
484 1.1 christos
485 1.1 christos vms_debug2 ((6, "vmstimestring:'%s'\n", tbuf));
486 1.1 christos
487 1.1 christos return tbuf;
488 1.1 christos }
489 1.1 christos
490 1.1 christos /* Create module name from filename (ie, extract the basename and convert it
491 1.1 christos in upper cases). Works on both VMS and UNIX pathes.
492 1.1 christos The result has to be free(). */
493 1.1 christos
494 1.1 christos char *
495 1.1 christos vms_get_module_name (const char *filename, bfd_boolean upcase)
496 1.1 christos {
497 1.1 christos char *fname, *fptr;
498 1.1 christos const char *fout;
499 1.1 christos
500 1.1 christos /* Strip VMS path. */
501 1.1 christos fout = strrchr (filename, ']');
502 1.1 christos if (fout == NULL)
503 1.1 christos fout = strchr (filename, ':');
504 1.1 christos if (fout != NULL)
505 1.1 christos fout++;
506 1.1 christos else
507 1.1 christos fout = filename;
508 1.1 christos
509 1.1 christos /* Strip UNIX path. */
510 1.1 christos fptr = strrchr (fout, '/');
511 1.1 christos if (fptr != NULL)
512 1.1 christos fout = fptr + 1;
513 1.1 christos
514 1.1 christos fname = strdup (fout);
515 1.1 christos
516 1.1 christos /* Strip suffix. */
517 1.1 christos fptr = strrchr (fname, '.');
518 1.1 christos if (fptr != 0)
519 1.1 christos *fptr = 0;
520 1.1 christos
521 1.1 christos /* Convert to upper case and truncate at 31 characters.
522 1.1 christos (VMS object file format restricts module name length to 31). */
523 1.1 christos fptr = fname;
524 1.1 christos for (fptr = fname; *fptr != 0; fptr++)
525 1.1.1.6 christos {
526 1.1.1.6 christos if (*fptr == ';' || (fptr - fname) >= 31)
527 1.1.1.6 christos {
528 1.1.1.6 christos *fptr = 0;
529 1.1 christos break;
530 1.1.1.6 christos }
531 1.1 christos if (upcase)
532 1.1 christos *fptr = TOUPPER (*fptr);
533 1.1 christos }
534 1.1 christos return fname;
535 1.1 christos }
536 1.1 christos
537 1.1 christos /* Compared to usual UNIX time_t, VMS time has less limits:
538 1.1 christos - 64 bit (63 bits in fact as the MSB must be 0)
539 1.1 christos - 100ns granularity
540 1.1.1.2 christos - epoch is Nov 17, 1858.
541 1.1.1.2 christos Here has the constants and the routines used to convert VMS from/to UNIX time.
542 1.1.1.2 christos The conversion routines don't assume 64 bits arithmetic.
543 1.1.1.2 christos
544 1.1 christos Here we assume that the definition of time_t is the UNIX one, ie integer
545 1.1 christos type, expressing seconds since the epoch. */
546 1.1 christos
547 1.1 christos /* UNIX time granularity for VMS, ie 1s / 100ns. */
548 1.1 christos #define VMS_TIME_FACTOR 10000000
549 1.1 christos
550 1.1 christos /* Number of seconds since VMS epoch of the UNIX epoch. */
551 1.1 christos #define VMS_TIME_OFFSET 3506716800U
552 1.1 christos
553 1.1 christos /* Convert a VMS time to a unix time. */
554 1.1 christos
555 1.1 christos time_t
556 1.1 christos vms_time_to_time_t (unsigned int hi, unsigned int lo)
557 1.1 christos {
558 1.1 christos unsigned int tmp;
559 1.1.1.2 christos unsigned int rlo;
560 1.1 christos int i;
561 1.1 christos time_t res;
562 1.1 christos
563 1.1 christos /* First convert to seconds. */
564 1.1 christos tmp = hi % VMS_TIME_FACTOR;
565 1.1 christos hi = hi / VMS_TIME_FACTOR;
566 1.1 christos rlo = 0;
567 1.1 christos for (i = 0; i < 4; i++)
568 1.1 christos {
569 1.1 christos tmp = (tmp << 8) | (lo >> 24);
570 1.1 christos lo <<= 8;
571 1.1 christos
572 1.1 christos rlo = (rlo << 8) | (tmp / VMS_TIME_FACTOR);
573 1.1 christos tmp %= VMS_TIME_FACTOR;
574 1.1 christos }
575 1.1 christos lo = rlo;
576 1.1.1.2 christos
577 1.1.1.2 christos /* Return 0 in case of overflow. */
578 1.1 christos if (hi > 1
579 1.1 christos || (hi == 1 && lo >= VMS_TIME_OFFSET))
580 1.1 christos return 0;
581 1.1.1.2 christos
582 1.1 christos /* Return 0 in case of underflow. */
583 1.1 christos if (hi == 0 && lo < VMS_TIME_OFFSET)
584 1.1.1.2 christos return 0;
585 1.1.1.2 christos
586 1.1.1.2 christos res = lo - VMS_TIME_OFFSET;
587 1.1.1.2 christos if (res <= 0)
588 1.1 christos return 0;
589 1.1 christos return res;
590 1.1 christos }
591 1.1 christos
592 1.1 christos /* Convert a time_t to a VMS time. */
593 1.1 christos
594 1.1 christos void
595 1.1.1.7 christos vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo)
596 1.1.1.7 christos {
597 1.1 christos unsigned int val[4];
598 1.1 christos unsigned int tmp[4];
599 1.1 christos unsigned int carry;
600 1.1 christos int i;
601 1.1 christos
602 1.1 christos /* Put into val. */
603 1.1 christos val[0] = ut & 0xffff;
604 1.1 christos val[1] = (ut >> 16) & 0xffff;
605 1.1 christos val[2] = sizeof (ut) > 4 ? (ut >> 32) & 0xffff : 0;
606 1.1 christos val[3] = sizeof (ut) > 4 ? (ut >> 48) & 0xffff : 0;
607 1.1 christos
608 1.1 christos /* Add offset. */
609 1.1 christos tmp[0] = VMS_TIME_OFFSET & 0xffff;
610 1.1 christos tmp[1] = VMS_TIME_OFFSET >> 16;
611 1.1 christos tmp[2] = 0;
612 1.1 christos tmp[3] = 0;
613 1.1 christos carry = 0;
614 1.1 christos for (i = 0; i < 4; i++)
615 1.1 christos {
616 1.1 christos carry += tmp[i] + val[i];
617 1.1 christos val[i] = carry & 0xffff;
618 1.1 christos carry = carry >> 16;
619 1.1 christos }
620 1.1 christos
621 1.1 christos /* Multiply by factor, well first by 10000 and then by 1000. */
622 1.1 christos carry = 0;
623 1.1 christos for (i = 0; i < 4; i++)
624 1.1 christos {
625 1.1 christos carry += val[i] * 10000;
626 1.1 christos val[i] = carry & 0xffff;
627 1.1 christos carry = carry >> 16;
628 1.1 christos }
629 1.1 christos carry = 0;
630 1.1 christos for (i = 0; i < 4; i++)
631 1.1 christos {
632 1.1 christos carry += val[i] * 1000;
633 1.1 christos val[i] = carry & 0xffff;
634 1.1 christos carry = carry >> 16;
635 1.1 christos }
636 1.1 christos
637 1.1 christos /* Write the result. */
638 1.1 christos *lo = val[0] | (val[1] << 16);
639 1.1 christos *hi = val[2] | (val[3] << 16);
640 1.1 christos }
641 1.1 christos
642 1.1 christos /* Convert a raw (stored in a buffer) VMS time to a unix time. */
643 1.1 christos
644 1.1 christos time_t
645 1.1 christos vms_rawtime_to_time_t (unsigned char *buf)
646 1.1 christos {
647 1.1 christos unsigned int hi = bfd_getl32 (buf + 4);
648 1.1 christos unsigned int lo = bfd_getl32 (buf + 0);
649 1.1 christos
650 1.1 christos return vms_time_to_time_t (hi, lo);
651 1.1 christos }
652 1.1 christos
653 1.1 christos void
654 1.1 christos vms_get_time (unsigned int *hi, unsigned int *lo)
655 1.1 christos {
656 1.1 christos #ifdef VMS
657 1.1 christos struct _generic_64 t;
658 1.1 christos
659 1.1 christos sys$gettim (&t);
660 1.1 christos *lo = t.gen64$q_quadword;
661 1.1 christos *hi = t.gen64$q_quadword >> 32;
662 1.1 christos #else
663 1.1 christos time_t t;
664 1.1 christos
665 1.1 christos time (&t);
666 1.1 christos vms_time_t_to_vms_time (t, hi, lo);
667 1.1 christos #endif
668 1.1 christos }
669 1.1 christos
670 1.1 christos /* Get the current time into a raw buffer BUF. */
671 1.1 christos
672 1.1 christos void
673 1.1 christos vms_raw_get_time (unsigned char *buf)
674 1.1 christos {
675 1.1 christos unsigned int hi, lo;
676 1.1 christos
677 1.1 christos vms_get_time (&hi, &lo);
678 1.1 christos bfd_putl32 (lo, buf + 0);
679 bfd_putl32 (hi, buf + 4);
680 }
681