VirtualBox

source: kBuild/trunk/src/kmk/vms_progname.c@ 3387

Last change on this file since 3387 was 3140, checked in by bird, 6 years ago

kmk: Merged in changes from GNU make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6 / https://git.savannah.gnu.org/git/make.git).

  • Property svn:eol-style set to native
File size: 14.3 KB
Line 
1/* File: vms_progname.c
2 *
3 * This module provides a fixup of the program name.
4 *
5 * This module is designed to be a plug in replacement for the
6 * progname module used by many GNU utilities with a few enhancements
7 * needed for GNU Make.
8 *
9 * It does not support the HAVE_DECL_PROGRAM_INVOCATION_* macros at this
10 * time.
11 *
12 * Make sure that the program_name string is set as close as possible to
13 * what the original command was given.
14 *
15 * When run from DCL, The argv[0] element is initialized with an absolute
16 * path name. The decc$ feature logical names can control the format
17 * of this pathname. In some cases it causes the UNIX format name to be
18 * formatted incorrectly.
19 *
20 * This DCL provided name is usually incompatible with what is expected to
21 * be provided by Unix programs and needs to be replaced.
22 *
23 * When run from an exec() call, the argv[0] element is initialized by the
24 * program. This name is compatible with what is expected to be provided
25 * by Unix programs and should be passed through unchanged.
26 *
27 * The DCL provided name can be detected because it always contains the
28 * device name.
29 *
30 * DCL examples:
31 * devname:[dir]program.exe;1 Normal VMS - remove path and .EXE;n
32 * devname:[dir]facility$program.exe;1 Facility also needs removal.
33 * /devname/dir/program.exe
34 * /DISK$VOLUME/dir/program.exe.1 Bug version should not be there.
35 * /DISK$VOLUME/dir/program. Bug Period should not be there.
36 *
37 */
38
39/* Copyright (C) 2014-2016 Free Software Foundation, Inc.
40
41GNU Make is free software; you can redistribute it and/or modify it under the
42terms of the GNU General Public License as published by the Free Software
43Foundation; either version 3 of the License, or (at your option) any later
44version.
45
46GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
47WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
48A PARTICULAR PURPOSE. See the GNU General Public License for more details.
49
50You should have received a copy of the GNU General Public License along with
51this program. If not, see <http://www.gnu.org/licenses/>. */
52
53
54/* Per copyright assignment agreement with the Free Software Foundation
55 this software may be available under under other license agreements
56 and copyrights. */
57
58
59#ifdef HAVE_CONFIG_H
60# include "config.h"
61#endif
62
63#include <stdio.h>
64#include <string.h>
65#include <ctype.h>
66#include <stdlib.h>
67
68#include <descrip.h>
69#include <dvidef.h>
70#include <efndef.h>
71#include <fscndef.h>
72#include <stsdef.h>
73
74#ifdef USE_PROGNAME_H
75# include "progname.h"
76#endif
77
78#pragma member_alignment save
79#pragma nomember_alignment longword
80struct item_list_3
81{
82 unsigned short len;
83 unsigned short code;
84 void * bufadr;
85 unsigned short * retlen;
86};
87
88struct filescan_itmlst_2
89{
90 unsigned short length;
91 unsigned short itmcode;
92 char * component;
93};
94
95#pragma member_alignment
96
97int
98SYS$GETDVIW (unsigned long efn,
99 unsigned short chan,
100 const struct dsc$descriptor_s * devnam,
101 const struct item_list_3 * itmlst,
102 void * iosb,
103 void (* astadr)(unsigned long),
104 unsigned long astprm,
105 void * nullarg);
106
107int
108SYS$FILESCAN (const struct dsc$descriptor_s * srcstr,
109 struct filescan_itmlst_2 * valuelist,
110 unsigned long * fldflags,
111 struct dsc$descriptor_s *auxout,
112 unsigned short * retlen);
113
114/* String containing name the program is called with.
115 To be initialized by main(). */
116
117const char *program_name = NULL;
118
119static int internal_need_vms_symbol = 0;
120
121static char vms_new_nam[256];
122
123int
124need_vms_symbol (void)
125{
126 return internal_need_vms_symbol;
127}
128
129
130void
131set_program_name (const char *argv0)
132{
133 int status;
134 int result;
135
136#ifdef DEBUG
137 printf ("original argv0 = %s\n", argv0);
138#endif
139
140 /* Posix requires non-NULL argv[0] */
141 if (argv0 == NULL)
142 {
143 fputs ("A NULL argv[0] was passed through an exec system call.\n",
144 stderr);
145 abort ();
146 }
147
148 program_name = argv0;
149 result = 0;
150 internal_need_vms_symbol = 0;
151
152 /* If the path name starts with a /, then it is an absolute path */
153 /* that may have been generated by the CRTL instead of the command name */
154 /* If it is the device name between the slashes, then this was likely */
155 /* from the run command and needs to be fixed up. */
156 /* If the DECC$POSIX_COMPLIANT_PATHNAMES is set to 2, then it is the */
157 /* DISK$VOLUME that will be present, and it will still need to be fixed. */
158 if (argv0[0] == '/')
159 {
160 char * nextslash;
161 int length;
162 struct item_list_3 itemlist[3];
163 unsigned short dvi_iosb[4];
164 char alldevnam[64];
165 unsigned short alldevnam_len;
166 struct dsc$descriptor_s devname_dsc;
167 char diskvolnam[256];
168 unsigned short diskvolnam_len;
169
170 internal_need_vms_symbol = 1;
171
172 /* Get some information about the disk */
173 /*--------------------------------------*/
174 itemlist[0].len = (sizeof alldevnam) - 1;
175 itemlist[0].code = DVI$_ALLDEVNAM;
176 itemlist[0].bufadr = alldevnam;
177 itemlist[0].retlen = &alldevnam_len;
178 itemlist[1].len = (sizeof diskvolnam) - 1 - 5;
179 itemlist[1].code = DVI$_VOLNAM;
180 itemlist[1].bufadr = &diskvolnam[5];
181 itemlist[1].retlen = &diskvolnam_len;
182 itemlist[2].len = 0;
183 itemlist[2].code = 0;
184
185 /* Add the prefix for the volume name. */
186 /* SYS$GETDVI will append the volume name to this */
187 strcpy (diskvolnam, "DISK$");
188
189 nextslash = strchr (&argv0[1], '/');
190 if (nextslash != NULL)
191 {
192 length = nextslash - argv0 - 1;
193
194 /* Cast needed for HP C compiler diagnostic */
195 devname_dsc.dsc$a_pointer = (char *)&argv0[1];
196 devname_dsc.dsc$w_length = length;
197 devname_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
198 devname_dsc.dsc$b_class = DSC$K_CLASS_S;
199
200 status = SYS$GETDVIW (EFN$C_ENF, 0, &devname_dsc, itemlist,
201 dvi_iosb, NULL, 0, 0);
202 if (!$VMS_STATUS_SUCCESS (status))
203 {
204 /* If the sys$getdviw fails, then this path was passed by */
205 /* An exec() program and not from DCL, so do nothing */
206 /* An example is "/tmp/program" where tmp: does not exist */
207#ifdef DEBUG
208 printf ("sys$getdviw failed with status %d\n", status);
209#endif
210 result = 0;
211 }
212 else if (!$VMS_STATUS_SUCCESS (dvi_iosb[0]))
213 {
214#ifdef DEBUG
215 printf ("sys$getdviw failed with iosb %d\n", dvi_iosb[0]);
216#endif
217 result = 0;
218 }
219 else
220 {
221 char * devnam;
222 int devnam_len;
223 char argv_dev[64];
224
225 /* Null terminate the returned alldevnam */
226 alldevnam[alldevnam_len] = 0;
227 devnam = alldevnam;
228 devnam_len = alldevnam_len;
229
230 /* Need to skip past any leading underscore */
231 if (devnam[0] == '_')
232 {
233 devnam++;
234 devnam_len--;
235 }
236
237 /* And remove the trailing colon */
238 if (devnam[devnam_len - 1] == ':')
239 {
240 devnam_len--;
241 devnam[devnam_len] = 0;
242 }
243
244 /* Null terminate the returned volnam */
245 diskvolnam_len += 5;
246 diskvolnam[diskvolnam_len] = 0;
247
248 /* Check first for normal CRTL behavior */
249 if (devnam_len == length)
250 {
251 strncpy (vms_new_nam, &argv0[1], length);
252 vms_new_nam[length] = 0;
253 result = (strcasecmp (devnam, vms_new_nam) == 0);
254 }
255
256 /* If we have not got a match, check for POSIX Compliant */
257 /* behavior. To be more accurate, we could also check */
258 /* to see if that feature is active. */
259 if ((result == 0) && (diskvolnam_len == length))
260 {
261 strncpy (vms_new_nam, &argv0[1], length);
262 vms_new_nam[length] = 0;
263 result = (strcasecmp (diskvolnam, vms_new_nam) == 0);
264 }
265 }
266 }
267 }
268 else
269 {
270 /* The path did not start with a slash, so it could be VMS format */
271 /* If it is vms format, it has a volume/device in it as it must */
272 /* be an absolute path */
273 struct dsc$descriptor_s path_desc;
274 int status;
275 unsigned long field_flags;
276 struct filescan_itmlst_2 item_list[5];
277 char * volume;
278 char * name;
279 int name_len;
280 char * ext;
281
282 path_desc.dsc$a_pointer = (char *)argv0; /* cast ok */
283 path_desc.dsc$w_length = strlen (argv0);
284 path_desc.dsc$b_dtype = DSC$K_DTYPE_T;
285 path_desc.dsc$b_class = DSC$K_CLASS_S;
286
287 /* Don't actually need to initialize anything buf itmcode */
288 /* I just do not like uninitialized input values */
289
290 /* Sanity check, this must be the same length as input */
291 item_list[0].itmcode = FSCN$_FILESPEC;
292 item_list[0].length = 0;
293 item_list[0].component = NULL;
294
295 /* If the device is present, then it if a VMS spec */
296 item_list[1].itmcode = FSCN$_DEVICE;
297 item_list[1].length = 0;
298 item_list[1].component = NULL;
299
300 /* we need the program name and type */
301 item_list[2].itmcode = FSCN$_NAME;
302 item_list[2].length = 0;
303 item_list[2].component = NULL;
304
305 item_list[3].itmcode = FSCN$_TYPE;
306 item_list[3].length = 0;
307 item_list[3].component = NULL;
308
309 /* End the list */
310 item_list[4].itmcode = 0;
311 item_list[4].length = 0;
312 item_list[4].component = NULL;
313
314 status = SYS$FILESCAN ((const struct dsc$descriptor_s *)&path_desc,
315 item_list, &field_flags, NULL, NULL);
316
317
318 if ($VMS_STATUS_SUCCESS (status) &&
319 (item_list[0].length == path_desc.dsc$w_length) &&
320 (item_list[1].length != 0))
321 {
322
323 char * dollar;
324 int keep_ext;
325 int i;
326
327 /* We need the filescan to be successful, */
328 /* same length as input, and a volume to be present */
329 internal_need_vms_symbol = 1;
330
331 /* We will assume that we only get to this path on a version */
332 /* of VMS that does not support the EFS character set */
333
334 /* There may be a xxx$ prefix on the image name. Linux */
335 /* programs do not handle that well, so strip the prefix */
336 name = item_list[2].component;
337 name_len = item_list[2].length;
338 dollar = strrchr (name, '$');
339 if (dollar != NULL)
340 {
341 dollar++;
342 name_len = name_len - (dollar - name);
343 name = dollar;
344 }
345
346 strncpy (vms_new_nam, name, name_len);
347 vms_new_nam[name_len] = 0;
348
349 /* Commit to using the new name */
350 program_name = vms_new_nam;
351
352 /* We only keep the extension if it is not ".exe" */
353 keep_ext = 0;
354 ext = item_list[3].component;
355
356 if (item_list[3].length != 1)
357 {
358 keep_ext = 1;
359 if (item_list[3].length == 4)
360 {
361 if ((ext[1] == 'e' || ext[1] == 'E') &&
362 (ext[2] == 'x' || ext[2] == 'X') &&
363 (ext[3] == 'e' || ext[3] == 'E'))
364 keep_ext = 0;
365 }
366 }
367
368 if (keep_ext == 1)
369 strncpy (&vms_new_nam[name_len], ext, item_list[3].length);
370 }
371 }
372
373 if (result)
374 {
375 char * lastslash;
376 char * dollar;
377 char * dotexe;
378 char * lastdot;
379 char * extension;
380
381 /* This means it is probably the name from a DCL command */
382 /* Find the last slash which separates the file from the */
383 /* path. */
384 lastslash = strrchr (argv0, '/');
385
386 if (lastslash != NULL) {
387 int i;
388
389 lastslash++;
390
391 /* There may be a xxx$ prefix on the image name. Linux */
392 /* programs do not handle that well, so strip the prefix */
393 dollar = strrchr (lastslash, '$');
394
395 if (dollar != NULL) {
396 dollar++;
397 lastslash = dollar;
398 }
399
400 strcpy (vms_new_nam, lastslash);
401
402 /* In UNIX mode + EFS character set, there should not be a */
403 /* version present, as it is not possible when parsing to */
404 /* tell if it is a version or part of the UNIX filename as */
405 /* UNIX programs use numeric extensions for many reasons. */
406
407 lastdot = strrchr (vms_new_nam, '.');
408 if (lastdot != NULL) {
409 int i;
410
411 i = 1;
412 while (isdigit (lastdot[i])) {
413 i++;
414 }
415 if (lastdot[i] == 0) {
416 *lastdot = 0;
417 }
418 }
419
420 /* Find the .exe on the name (case insenstive) and toss it */
421 dotexe = strrchr (vms_new_nam, '.');
422 if (dotexe != NULL) {
423 if ((dotexe[1] == 'e' || dotexe[1] == 'E') &&
424 (dotexe[2] == 'x' || dotexe[2] == 'X') &&
425 (dotexe[3] == 'e' || dotexe[3] == 'E') &&
426 (dotexe[4] == 0)) {
427
428 *dotexe = 0;
429 } else {
430 /* Also need to handle a null extension because of a */
431 /* CRTL bug. */
432 if (dotexe[1] == 0) {
433 *dotexe = 0;
434 }
435 }
436 }
437
438 /* Commit to new name */
439 program_name = vms_new_nam;
440
441 } else {
442 /* There is no way that the code should ever get here */
443 /* As we already verified that the '/' was present */
444 fprintf (stderr, "Sanity failure somewhere we lost a '/'\n");
445 }
446 }
447}
448
449#ifdef DEBUG
450
451int
452main (int argc, char ** argv, char **env)
453{
454
455 char command[1024];
456
457 set_program_name (argv[0]);
458
459 printf ("modified argv[0] = %s\n", program_name);
460
461 return 0;
462}
463#endif
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use