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