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