vms-misc.c revision 1.1.1.5 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.5 christos Copyright (C) 1996-2017 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 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 christos char *
143 1.1 christos _bfd_vms_save_sized_string (unsigned char *str, int size)
144 1.1 christos {
145 1.1 christos char *newstr = bfd_malloc ((bfd_size_type) size + 1);
146 1.1 christos
147 1.1 christos if (newstr == NULL)
148 1.1 christos return NULL;
149 1.1 christos memcpy (newstr, (char *) str, (size_t) size);
150 1.1 christos newstr[size] = 0;
151 1.1 christos
152 1.1 christos return newstr;
153 1.1 christos }
154 1.1 christos
155 1.1 christos /* Copy counted string (string with size at first byte) to new allocated area
156 1.1 christos ptr points to size byte on entry */
157 1.1 christos
158 1.1 christos char *
159 1.1 christos _bfd_vms_save_counted_string (unsigned char *ptr)
160 1.1 christos {
161 1.1 christos int len = *ptr++;
162 1.1 christos
163 1.1 christos return _bfd_vms_save_sized_string (ptr, len);
164 1.1 christos }
165 1.1 christos
166 1.1 christos /* Object output routines. */
168 1.1 christos
169 1.1 christos /* Begin new record.
170 1.1 christos Write 2 bytes rectype and 2 bytes record length. */
171 1.1 christos
172 1.1 christos void
173 1.1 christos _bfd_vms_output_begin (struct vms_rec_wr *recwr, int rectype)
174 1.1 christos {
175 1.1 christos vms_debug2 ((6, "_bfd_vms_output_begin (type %d)\n", rectype));
176 1.1 christos
177 1.1 christos /* Record must have been closed. */
178 1.1 christos BFD_ASSERT (recwr->size == 0);
179 1.1 christos
180 1.1 christos _bfd_vms_output_short (recwr, (unsigned int) rectype);
181 1.1 christos
182 1.1 christos /* Placeholder for length. */
183 1.1 christos _bfd_vms_output_short (recwr, 0);
184 1.1 christos }
185 1.1 christos
186 1.1 christos /* Begin new sub-record.
187 1.1 christos Write 2 bytes rectype, and 2 bytes record length. */
188 1.1 christos
189 1.1 christos void
190 1.1 christos _bfd_vms_output_begin_subrec (struct vms_rec_wr *recwr, int rectype)
191 1.1 christos {
192 1.1 christos vms_debug2 ((6, "_bfd_vms_output_begin_subrec (type %d)\n", rectype));
193 1.1 christos
194 1.1 christos /* Subrecord must have been closed. */
195 1.1 christos BFD_ASSERT (recwr->subrec_offset == 0);
196 1.1 christos
197 1.1 christos /* Save start of subrecord offset. */
198 1.1 christos recwr->subrec_offset = recwr->size;
199 1.1 christos
200 1.1 christos /* Subrecord type. */
201 1.1 christos _bfd_vms_output_short (recwr, (unsigned int) rectype);
202 1.1 christos
203 1.1 christos /* Placeholder for length. */
204 1.1 christos _bfd_vms_output_short (recwr, 0);
205 1.1 christos }
206 1.1 christos
207 1.1 christos /* Set record/subrecord alignment. */
208 1.1 christos
209 1.1 christos void
210 1.1 christos _bfd_vms_output_alignment (struct vms_rec_wr *recwr, int alignto)
211 1.1 christos {
212 1.1 christos vms_debug2 ((6, "_bfd_vms_output_alignment (%d)\n", alignto));
213 1.1 christos recwr->align = alignto;
214 1.1 christos }
215 1.1 christos
216 1.1 christos /* Align the size of the current record (whose length is LENGTH).
217 1.1 christos Warning: this obviously changes the record (and the possible subrecord)
218 1.1 christos length. */
219 1.1 christos
220 1.1 christos static void
221 1.1 christos _bfd_vms_output_align (struct vms_rec_wr *recwr, unsigned int length)
222 1.1 christos {
223 1.1 christos unsigned int real_size = recwr->size;
224 1.1 christos unsigned int aligncount;
225 1.1 christos
226 1.1 christos /* Pad with 0 if alignment is required. */
227 1.1 christos aligncount = (recwr->align - (length % recwr->align)) % recwr->align;
228 1.1 christos vms_debug2 ((6, "align: adding %d bytes\n", aligncount));
229 1.1 christos while (aligncount-- > 0)
230 1.1 christos recwr->buf[real_size++] = 0;
231 1.1 christos
232 1.1 christos recwr->size = real_size;
233 1.1 christos }
234 1.1 christos
235 1.1 christos /* Ends current sub-record. Set length field. */
236 1.1 christos
237 1.1 christos void
238 1.1 christos _bfd_vms_output_end_subrec (struct vms_rec_wr *recwr)
239 1.1 christos {
240 1.1 christos int real_size = recwr->size;
241 1.1 christos int length;
242 1.1 christos
243 1.1 christos /* Subrecord must be open. */
244 1.1 christos BFD_ASSERT (recwr->subrec_offset != 0);
245 1.1 christos
246 1.1 christos length = real_size - recwr->subrec_offset;
247 1.1 christos
248 1.1 christos if (length == 0)
249 1.1 christos return;
250 1.1 christos
251 1.1 christos _bfd_vms_output_align (recwr, length);
252 1.1 christos
253 1.1 christos /* Put length to buffer. */
254 1.1 christos bfd_putl16 ((bfd_vma) (recwr->size - recwr->subrec_offset),
255 1.1 christos recwr->buf + recwr->subrec_offset + 2);
256 1.1 christos
257 1.1 christos /* Close the subrecord. */
258 1.1 christos recwr->subrec_offset = 0;
259 1.1 christos }
260 1.1 christos
261 1.1 christos /* Ends current record (and write it). */
262 1.1 christos
263 1.1 christos void
264 1.1 christos _bfd_vms_output_end (bfd *abfd, struct vms_rec_wr *recwr)
265 1.1 christos {
266 1.1 christos vms_debug2 ((6, "_bfd_vms_output_end (size %u)\n", recwr->size));
267 1.1 christos
268 1.1 christos /* Subrecord must have been closed. */
269 1.1 christos BFD_ASSERT (recwr->subrec_offset == 0);
270 1.1 christos
271 1.1 christos if (recwr->size == 0)
272 1.1 christos return;
273 1.1 christos
274 1.1 christos _bfd_vms_output_align (recwr, recwr->size);
275 1.1 christos
276 1.1 christos /* Write the length word. */
277 1.1 christos bfd_putl16 ((bfd_vma) recwr->size, recwr->buf + 2);
278 1.1 christos
279 1.1 christos /* File is open in undefined (UDF) format on VMS, but ultimately will be
280 1.1 christos converted to variable length (VAR) format. VAR format has a length
281 1.1 christos word first which must be explicitly output in UDF format. */
282 1.1 christos /* So, first the length word. */
283 1.1 christos bfd_bwrite (recwr->buf + 2, 2, abfd);
284 1.1 christos
285 1.1 christos /* Align. */
286 1.1 christos if (recwr->size & 1)
287 1.1 christos recwr->buf[recwr->size++] = 0;
288 1.1 christos
289 1.1 christos /* Then the record. */
290 1.1 christos bfd_bwrite (recwr->buf, (size_t) recwr->size, abfd);
291 1.1 christos
292 1.1 christos recwr->size = 0;
293 1.1 christos }
294 1.1 christos
295 1.1 christos /* Check remaining buffer size. Return what's left. */
296 1.1 christos
297 1.1 christos int
298 1.1 christos _bfd_vms_output_check (struct vms_rec_wr *recwr, int size)
299 1.1 christos {
300 1.1 christos vms_debug2 ((6, "_bfd_vms_output_check (%d)\n", size));
301 1.1 christos
302 1.1 christos return (MAX_OUTREC_SIZE - (recwr->size + size + MIN_OUTREC_LUFT));
303 1.1 christos }
304 1.1 christos
305 1.1 christos /* Output byte (8 bit) value. */
306 1.1 christos
307 1.1 christos void
308 1.1 christos _bfd_vms_output_byte (struct vms_rec_wr *recwr, unsigned int value)
309 1.1 christos {
310 1.1 christos vms_debug2 ((6, "_bfd_vms_output_byte (%02x)\n", value));
311 1.1 christos
312 1.1 christos *(recwr->buf + recwr->size) = value;
313 1.1 christos recwr->size += 1;
314 1.1 christos }
315 1.1 christos
316 1.1 christos /* Output short (16 bit) value. */
317 1.1 christos
318 1.1 christos void
319 1.1 christos _bfd_vms_output_short (struct vms_rec_wr *recwr, unsigned int value)
320 1.1 christos {
321 1.1 christos vms_debug2 ((6, "_bfd_vms_output_short (%04x)\n", value));
322 1.1 christos
323 1.1 christos bfd_putl16 ((bfd_vma) value & 0xffff, recwr->buf + recwr->size);
324 1.1 christos recwr->size += 2;
325 1.1 christos }
326 1.1 christos
327 1.1 christos /* Output long (32 bit) value. */
328 1.1 christos
329 1.1 christos void
330 1.1 christos _bfd_vms_output_long (struct vms_rec_wr *recwr, unsigned long value)
331 1.1 christos {
332 1.1 christos vms_debug2 ((6, "_bfd_vms_output_long (%08lx)\n", value));
333 1.1 christos
334 1.1 christos bfd_putl32 ((bfd_vma) value, recwr->buf + recwr->size);
335 1.1 christos recwr->size += 4;
336 1.1 christos }
337 1.1 christos
338 1.1 christos /* Output quad (64 bit) value. */
339 1.1 christos
340 1.1 christos void
341 1.1 christos _bfd_vms_output_quad (struct vms_rec_wr *recwr, bfd_vma value)
342 1.1 christos {
343 1.1 christos vms_debug2 ((6, "_bfd_vms_output_quad (%08lx)\n", (unsigned long)value));
344 1.1 christos
345 1.1 christos bfd_putl64 (value, recwr->buf + recwr->size);
346 1.1 christos recwr->size += 8;
347 1.1 christos }
348 1.1 christos
349 1.1 christos /* Output c-string as counted string. */
350 1.1 christos
351 1.1 christos void
352 1.1 christos _bfd_vms_output_counted (struct vms_rec_wr *recwr, const char *value)
353 1.1 christos {
354 1.1 christos int len;
355 1.1 christos
356 1.1 christos vms_debug2 ((6, "_bfd_vms_output_counted (%s)\n", value));
357 1.1 christos
358 1.1 christos len = strlen (value);
359 1.1.1.5 christos if (len == 0)
360 1.1 christos {
361 1.1 christos _bfd_error_handler (_("_bfd_vms_output_counted called with zero bytes"));
362 1.1 christos return;
363 1.1 christos }
364 1.1.1.5 christos if (len > 255)
365 1.1 christos {
366 1.1 christos _bfd_error_handler (_("_bfd_vms_output_counted called with too many bytes"));
367 1.1 christos return;
368 1.1 christos }
369 1.1 christos _bfd_vms_output_byte (recwr, (unsigned int) len & 0xff);
370 1.1 christos _bfd_vms_output_dump (recwr, (const unsigned char *)value, len);
371 1.1 christos }
372 1.1 christos
373 1.1 christos /* Output character area. */
374 1.1 christos
375 1.1 christos void
376 1.1 christos _bfd_vms_output_dump (struct vms_rec_wr *recwr, const unsigned char *data, int len)
377 1.1 christos {
378 1.1 christos vms_debug2 ((6, "_bfd_vms_output_dump (%d)\n", len));
379 1.1 christos
380 1.1 christos if (len == 0)
381 1.1 christos return;
382 1.1 christos
383 1.1 christos memcpy (recwr->buf + recwr->size, data, (size_t) len);
384 1.1 christos recwr->size += len;
385 1.1 christos }
386 1.1 christos
387 1.1 christos /* Output count bytes of value. */
388 1.1 christos
389 1.1 christos void
390 1.1 christos _bfd_vms_output_fill (struct vms_rec_wr *recwr, int value, int count)
391 1.1 christos {
392 1.1 christos vms_debug2 ((6, "_bfd_vms_output_fill (val %02x times %d)\n", value, count));
393 1.1 christos
394 1.1 christos if (count == 0)
395 1.1 christos return;
396 1.1 christos memset (recwr->buf + recwr->size, value, (size_t) count);
397 1.1 christos recwr->size += count;
398 1.1 christos }
399 1.1 christos
400 1.1 christos #ifdef VMS
401 1.1 christos /* Convert the file to variable record length format. This is done
402 1.1 christos using undocumented system call sys$modify().
403 1.1 christos Pure VMS version. */
404 1.1 christos
405 1.1 christos static void
406 1.1 christos vms_convert_to_var (char * vms_filename)
407 1.1 christos {
408 1.1 christos struct FAB fab = cc$rms_fab;
409 1.1 christos
410 1.1 christos fab.fab$l_fna = vms_filename;
411 1.1 christos fab.fab$b_fns = strlen (vms_filename);
412 1.1 christos fab.fab$b_fac = FAB$M_PUT;
413 1.1 christos fab.fab$l_fop = FAB$M_ESC;
414 1.1 christos fab.fab$l_ctx = RME$C_SETRFM;
415 1.1 christos
416 1.1 christos sys$open (&fab);
417 1.1 christos
418 1.1 christos fab.fab$b_rfm = FAB$C_VAR;
419 1.1 christos
420 1.1 christos sys$modify (&fab);
421 1.1 christos sys$close (&fab);
422 1.1 christos }
423 1.1 christos
424 1.1 christos static int
425 1.1 christos vms_convert_to_var_1 (char *filename, int type)
426 1.1 christos {
427 1.1 christos if (type != DECC$K_FILE)
428 1.1 christos return FALSE;
429 1.1 christos vms_convert_to_var (filename);
430 1.1 christos return TRUE;
431 1.1 christos }
432 1.1 christos
433 1.1 christos /* Convert the file to variable record length format. This is done
434 1.1 christos using undocumented system call sys$modify().
435 1.1 christos Unix filename version. */
436 1.1 christos
437 1.1 christos int
438 1.1 christos _bfd_vms_convert_to_var_unix_filename (const char *unix_filename)
439 1.1 christos {
440 1.1 christos if (decc$to_vms (unix_filename, &vms_convert_to_var_1, 0, 1) != 1)
441 1.1 christos return FALSE;
442 1.1 christos return TRUE;
443 1.1 christos }
444 1.1 christos #endif /* VMS */
445 1.1 christos
446 1.1 christos /* Manufacture a VMS like time on a unix based system.
447 1.1 christos stolen from obj-vms.c. */
448 1.1 christos
449 1.1 christos unsigned char *
450 1.1 christos get_vms_time_string (void)
451 1.1 christos {
452 1.1 christos static unsigned char tbuf[18];
453 1.1 christos #ifndef VMS
454 1.1 christos char *pnt;
455 1.1 christos time_t timeb;
456 1.1 christos
457 1.1 christos time (& timeb);
458 1.1 christos pnt = ctime (&timeb);
459 1.1 christos pnt[3] = 0;
460 1.1 christos pnt[7] = 0;
461 1.1 christos pnt[10] = 0;
462 1.1 christos pnt[16] = 0;
463 1.1 christos pnt[24] = 0;
464 1.1 christos sprintf ((char *) tbuf, "%2s-%3s-%s %s",
465 1.1 christos pnt + 8, pnt + 4, pnt + 20, pnt + 11);
466 1.1 christos #else
467 1.1 christos struct
468 1.1 christos {
469 1.1 christos int Size;
470 1.1 christos unsigned char *Ptr;
471 1.1 christos } Descriptor;
472 1.1 christos Descriptor.Size = 17;
473 1.1 christos Descriptor.Ptr = tbuf;
474 1.1 christos SYS$ASCTIM (0, &Descriptor, 0, 0);
475 1.1 christos #endif /* not VMS */
476 1.1 christos
477 1.1 christos vms_debug2 ((6, "vmstimestring:'%s'\n", tbuf));
478 1.1 christos
479 1.1 christos return tbuf;
480 1.1 christos }
481 1.1 christos
482 1.1 christos /* Create module name from filename (ie, extract the basename and convert it
483 1.1 christos in upper cases). Works on both VMS and UNIX pathes.
484 1.1 christos The result has to be free(). */
485 1.1 christos
486 1.1 christos char *
487 1.1 christos vms_get_module_name (const char *filename, bfd_boolean upcase)
488 1.1 christos {
489 1.1 christos char *fname, *fptr;
490 1.1 christos const char *fout;
491 1.1 christos
492 1.1 christos /* Strip VMS path. */
493 1.1 christos fout = strrchr (filename, ']');
494 1.1 christos if (fout == NULL)
495 1.1 christos fout = strchr (filename, ':');
496 1.1 christos if (fout != NULL)
497 1.1 christos fout++;
498 1.1 christos else
499 1.1 christos fout = filename;
500 1.1 christos
501 1.1 christos /* Strip UNIX path. */
502 1.1 christos fptr = strrchr (fout, '/');
503 1.1 christos if (fptr != NULL)
504 1.1 christos fout = fptr + 1;
505 1.1 christos
506 1.1 christos fname = strdup (fout);
507 1.1 christos
508 1.1 christos /* Strip suffix. */
509 1.1 christos fptr = strrchr (fname, '.');
510 1.1 christos if (fptr != 0)
511 1.1 christos *fptr = 0;
512 1.1 christos
513 1.1 christos /* Convert to upper case and truncate at 31 characters.
514 1.1 christos (VMS object file format restricts module name length to 31). */
515 1.1 christos fptr = fname;
516 1.1 christos for (fptr = fname; *fptr != 0; fptr++)
517 1.1 christos {
518 1.1 christos if (*fptr == ';' || (fptr - fname) >= 31)
519 1.1 christos {
520 1.1 christos *fptr = 0;
521 1.1 christos break;
522 1.1 christos }
523 1.1 christos if (upcase)
524 1.1 christos *fptr = TOUPPER (*fptr);
525 1.1 christos }
526 1.1 christos return fname;
527 1.1 christos }
528 1.1 christos
529 1.1 christos /* Compared to usual UNIX time_t, VMS time has less limits:
530 1.1 christos - 64 bit (63 bits in fact as the MSB must be 0)
531 1.1 christos - 100ns granularity
532 1.1.1.2 christos - epoch is Nov 17, 1858.
533 1.1.1.2 christos Here has the constants and the routines used to convert VMS from/to UNIX time.
534 1.1.1.2 christos The conversion routines don't assume 64 bits arithmetic.
535 1.1.1.2 christos
536 1.1 christos Here we assume that the definition of time_t is the UNIX one, ie integer
537 1.1 christos type, expressing seconds since the epoch. */
538 1.1 christos
539 1.1 christos /* UNIX time granularity for VMS, ie 1s / 100ns. */
540 1.1 christos #define VMS_TIME_FACTOR 10000000
541 1.1 christos
542 1.1 christos /* Number of seconds since VMS epoch of the UNIX epoch. */
543 1.1 christos #define VMS_TIME_OFFSET 3506716800U
544 1.1 christos
545 1.1 christos /* Convert a VMS time to a unix time. */
546 1.1 christos
547 1.1 christos time_t
548 1.1 christos vms_time_to_time_t (unsigned int hi, unsigned int lo)
549 1.1 christos {
550 1.1 christos unsigned int tmp;
551 1.1.1.2 christos unsigned int rlo;
552 1.1 christos int i;
553 1.1 christos time_t res;
554 1.1 christos
555 1.1 christos /* First convert to seconds. */
556 1.1 christos tmp = hi % VMS_TIME_FACTOR;
557 1.1 christos hi = hi / VMS_TIME_FACTOR;
558 1.1 christos rlo = 0;
559 1.1 christos for (i = 0; i < 4; i++)
560 1.1 christos {
561 1.1 christos tmp = (tmp << 8) | (lo >> 24);
562 1.1 christos lo <<= 8;
563 1.1 christos
564 1.1 christos rlo = (rlo << 8) | (tmp / VMS_TIME_FACTOR);
565 1.1 christos tmp %= VMS_TIME_FACTOR;
566 1.1 christos }
567 1.1 christos lo = rlo;
568 1.1.1.2 christos
569 1.1.1.2 christos /* Return 0 in case of overflow. */
570 1.1 christos if (hi > 1
571 1.1 christos || (hi == 1 && lo >= VMS_TIME_OFFSET))
572 1.1 christos return 0;
573 1.1.1.2 christos
574 1.1 christos /* Return 0 in case of underflow. */
575 1.1 christos if (hi == 0 && lo < VMS_TIME_OFFSET)
576 1.1.1.2 christos return 0;
577 1.1.1.2 christos
578 1.1.1.2 christos res = lo - VMS_TIME_OFFSET;
579 1.1.1.2 christos if (res <= 0)
580 1.1 christos return 0;
581 1.1 christos return res;
582 1.1 christos }
583 1.1 christos
584 1.1 christos /* Convert a time_t to a VMS time. */
585 1.1 christos
586 1.1 christos void
587 1.1 christos vms_time_t_to_vms_time (time_t ut, unsigned int *hi, unsigned int *lo)
588 1.1 christos {
589 1.1 christos unsigned short val[4];
590 1.1 christos unsigned short tmp[4];
591 1.1 christos unsigned int carry;
592 1.1 christos int i;
593 1.1 christos
594 1.1 christos /* Put into val. */
595 1.1 christos val[0] = ut & 0xffff;
596 1.1 christos val[1] = (ut >> 16) & 0xffff;
597 1.1 christos val[2] = sizeof (ut) > 4 ? (ut >> 32) & 0xffff : 0;
598 1.1 christos val[3] = sizeof (ut) > 4 ? (ut >> 48) & 0xffff : 0;
599 1.1 christos
600 1.1 christos /* Add offset. */
601 1.1 christos tmp[0] = VMS_TIME_OFFSET & 0xffff;
602 1.1 christos tmp[1] = VMS_TIME_OFFSET >> 16;
603 1.1 christos tmp[2] = 0;
604 1.1 christos tmp[3] = 0;
605 1.1 christos carry = 0;
606 1.1 christos for (i = 0; i < 4; i++)
607 1.1 christos {
608 1.1 christos carry += tmp[i] + val[i];
609 1.1 christos val[i] = carry & 0xffff;
610 1.1 christos carry = carry >> 16;
611 1.1 christos }
612 1.1 christos
613 1.1 christos /* Multiply by factor, well first by 10000 and then by 1000. */
614 1.1 christos carry = 0;
615 1.1 christos for (i = 0; i < 4; i++)
616 1.1 christos {
617 1.1 christos carry += val[i] * 10000;
618 1.1 christos val[i] = carry & 0xffff;
619 1.1 christos carry = carry >> 16;
620 1.1 christos }
621 1.1 christos carry = 0;
622 1.1 christos for (i = 0; i < 4; i++)
623 1.1 christos {
624 1.1 christos carry += val[i] * 1000;
625 1.1 christos val[i] = carry & 0xffff;
626 1.1 christos carry = carry >> 16;
627 1.1 christos }
628 1.1 christos
629 1.1 christos /* Write the result. */
630 1.1 christos *lo = val[0] | (val[1] << 16);
631 1.1 christos *hi = val[2] | (val[3] << 16);
632 1.1 christos }
633 1.1 christos
634 1.1 christos /* Convert a raw (stored in a buffer) VMS time to a unix time. */
635 1.1 christos
636 1.1 christos time_t
637 1.1 christos vms_rawtime_to_time_t (unsigned char *buf)
638 1.1 christos {
639 1.1 christos unsigned int hi = bfd_getl32 (buf + 4);
640 1.1 christos unsigned int lo = bfd_getl32 (buf + 0);
641 1.1 christos
642 1.1 christos return vms_time_to_time_t (hi, lo);
643 1.1 christos }
644 1.1 christos
645 1.1 christos void
646 1.1 christos vms_get_time (unsigned int *hi, unsigned int *lo)
647 1.1 christos {
648 1.1 christos #ifdef VMS
649 1.1 christos struct _generic_64 t;
650 1.1 christos
651 1.1 christos sys$gettim (&t);
652 1.1 christos *lo = t.gen64$q_quadword;
653 1.1 christos *hi = t.gen64$q_quadword >> 32;
654 1.1 christos #else
655 1.1 christos time_t t;
656 1.1 christos
657 1.1 christos time (&t);
658 1.1 christos vms_time_t_to_vms_time (t, hi, lo);
659 1.1 christos #endif
660 1.1 christos }
661 1.1 christos
662 1.1 christos /* Get the current time into a raw buffer BUF. */
663 1.1 christos
664 1.1 christos void
665 1.1 christos vms_raw_get_time (unsigned char *buf)
666 1.1 christos {
667 1.1 christos unsigned int hi, lo;
668 1.1 christos
669 1.1 christos vms_get_time (&hi, &lo);
670 1.1 christos bfd_putl32 (lo, buf + 0);
671 bfd_putl32 (hi, buf + 4);
672 }
673