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