1 /* File: vms_export_symbol.c
3 * Some programs need special environment variables deported as DCL
7 /* Copyright (C) 2014-2020 Free Software Foundation, Inc.
9 GNU Make is free software; you can redistribute it and/or modify it under the
10 terms of the GNU General Public License as published by the Free Software
11 Foundation; either version 3 of the License, or (at your option) any later
14 GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License along with
19 this program. If not, see <http://www.gnu.org/licenses/>. */
22 /* Per copyright assignment agreement with the Free Software Foundation
23 this software may be available under under other license agreements
36 #include <libclidef.h>
38 #pragma member_alignment save
39 #pragma nomember_alignment longword
45 unsigned short * retlen;
49 #pragma member_alignment
52 LIB$GET_SYMBOL (const struct dsc$descriptor_s * symbol,
53 struct dsc$descriptor_s * value,
54 unsigned short * value_len,
55 const unsigned long * table);
58 LIB$SET_SYMBOL (const struct dsc$descriptor_s * symbol,
59 const struct dsc$descriptor_s * value,
60 const unsigned long * table);
63 LIB$DELETE_SYMBOL (const struct dsc$descriptor_s * symbol,
64 const unsigned long * table);
66 #define MAX_DCL_SYMBOL_LEN (255)
67 #if __CRTL_VER >= 70302000 && !defined(__VAX)
68 # define MAX_DCL_SYMBOL_VALUE (8192)
70 # define MAX_DCL_SYMBOL_VALUE (1024)
75 struct dcl_symbol * link;
76 struct dsc$descriptor_s name_desc;
77 struct dsc$descriptor_s value_desc;
78 char name[MAX_DCL_SYMBOL_LEN + 1]; /* + 1 byte for null terminator */
79 char value[MAX_DCL_SYMBOL_VALUE +1]; /* + 1 byte for null terminator */
80 char pad[3]; /* Pad structure to longword allignment */
83 static struct dcl_symbol * vms_dcl_symbol_head = NULL;
85 /* Restore symbol state to original condition. */
87 clear_dcl_symbol (struct dcl_symbol * symbol)
90 const unsigned long symtbl = LIB$K_CLI_LOCAL_SYM;
93 if (symbol->value_desc.dsc$w_length == (unsigned short)-1)
94 status = LIB$DELETE_SYMBOL (&symbol->name_desc, &symtbl);
96 status = LIB$SET_SYMBOL (&symbol->name_desc,
97 &symbol->value_desc, &symtbl);
102 /* Restore all exported symbols to their original conditions */
104 clear_exported_symbols (void)
107 struct dcl_symbol * symbol;
109 symbol = vms_dcl_symbol_head;
111 /* Walk the list of symbols. This is done durring exit,
112 * so no need to free memory.
114 while (symbol != NULL)
116 clear_dcl_symbol (symbol);
117 symbol = symbol->link;
123 /* Restore the symbol back to the original value
124 * symbol name is either a plain name or of the form "symbol=name" where
125 * the name portion is ignored.
128 vms_restore_symbol (const char * string)
131 struct dcl_symbol * symbol;
132 char name[MAX_DCL_SYMBOL_LEN + 1];
137 symbol = vms_dcl_symbol_head;
139 /* Isolate the name from the value */
140 value = strchr (string, '=');
143 /* Copy the name from the string */
144 name_len = (value - string);
147 name_len = strlen (string);
149 if (name_len > MAX_DCL_SYMBOL_LEN)
150 name_len = MAX_DCL_SYMBOL_LEN;
152 strncpy (name, string, name_len);
155 /* Walk the list of symbols. The saved symbol is not freed
156 * symbols are likely to be overwritten multiple times, so this
157 * saves time in saving them each time.
159 while (symbol != NULL)
162 result = strcmp (symbol->name, name);
165 clear_dcl_symbol (symbol);
168 symbol = symbol->link;
173 vms_export_dcl_symbol (const char * name, const char * value)
176 struct dcl_symbol * symbol;
177 struct dcl_symbol * next;
178 struct dcl_symbol * link;
180 const unsigned long symtbl = LIB$K_CLI_LOCAL_SYM;
181 struct dsc$descriptor_s value_desc;
184 char new_value[MAX_DCL_SYMBOL_VALUE + 1];
187 next = vms_dcl_symbol_head;
188 link = vms_dcl_symbol_head;
190 /* Is symbol already exported? */
192 while ((found == 0) && (link != NULL))
195 found = !strncasecmp (link->name, name, MAX_DCL_SYMBOL_LEN);
202 /* New symbol, set it up */
205 symbol = malloc (sizeof (struct dcl_symbol));
209 /* Construct the symbol descriptor, used for both saving
210 * the old symbol and creating the new symbol.
212 symbol->name_desc.dsc$w_length = strlen (name);
213 if (symbol->name_desc.dsc$w_length > MAX_DCL_SYMBOL_LEN)
214 symbol->name_desc.dsc$w_length = MAX_DCL_SYMBOL_LEN;
216 strncpy (symbol->name, name, symbol->name_desc.dsc$w_length);
217 symbol->name[symbol->name_desc.dsc$w_length] = 0;
218 symbol->name_desc.dsc$a_pointer = symbol->name;
219 symbol->name_desc.dsc$b_dtype = DSC$K_DTYPE_T;
220 symbol->name_desc.dsc$b_class = DSC$K_CLASS_S;
222 /* construct the value descriptor, used only for saving
225 symbol->value_desc.dsc$a_pointer = symbol->value;
226 symbol->value_desc.dsc$w_length = MAX_DCL_SYMBOL_VALUE;
227 symbol->value_desc.dsc$b_dtype = DSC$K_DTYPE_T;
228 symbol->value_desc.dsc$b_class = DSC$K_CLASS_S;
233 unsigned long old_symtbl;
234 unsigned short value_len;
236 /* Look up the symbol */
237 status = LIB$GET_SYMBOL (&symbol->name_desc, &symbol->value_desc,
238 &value_len, &old_symtbl);
239 if (!$VMS_STATUS_SUCCESS (status))
240 value_len = (unsigned short)-1;
241 else if (old_symtbl != symtbl)
242 value_len = (unsigned short)-1;
244 symbol->value_desc.dsc$w_length = value_len;
247 if (value_len != (unsigned short) -1)
248 symbol->value[value_len] = 0;
250 /* Make sure atexit scheduled */
251 if (vms_dcl_symbol_head == NULL)
253 vms_dcl_symbol_head = symbol;
254 atexit (clear_exported_symbols);
258 /* Extend the chain */
263 /* Create or replace a symbol */
264 value_desc.dsc$a_pointer = new_value;
265 string_len = strlen (value);
266 if (string_len > MAX_DCL_SYMBOL_VALUE)
267 string_len = MAX_DCL_SYMBOL_VALUE;
269 strncpy (new_value, value, string_len);
270 new_value[string_len] = 0;
272 /* Special handling for GNU Make. GNU Make doubles the dollar signs
273 * in environment variables read in from getenv(). Make exports symbols
274 * with the dollar signs already doubled. So all $$ must be converted
276 * If the first $ is not doubled, then do not convert at all.
278 dollarp = strchr (new_value, '$');
279 while (dollarp && dollarp[1] == '$')
283 left = string_len - (dollarp - new_value - 1);
287 memmove (dollarp, &dollarp[1], left);
288 dollarp = strchr (&dollarp[1], '$');
292 /* Ended with $$, simple case */
297 value_desc.dsc$w_length = string_len;
298 value_desc.dsc$b_dtype = DSC$K_DTYPE_T;
299 value_desc.dsc$b_class = DSC$K_CLASS_S;
300 status = LIB$SET_SYMBOL (&symbol->name_desc, &value_desc, &symtbl);
304 /* export a DCL symbol using a string in the same syntax as putenv */
306 vms_putenv_symbol (const char * string)
309 char name[MAX_DCL_SYMBOL_LEN + 1];
314 /* Isolate the name from the value */
315 value = strchr (string, '=');
322 /* Copy the name from the string */
323 name_len = (value - string);
324 if (name_len > MAX_DCL_SYMBOL_LEN)
325 name_len = MAX_DCL_SYMBOL_LEN;
327 strncpy (name, string, name_len);
330 /* Skip past the "=" */
333 /* Export the symbol */
334 status = vms_export_dcl_symbol (name, value);
336 /* Convert the error to Unix format */
337 if (!$VMS_STATUS_SUCCESS (status))
346 #if __CRTL_VER >= 70301000
347 # define transpath_parm transpath
349 static char transpath[MAX_DCL_SYMBOL_VALUE];
352 /* Helper callback routine for converting Unix paths to VMS */
354 to_vms_action (char * vms_spec, int flag, char * transpath_parm)
356 strncpy (transpath, vms_spec, MAX_DCL_SYMBOL_VALUE - 1);
357 transpath[MAX_DCL_SYMBOL_VALUE - 1] = 0;
362 # pragma message save
363 /* Undocumented extra parameter use triggers a ptrmismatch warning */
364 # pragma message disable ptrmismatch
367 /* Create a foreign command only visible to children */
369 create_foreign_command (const char * command, const char * image)
371 char vms_command[MAX_DCL_SYMBOL_VALUE + 1];
374 vms_command[0] = '$';
378 #if __CRTL_VER >= 70301000
379 /* Current decc$to_vms is reentrant */
380 decc$to_vms (image, to_vms_action, 0, 1, &vms_command[1]);
382 /* Older decc$to_vms is not reentrant */
383 decc$to_vms (image, to_vms_action, 0, 1);
384 strncpy (&vms_command[1], transpath, MAX_DCL_SYMBOL_VALUE - 1);
385 vms_command[MAX_DCL_SYMBOL_VALUE] = 0;
390 strncpy (&vms_command[1], image, MAX_DCL_SYMBOL_VALUE - 1);
391 vms_command[MAX_DCL_SYMBOL_VALUE] = 0;
393 status = vms_export_dcl_symbol (command, vms_command);
398 # pragma message restore
405 main(int argc, char ** argv, char **env)
408 char value[MAX_DCL_SYMBOL_VALUE +1];
412 struct dsc$descriptor_s name_desc;
413 struct dsc$descriptor_s value_desc;
414 const unsigned long symtbl = LIB$K_CLI_LOCAL_SYM;
415 unsigned short value_len;
416 unsigned long old_symtbl;
418 const char * vms_command = "vms_export_symbol";
419 const char * vms_image = "test_image.exe";
420 const char * vms_symbol1 = "test_symbol1";
421 const char * value1 = "test_value1";
422 const char * vms_symbol2 = "test_symbol2";
423 const char * putenv_string = "test_symbol2=value2";
424 const char * value2 = "value2";
426 /* Test creating a foreign command */
427 vms_status = create_foreign_command (vms_command, vms_image);
428 if (!$VMS_STATUS_SUCCESS (vms_status))
430 printf("Create foreign command failed: %d\n", vms_status);
434 name_desc.dsc$a_pointer = (char *)vms_command;
435 name_desc.dsc$w_length = strlen (vms_command);
436 name_desc.dsc$b_dtype = DSC$K_DTYPE_T;
437 name_desc.dsc$b_class = DSC$K_CLASS_S;
439 value_desc.dsc$a_pointer = value;
440 value_desc.dsc$w_length = MAX_DCL_SYMBOL_VALUE;
441 value_desc.dsc$b_dtype = DSC$K_DTYPE_T;
442 value_desc.dsc$b_class = DSC$K_CLASS_S;
444 vms_status = LIB$GET_SYMBOL (&name_desc, &value_desc,
445 &value_len, &old_symtbl);
446 if (!$VMS_STATUS_SUCCESS (vms_status))
448 printf ("lib$get_symbol for command failed: %d\n", vms_status);
452 value[value_len] = 0;
453 result = strncasecmp (&value[1], vms_image, value_len - 1);
456 printf ("create_foreign_command failed! expected '%s', got '%s'\n",
457 vms_image, &value[1]);
461 /* Test exporting a symbol */
462 vms_status = vms_export_dcl_symbol (vms_symbol1, value1);
463 if (!$VMS_STATUS_SUCCESS (vms_status))
465 printf ("vms_export_dcl_symbol for command failed: %d\n", vms_status);
469 name_desc.dsc$a_pointer = (char *)vms_symbol1;
470 name_desc.dsc$w_length = strlen (vms_symbol1);
471 vms_status = LIB$GET_SYMBOL(&name_desc, &value_desc,
472 &value_len, &old_symtbl);
473 if (!$VMS_STATUS_SUCCESS(vms_status))
475 printf ("lib$get_symbol for command failed: %d\n", vms_status);
479 value[value_len] = 0;
480 result = strncmp (value, value1, value_len);
483 printf ("vms_export_dcl_symbol failed! expected '%s', got '%s'\n",
488 /* Test putenv for DCL symbols */
489 putenv_status = vms_putenv_symbol (putenv_string);
490 if (putenv_status != 0)
492 perror ("vms_putenv_symbol");
496 name_desc.dsc$a_pointer = (char *)vms_symbol2;
497 name_desc.dsc$w_length = strlen(vms_symbol2);
498 vms_status = LIB$GET_SYMBOL (&name_desc, &value_desc,
499 &value_len, &old_symtbl);
500 if (!$VMS_STATUS_SUCCESS (vms_status))
502 printf ("lib$get_symbol for command failed: %d\n", vms_status);
506 value[value_len] = 0;
507 result = strncmp (value, value2, value_len);
510 printf ("vms_putenv_symbol failed! expected '%s', got '%s'\n",
515 vms_restore_symbol (putenv_string);
516 vms_status = LIB$GET_SYMBOL (&name_desc, &value_desc,
517 &value_len, &old_symtbl);
518 if ($VMS_STATUS_SUCCESS (vms_status))
520 printf ("lib$get_symbol for command succeeded, should have failed\n");