3 * VMS-specific routines for perl5
5 * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
6 * 2002, 2003, 2004, 2005, 2006, 2007 by Charles Bailey and others.
8 * You may distribute under the terms of either the GNU General Public
9 * License or the Artistic License, as specified in the README file.
11 * Please see Changes*.* or the Perl Repository Browser for revision history.
15 * Yet small as was their hunted band
16 * still fell and fearless was each hand,
17 * and strong deeds they wrought yet oft,
18 * and loved the woods, whose ways more soft
19 * them seemed than thralls of that black throne
20 * to live and languish in halls of stone.
21 * "The Lay of Leithian", Canto II, lines 135-40
23 * [p.162 of _The Lays of Beleriand_]
29 #if __CRTL_VER < 70300000
30 /* needed for home-rolled utime() */
36 #include <climsgdef.h>
46 #include <libclidef.h>
48 #include <lib$routines.h>
51 #if __CRTL_VER >= 70301000 && !defined(__VAX)
61 #include <str$routines.h>
67 #define NO_EFN EFN$C_ENF
69 #if __CRTL_VER < 70301000 && __CRTL_VER >= 70300000
70 int decc$feature_get_index(const char *name);
71 char* decc$feature_get_name(int index);
72 int decc$feature_get_value(int index, int mode);
73 int decc$feature_set_value(int index, int mode, int value);
78 #pragma member_alignment save
79 #pragma nomember_alignment longword
84 unsigned short * retadr;
86 #pragma member_alignment restore
88 #if __CRTL_VER >= 70300000 && !defined(__VAX)
90 static int set_feature_default(const char *name, int value)
95 index = decc$feature_get_index(name);
97 status = decc$feature_set_value(index, 1, value);
98 if (index == -1 || (status == -1)) {
102 status = decc$feature_get_value(index, 1);
103 if (status != value) {
111 /* Older versions of ssdef.h don't have these */
112 #ifndef SS$_INVFILFOROP
113 # define SS$_INVFILFOROP 3930
115 #ifndef SS$_NOSUCHOBJECT
116 # define SS$_NOSUCHOBJECT 2696
119 /* We implement I/O here, so we will be mixing PerlIO and stdio calls. */
120 #define PERLIO_NOT_STDIO 0
122 /* Don't replace system definitions of vfork, getenv, lstat, and stat,
123 * code below needs to get to the underlying CRTL routines. */
124 #define DONT_MASK_RTL_CALLS
128 /* Anticipating future expansion in lexical warnings . . . */
129 #ifndef WARN_INTERNAL
130 # define WARN_INTERNAL WARN_MISC
133 #ifdef VMS_LONGNAME_SUPPORT
134 #include <libfildef.h>
137 #if !defined(__VAX) && __CRTL_VER >= 80200000
145 #define lstat(_x, _y) stat(_x, _y)
148 /* Routine to create a decterm for use with the Perl debugger */
149 /* No headers, this information was found in the Programming Concepts Manual */
151 static int (*decw_term_port)
152 (const struct dsc$descriptor_s * display,
153 const struct dsc$descriptor_s * setup_file,
154 const struct dsc$descriptor_s * customization,
155 struct dsc$descriptor_s * result_device_name,
156 unsigned short * result_device_name_length,
159 void * char_change_buffer) = 0;
161 /* gcc's header files don't #define direct access macros
162 * corresponding to VAXC's variant structs */
164 # define uic$v_format uic$r_uic_form.uic$v_format
165 # define uic$v_group uic$r_uic_form.uic$v_group
166 # define uic$v_member uic$r_uic_form.uic$v_member
167 # define prv$v_bypass prv$r_prvdef_bits0.prv$v_bypass
168 # define prv$v_grpprv prv$r_prvdef_bits0.prv$v_grpprv
169 # define prv$v_readall prv$r_prvdef_bits0.prv$v_readall
170 # define prv$v_sysprv prv$r_prvdef_bits0.prv$v_sysprv
173 #if defined(NEED_AN_H_ERRNO)
178 #pragma message disable pragma
179 #pragma member_alignment save
180 #pragma nomember_alignment longword
182 #pragma message disable misalgndmem
185 unsigned short int buflen;
186 unsigned short int itmcode;
188 unsigned short int *retlen;
191 struct filescan_itmlst_2 {
192 unsigned short length;
193 unsigned short itmcode;
198 unsigned short length;
199 char str[VMS_MAXRSS];
200 unsigned short pad; /* for longword struct alignment */
204 #pragma message restore
205 #pragma member_alignment restore
208 #define do_fileify_dirspec(a,b,c,d) mp_do_fileify_dirspec(aTHX_ a,b,c,d)
209 #define do_pathify_dirspec(a,b,c,d) mp_do_pathify_dirspec(aTHX_ a,b,c,d)
210 #define do_tovmsspec(a,b,c,d) mp_do_tovmsspec(aTHX_ a,b,c,0,d)
211 #define do_tovmspath(a,b,c,d) mp_do_tovmspath(aTHX_ a,b,c,d)
212 #define do_rmsexpand(a,b,c,d,e,f,g) mp_do_rmsexpand(aTHX_ a,b,c,d,e,f,g)
213 #define do_vms_realpath(a,b,c) mp_do_vms_realpath(aTHX_ a,b,c)
214 #define do_vms_realname(a,b,c) mp_do_vms_realname(aTHX_ a,b,c)
215 #define do_tounixspec(a,b,c,d) mp_do_tounixspec(aTHX_ a,b,c,d)
216 #define do_tounixpath(a,b,c,d) mp_do_tounixpath(aTHX_ a,b,c,d)
217 #define do_vms_case_tolerant(a) mp_do_vms_case_tolerant(a)
218 #define expand_wild_cards(a,b,c,d) mp_expand_wild_cards(aTHX_ a,b,c,d)
219 #define getredirection(a,b) mp_getredirection(aTHX_ a,b)
221 static char *mp_do_tovmspath(pTHX_ const char *path, char *buf, int ts, int *);
222 static char *mp_do_tounixpath(pTHX_ const char *path, char *buf, int ts, int *);
223 static char *mp_do_tounixspec(pTHX_ const char *, char *, int, int *);
224 static char *mp_do_pathify_dirspec(pTHX_ const char *dir,char *buf, int ts, int *);
226 static char * int_rmsexpand_vms(
227 const char * filespec, char * outbuf, unsigned opts);
228 static char * int_rmsexpand_tovms(
229 const char * filespec, char * outbuf, unsigned opts);
230 static char *int_tovmsspec
231 (const char *path, char *buf, int dir_flag, int * utf8_flag);
232 static char * int_fileify_dirspec(const char *dir, char *buf, int *utf8_fl);
233 static char * int_tounixspec(const char *spec, char *buf, int * utf8_fl);
234 static char * int_tovmspath(const char *path, char *buf, int * utf8_fl);
236 /* see system service docs for $TRNLNM -- NOT the same as LNM$_MAX_INDEX */
237 #define PERL_LNM_MAX_ALLOWED_INDEX 127
239 /* OpenVMS User's Guide says at least 9 iterative translations will be performed,
240 * depending on the facility. SHOW LOGICAL does 10, so we'll imitate that for
243 #define PERL_LNM_MAX_ITER 10
245 /* New values with 7.3-2*/ /* why does max DCL have 4 byte subtracted from it? */
246 #if __CRTL_VER >= 70302000 && !defined(__VAX)
247 #define MAX_DCL_SYMBOL (8192)
248 #define MAX_DCL_LINE_LENGTH (4096 - 4)
250 #define MAX_DCL_SYMBOL (1024)
251 #define MAX_DCL_LINE_LENGTH (1024 - 4)
254 static char *__mystrtolower(char *str)
256 if (str) for (; *str; ++str) *str= tolower(*str);
260 static struct dsc$descriptor_s fildevdsc =
261 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "LNM$FILE_DEV" };
262 static struct dsc$descriptor_s crtlenvdsc =
263 { 8, DSC$K_DTYPE_T, DSC$K_CLASS_S, "CRTL_ENV" };
264 static struct dsc$descriptor_s *fildev[] = { &fildevdsc, NULL };
265 static struct dsc$descriptor_s *defenv[] = { &fildevdsc, &crtlenvdsc, NULL };
266 static struct dsc$descriptor_s **env_tables = defenv;
267 static bool will_taint = FALSE; /* tainting active, but no PL_curinterp yet */
269 /* True if we shouldn't treat barewords as logicals during directory */
271 static int no_translate_barewords;
273 /* DECC Features that may need to affect how Perl interprets
274 * displays filename information
276 static int decc_disable_to_vms_logname_translation = 1;
277 static int decc_disable_posix_root = 1;
278 int decc_efs_case_preserve = 0;
279 static int decc_efs_charset = 0;
280 static int decc_efs_charset_index = -1;
281 static int decc_filename_unix_no_version = 0;
282 static int decc_filename_unix_only = 0;
283 int decc_filename_unix_report = 0;
284 int decc_posix_compliant_pathnames = 0;
285 int decc_readdir_dropdotnotype = 0;
286 static int vms_process_case_tolerant = 1;
287 int vms_vtf7_filenames = 0;
288 int gnv_unix_shell = 0;
289 static int vms_unlink_all_versions = 0;
290 static int vms_posix_exit = 0;
292 /* bug workarounds if needed */
293 int decc_bug_devnull = 1;
294 int decc_dir_barename = 0;
295 int vms_bug_stat_filename = 0;
297 static int vms_debug_on_exception = 0;
298 static int vms_debug_fileify = 0;
300 /* Simple logical name translation */
301 static int simple_trnlnm
302 (const char * logname,
306 const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV");
307 const unsigned long attr = LNM$M_CASE_BLIND;
308 struct dsc$descriptor_s name_dsc;
310 unsigned short result;
311 struct itmlst_3 itlst[2] = {{value_len, LNM$_STRING, value, &result},
314 name_dsc.dsc$w_length = strlen(logname);
315 name_dsc.dsc$a_pointer = (char *)logname;
316 name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
317 name_dsc.dsc$b_class = DSC$K_CLASS_S;
319 status = sys$trnlnm(&attr, &table_dsc, &name_dsc, 0, itlst);
321 if ($VMS_STATUS_SUCCESS(status)) {
323 /* Null terminate and return the string */
324 /*--------------------------------------*/
333 /* Is this a UNIX file specification?
334 * No longer a simple check with EFS file specs
335 * For now, not a full check, but need to
336 * handle POSIX ^UP^ specifications
337 * Fixing to handle ^/ cases would require
338 * changes to many other conversion routines.
341 static int is_unix_filespec(const char *path)
347 if (strncmp(path,"\"^UP^",5) != 0) {
348 pch1 = strchr(path, '/');
353 /* If the user wants UNIX files, "." needs to be treated as in UNIX */
354 if (decc_filename_unix_report || decc_filename_unix_only) {
355 if (strcmp(path,".") == 0)
363 /* This routine converts a UCS-2 character to be VTF-7 encoded.
366 static void ucs2_to_vtf7
368 unsigned long ucs2_char,
371 unsigned char * ucs_ptr;
374 ucs_ptr = (unsigned char *)&ucs2_char;
378 hex = (ucs_ptr[1] >> 4) & 0xf;
380 outspec[2] = hex + '0';
382 outspec[2] = (hex - 9) + 'A';
383 hex = ucs_ptr[1] & 0xF;
385 outspec[3] = hex + '0';
387 outspec[3] = (hex - 9) + 'A';
389 hex = (ucs_ptr[0] >> 4) & 0xf;
391 outspec[4] = hex + '0';
393 outspec[4] = (hex - 9) + 'A';
394 hex = ucs_ptr[1] & 0xF;
396 outspec[5] = hex + '0';
398 outspec[5] = (hex - 9) + 'A';
404 /* This handles the conversion of a UNIX extended character set to a ^
405 * escaped VMS character.
406 * in a UNIX file specification.
408 * The output count variable contains the number of characters added
409 * to the output string.
411 * The return value is the number of characters read from the input string
413 static int copy_expand_unix_filename_escape
414 (char *outspec, const char *inspec, int *output_cnt, const int * utf8_fl)
421 utf8_flag = *utf8_fl;
425 if (*inspec >= 0x80) {
426 if (utf8_fl && vms_vtf7_filenames) {
427 unsigned long ucs_char;
431 if ((*inspec & 0xE0) == 0xC0) {
433 ucs_char = ((inspec[0] & 0x1F) << 6) + (inspec[1] & 0x3f);
434 if (ucs_char >= 0x80) {
435 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
438 } else if ((*inspec & 0xF0) == 0xE0) {
440 ucs_char = ((inspec[0] & 0xF) << 12) +
441 ((inspec[1] & 0x3f) << 6) +
443 if (ucs_char >= 0x800) {
444 ucs2_to_vtf7(outspec, ucs_char, output_cnt);
448 #if 0 /* I do not see longer sequences supported by OpenVMS */
449 /* Maybe some one can fix this later */
450 } else if ((*inspec & 0xF8) == 0xF0) {
453 } else if ((*inspec & 0xFC) == 0xF8) {
456 } else if ((*inspec & 0xFE) == 0xFC) {
463 /* High bit set, but not a Unicode character! */
465 /* Non printing DECMCS or ISO Latin-1 character? */
466 if ((unsigned char)*inspec <= 0x9F) {
470 hex = (*inspec >> 4) & 0xF;
472 outspec[1] = hex + '0';
474 outspec[1] = (hex - 9) + 'A';
478 outspec[2] = hex + '0';
480 outspec[2] = (hex - 9) + 'A';
484 } else if ((unsigned char)*inspec == 0xA0) {
490 } else if ((unsigned char)*inspec == 0xFF) {
502 /* Is this a macro that needs to be passed through?
503 * Macros start with $( and an alpha character, followed
504 * by a string of alpha numeric characters ending with a )
505 * If this does not match, then encode it as ODS-5.
507 if ((inspec[0] == '$') && (inspec[1] == '(')) {
510 if (isalnum(inspec[2]) || (inspec[2] == '.') || (inspec[2] == '_')) {
512 outspec[0] = inspec[0];
513 outspec[1] = inspec[1];
514 outspec[2] = inspec[2];
516 while(isalnum(inspec[tcnt]) ||
517 (inspec[2] == '.') || (inspec[2] == '_')) {
518 outspec[tcnt] = inspec[tcnt];
521 if (inspec[tcnt] == ')') {
522 outspec[tcnt] = inspec[tcnt];
539 if (decc_efs_charset == 0)
566 /* Don't escape again if following character is
567 * already something we escape.
569 if (strchr(".~!#&\'`()+@{},;[]%^=_\\", *(inspec+1))) {
575 /* But otherwise fall through and escape it. */
577 /* Assume that this is to be escaped */
579 outspec[1] = *inspec;
583 case ' ': /* space */
584 /* Assume that this is to be escaped */
600 /* This handles the expansion of a '^' prefix to the proper character
601 * in a UNIX file specification.
603 * The output count variable contains the number of characters added
604 * to the output string.
606 * The return value is the number of characters read from the input
609 static int copy_expand_vms_filename_escape
610 (char *outspec, const char *inspec, int *output_cnt)
617 if (*inspec == '^') {
620 /* Spaces and non-trailing dots should just be passed through,
621 * but eat the escape character.
628 case '_': /* space */
634 /* Hmm. Better leave the escape escaped. */
640 case 'U': /* Unicode - FIX-ME this is wrong. */
643 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
646 scnt = sscanf(inspec, "%2x%2x", &c1, &c2);
647 outspec[0] = c1 & 0xff;
648 outspec[1] = c2 & 0xff;
655 /* Error - do best we can to continue */
665 scnt = strspn(inspec, "0123456789ABCDEFabcdef");
669 scnt = sscanf(inspec, "%2x", &c1);
670 outspec[0] = c1 & 0xff;
691 /* vms_split_path - Verify that the input file specification is a
692 * VMS format file specification, and provide pointers to the components of
693 * it. With EFS format filenames, this is virtually the only way to
694 * parse a VMS path specification into components.
696 * If the sum of the components do not add up to the length of the
697 * string, then the passed file specification is probably a UNIX style
700 static int vms_split_path
715 struct dsc$descriptor path_desc;
719 struct filescan_itmlst_2 item_list[9];
720 const int filespec = 0;
721 const int nodespec = 1;
722 const int devspec = 2;
723 const int rootspec = 3;
724 const int dirspec = 4;
725 const int namespec = 5;
726 const int typespec = 6;
727 const int verspec = 7;
729 /* Assume the worst for an easy exit */
743 path_desc.dsc$a_pointer = (char *)path; /* cast ok */
744 path_desc.dsc$w_length = strlen(path);
745 path_desc.dsc$b_dtype = DSC$K_DTYPE_T;
746 path_desc.dsc$b_class = DSC$K_CLASS_S;
748 /* Get the total length, if it is shorter than the string passed
749 * then this was probably not a VMS formatted file specification
751 item_list[filespec].itmcode = FSCN$_FILESPEC;
752 item_list[filespec].length = 0;
753 item_list[filespec].component = NULL;
755 /* If the node is present, then it gets considered as part of the
756 * volume name to hopefully make things simple.
758 item_list[nodespec].itmcode = FSCN$_NODE;
759 item_list[nodespec].length = 0;
760 item_list[nodespec].component = NULL;
762 item_list[devspec].itmcode = FSCN$_DEVICE;
763 item_list[devspec].length = 0;
764 item_list[devspec].component = NULL;
766 /* root is a special case, adding it to either the directory or
767 * the device components will probably complicate things for the
768 * callers of this routine, so leave it separate.
770 item_list[rootspec].itmcode = FSCN$_ROOT;
771 item_list[rootspec].length = 0;
772 item_list[rootspec].component = NULL;
774 item_list[dirspec].itmcode = FSCN$_DIRECTORY;
775 item_list[dirspec].length = 0;
776 item_list[dirspec].component = NULL;
778 item_list[namespec].itmcode = FSCN$_NAME;
779 item_list[namespec].length = 0;
780 item_list[namespec].component = NULL;
782 item_list[typespec].itmcode = FSCN$_TYPE;
783 item_list[typespec].length = 0;
784 item_list[typespec].component = NULL;
786 item_list[verspec].itmcode = FSCN$_VERSION;
787 item_list[verspec].length = 0;
788 item_list[verspec].component = NULL;
790 item_list[8].itmcode = 0;
791 item_list[8].length = 0;
792 item_list[8].component = NULL;
794 status = sys$filescan
795 ((const struct dsc$descriptor_s *)&path_desc, item_list,
797 _ckvmssts_noperl(status); /* All failure status values indicate a coding error */
799 /* If we parsed it successfully these two lengths should be the same */
800 if (path_desc.dsc$w_length != item_list[filespec].length)
803 /* If we got here, then it is a VMS file specification */
806 /* set the volume name */
807 if (item_list[nodespec].length > 0) {
808 *volume = item_list[nodespec].component;
809 *vol_len = item_list[nodespec].length + item_list[devspec].length;
812 *volume = item_list[devspec].component;
813 *vol_len = item_list[devspec].length;
816 *root = item_list[rootspec].component;
817 *root_len = item_list[rootspec].length;
819 *dir = item_list[dirspec].component;
820 *dir_len = item_list[dirspec].length;
822 /* Now fun with versions and EFS file specifications
823 * The parser can not tell the difference when a "." is a version
824 * delimiter or a part of the file specification.
826 if ((decc_efs_charset) &&
827 (item_list[verspec].length > 0) &&
828 (item_list[verspec].component[0] == '.')) {
829 *name = item_list[namespec].component;
830 *name_len = item_list[namespec].length + item_list[typespec].length;
831 *ext = item_list[verspec].component;
832 *ext_len = item_list[verspec].length;
837 *name = item_list[namespec].component;
838 *name_len = item_list[namespec].length;
839 *ext = item_list[typespec].component;
840 *ext_len = item_list[typespec].length;
841 *version = item_list[verspec].component;
842 *ver_len = item_list[verspec].length;
847 /* Routine to determine if the file specification ends with .dir */
848 static int is_dir_ext(char * e_spec, int e_len, char * vs_spec, int vs_len) {
850 /* e_len must be 4, and version must be <= 2 characters */
851 if (e_len != 4 || vs_len > 2)
854 /* If a version number is present, it needs to be one */
855 if ((vs_len == 2) && (vs_spec[1] != '1'))
858 /* Look for the DIR on the extension */
859 if (vms_process_case_tolerant) {
860 if ((toupper(e_spec[1]) == 'D') &&
861 (toupper(e_spec[2]) == 'I') &&
862 (toupper(e_spec[3]) == 'R')) {
866 /* Directory extensions are supposed to be in upper case only */
867 /* I would not be surprised if this rule can not be enforced */
868 /* if and when someone fully debugs the case sensitive mode */
869 if ((e_spec[1] == 'D') &&
870 (e_spec[2] == 'I') &&
871 (e_spec[3] == 'R')) {
880 * Routine to retrieve the maximum equivalence index for an input
881 * logical name. Some calls to this routine have no knowledge if
882 * the variable is a logical or not. So on error we return a max
885 /*{{{int my_maxidx(const char *lnm) */
887 my_maxidx(const char *lnm)
891 int attr = LNM$M_CASE_BLIND;
892 struct dsc$descriptor lnmdsc;
893 struct itmlst_3 itlst[2] = {{sizeof(midx), LNM$_MAX_INDEX, &midx, 0},
896 lnmdsc.dsc$w_length = strlen(lnm);
897 lnmdsc.dsc$b_dtype = DSC$K_DTYPE_T;
898 lnmdsc.dsc$b_class = DSC$K_CLASS_S;
899 lnmdsc.dsc$a_pointer = (char *) lnm; /* Cast ok for read only parameter */
901 status = sys$trnlnm(&attr, &fildevdsc, &lnmdsc, 0, itlst);
902 if ((status & 1) == 0)
909 /*{{{int vmstrnenv(const char *lnm, char *eqv, unsigned long int idx, struct dsc$descriptor_s **tabvec, unsigned long int flags) */
911 Perl_vmstrnenv(const char *lnm, char *eqv, unsigned long int idx,
912 struct dsc$descriptor_s **tabvec, unsigned long int flags)
915 char uplnm[LNM$C_NAMLENGTH+1], *cp2;
916 unsigned short int eqvlen, curtab, ivlnm = 0, ivsym = 0, ivenv = 0, secure;
917 unsigned long int retsts, attr = LNM$M_CASE_BLIND;
919 unsigned char acmode;
920 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
921 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
922 struct itmlst_3 lnmlst[3] = {{sizeof idx, LNM$_INDEX, &idx, 0},
923 {LNM$C_NAMLENGTH, LNM$_STRING, eqv, &eqvlen},
925 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
926 #if defined(PERL_IMPLICIT_CONTEXT)
929 aTHX = PERL_GET_INTERP;
935 if (!lnm || !eqv || ((idx != 0) && ((idx-1) > PERL_LNM_MAX_ALLOWED_INDEX))) {
936 set_errno(EINVAL); set_vaxc_errno(SS$_BADPARAM); return 0;
938 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
939 *cp2 = _toupper(*cp1);
940 if (cp1 - lnm > LNM$C_NAMLENGTH) {
941 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
945 lnmdsc.dsc$w_length = cp1 - lnm;
946 lnmdsc.dsc$a_pointer = uplnm;
947 uplnm[lnmdsc.dsc$w_length] = '\0';
948 secure = flags & PERL__TRNENV_SECURE;
949 acmode = secure ? PSL$C_EXEC : PSL$C_USER;
950 if (!tabvec || !*tabvec) tabvec = env_tables;
952 for (curtab = 0; tabvec[curtab]; curtab++) {
953 if (!str$case_blind_compare(tabvec[curtab],&crtlenv)) {
954 if (!ivenv && !secure) {
959 #if defined(PERL_IMPLICIT_CONTEXT)
962 "Can't read CRTL environ\n");
965 Perl_warn(aTHX_ "Can't read CRTL environ\n");
968 retsts = SS$_NOLOGNAM;
969 for (i = 0; environ[i]; i++) {
970 if ((eq = strchr(environ[i],'=')) &&
971 lnmdsc.dsc$w_length == (eq - environ[i]) &&
972 !strncmp(environ[i],uplnm,eq - environ[i])) {
974 for (eqvlen = 0; eq[eqvlen]; eqvlen++) eqv[eqvlen] = eq[eqvlen];
975 if (!eqvlen) continue;
980 if (retsts != SS$_NOLOGNAM) break;
983 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
984 !str$case_blind_compare(&tmpdsc,&clisym)) {
985 if (!ivsym && !secure) {
986 unsigned short int deflen = LNM$C_NAMLENGTH;
987 struct dsc$descriptor_d eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
988 /* dynamic dsc to accommodate possible long value */
989 _ckvmssts_noperl(lib$sget1_dd(&deflen,&eqvdsc));
990 retsts = lib$get_symbol(&lnmdsc,&eqvdsc,&eqvlen,0);
992 if (eqvlen > MAX_DCL_SYMBOL) {
993 set_errno(EVMSERR); set_vaxc_errno(LIB$_STRTRU);
994 eqvlen = MAX_DCL_SYMBOL;
995 /* Special hack--we might be called before the interpreter's */
996 /* fully initialized, in which case either thr or PL_curcop */
997 /* might be bogus. We have to check, since ckWARN needs them */
998 /* both to be valid if running threaded */
999 #if defined(PERL_IMPLICIT_CONTEXT)
1002 "Value of CLI symbol \"%s\" too long",lnm);
1005 if (ckWARN(WARN_MISC)) {
1006 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of CLI symbol \"%s\" too long",lnm);
1009 strncpy(eqv,eqvdsc.dsc$a_pointer,eqvlen);
1011 _ckvmssts_noperl(lib$sfree1_dd(&eqvdsc));
1012 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1013 if (retsts == LIB$_NOSUCHSYM) continue;
1018 if ( (idx == 0) && (flags & PERL__TRNENV_JOIN_SEARCHLIST) ) {
1019 midx = my_maxidx(lnm);
1020 for (idx = 0, cp2 = eqv; idx <= midx; idx++) {
1021 lnmlst[1].bufadr = cp2;
1023 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1024 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; break; }
1025 if (retsts == SS$_NOLOGNAM) break;
1026 /* PPFs have a prefix */
1029 *((int *)uplnm) == *((int *)"SYS$") &&
1031 eqvlen >= 4 && eqv[0] == 0x1b && eqv[1] == 0x00 &&
1032 ( (uplnm[4] == 'O' && !strcmp(uplnm,"SYS$OUTPUT")) ||
1033 (uplnm[4] == 'I' && !strcmp(uplnm,"SYS$INPUT")) ||
1034 (uplnm[4] == 'E' && !strcmp(uplnm,"SYS$ERROR")) ||
1035 (uplnm[4] == 'C' && !strcmp(uplnm,"SYS$COMMAND")) ) ) {
1036 memmove(eqv,eqv+4,eqvlen-4);
1042 if ((retsts == SS$_IVLOGNAM) ||
1043 (retsts == SS$_NOLOGNAM)) { continue; }
1046 retsts = sys$trnlnm(&attr,tabvec[curtab],&lnmdsc,&acmode,lnmlst);
1047 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1048 if (retsts == SS$_NOLOGNAM) continue;
1051 eqvlen = strlen(eqv);
1055 if (retsts & 1) { eqv[eqvlen] = '\0'; return eqvlen; }
1056 else if (retsts == LIB$_NOSUCHSYM || retsts == LIB$_INVSYMNAM ||
1057 retsts == SS$_IVLOGNAM || retsts == SS$_IVLOGTAB ||
1058 retsts == SS$_NOLOGNAM) {
1059 set_errno(EINVAL); set_vaxc_errno(retsts);
1061 else _ckvmssts_noperl(retsts);
1063 } /* end of vmstrnenv */
1066 /*{{{ int my_trnlnm(const char *lnm, char *eqv, unsigned long int idx)*/
1067 /* Define as a function so we can access statics. */
1068 int Perl_my_trnlnm(pTHX_ const char *lnm, char *eqv, unsigned long int idx)
1072 #if defined(PERL_IMPLICIT_CONTEXT)
1075 #ifdef SECURE_INTERNAL_GETENV
1076 flags = (PL_curinterp ? PL_tainting : will_taint) ?
1077 PERL__TRNENV_SECURE : 0;
1080 return vmstrnenv(lnm, eqv, idx, fildev, flags);
1085 * Note: Uses Perl temp to store result so char * can be returned to
1086 * caller; this pointer will be invalidated at next Perl statement
1088 * We define this as a function rather than a macro in terms of my_getenv_len()
1089 * so that it'll work when PL_curinterp is undefined (and we therefore can't
1092 /*{{{ char *my_getenv(const char *lnm, bool sys)*/
1094 Perl_my_getenv(pTHX_ const char *lnm, bool sys)
1097 static char *__my_getenv_eqv = NULL;
1098 char uplnm[LNM$C_NAMLENGTH+1], *cp2, *eqv;
1099 unsigned long int idx = 0;
1100 int success, secure, saverr, savvmserr;
1104 midx = my_maxidx(lnm) + 1;
1106 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1107 /* Set up a temporary buffer for the return value; Perl will
1108 * clean it up at the next statement transition */
1109 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1110 if (!tmpsv) return NULL;
1114 /* Assume no interpreter ==> single thread */
1115 if (__my_getenv_eqv != NULL) {
1116 Renew(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1119 Newx(__my_getenv_eqv,LNM$C_NAMLENGTH*midx+1,char);
1121 eqv = __my_getenv_eqv;
1124 for (cp1 = lnm, cp2 = eqv; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1125 if (cp1 - lnm == 7 && !strncmp(eqv,"DEFAULT",7)) {
1127 getcwd(eqv,LNM$C_NAMLENGTH);
1131 /* Get rid of "000000/ in rooted filespecs */
1134 zeros = strstr(eqv, "/000000/");
1135 if (zeros != NULL) {
1137 mlen = len - (zeros - eqv) - 7;
1138 memmove(zeros, &zeros[7], mlen);
1146 /* Impose security constraints only if tainting */
1148 /* Impose security constraints only if tainting */
1149 secure = PL_curinterp ? PL_tainting : will_taint;
1150 saverr = errno; savvmserr = vaxc$errno;
1157 #ifdef SECURE_INTERNAL_GETENV
1158 secure ? PERL__TRNENV_SECURE : 0
1164 /* For the getenv interface we combine all the equivalence names
1165 * of a search list logical into one value to acquire a maximum
1166 * value length of 255*128 (assuming %ENV is using logicals).
1168 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1170 /* If the name contains a semicolon-delimited index, parse it
1171 * off and make sure we only retrieve the equivalence name for
1173 if ((cp2 = strchr(lnm,';')) != NULL) {
1174 my_strlcpy(uplnm, lnm, cp2 - lnm + 1);
1175 idx = strtoul(cp2+1,NULL,0);
1177 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1180 success = vmstrnenv(lnm,eqv,idx,secure ? fildev : NULL,flags);
1182 /* Discard NOLOGNAM on internal calls since we're often looking
1183 * for an optional name, and this "error" often shows up as the
1184 * (bogus) exit status for a die() call later on. */
1185 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1186 return success ? eqv : NULL;
1189 } /* end of my_getenv() */
1193 /*{{{ SV *my_getenv_len(const char *lnm, bool sys)*/
1195 Perl_my_getenv_len(pTHX_ const char *lnm, unsigned long *len, bool sys)
1199 unsigned long idx = 0;
1201 static char *__my_getenv_len_eqv = NULL;
1202 int secure, saverr, savvmserr;
1205 midx = my_maxidx(lnm) + 1;
1207 if (PL_curinterp) { /* Perl interpreter running -- may be threaded */
1208 /* Set up a temporary buffer for the return value; Perl will
1209 * clean it up at the next statement transition */
1210 tmpsv = sv_2mortal(newSVpv("",(LNM$C_NAMLENGTH*midx)+1));
1211 if (!tmpsv) return NULL;
1215 /* Assume no interpreter ==> single thread */
1216 if (__my_getenv_len_eqv != NULL) {
1217 Renew(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1220 Newx(__my_getenv_len_eqv,LNM$C_NAMLENGTH*midx+1,char);
1222 buf = __my_getenv_len_eqv;
1225 for (cp1 = lnm, cp2 = buf; *cp1; cp1++,cp2++) *cp2 = _toupper(*cp1);
1226 if (cp1 - lnm == 7 && !strncmp(buf,"DEFAULT",7)) {
1229 getcwd(buf,LNM$C_NAMLENGTH);
1232 /* Get rid of "000000/ in rooted filespecs */
1234 zeros = strstr(buf, "/000000/");
1235 if (zeros != NULL) {
1237 mlen = *len - (zeros - buf) - 7;
1238 memmove(zeros, &zeros[7], mlen);
1247 /* Impose security constraints only if tainting */
1248 secure = PL_curinterp ? PL_tainting : will_taint;
1249 saverr = errno; savvmserr = vaxc$errno;
1256 #ifdef SECURE_INTERNAL_GETENV
1257 secure ? PERL__TRNENV_SECURE : 0
1263 flags |= PERL__TRNENV_JOIN_SEARCHLIST;
1265 if ((cp2 = strchr(lnm,';')) != NULL) {
1266 my_strlcpy(buf, lnm, cp2 - lnm + 1);
1267 idx = strtoul(cp2+1,NULL,0);
1269 flags &= ~PERL__TRNENV_JOIN_SEARCHLIST;
1272 *len = vmstrnenv(lnm,buf,idx,secure ? fildev : NULL,flags);
1274 /* Get rid of "000000/ in rooted filespecs */
1277 zeros = strstr(buf, "/000000/");
1278 if (zeros != NULL) {
1280 mlen = *len - (zeros - buf) - 7;
1281 memmove(zeros, &zeros[7], mlen);
1287 /* Discard NOLOGNAM on internal calls since we're often looking
1288 * for an optional name, and this "error" often shows up as the
1289 * (bogus) exit status for a die() call later on. */
1290 if (sys && vaxc$errno == SS$_NOLOGNAM) SETERRNO(saverr,savvmserr);
1291 return *len ? buf : NULL;
1294 } /* end of my_getenv_len() */
1297 static void create_mbx(unsigned short int *, struct dsc$descriptor_s *);
1299 static void riseandshine(unsigned long int dummy) { sys$wake(0,0); }
1301 /*{{{ void prime_env_iter() */
1303 prime_env_iter(void)
1304 /* Fill the %ENV associative array with all logical names we can
1305 * find, in preparation for iterating over it.
1308 static int primed = 0;
1309 HV *seenhv = NULL, *envhv;
1311 char cmd[LNM$C_NAMLENGTH+24], mbxnam[LNM$C_NAMLENGTH], *buf = NULL;
1312 unsigned short int chan;
1313 #ifndef CLI$M_TRUSTED
1314 # define CLI$M_TRUSTED 0x40 /* Missing from VAXC headers */
1316 unsigned long int defflags = CLI$M_NOWAIT | CLI$M_NOKEYPAD | CLI$M_TRUSTED;
1317 unsigned long int mbxbufsiz, flags, retsts, subpid = 0, substs = 0;
1319 bool have_sym = FALSE, have_lnm = FALSE;
1320 struct dsc$descriptor_s tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1321 $DESCRIPTOR(cmddsc,cmd); $DESCRIPTOR(nldsc,"_NLA0:");
1322 $DESCRIPTOR(clidsc,"DCL"); $DESCRIPTOR(clitabdsc,"DCLTABLES");
1323 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1324 $DESCRIPTOR(local,"_LOCAL"); $DESCRIPTOR(mbxdsc,mbxnam);
1325 #if defined(PERL_IMPLICIT_CONTEXT)
1328 #if defined(USE_ITHREADS)
1329 static perl_mutex primenv_mutex;
1330 MUTEX_INIT(&primenv_mutex);
1333 #if defined(PERL_IMPLICIT_CONTEXT)
1334 /* We jump through these hoops because we can be called at */
1335 /* platform-specific initialization time, which is before anything is */
1336 /* set up--we can't even do a plain dTHX since that relies on the */
1337 /* interpreter structure to be initialized */
1339 aTHX = PERL_GET_INTERP;
1341 /* we never get here because the NULL pointer will cause the */
1342 /* several of the routines called by this routine to access violate */
1344 /* This routine is only called by hv.c/hv_iterinit which has a */
1345 /* context, so the real fix may be to pass it through instead of */
1346 /* the hoops above */
1351 if (primed || !PL_envgv) return;
1352 MUTEX_LOCK(&primenv_mutex);
1353 if (primed) { MUTEX_UNLOCK(&primenv_mutex); return; }
1354 envhv = GvHVn(PL_envgv);
1355 /* Perform a dummy fetch as an lval to insure that the hash table is
1356 * set up. Otherwise, the hv_store() will turn into a nullop. */
1357 (void) hv_fetch(envhv,"DEFAULT",7,TRUE);
1359 for (i = 0; env_tables[i]; i++) {
1360 if (!have_sym && (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1361 !str$case_blind_compare(&tmpdsc,&clisym)) have_sym = 1;
1362 if (!have_lnm && str$case_blind_compare(env_tables[i],&crtlenv)) have_lnm = 1;
1364 if (have_sym || have_lnm) {
1365 long int syiitm = SYI$_MAXBUF, dviitm = DVI$_DEVNAM;
1366 _ckvmssts(lib$getsyi(&syiitm, &mbxbufsiz, 0, 0, 0, 0));
1367 _ckvmssts(sys$crembx(0,&chan,mbxbufsiz,mbxbufsiz,0xff0f,0,0));
1368 _ckvmssts(lib$getdvi(&dviitm, &chan, NULL, NULL, &mbxdsc, &mbxdsc.dsc$w_length));
1371 for (i--; i >= 0; i--) {
1372 if (!str$case_blind_compare(env_tables[i],&crtlenv)) {
1375 for (j = 0; environ[j]; j++) {
1376 if (!(start = strchr(environ[j],'='))) {
1377 if (ckWARN(WARN_INTERNAL))
1378 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed CRTL environ value \"%s\"\n",environ[j]);
1382 sv = newSVpv(start,0);
1384 (void) hv_store(envhv,environ[j],start - environ[j] - 1,sv,0);
1389 else if ((tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer) &&
1390 !str$case_blind_compare(&tmpdsc,&clisym)) {
1391 my_strlcpy(cmd, "Show Symbol/Global *", sizeof(cmd));
1392 cmddsc.dsc$w_length = 20;
1393 if (env_tables[i]->dsc$w_length == 12 &&
1394 (tmpdsc.dsc$a_pointer = env_tables[i]->dsc$a_pointer + 6) &&
1395 !str$case_blind_compare(&tmpdsc,&local)) my_strlcpy(cmd+12, "Local *", sizeof(cmd)-12);
1396 flags = defflags | CLI$M_NOLOGNAM;
1399 my_strlcpy(cmd, "Show Logical *", sizeof(cmd));
1400 if (str$case_blind_compare(env_tables[i],&fildevdsc)) {
1401 my_strlcat(cmd," /Table=", sizeof(cmd));
1402 cmddsc.dsc$w_length = my_strlcat(cmd, env_tables[i]->dsc$a_pointer, env_tables[i]->dsc$w_length + 1);
1404 else cmddsc.dsc$w_length = 14; /* N.B. We test this below */
1405 flags = defflags | CLI$M_NOCLISYM;
1408 /* Create a new subprocess to execute each command, to exclude the
1409 * remote possibility that someone could subvert a mbx or file used
1410 * to write multiple commands to a single subprocess.
1413 retsts = lib$spawn(&cmddsc,&nldsc,&mbxdsc,&flags,0,&subpid,&substs,
1414 0,&riseandshine,0,0,&clidsc,&clitabdsc);
1415 flags &= ~CLI$M_TRUSTED; /* Just in case we hit a really old version */
1416 defflags &= ~CLI$M_TRUSTED;
1417 } while (retsts == LIB$_INVARG && (flags | CLI$M_TRUSTED));
1419 if (!buf) Newx(buf,mbxbufsiz + 1,char);
1420 if (seenhv) SvREFCNT_dec(seenhv);
1423 char *cp1, *cp2, *key;
1424 unsigned long int sts, iosb[2], retlen, keylen;
1427 sts = sys$qiow(0,chan,IO$_READVBLK,iosb,0,0,buf,mbxbufsiz,0,0,0,0);
1428 if (sts & 1) sts = iosb[0] & 0xffff;
1429 if (sts == SS$_ENDOFFILE) {
1431 while (substs == 0) { sys$hiber(); wakect++;}
1432 if (wakect > 1) sys$wake(0,0); /* Stole someone else's wake */
1437 retlen = iosb[0] >> 16;
1438 if (!retlen) continue; /* blank line */
1440 if (iosb[1] != subpid) {
1442 Perl_croak(aTHX_ "Unknown process %x sent message to prime_env_iter: %s",buf);
1446 if (sts == SS$_BUFFEROVF && ckWARN(WARN_INTERNAL))
1447 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Buffer overflow in prime_env_iter: %s",buf);
1449 for (cp1 = buf; *cp1 && isspace(*cp1); cp1++) ;
1450 if (*cp1 == '(' || /* Logical name table name */
1451 *cp1 == '=' /* Next eqv of searchlist */) continue;
1452 if (*cp1 == '"') cp1++;
1453 for (cp2 = cp1; *cp2 && *cp2 != '"' && *cp2 != ' '; cp2++) ;
1454 key = cp1; keylen = cp2 - cp1;
1455 if (keylen && hv_exists(seenhv,key,keylen)) continue;
1456 while (*cp2 && *cp2 != '=') cp2++;
1457 while (*cp2 && *cp2 == '=') cp2++;
1458 while (*cp2 && *cp2 == ' ') cp2++;
1459 if (*cp2 == '"') { /* String translation; may embed "" */
1460 for (cp1 = buf + retlen; *cp1 != '"'; cp1--) ;
1461 cp2++; cp1--; /* Skip "" surrounding translation */
1463 else { /* Numeric translation */
1464 for (cp1 = cp2; *cp1 && *cp1 != ' '; cp1++) ;
1465 cp1--; /* stop on last non-space char */
1467 if ((!keylen || (cp1 - cp2 < -1)) && ckWARN(WARN_INTERNAL)) {
1468 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"Ill-formed message in prime_env_iter: |%s|",buf);
1471 PERL_HASH(hash,key,keylen);
1473 if (cp1 == cp2 && *cp2 == '.') {
1474 /* A single dot usually means an unprintable character, such as a null
1475 * to indicate a zero-length value. Get the actual value to make sure.
1477 char lnm[LNM$C_NAMLENGTH+1];
1478 char eqv[MAX_DCL_SYMBOL+1];
1480 strncpy(lnm, key, keylen);
1481 trnlen = vmstrnenv(lnm, eqv, 0, fildev, 0);
1482 sv = newSVpvn(eqv, strlen(eqv));
1485 sv = newSVpvn(cp2,cp1 - cp2 + 1);
1489 hv_store(envhv,key,keylen,sv,hash);
1490 hv_store(seenhv,key,keylen,&PL_sv_yes,hash);
1492 if (cmddsc.dsc$w_length == 14) { /* We just read LNM$FILE_DEV */
1493 /* get the PPFs for this process, not the subprocess */
1494 const char *ppfs[] = {"SYS$COMMAND", "SYS$INPUT", "SYS$OUTPUT", "SYS$ERROR", NULL};
1495 char eqv[LNM$C_NAMLENGTH+1];
1497 for (i = 0; ppfs[i]; i++) {
1498 trnlen = vmstrnenv(ppfs[i],eqv,0,fildev,0);
1499 sv = newSVpv(eqv,trnlen);
1501 hv_store(envhv,ppfs[i],strlen(ppfs[i]),sv,0);
1506 if (have_sym || have_lnm) _ckvmssts(sys$dassgn(chan));
1507 if (buf) Safefree(buf);
1508 if (seenhv) SvREFCNT_dec(seenhv);
1509 MUTEX_UNLOCK(&primenv_mutex);
1512 } /* end of prime_env_iter */
1516 /*{{{ int vmssetenv(const char *lnm, const char *eqv)*/
1517 /* Define or delete an element in the same "environment" as
1518 * vmstrnenv(). If an element is to be deleted, it's removed from
1519 * the first place it's found. If it's to be set, it's set in the
1520 * place designated by the first element of the table vector.
1521 * Like setenv() returns 0 for success, non-zero on error.
1524 Perl_vmssetenv(pTHX_ const char *lnm, const char *eqv, struct dsc$descriptor_s **tabvec)
1527 char uplnm[LNM$C_NAMLENGTH], *cp2, *c;
1528 unsigned short int curtab, ivlnm = 0, ivsym = 0, ivenv = 0;
1530 unsigned long int retsts, usermode = PSL$C_USER;
1531 struct itmlst_3 *ile, *ilist;
1532 struct dsc$descriptor_s lnmdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,uplnm},
1533 eqvdsc = {0,DSC$K_DTYPE_T,DSC$K_CLASS_S,0},
1534 tmpdsc = {6,DSC$K_DTYPE_T,DSC$K_CLASS_S,0};
1535 $DESCRIPTOR(crtlenv,"CRTL_ENV"); $DESCRIPTOR(clisym,"CLISYM");
1536 $DESCRIPTOR(local,"_LOCAL");
1539 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1540 return SS$_IVLOGNAM;
1543 for (cp1 = lnm, cp2 = uplnm; *cp1; cp1++, cp2++) {
1544 *cp2 = _toupper(*cp1);
1545 if (cp1 - lnm > LNM$C_NAMLENGTH) {
1546 set_errno(EINVAL); set_vaxc_errno(SS$_IVLOGNAM);
1547 return SS$_IVLOGNAM;
1550 lnmdsc.dsc$w_length = cp1 - lnm;
1551 if (!tabvec || !*tabvec) tabvec = env_tables;
1553 if (!eqv) { /* we're deleting n element */
1554 for (curtab = 0; tabvec[curtab]; curtab++) {
1555 if (!ivenv && !str$case_blind_compare(tabvec[curtab],&crtlenv)) {
1557 for (i = 0; environ[i]; i++) { /* If it's an environ elt, reset */
1558 if ((cp1 = strchr(environ[i],'=')) &&
1559 lnmdsc.dsc$w_length == (cp1 - environ[i]) &&
1560 !strncmp(environ[i],lnm,cp1 - environ[i])) {
1562 return setenv(lnm,"",1) ? vaxc$errno : 0;
1565 ivenv = 1; retsts = SS$_NOLOGNAM;
1567 if (ckWARN(WARN_INTERNAL))
1568 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't reset CRTL environ elements (%s)",lnm);
1569 ivenv = 1; retsts = SS$_NOSUCHPGM;
1575 else if ((tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer) &&
1576 !str$case_blind_compare(&tmpdsc,&clisym)) {
1577 unsigned int symtype;
1578 if (tabvec[curtab]->dsc$w_length == 12 &&
1579 (tmpdsc.dsc$a_pointer = tabvec[curtab]->dsc$a_pointer + 6) &&
1580 !str$case_blind_compare(&tmpdsc,&local))
1581 symtype = LIB$K_CLI_LOCAL_SYM;
1582 else symtype = LIB$K_CLI_GLOBAL_SYM;
1583 retsts = lib$delete_symbol(&lnmdsc,&symtype);
1584 if (retsts == LIB$_INVSYMNAM) { ivsym = 1; continue; }
1585 if (retsts == LIB$_NOSUCHSYM) continue;
1589 retsts = sys$dellnm(tabvec[curtab],&lnmdsc,&usermode); /* try user mode first */
1590 if (retsts == SS$_IVLOGNAM) { ivlnm = 1; continue; }
1591 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1592 retsts = lib$delete_logical(&lnmdsc,tabvec[curtab]); /* then supervisor mode */
1593 if (retsts != SS$_NOLOGNAM && retsts != SS$_NOLOGTAB) break;
1597 else { /* we're defining a value */
1598 if (!ivenv && !str$case_blind_compare(tabvec[0],&crtlenv)) {
1600 return setenv(lnm,eqv,1) ? vaxc$errno : 0;
1602 if (ckWARN(WARN_INTERNAL))
1603 Perl_warner(aTHX_ packWARN(WARN_INTERNAL),"This Perl can't set CRTL environ elements (%s=%s)",lnm,eqv);
1604 retsts = SS$_NOSUCHPGM;
1608 eqvdsc.dsc$a_pointer = (char *) eqv; /* cast ok to readonly parameter */
1609 eqvdsc.dsc$w_length = strlen(eqv);
1610 if ((tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer) &&
1611 !str$case_blind_compare(&tmpdsc,&clisym)) {
1612 unsigned int symtype;
1613 if (tabvec[0]->dsc$w_length == 12 &&
1614 (tmpdsc.dsc$a_pointer = tabvec[0]->dsc$a_pointer + 6) &&
1615 !str$case_blind_compare(&tmpdsc,&local))
1616 symtype = LIB$K_CLI_LOCAL_SYM;
1617 else symtype = LIB$K_CLI_GLOBAL_SYM;
1618 retsts = lib$set_symbol(&lnmdsc,&eqvdsc,&symtype);
1621 if (!*eqv) eqvdsc.dsc$w_length = 1;
1622 if (eqvdsc.dsc$w_length > LNM$C_NAMLENGTH) {
1624 nseg = (eqvdsc.dsc$w_length + LNM$C_NAMLENGTH - 1) / LNM$C_NAMLENGTH;
1625 if (nseg > PERL_LNM_MAX_ALLOWED_INDEX + 1) {
1626 Perl_warner(aTHX_ packWARN(WARN_MISC),"Value of logical \"%s\" too long. Truncating to %i bytes",
1627 lnm, LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1));
1628 eqvdsc.dsc$w_length = LNM$C_NAMLENGTH * (PERL_LNM_MAX_ALLOWED_INDEX+1);
1629 nseg = PERL_LNM_MAX_ALLOWED_INDEX + 1;
1632 Newx(ilist,nseg+1,struct itmlst_3);
1635 set_errno(ENOMEM); set_vaxc_errno(SS$_INSFMEM);
1638 memset(ilist, 0, (sizeof(struct itmlst_3) * (nseg+1)));
1640 for (j = 0, c = eqvdsc.dsc$a_pointer; j < nseg; j++, ile++, c += LNM$C_NAMLENGTH) {
1641 ile->itmcode = LNM$_STRING;
1643 if ((j+1) == nseg) {
1644 ile->buflen = strlen(c);
1645 /* in case we are truncating one that's too long */
1646 if (ile->buflen > LNM$C_NAMLENGTH) ile->buflen = LNM$C_NAMLENGTH;
1649 ile->buflen = LNM$C_NAMLENGTH;
1653 retsts = lib$set_logical(&lnmdsc,0,tabvec[0],0,ilist);
1657 retsts = lib$set_logical(&lnmdsc,&eqvdsc,tabvec[0],0,0);
1662 if (!(retsts & 1)) {
1664 case LIB$_AMBSYMDEF: case LIB$_INSCLIMEM:
1665 case SS$_NOLOGTAB: case SS$_TOOMANYLNAM: case SS$_IVLOGTAB:
1666 set_errno(EVMSERR); break;
1667 case LIB$_INVARG: case LIB$_INVSYMNAM: case SS$_IVLOGNAM:
1668 case LIB$_NOSUCHSYM: case SS$_NOLOGNAM:
1669 set_errno(EINVAL); break;
1671 set_errno(EACCES); break;
1676 set_vaxc_errno(retsts);
1677 return (int) retsts || 44; /* retsts should never be 0, but just in case */
1680 /* We reset error values on success because Perl does an hv_fetch()
1681 * before each hv_store(), and if the thing we're setting didn't
1682 * previously exist, we've got a leftover error message. (Of course,
1683 * this fails in the face of
1684 * $foo = $ENV{nonexistent}; $ENV{existent} = 'foo';
1685 * in that the error reported in $! isn't spurious,
1686 * but it's right more often than not.)
1688 set_errno(0); set_vaxc_errno(retsts);
1692 } /* end of vmssetenv() */
1695 /*{{{ void my_setenv(const char *lnm, const char *eqv)*/
1696 /* This has to be a function since there's a prototype for it in proto.h */
1698 Perl_my_setenv(pTHX_ const char *lnm, const char *eqv)
1701 int len = strlen(lnm);
1705 for (i = 0; lnm[i]; i++) uplnm[i] = _toupper(lnm[i]);
1706 if (!strcmp(uplnm,"DEFAULT")) {
1707 if (eqv && *eqv) my_chdir(eqv);
1712 (void) vmssetenv(lnm,eqv,NULL);
1716 /*{{{static void vmssetuserlnm(char *name, char *eqv); */
1718 * sets a user-mode logical in the process logical name table
1719 * used for redirection of sys$error
1721 * Fix-me: The pTHX is not needed for this routine, however doio.c
1722 * is calling it with one instead of using a macro.
1723 * A macro needs to be added to vmsish.h and doio.c updated to use it.
1727 Perl_vmssetuserlnm(pTHX_ const char *name, const char *eqv)
1729 $DESCRIPTOR(d_tab, "LNM$PROCESS");
1730 struct dsc$descriptor_d d_name = {0,DSC$K_DTYPE_T,DSC$K_CLASS_D,0};
1731 unsigned long int iss, attr = LNM$M_CONFINE;
1732 unsigned char acmode = PSL$C_USER;
1733 struct itmlst_3 lnmlst[2] = {{0, LNM$_STRING, 0, 0},
1735 d_name.dsc$a_pointer = (char *)name; /* Cast OK for read only parameter */
1736 d_name.dsc$w_length = strlen(name);
1738 lnmlst[0].buflen = strlen(eqv);
1739 lnmlst[0].bufadr = (char *)eqv; /* Cast OK for read only parameter */
1741 iss = sys$crelnm(&attr,&d_tab,&d_name,&acmode,lnmlst);
1742 if (!(iss&1)) lib$signal(iss);
1747 /*{{{ char *my_crypt(const char *textpasswd, const char *usrname)*/
1748 /* my_crypt - VMS password hashing
1749 * my_crypt() provides an interface compatible with the Unix crypt()
1750 * C library function, and uses sys$hash_password() to perform VMS
1751 * password hashing. The quadword hashed password value is returned
1752 * as a NUL-terminated 8 character string. my_crypt() does not change
1753 * the case of its string arguments; in order to match the behavior
1754 * of LOGINOUT et al., alphabetic characters in both arguments must
1755 * be upcased by the caller.
1757 * - fix me to call ACM services when available
1760 Perl_my_crypt(pTHX_ const char *textpasswd, const char *usrname)
1762 # ifndef UAI$C_PREFERRED_ALGORITHM
1763 # define UAI$C_PREFERRED_ALGORITHM 127
1765 unsigned char alg = UAI$C_PREFERRED_ALGORITHM;
1766 unsigned short int salt = 0;
1767 unsigned long int sts;
1769 unsigned short int dsc$w_length;
1770 unsigned char dsc$b_type;
1771 unsigned char dsc$b_class;
1772 const char * dsc$a_pointer;
1773 } usrdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0},
1774 txtdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1775 struct itmlst_3 uailst[3] = {
1776 { sizeof alg, UAI$_ENCRYPT, &alg, 0},
1777 { sizeof salt, UAI$_SALT, &salt, 0},
1778 { 0, 0, NULL, NULL}};
1779 static char hash[9];
1781 usrdsc.dsc$w_length = strlen(usrname);
1782 usrdsc.dsc$a_pointer = usrname;
1783 if (!((sts = sys$getuai(0, 0, &usrdsc, uailst, 0, 0, 0)) & 1)) {
1785 case SS$_NOGRPPRV: case SS$_NOSYSPRV:
1789 set_errno(ESRCH); /* There isn't a Unix no-such-user error */
1794 set_vaxc_errno(sts);
1795 if (sts != RMS$_RNF) return NULL;
1798 txtdsc.dsc$w_length = strlen(textpasswd);
1799 txtdsc.dsc$a_pointer = textpasswd;
1800 if (!((sts = sys$hash_password(&txtdsc, alg, salt, &usrdsc, &hash)) & 1)) {
1801 set_errno(EVMSERR); set_vaxc_errno(sts); return NULL;
1804 return (char *) hash;
1806 } /* end of my_crypt() */
1810 static char *mp_do_rmsexpand(pTHX_ const char *, char *, int, const char *, unsigned, int *, int *);
1811 static char *mp_do_fileify_dirspec(pTHX_ const char *, char *, int, int *);
1812 static char *mp_do_tovmsspec(pTHX_ const char *, char *, int, int, int *);
1814 /* fixup barenames that are directories for internal use.
1815 * There have been problems with the consistent handling of UNIX
1816 * style directory names when routines are presented with a name that
1817 * has no directory delimiters at all. So this routine will eventually
1820 static char * fixup_bare_dirnames(const char * name)
1822 if (decc_disable_to_vms_logname_translation) {
1828 /* 8.3, remove() is now broken on symbolic links */
1829 static int rms_erase(const char * vmsname);
1833 * A little hack to get around a bug in some implementation of remove()
1834 * that do not know how to delete a directory
1836 * Delete any file to which user has control access, regardless of whether
1837 * delete access is explicitly allowed.
1838 * Limitations: User must have write access to parent directory.
1839 * Does not block signals or ASTs; if interrupted in midstream
1840 * may leave file with an altered ACL.
1843 /*{{{int mp_do_kill_file(const char *name, int dirflag)*/
1845 mp_do_kill_file(pTHX_ const char *name, int dirflag)
1849 unsigned long int jpicode = JPI$_UIC, type = ACL$C_FILE;
1850 unsigned long int cxt = 0, aclsts, fndsts, rmsts = -1;
1851 struct dsc$descriptor_s fildsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
1853 unsigned char myace$b_length;
1854 unsigned char myace$b_type;
1855 unsigned short int myace$w_flags;
1856 unsigned long int myace$l_access;
1857 unsigned long int myace$l_ident;
1858 } newace = { sizeof(struct myacedef), ACE$C_KEYID, 0,
1859 ACE$M_READ | ACE$M_WRITE | ACE$M_DELETE | ACE$M_CONTROL, 0},
1860 oldace = { sizeof(struct myacedef), ACE$C_KEYID, 0, 0, 0};
1862 findlst[3] = {{sizeof oldace, ACL$C_FNDACLENT, &oldace, 0},
1863 {sizeof oldace, ACL$C_READACE, &oldace, 0},{0,0,0,0}},
1864 addlst[2] = {{sizeof newace, ACL$C_ADDACLENT, &newace, 0},{0,0,0,0}},
1865 dellst[2] = {{sizeof newace, ACL$C_DELACLENT, &newace, 0},{0,0,0,0}},
1866 lcklst[2] = {{sizeof newace, ACL$C_WLOCK_ACL, &newace, 0},{0,0,0,0}},
1867 ulklst[2] = {{sizeof newace, ACL$C_UNLOCK_ACL, &newace, 0},{0,0,0,0}};
1869 /* Expand the input spec using RMS, since the CRTL remove() and
1870 * system services won't do this by themselves, so we may miss
1871 * a file "hiding" behind a logical name or search list. */
1872 vmsname = (char *)PerlMem_malloc(NAM$C_MAXRSS+1);
1873 if (vmsname == NULL) _ckvmssts_noperl(SS$_INSFMEM);
1875 rslt = int_rmsexpand_tovms(name, vmsname, PERL_RMSEXPAND_M_SYMLINK);
1877 PerlMem_free(vmsname);
1881 /* Erase the file */
1882 rmsts = rms_erase(vmsname);
1884 /* Did it succeed */
1885 if ($VMS_STATUS_SUCCESS(rmsts)) {
1886 PerlMem_free(vmsname);
1890 /* If not, can changing protections help? */
1891 if (rmsts != RMS$_PRV) {
1892 set_vaxc_errno(rmsts);
1893 PerlMem_free(vmsname);
1897 /* No, so we get our own UIC to use as a rights identifier,
1898 * and the insert an ACE at the head of the ACL which allows us
1899 * to delete the file.
1901 _ckvmssts_noperl(lib$getjpi(&jpicode,0,0,&(oldace.myace$l_ident),0,0));
1902 fildsc.dsc$w_length = strlen(vmsname);
1903 fildsc.dsc$a_pointer = vmsname;
1905 newace.myace$l_ident = oldace.myace$l_ident;
1907 if (!((aclsts = sys$change_acl(0,&type,&fildsc,lcklst,0,0,0)) & 1)) {
1909 case RMS$_FNF: case RMS$_DNF: case SS$_NOSUCHOBJECT:
1910 set_errno(ENOENT); break;
1912 set_errno(ENOTDIR); break;
1914 set_errno(ENODEV); break;
1915 case RMS$_SYN: case SS$_INVFILFOROP:
1916 set_errno(EINVAL); break;
1918 set_errno(EACCES); break;
1920 _ckvmssts_noperl(aclsts);
1922 set_vaxc_errno(aclsts);
1923 PerlMem_free(vmsname);
1926 /* Grab any existing ACEs with this identifier in case we fail */
1927 aclsts = fndsts = sys$change_acl(0,&type,&fildsc,findlst,0,0,&cxt);
1928 if ( fndsts & 1 || fndsts == SS$_ACLEMPTY || fndsts == SS$_NOENTRY
1929 || fndsts == SS$_NOMOREACE ) {
1930 /* Add the new ACE . . . */
1931 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,0)) & 1))
1934 rmsts = rms_erase(vmsname);
1935 if ($VMS_STATUS_SUCCESS(rmsts)) {
1940 /* We blew it - dir with files in it, no write priv for
1941 * parent directory, etc. Put things back the way they were. */
1942 if (!((aclsts = sys$change_acl(0,&type,&fildsc,dellst,0,0,0)) & 1))
1945 addlst[0].bufadr = &oldace;
1946 if (!((aclsts = sys$change_acl(0,&type,&fildsc,addlst,0,0,&cxt)) & 1))
1953 fndsts = sys$change_acl(0,&type,&fildsc,ulklst,0,0,0);
1954 /* We just deleted it, so of course it's not there. Some versions of
1955 * VMS seem to return success on the unlock operation anyhow (after all
1956 * the unlock is successful), but others don't.
1958 if (fndsts == RMS$_FNF || fndsts == SS$_NOSUCHOBJECT) fndsts = SS$_NORMAL;
1959 if (aclsts & 1) aclsts = fndsts;
1960 if (!(aclsts & 1)) {
1962 set_vaxc_errno(aclsts);
1965 PerlMem_free(vmsname);
1968 } /* end of kill_file() */
1972 /*{{{int do_rmdir(char *name)*/
1974 Perl_do_rmdir(pTHX_ const char *name)
1980 /* lstat returns a VMS fileified specification of the name */
1981 /* that is looked up, and also lets verifies that this is a directory */
1983 retval = flex_lstat(name, &st);
1987 /* Due to a historical feature, flex_stat/lstat can not see some */
1988 /* Unix format file names that the rest of the CRTL can see */
1989 /* Fixing that feature will cause some perl tests to fail */
1990 /* So try this one more time. */
1992 retval = lstat(name, &st.crtl_stat);
1996 /* force it to a file spec for the kill file to work. */
1997 ret_spec = do_fileify_dirspec(name, st.st_devnam, 0, NULL);
1998 if (ret_spec == NULL) {
2004 if (!S_ISDIR(st.st_mode)) {
2009 dirfile = st.st_devnam;
2011 /* It may be possible for flex_stat to find a file and vmsify() to */
2012 /* fail with ODS-2 specifications. mp_do_kill_file can not deal */
2013 /* with that case, so fail it */
2014 if (dirfile[0] == 0) {
2019 retval = mp_do_kill_file(aTHX_ dirfile, 1);
2024 } /* end of do_rmdir */
2028 * Delete any file to which user has control access, regardless of whether
2029 * delete access is explicitly allowed.
2030 * Limitations: User must have write access to parent directory.
2031 * Does not block signals or ASTs; if interrupted in midstream
2032 * may leave file with an altered ACL.
2035 /*{{{int kill_file(char *name)*/
2037 Perl_kill_file(pTHX_ const char *name)
2043 /* Convert the filename to VMS format and see if it is a directory */
2044 /* flex_lstat returns a vmsified file specification */
2045 rmsts = flex_lstat(name, &st);
2048 /* Due to a historical feature, flex_stat/lstat can not see some */
2049 /* Unix format file names that the rest of the CRTL can see when */
2050 /* ODS-2 file specifications are in use. */
2051 /* Fixing that feature will cause some perl tests to fail */
2052 /* [.lib.ExtUtils.t]Manifest.t is one of them */
2054 vmsfile = (char *) name; /* cast ok */
2057 vmsfile = st.st_devnam;
2058 if (vmsfile[0] == 0) {
2059 /* It may be possible for flex_stat to find a file and vmsify() */
2060 /* to fail with ODS-2 specifications. mp_do_kill_file can not */
2061 /* deal with that case, so fail it */
2067 /* Remove() is allowed to delete directories, according to the X/Open
2069 * This may need special handling to work with the ACL hacks.
2071 if (S_ISDIR(st.st_mode)) {
2072 rmsts = mp_do_kill_file(aTHX_ vmsfile, 1);
2076 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
2078 /* Need to delete all versions ? */
2079 if ((rmsts == 0) && (vms_unlink_all_versions == 1)) {
2082 /* Just use lstat() here as do not need st_dev */
2083 /* and we know that the file is in VMS format or that */
2084 /* because of a historical bug, flex_stat can not see the file */
2085 while (lstat(vmsfile, (stat_t *)&st) == 0) {
2086 rmsts = mp_do_kill_file(aTHX_ vmsfile, 0);
2091 /* Make sure that we do not loop forever */
2102 } /* end of kill_file() */
2106 /*{{{int my_mkdir(char *,Mode_t)*/
2108 Perl_my_mkdir(pTHX_ const char *dir, Mode_t mode)
2110 STRLEN dirlen = strlen(dir);
2112 /* zero length string sometimes gives ACCVIO */
2113 if (dirlen == 0) return -1;
2115 /* CRTL mkdir() doesn't tolerate trailing /, since that implies
2116 * null file name/type. However, it's commonplace under Unix,
2117 * so we'll allow it for a gain in portability.
2119 if (dir[dirlen-1] == '/') {
2120 char *newdir = savepvn(dir,dirlen-1);
2121 int ret = mkdir(newdir,mode);
2125 else return mkdir(dir,mode);
2126 } /* end of my_mkdir */
2129 /*{{{int my_chdir(char *)*/
2131 Perl_my_chdir(pTHX_ const char *dir)
2133 STRLEN dirlen = strlen(dir);
2135 /* zero length string sometimes gives ACCVIO */
2136 if (dirlen == 0) return -1;
2139 /* Perl is passing the output of the DCL SHOW DEFAULT with leading spaces.
2140 * This does not work if DECC$EFS_CHARSET is active. Hack it here
2141 * so that existing scripts do not need to be changed.
2144 while ((dirlen > 0) && (*dir1 == ' ')) {
2149 /* some versions of CRTL chdir() doesn't tolerate trailing /, since
2151 * null file name/type. However, it's commonplace under Unix,
2152 * so we'll allow it for a gain in portability.
2154 * '/' is valid when SYS$POSIX_ROOT or POSIX compliant pathnames are active.
2156 if ((dirlen > 1) && (dir1[dirlen-1] == '/')) {
2159 newdir = (char *)PerlMem_malloc(dirlen);
2161 _ckvmssts_noperl(SS$_INSFMEM);
2162 memcpy(newdir, dir1, dirlen-1);
2163 newdir[dirlen-1] = '\0';
2164 ret = chdir(newdir);
2165 PerlMem_free(newdir);
2168 else return chdir(dir1);
2169 } /* end of my_chdir */
2173 /*{{{int my_chmod(char *, mode_t)*/
2175 Perl_my_chmod(pTHX_ const char *file_spec, mode_t mode)
2180 STRLEN speclen = strlen(file_spec);
2182 /* zero length string sometimes gives ACCVIO */
2183 if (speclen == 0) return -1;
2185 /* some versions of CRTL chmod() doesn't tolerate trailing /, since
2186 * that implies null file name/type. However, it's commonplace under Unix,
2187 * so we'll allow it for a gain in portability.
2189 * Tests are showing that chmod() on VMS 8.3 is only accepting directories
2190 * in VMS file.dir notation.
2192 changefile = (char *) file_spec; /* cast ok */
2193 ret = flex_lstat(file_spec, &st);
2196 /* Due to a historical feature, flex_stat/lstat can not see some */
2197 /* Unix format file names that the rest of the CRTL can see when */
2198 /* ODS-2 file specifications are in use. */
2199 /* Fixing that feature will cause some perl tests to fail */
2200 /* [.lib.ExtUtils.t]Manifest.t is one of them */
2204 /* It may be possible to get here with nothing in st_devname */
2205 /* chmod still may work though */
2206 if (st.st_devnam[0] != 0) {
2207 changefile = st.st_devnam;
2210 ret = chmod(changefile, mode);
2212 } /* end of my_chmod */
2216 /*{{{FILE *my_tmpfile()*/
2223 if ((fp = tmpfile())) return fp;
2225 cp = (char *)PerlMem_malloc(L_tmpnam+24);
2226 if (cp == NULL) _ckvmssts_noperl(SS$_INSFMEM);
2228 if (decc_filename_unix_only == 0)
2229 strcpy(cp,"Sys$Scratch:");
2232 tmpnam(cp+strlen(cp));
2233 strcat(cp,".Perltmp");
2234 fp = fopen(cp,"w+","fop=dlt");
2242 * The C RTL's sigaction fails to check for invalid signal numbers so we
2243 * help it out a bit. The docs are correct, but the actual routine doesn't
2244 * do what the docs say it will.
2246 /*{{{int Perl_my_sigaction (pTHX_ int, const struct sigaction*, struct sigaction*);*/
2248 Perl_my_sigaction (pTHX_ int sig, const struct sigaction* act,
2249 struct sigaction* oact)
2251 if (sig == SIGKILL || sig == SIGSTOP || sig == SIGCONT) {
2252 SETERRNO(EINVAL, SS$_INVARG);
2255 return sigaction(sig, act, oact);
2259 #ifdef KILL_BY_SIGPRC
2260 #include <errnodef.h>
2262 /* We implement our own kill() using the undocumented system service
2263 sys$sigprc for one of two reasons:
2265 1.) If the kill() in an older CRTL uses sys$forcex, causing the
2266 target process to do a sys$exit, which usually can't be handled
2267 gracefully...certainly not by Perl and the %SIG{} mechanism.
2269 2.) If the kill() in the CRTL can't be called from a signal
2270 handler without disappearing into the ether, i.e., the signal
2271 it purportedly sends is never trapped. Still true as of VMS 7.3.
2273 sys$sigprc has the same parameters as sys$forcex, but throws an exception
2274 in the target process rather than calling sys$exit.
2276 Note that distinguishing SIGSEGV from SIGBUS requires an extra arg
2277 on the ACCVIO condition, which sys$sigprc (and sys$forcex) don't
2278 provide. On VMS 7.0+ this is taken care of by doing sys$sigprc
2279 with condition codes C$_SIG0+nsig*8, catching the exception on the
2280 target process and resignaling with appropriate arguments.
2282 But we don't have that VMS 7.0+ exception handler, so if you
2283 Perl_my_kill(.., SIGSEGV) it will show up as a SIGBUS. Oh well.
2285 Also note that SIGTERM is listed in the docs as being "unimplemented",
2286 yet always seems to be signaled with a VMS condition code of 4 (and
2287 correctly handled for that code). So we hardwire it in.
2289 Unlike the VMS 7.0+ CRTL kill() function, we actually check the signal
2290 number to see if it's valid. So Perl_my_kill(pid,0) returns -1 rather
2291 than signalling with an unrecognized (and unhandled by CRTL) code.
2294 #define _MY_SIG_MAX 28
2297 Perl_sig_to_vmscondition_int(int sig)
2299 static unsigned int sig_code[_MY_SIG_MAX+1] =
2302 SS$_HANGUP, /* 1 SIGHUP */
2303 SS$_CONTROLC, /* 2 SIGINT */
2304 SS$_CONTROLY, /* 3 SIGQUIT */
2305 SS$_RADRMOD, /* 4 SIGILL */
2306 SS$_BREAK, /* 5 SIGTRAP */
2307 SS$_OPCCUS, /* 6 SIGABRT */
2308 SS$_COMPAT, /* 7 SIGEMT */
2310 SS$_FLTOVF, /* 8 SIGFPE VAX */
2312 SS$_HPARITH, /* 8 SIGFPE AXP */
2314 SS$_ABORT, /* 9 SIGKILL */
2315 SS$_ACCVIO, /* 10 SIGBUS */
2316 SS$_ACCVIO, /* 11 SIGSEGV */
2317 SS$_BADPARAM, /* 12 SIGSYS */
2318 SS$_NOMBX, /* 13 SIGPIPE */
2319 SS$_ASTFLT, /* 14 SIGALRM */
2336 static int initted = 0;
2339 sig_code[16] = C$_SIGUSR1;
2340 sig_code[17] = C$_SIGUSR2;
2341 sig_code[20] = C$_SIGCHLD;
2342 #if __CRTL_VER >= 70300000
2343 sig_code[28] = C$_SIGWINCH;
2347 if (sig < _SIG_MIN) return 0;
2348 if (sig > _MY_SIG_MAX) return 0;
2349 return sig_code[sig];
2353 Perl_sig_to_vmscondition(int sig)
2356 if (vms_debug_on_exception != 0)
2357 lib$signal(SS$_DEBUG);
2359 return Perl_sig_to_vmscondition_int(sig);
2363 #define sys$sigprc SYS$SIGPRC
2367 int sys$sigprc(unsigned int *pidadr,
2368 struct dsc$descriptor_s *prcname,
2375 Perl_my_kill(int pid, int sig)
2380 /* sig 0 means validate the PID */
2381 /*------------------------------*/
2383 const unsigned long int jpicode = JPI$_PID;
2386 status = lib$getjpi(&jpicode, &pid, NULL, &ret_pid, NULL, NULL);
2387 if ($VMS_STATUS_SUCCESS(status))
2390 case SS$_NOSUCHNODE:
2391 case SS$_UNREACHABLE:
2405 code = Perl_sig_to_vmscondition_int(sig);
2408 SETERRNO(EINVAL, SS$_BADPARAM);
2412 /* Fixme: Per official UNIX specification: If pid = 0, or negative then
2413 * signals are to be sent to multiple processes.
2414 * pid = 0 - all processes in group except ones that the system exempts
2415 * pid = -1 - all processes except ones that the system exempts
2416 * pid = -n - all processes in group (abs(n)) except ...
2417 * For now, just report as not supported.
2421 SETERRNO(ENOTSUP, SS$_UNSUPPORTED);
2425 iss = sys$sigprc((unsigned int *)&pid,0,code);
2426 if (iss&1) return 0;
2430 set_errno(EPERM); break;
2432 case SS$_NOSUCHNODE:
2433 case SS$_UNREACHABLE:
2434 set_errno(ESRCH); break;
2436 set_errno(ENOMEM); break;
2438 _ckvmssts_noperl(iss);
2441 set_vaxc_errno(iss);
2447 /* Routine to convert a VMS status code to a UNIX status code.
2448 ** More tricky than it appears because of conflicting conventions with
2451 ** VMS status codes are a bit mask, with the least significant bit set for
2454 ** Special UNIX status of EVMSERR indicates that no translation is currently
2455 ** available, and programs should check the VMS status code.
2457 ** Programs compiled with _POSIX_EXIT have a special encoding that requires
2461 #ifndef C_FACILITY_NO
2462 #define C_FACILITY_NO 0x350000
2465 #define DCL_IVVERB 0x38090
2468 int Perl_vms_status_to_unix(int vms_status, int child_flag)
2476 /* Assume the best or the worst */
2477 if (vms_status & STS$M_SUCCESS)
2480 unix_status = EVMSERR;
2482 msg_status = vms_status & ~STS$M_CONTROL;
2484 facility = vms_status & STS$M_FAC_NO;
2485 fac_sp = vms_status & STS$M_FAC_SP;
2486 msg_no = vms_status & (STS$M_MSG_NO | STS$M_SEVERITY);
2488 if (((facility == 0) || (fac_sp == 0)) && (child_flag == 0)) {
2494 unix_status = EFAULT;
2496 case SS$_DEVOFFLINE:
2497 unix_status = EBUSY;
2500 unix_status = ENOTCONN;
2508 case SS$_INVFILFOROP:
2512 unix_status = EINVAL;
2514 case SS$_UNSUPPORTED:
2515 unix_status = ENOTSUP;
2520 unix_status = EACCES;
2522 case SS$_DEVICEFULL:
2523 unix_status = ENOSPC;
2526 unix_status = ENODEV;
2528 case SS$_NOSUCHFILE:
2529 case SS$_NOSUCHOBJECT:
2530 unix_status = ENOENT;
2532 case SS$_ABORT: /* Fatal case */
2533 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_ERROR): /* Error case */
2534 case ((SS$_ABORT & STS$M_COND_ID) | STS$K_WARNING): /* Warning case */
2535 unix_status = EINTR;
2538 unix_status = E2BIG;
2541 unix_status = ENOMEM;
2544 unix_status = EPERM;
2546 case SS$_NOSUCHNODE:
2547 case SS$_UNREACHABLE:
2548 unix_status = ESRCH;
2551 unix_status = ECHILD;
2554 if ((facility == 0) && (msg_no < 8)) {
2555 /* These are not real VMS status codes so assume that they are
2556 ** already UNIX status codes
2558 unix_status = msg_no;
2564 /* Translate a POSIX exit code to a UNIX exit code */
2565 if ((facility == C_FACILITY_NO) && ((msg_no & 0xA000) == 0xA000)) {
2566 unix_status = (msg_no & 0x07F8) >> 3;
2570 /* Documented traditional behavior for handling VMS child exits */
2571 /*--------------------------------------------------------------*/
2572 if (child_flag != 0) {
2574 /* Success / Informational return 0 */
2575 /*----------------------------------*/
2576 if (msg_no & STS$K_SUCCESS)
2579 /* Warning returns 1 */
2580 /*-------------------*/
2581 if ((msg_no & (STS$K_ERROR | STS$K_SEVERE)) == 0)
2584 /* Everything else pass through the severity bits */
2585 /*------------------------------------------------*/
2586 return (msg_no & STS$M_SEVERITY);
2589 /* Normal VMS status to ERRNO mapping attempt */
2590 /*--------------------------------------------*/
2591 switch(msg_status) {
2592 /* case RMS$_EOF: */ /* End of File */
2593 case RMS$_FNF: /* File Not Found */
2594 case RMS$_DNF: /* Dir Not Found */
2595 unix_status = ENOENT;
2597 case RMS$_RNF: /* Record Not Found */
2598 unix_status = ESRCH;
2601 unix_status = ENOTDIR;
2604 unix_status = ENODEV;
2609 unix_status = EBADF;
2612 unix_status = EEXIST;
2616 case LIB$_INVSTRDES:
2618 case LIB$_NOSUCHSYM:
2619 case LIB$_INVSYMNAM:
2621 unix_status = EINVAL;
2627 unix_status = E2BIG;
2629 case RMS$_PRV: /* No privilege */
2630 case RMS$_ACC: /* ACP file access failed */
2631 case RMS$_WLK: /* Device write locked */
2632 unix_status = EACCES;
2634 case RMS$_MKD: /* Failed to mark for delete */
2635 unix_status = EPERM;
2637 /* case RMS$_NMF: */ /* No more files */
2645 /* Try to guess at what VMS error status should go with a UNIX errno
2646 * value. This is hard to do as there could be many possible VMS
2647 * error statuses that caused the errno value to be set.
2650 int Perl_unix_status_to_vms(int unix_status)
2652 int test_unix_status;
2654 /* Trivial cases first */
2655 /*---------------------*/
2656 if (unix_status == EVMSERR)
2659 /* Is vaxc$errno sane? */
2660 /*---------------------*/
2661 test_unix_status = Perl_vms_status_to_unix(vaxc$errno, 0);
2662 if (test_unix_status == unix_status)
2665 /* If way out of range, must be VMS code already */
2666 /*-----------------------------------------------*/
2667 if (unix_status > EVMSERR)
2670 /* If out of range, punt */
2671 /*-----------------------*/
2672 if (unix_status > __ERRNO_MAX)
2676 /* Ok, now we have to do it the hard way. */
2677 /*----------------------------------------*/
2678 switch(unix_status) {
2679 case 0: return SS$_NORMAL;
2680 case EPERM: return SS$_NOPRIV;
2681 case ENOENT: return SS$_NOSUCHOBJECT;
2682 case ESRCH: return SS$_UNREACHABLE;
2683 case EINTR: return SS$_ABORT;
2686 case E2BIG: return SS$_BUFFEROVF;
2688 case EBADF: return RMS$_IFI;
2689 case ECHILD: return SS$_NONEXPR;
2691 case ENOMEM: return SS$_INSFMEM;
2692 case EACCES: return SS$_FILACCERR;
2693 case EFAULT: return SS$_ACCVIO;
2695 case EBUSY: return SS$_DEVOFFLINE;
2696 case EEXIST: return RMS$_FEX;
2698 case ENODEV: return SS$_NOSUCHDEV;
2699 case ENOTDIR: return RMS$_DIR;
2701 case EINVAL: return SS$_INVARG;
2707 case ENOSPC: return SS$_DEVICEFULL;
2708 case ESPIPE: return LIB$_INVARG;
2713 case ERANGE: return LIB$_INVARG;
2714 /* case EWOULDBLOCK */
2715 /* case EINPROGRESS */
2718 /* case EDESTADDRREQ */
2720 /* case EPROTOTYPE */
2721 /* case ENOPROTOOPT */
2722 /* case EPROTONOSUPPORT */
2723 /* case ESOCKTNOSUPPORT */
2724 /* case EOPNOTSUPP */
2725 /* case EPFNOSUPPORT */
2726 /* case EAFNOSUPPORT */
2727 /* case EADDRINUSE */
2728 /* case EADDRNOTAVAIL */
2730 /* case ENETUNREACH */
2731 /* case ENETRESET */
2732 /* case ECONNABORTED */
2733 /* case ECONNRESET */
2736 case ENOTCONN: return SS$_CLEARED;
2737 /* case ESHUTDOWN */
2738 /* case ETOOMANYREFS */
2739 /* case ETIMEDOUT */
2740 /* case ECONNREFUSED */
2742 /* case ENAMETOOLONG */
2743 /* case EHOSTDOWN */
2744 /* case EHOSTUNREACH */
2745 /* case ENOTEMPTY */
2757 /* case ECANCELED */
2761 return SS$_UNSUPPORTED;
2767 /* case EABANDONED */
2769 return SS$_ABORT; /* punt */
2774 /* default piping mailbox size */
2776 # define PERL_BUFSIZ 512
2778 # define PERL_BUFSIZ 8192
2783 create_mbx(unsigned short int *chan, struct dsc$descriptor_s *namdsc)
2785 unsigned long int mbxbufsiz;
2786 static unsigned long int syssize = 0;
2787 unsigned long int dviitm = DVI$_DEVNAM;
2788 char csize[LNM$C_NAMLENGTH+1];
2792 unsigned long syiitm = SYI$_MAXBUF;
2794 * Get the SYSGEN parameter MAXBUF
2796 * If the logical 'PERL_MBX_SIZE' is defined
2797 * use the value of the logical instead of PERL_BUFSIZ, but
2798 * keep the size between 128 and MAXBUF.
2801 _ckvmssts_noperl(lib$getsyi(&syiitm, &syssize, 0, 0, 0, 0));
2804 if (vmstrnenv("PERL_MBX_SIZE", csize, 0, fildev, 0)) {
2805 mbxbufsiz = atoi(csize);
2807 mbxbufsiz = PERL_BUFSIZ;
2809 if (mbxbufsiz < 128) mbxbufsiz = 128;
2810 if (mbxbufsiz > syssize) mbxbufsiz = syssize;
2812 _ckvmssts_noperl(sts = sys$crembx(0,chan,mbxbufsiz,mbxbufsiz,0,0,0));
2814 sts = lib$getdvi(&dviitm, chan, NULL, NULL, namdsc, &namdsc->dsc$w_length);
2815 _ckvmssts_noperl(sts);
2816 namdsc->dsc$a_pointer[namdsc->dsc$w_length] = '\0';
2818 } /* end of create_mbx() */
2821 /*{{{ my_popen and my_pclose*/
2823 typedef struct _iosb IOSB;
2824 typedef struct _iosb* pIOSB;
2825 typedef struct _pipe Pipe;
2826 typedef struct _pipe* pPipe;
2827 typedef struct pipe_details Info;
2828 typedef struct pipe_details* pInfo;
2829 typedef struct _srqp RQE;
2830 typedef struct _srqp* pRQE;
2831 typedef struct _tochildbuf CBuf;
2832 typedef struct _tochildbuf* pCBuf;
2835 unsigned short status;
2836 unsigned short count;
2837 unsigned long dvispec;
2840 #pragma member_alignment save
2841 #pragma nomember_alignment quadword
2842 struct _srqp { /* VMS self-relative queue entry */
2843 unsigned long qptr[2];
2845 #pragma member_alignment restore
2846 static RQE RQE_ZERO = {0,0};
2848 struct _tochildbuf {
2851 unsigned short size;
2859 unsigned short chan_in;
2860 unsigned short chan_out;
2862 unsigned int bufsize;
2874 #if defined(PERL_IMPLICIT_CONTEXT)
2875 void *thx; /* Either a thread or an interpreter */
2876 /* pointer, depending on how we're built */
2884 PerlIO *fp; /* file pointer to pipe mailbox */
2885 int useFILE; /* using stdio, not perlio */
2886 int pid; /* PID of subprocess */
2887 int mode; /* == 'r' if pipe open for reading */
2888 int done; /* subprocess has completed */
2889 int waiting; /* waiting for completion/closure */
2890 int closing; /* my_pclose is closing this pipe */
2891 unsigned long completion; /* termination status of subprocess */
2892 pPipe in; /* pipe in to sub */
2893 pPipe out; /* pipe out of sub */
2894 pPipe err; /* pipe of sub's sys$error */
2895 int in_done; /* true when in pipe finished */
2898 unsigned short xchan; /* channel to debug xterm */
2899 unsigned short xchan_valid; /* channel is assigned */
2902 struct exit_control_block
2904 struct exit_control_block *flink;
2905 unsigned long int (*exit_routine)(void);
2906 unsigned long int arg_count;
2907 unsigned long int *status_address;
2908 unsigned long int exit_status;
2911 typedef struct _closed_pipes Xpipe;
2912 typedef struct _closed_pipes* pXpipe;
2914 struct _closed_pipes {
2915 int pid; /* PID of subprocess */
2916 unsigned long completion; /* termination status of subprocess */
2918 #define NKEEPCLOSED 50
2919 static Xpipe closed_list[NKEEPCLOSED];
2920 static int closed_index = 0;
2921 static int closed_num = 0;
2923 #define RETRY_DELAY "0 ::0.20"
2924 #define MAX_RETRY 50
2926 static int pipe_ef = 0; /* first call to safe_popen inits these*/
2927 static unsigned long mypid;
2928 static unsigned long delaytime[2];
2930 static pInfo open_pipes = NULL;
2931 static $DESCRIPTOR(nl_desc, "NL:");
2933 #define PIPE_COMPLETION_WAIT 30 /* seconds, for EOF/FORCEX wait */
2937 static unsigned long int
2938 pipe_exit_routine(void)
2941 unsigned long int retsts = SS$_NORMAL, abort = SS$_TIMEOUT;
2942 int sts, did_stuff, j;
2945 * Flush any pending i/o, but since we are in process run-down, be
2946 * careful about referencing PerlIO structures that may already have
2947 * been deallocated. We may not even have an interpreter anymore.
2952 #if defined(PERL_IMPLICIT_CONTEXT)
2953 /* We need to use the Perl context of the thread that created */
2957 aTHX = info->err->thx;
2959 aTHX = info->out->thx;
2961 aTHX = info->in->thx;
2964 #if defined(USE_ITHREADS)
2968 && PL_perlio_fd_refcnt
2971 PerlIO_flush(info->fp);
2973 fflush((FILE *)info->fp);
2979 next we try sending an EOF...ignore if doesn't work, make sure we
2986 _ckvmssts_noperl(sys$setast(0));
2987 if (info->in && !info->in->shut_on_empty) {
2988 _ckvmssts_noperl(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
2993 _ckvmssts_noperl(sys$setast(1));
2997 /* wait for EOF to have effect, up to ~ 30 sec [default] */
2999 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3004 _ckvmssts_noperl(sys$setast(0));
3005 if (info->waiting && info->done)
3007 nwait += info->waiting;
3008 _ckvmssts_noperl(sys$setast(1));
3018 _ckvmssts_noperl(sys$setast(0));
3019 if (!info->done) { /* Tap them gently on the shoulder . . .*/
3020 sts = sys$forcex(&info->pid,0,&abort);
3021 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3024 _ckvmssts_noperl(sys$setast(1));
3028 /* again, wait for effect */
3030 for (j = 0; did_stuff && j < PIPE_COMPLETION_WAIT; j++) {
3035 _ckvmssts_noperl(sys$setast(0));
3036 if (info->waiting && info->done)
3038 nwait += info->waiting;
3039 _ckvmssts_noperl(sys$setast(1));
3048 _ckvmssts_noperl(sys$setast(0));
3049 if (!info->done) { /* We tried to be nice . . . */
3050 sts = sys$delprc(&info->pid,0);
3051 if (!(sts&1) && sts != SS$_NONEXPR) _ckvmssts_noperl(sts);
3052 info->done = 1; /* sys$delprc is as done as we're going to get. */
3054 _ckvmssts_noperl(sys$setast(1));
3060 #if defined(PERL_IMPLICIT_CONTEXT)
3061 /* We need to use the Perl context of the thread that created */
3064 if (open_pipes->err)
3065 aTHX = open_pipes->err->thx;
3066 else if (open_pipes->out)
3067 aTHX = open_pipes->out->thx;
3068 else if (open_pipes->in)
3069 aTHX = open_pipes->in->thx;
3071 if ((sts = my_pclose(open_pipes->fp)) == -1) retsts = vaxc$errno;
3072 else if (!(sts & 1)) retsts = sts;
3077 static struct exit_control_block pipe_exitblock =
3078 {(struct exit_control_block *) 0,
3079 pipe_exit_routine, 0, &pipe_exitblock.exit_status, 0};
3081 static void pipe_mbxtofd_ast(pPipe p);
3082 static void pipe_tochild1_ast(pPipe p);
3083 static void pipe_tochild2_ast(pPipe p);
3086 popen_completion_ast(pInfo info)
3088 pInfo i = open_pipes;
3091 info->completion &= 0x0FFFFFFF; /* strip off "control" field */
3092 closed_list[closed_index].pid = info->pid;
3093 closed_list[closed_index].completion = info->completion;
3095 if (closed_index == NKEEPCLOSED)
3100 if (i == info) break;
3103 if (!i) return; /* unlinked, probably freed too */
3108 Writing to subprocess ...
3109 if my_pclose'd: EOF already sent, should shutdown chan_in part of pipe
3111 chan_out may be waiting for "done" flag, or hung waiting
3112 for i/o completion to child...cancel the i/o. This will
3113 put it into "snarf mode" (done but no EOF yet) that discards
3116 Output from subprocess (stdout, stderr) needs to be flushed and
3117 shut down. We try sending an EOF, but if the mbx is full the pipe
3118 routine should still catch the "shut_on_empty" flag, telling it to
3119 use immediate-style reads so that "mbx empty" -> EOF.
3123 if (info->in && !info->in_done) { /* only for mode=w */
3124 if (info->in->shut_on_empty && info->in->need_wake) {
3125 info->in->need_wake = FALSE;
3126 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,info->in,0));
3128 _ckvmssts_noperl(sys$cancel(info->in->chan_out));
3132 if (info->out && !info->out_done) { /* were we also piping output? */
3133 info->out->shut_on_empty = TRUE;
3134 iss = sys$qio(0,info->out->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3135 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3136 _ckvmssts_noperl(iss);
3139 if (info->err && !info->err_done) { /* we were piping stderr */
3140 info->err->shut_on_empty = TRUE;
3141 iss = sys$qio(0,info->err->chan_in,IO$_WRITEOF|IO$M_NORSWAIT, 0, 0, 0, 0, 0, 0, 0, 0, 0);
3142 if (iss == SS$_MBFULL) iss = SS$_NORMAL;
3143 _ckvmssts_noperl(iss);
3145 _ckvmssts_noperl(sys$setef(pipe_ef));
3149 static unsigned long int setup_cmddsc(pTHX_ const char *cmd, int check_img, int *suggest_quote, struct dsc$descriptor_s **pvmscmd);
3150 static void vms_execfree(struct dsc$descriptor_s *vmscmd);
3151 static void pipe_infromchild_ast(pPipe p);
3154 I'm using LIB$(GET|FREE)_VM here so that we can allocate and deallocate
3155 inside an AST routine without worrying about reentrancy and which Perl
3156 memory allocator is being used.
3158 We read data and queue up the buffers, then spit them out one at a
3159 time to the output mailbox when the output mailbox is ready for one.
3162 #define INITIAL_TOCHILDQUEUE 2
3165 pipe_tochild_setup(pTHX_ char *rmbx, char *wmbx)
3169 char mbx1[64], mbx2[64];
3170 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3171 DSC$K_CLASS_S, mbx1},
3172 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3173 DSC$K_CLASS_S, mbx2};
3174 unsigned int dviitm = DVI$_DEVBUFSIZ;
3178 _ckvmssts_noperl(lib$get_vm(&n, &p));
3180 create_mbx(&p->chan_in , &d_mbx1);
3181 create_mbx(&p->chan_out, &d_mbx2);
3182 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3185 p->shut_on_empty = FALSE;
3186 p->need_wake = FALSE;
3189 p->iosb.status = SS$_NORMAL;
3190 p->iosb2.status = SS$_NORMAL;
3196 #ifdef PERL_IMPLICIT_CONTEXT
3200 n = sizeof(CBuf) + p->bufsize;
3202 for (j = 0; j < INITIAL_TOCHILDQUEUE; j++) {
3203 _ckvmssts_noperl(lib$get_vm(&n, &b));
3204 b->buf = (char *) b + sizeof(CBuf);
3205 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3208 pipe_tochild2_ast(p);
3209 pipe_tochild1_ast(p);
3215 /* reads the MBX Perl is writing, and queues */
3218 pipe_tochild1_ast(pPipe p)
3221 int iss = p->iosb.status;
3222 int eof = (iss == SS$_ENDOFFILE);
3224 #ifdef PERL_IMPLICIT_CONTEXT
3230 p->shut_on_empty = TRUE;
3232 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3234 _ckvmssts_noperl(iss);
3238 b->size = p->iosb.count;
3239 _ckvmssts_noperl(sts = lib$insqhi(b, &p->wait));
3241 p->need_wake = FALSE;
3242 _ckvmssts_noperl(sys$dclast(pipe_tochild2_ast,p,0));
3245 p->retry = 1; /* initial call */
3248 if (eof) { /* flush the free queue, return when done */
3249 int n = sizeof(CBuf) + p->bufsize;
3251 iss = lib$remqti(&p->free, &b);
3252 if (iss == LIB$_QUEWASEMP) return;
3253 _ckvmssts_noperl(iss);
3254 _ckvmssts_noperl(lib$free_vm(&n, &b));
3258 iss = lib$remqti(&p->free, &b);
3259 if (iss == LIB$_QUEWASEMP) {
3260 int n = sizeof(CBuf) + p->bufsize;
3261 _ckvmssts_noperl(lib$get_vm(&n, &b));
3262 b->buf = (char *) b + sizeof(CBuf);
3264 _ckvmssts_noperl(iss);
3268 iss = sys$qio(0,p->chan_in,
3269 IO$_READVBLK|(p->shut_on_empty ? IO$M_NOWAIT : 0),
3271 pipe_tochild1_ast, p, b->buf, p->bufsize, 0, 0, 0, 0);
3272 if (iss == SS$_ENDOFFILE && p->shut_on_empty) iss = SS$_NORMAL;
3273 _ckvmssts_noperl(iss);
3277 /* writes queued buffers to output, waits for each to complete before
3281 pipe_tochild2_ast(pPipe p)
3284 int iss = p->iosb2.status;
3285 int n = sizeof(CBuf) + p->bufsize;
3286 int done = (p->info && p->info->done) ||
3287 iss == SS$_CANCEL || iss == SS$_ABORT;
3288 #if defined(PERL_IMPLICIT_CONTEXT)
3293 if (p->type) { /* type=1 has old buffer, dispose */
3294 if (p->shut_on_empty) {
3295 _ckvmssts_noperl(lib$free_vm(&n, &b));
3297 _ckvmssts_noperl(lib$insqhi(b, &p->free));
3302 iss = lib$remqti(&p->wait, &b);
3303 if (iss == LIB$_QUEWASEMP) {
3304 if (p->shut_on_empty) {
3306 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3307 *p->pipe_done = TRUE;
3308 _ckvmssts_noperl(sys$setef(pipe_ef));
3310 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3311 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3315 p->need_wake = TRUE;
3318 _ckvmssts_noperl(iss);
3325 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF,
3326 &p->iosb2, pipe_tochild2_ast, p, 0, 0, 0, 0, 0, 0));
3328 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,
3329 &p->iosb2, pipe_tochild2_ast, p, b->buf, b->size, 0, 0, 0, 0));
3338 pipe_infromchild_setup(pTHX_ char *rmbx, char *wmbx)
3341 char mbx1[64], mbx2[64];
3342 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3343 DSC$K_CLASS_S, mbx1},
3344 d_mbx2 = {sizeof mbx2, DSC$K_DTYPE_T,
3345 DSC$K_CLASS_S, mbx2};
3346 unsigned int dviitm = DVI$_DEVBUFSIZ;
3348 int n = sizeof(Pipe);
3349 _ckvmssts_noperl(lib$get_vm(&n, &p));
3350 create_mbx(&p->chan_in , &d_mbx1);
3351 create_mbx(&p->chan_out, &d_mbx2);
3353 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3354 n = p->bufsize * sizeof(char);
3355 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3356 p->shut_on_empty = FALSE;
3359 p->iosb.status = SS$_NORMAL;
3360 #if defined(PERL_IMPLICIT_CONTEXT)
3363 pipe_infromchild_ast(p);
3371 pipe_infromchild_ast(pPipe p)
3373 int iss = p->iosb.status;
3374 int eof = (iss == SS$_ENDOFFILE);
3375 int myeof = (eof && (p->iosb.dvispec == mypid || p->iosb.dvispec == 0));
3376 int kideof = (eof && (p->iosb.dvispec == p->info->pid));
3377 #if defined(PERL_IMPLICIT_CONTEXT)
3381 if (p->info && p->info->closing && p->chan_out) { /* output shutdown */
3382 _ckvmssts_noperl(sys$dassgn(p->chan_out));
3387 input shutdown if EOF from self (done or shut_on_empty)
3388 output shutdown if closing flag set (my_pclose)
3389 send data/eof from child or eof from self
3390 otherwise, re-read (snarf of data from child)
3395 if (myeof && p->chan_in) { /* input shutdown */
3396 _ckvmssts_noperl(sys$dassgn(p->chan_in));
3401 if (myeof || kideof) { /* pass EOF to parent */
3402 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEOF, &p->iosb,
3403 pipe_infromchild_ast, p,
3406 } else if (eof) { /* eat EOF --- fall through to read*/
3408 } else { /* transmit data */
3409 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_WRITEVBLK,&p->iosb,
3410 pipe_infromchild_ast,p,
3411 p->buf, p->iosb.count, 0, 0, 0, 0));
3417 /* everything shut? flag as done */
3419 if (!p->chan_in && !p->chan_out) {
3420 *p->pipe_done = TRUE;
3421 _ckvmssts_noperl(sys$setef(pipe_ef));
3425 /* write completed (or read, if snarfing from child)
3426 if still have input active,
3427 queue read...immediate mode if shut_on_empty so we get EOF if empty
3429 check if Perl reading, generate EOFs as needed
3435 iss = sys$qio(0,p->chan_in,IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0),&p->iosb,
3436 pipe_infromchild_ast,p,
3437 p->buf, p->bufsize, 0, 0, 0, 0);
3438 if (p->shut_on_empty && iss == SS$_ENDOFFILE) iss = SS$_NORMAL;
3439 _ckvmssts_noperl(iss);
3440 } else { /* send EOFs for extra reads */
3441 p->iosb.status = SS$_ENDOFFILE;
3442 p->iosb.dvispec = 0;
3443 _ckvmssts_noperl(sys$qio(0,p->chan_out,IO$_SETMODE|IO$M_READATTN,
3445 pipe_infromchild_ast, p, 0, 0, 0, 0));
3451 pipe_mbxtofd_setup(pTHX_ int fd, char *out)
3455 unsigned long dviitm = DVI$_DEVBUFSIZ;
3457 struct dsc$descriptor_s d_mbx = {sizeof mbx, DSC$K_DTYPE_T,
3458 DSC$K_CLASS_S, mbx};
3459 int n = sizeof(Pipe);
3461 /* things like terminals and mbx's don't need this filter */
3462 if (fd && fstat(fd,&s) == 0) {
3463 unsigned long devchar;
3465 unsigned short dev_len;
3466 struct dsc$descriptor_s d_dev;
3468 struct item_list_3 items[3];
3470 unsigned short dvi_iosb[4];
3472 cptr = getname(fd, out, 1);
3473 if (cptr == NULL) _ckvmssts_noperl(SS$_NOSUCHDEV);
3474 d_dev.dsc$a_pointer = out;
3475 d_dev.dsc$w_length = strlen(out);
3476 d_dev.dsc$b_dtype = DSC$K_DTYPE_T;
3477 d_dev.dsc$b_class = DSC$K_CLASS_S;
3480 items[0].code = DVI$_DEVCHAR;
3481 items[0].bufadr = &devchar;
3482 items[0].retadr = NULL;
3484 items[1].code = DVI$_FULLDEVNAM;
3485 items[1].bufadr = device;
3486 items[1].retadr = &dev_len;
3490 status = sys$getdviw
3491 (NO_EFN, 0, &d_dev, items, dvi_iosb, NULL, NULL, NULL);
3492 _ckvmssts_noperl(status);
3493 if ($VMS_STATUS_SUCCESS(dvi_iosb[0])) {
3494 device[dev_len] = 0;
3496 if (!(devchar & DEV$M_DIR)) {
3497 strcpy(out, device);
3503 _ckvmssts_noperl(lib$get_vm(&n, &p));
3504 p->fd_out = dup(fd);
3505 create_mbx(&p->chan_in, &d_mbx);
3506 _ckvmssts_noperl(lib$getdvi(&dviitm, &p->chan_in, 0, &p->bufsize));
3507 n = (p->bufsize+1) * sizeof(char);
3508 _ckvmssts_noperl(lib$get_vm(&n, &p->buf));
3509 p->shut_on_empty = FALSE;
3514 _ckvmssts_noperl(sys$qio(0, p->chan_in, IO$_READVBLK, &p->iosb,
3515 pipe_mbxtofd_ast, p,
3516 p->buf, p->bufsize, 0, 0, 0, 0));
3522 pipe_mbxtofd_ast(pPipe p)
3524 int iss = p->iosb.status;
3525 int done = p->info->done;
3527 int eof = (iss == SS$_ENDOFFILE);
3528 int myeof = eof && ((p->iosb.dvispec == mypid)||(p->iosb.dvispec == 0));
3529 int err = !(iss&1) && !eof;
3530 #if defined(PERL_IMPLICIT_CONTEXT)
3534 if (done && myeof) { /* end piping */
3536 sys$dassgn(p->chan_in);
3537 *p->pipe_done = TRUE;
3538 _ckvmssts_noperl(sys$setef(pipe_ef));
3542 if (!err && !eof) { /* good data to send to file */
3543 p->buf[p->iosb.count] = '\n';
3544 iss2 = write(p->fd_out, p->buf, p->iosb.count+1);
3547 if (p->retry < MAX_RETRY) {
3548 _ckvmssts_noperl(sys$setimr(0,delaytime,pipe_mbxtofd_ast,p));
3554 _ckvmssts_noperl(iss);
3558 iss = sys$qio(0, p->chan_in, IO$_READVBLK|(p->shut_on_empty ? IO$M_NOW : 0), &p->iosb,
3559 pipe_mbxtofd_ast, p,
3560 p->buf, p->bufsize, 0, 0, 0, 0);
3561 if (p->shut_on_empty && (iss == SS$_ENDOFFILE)) iss = SS$_NORMAL;
3562 _ckvmssts_noperl(iss);
3566 typedef struct _pipeloc PLOC;
3567 typedef struct _pipeloc* pPLOC;
3571 char dir[NAM$C_MAXRSS+1];
3573 static pPLOC head_PLOC = 0;
3576 free_pipelocs(pTHX_ void *head)
3579 pPLOC *pHead = (pPLOC *)head;
3591 store_pipelocs(pTHX)
3599 char temp[NAM$C_MAXRSS+1];
3603 free_pipelocs(aTHX_ &head_PLOC);
3605 /* the . directory from @INC comes last */
3607 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3608 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3609 p->next = head_PLOC;
3611 strcpy(p->dir,"./");
3613 /* get the directory from $^X */
3615 unixdir = (char *)PerlMem_malloc(VMS_MAXRSS);
3616 if (unixdir == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3618 #ifdef PERL_IMPLICIT_CONTEXT
3619 if (aTHX && PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3621 if (PL_origargv && PL_origargv[0]) { /* maybe nul if embedded Perl */
3623 my_strlcpy(temp, PL_origargv[0], sizeof(temp));
3624 x = strrchr(temp,']');
3626 x = strrchr(temp,'>');
3628 /* It could be a UNIX path */
3629 x = strrchr(temp,'/');
3635 /* Got a bare name, so use default directory */
3640 if ((tounixpath_utf8(temp, unixdir, NULL)) != NULL) {
3641 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3642 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3643 p->next = head_PLOC;
3645 my_strlcpy(p->dir, unixdir, sizeof(p->dir));
3649 /* reverse order of @INC entries, skip "." since entered above */
3651 #ifdef PERL_IMPLICIT_CONTEXT
3654 if (PL_incgv) av = GvAVn(PL_incgv);
3656 for (i = 0; av && i <= AvFILL(av); i++) {
3657 dirsv = *av_fetch(av,i,TRUE);
3659 if (SvROK(dirsv)) continue;
3660 dir = SvPVx(dirsv,n_a);
3661 if (strcmp(dir,".") == 0) continue;
3662 if ((tounixpath_utf8(dir, unixdir, NULL)) == NULL)
3665 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3666 p->next = head_PLOC;
3668 my_strlcpy(p->dir, unixdir, sizeof(p->dir));
3671 /* most likely spot (ARCHLIB) put first in the list */
3674 if ((tounixpath_utf8(ARCHLIB_EXP, unixdir, NULL)) != NULL) {
3675 p = (pPLOC) PerlMem_malloc(sizeof(PLOC));
3676 if (p == NULL) _ckvmssts_noperl(SS$_INSFMEM);
3677 p->next = head_PLOC;
3679 my_strlcpy(p->dir, unixdir, sizeof(p->dir));
3682 PerlMem_free(unixdir);
3686 Perl_cando_by_name_int
3687 (pTHX_ I32 bit, bool effective, const char *fname, int opts);
3688 #if !defined(PERL_IMPLICIT_CONTEXT)
3689 #define cando_by_name_int Perl_cando_by_name_int
3691 #define cando_by_name_int(a,b,c,d) Perl_cando_by_name_int(aTHX_ a,b,c,d)
3697 static int vmspipe_file_status = 0;
3698 static char vmspipe_file[NAM$C_MAXRSS+1];
3700 /* already found? Check and use ... need read+execute permission */
3702 if (vmspipe_file_status == 1) {
3703 if (cando_by_name_int(S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3704 && cando_by_name_int
3705 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3706 return vmspipe_file;
3708 vmspipe_file_status = 0;
3711 /* scan through stored @INC, $^X */
3713 if (vmspipe_file_status == 0) {
3714 char file[NAM$C_MAXRSS+1];
3715 pPLOC p = head_PLOC;
3720 dirlen = my_strlcpy(file, p->dir, sizeof(file));
3721 my_strlcat(file, "vmspipe.com", sizeof(file));
3724 exp_res = int_rmsexpand_tovms(file, vmspipe_file, 0);
3725 if (!exp_res) continue;
3727 if (cando_by_name_int
3728 (S_IRUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)
3729 && cando_by_name_int
3730 (S_IXUSR, 0, vmspipe_file, PERL_RMSEXPAND_M_VMS_IN)) {
3731 vmspipe_file_status = 1;
3732 return vmspipe_file;
3735 vmspipe_file_status = -1; /* failed, use tempfiles */
3742 vmspipe_tempfile(pTHX)
3744 char file[NAM$C_MAXRSS+1];
3746 static int index = 0;
3750 /* create a tempfile */
3752 /* we can't go from W, shr=get to R, shr=get without
3753 an intermediate vulnerable state, so don't bother trying...
3755 and lib$spawn doesn't shr=put, so have to close the write
3757 So... match up the creation date/time and the FID to
3758 make sure we're dealing with the same file
3763 if (!decc_filename_unix_only) {
3764 sprintf(file,"sys$scratch:perlpipe_%08.8x_%d.com",mypid,index);
3765 fp = fopen(file,"w");
3767 sprintf(file,"sys$login:perlpipe_%08.8x_%d.com",mypid,index);
3768 fp = fopen(file,"w");
3770 sprintf(file,"sys$disk:[]perlpipe_%08.8x_%d.com",mypid,index);
3771 fp = fopen(file,"w");
3776 sprintf(file,"/tmp/perlpipe_%08.8x_%d.com",mypid,index);
3777 fp = fopen(file,"w");
3779 sprintf(file,"/sys$login/perlpipe_%08.8x_%d.com",mypid,index);
3780 fp = fopen(file,"w");
3782 sprintf(file,"./perlpipe_%08.8x_%d.com",mypid,index);
3783 fp = fopen(file,"w");
3787 if (!fp) return 0; /* we're hosed */
3789 fprintf(fp,"$! 'f$verify(0)'\n");
3790 fprintf(fp,"$! --- protect against nonstandard definitions ---\n");
3791 fprintf(fp,"$ perl_cfile = f$environment(\"procedure\")\n");
3792 fprintf(fp,"$ perl_define = \"define/nolog\"\n");
3793 fprintf(fp,"$ perl_on = \"set noon\"\n");
3794 fprintf(fp,"$ perl_exit = \"exit\"\n");
3795 fprintf(fp,"$ perl_del = \"delete\"\n");
3796 fprintf(fp,"$ pif = \"if\"\n");
3797 fprintf(fp,"$! --- define i/o redirection (sys$output set by lib$spawn)\n");
3798 fprintf(fp,"$ pif perl_popen_in .nes. \"\" then perl_define/user/name_attributes=confine sys$input 'perl_popen_in'\n");
3799 fprintf(fp,"$ pif perl_popen_err .nes. \"\" then perl_define/user/name_attributes=confine sys$error 'perl_popen_err'\n");
3800 fprintf(fp,"$ pif perl_popen_out .nes. \"\" then perl_define sys$output 'perl_popen_out'\n");
3801 fprintf(fp,"$! --- build command line to get max possible length\n");
3802 fprintf(fp,"$c=perl_popen_cmd0\n");
3803 fprintf(fp,"$c=c+perl_popen_cmd1\n");
3804 fprintf(fp,"$c=c+perl_popen_cmd2\n");
3805 fprintf(fp,"$x=perl_popen_cmd3\n");
3806 fprintf(fp,"$c=c+x\n");
3807 fprintf(fp,"$ perl_on\n");
3808 fprintf(fp,"$ 'c'\n");
3809 fprintf(fp,"$ perl_status = $STATUS\n");
3810 fprintf(fp,"$ perl_del 'perl_cfile'\n");
3811 fprintf(fp,"$ perl_exit 'perl_status'\n");
3814 fgetname(fp, file, 1);
3815 fstat(fileno(fp), &s0.crtl_stat);
3818 if (decc_filename_unix_only)
3819 int_tounixspec(file, file, NULL);
3820 fp = fopen(file,"r","shr=get");
3822 fstat(fileno(fp), &s1.crtl_stat);
3824 cmp_result = VMS_INO_T_COMPARE(s0.crtl_stat.st_ino, s1.crtl_stat.st_ino);
3825 if ((cmp_result != 0) && (s0.st_ctime != s1.st_ctime)) {
3834 static int vms_is_syscommand_xterm(void)
3836 const static struct dsc$descriptor_s syscommand_dsc =
3837 { 11, DSC$K_DTYPE_T, DSC$K_CLASS_S, "SYS$COMMAND" };
3839 const static struct dsc$descriptor_s decwdisplay_dsc =
3840 { 12, DSC$K_DTYPE_T, DSC$K_CLASS_S, "DECW$DISPLAY" };
3842 struct item_list_3 items[2];
3843 unsigned short dvi_iosb[4];
3844 unsigned long devchar;
3845 unsigned long devclass;
3848 /* Very simple check to guess if sys$command is a decterm? */
3849 /* First see if the DECW$DISPLAY: device exists */
3851 items[0].code = DVI$_DEVCHAR;
3852 items[0].bufadr = &devchar;
3853 items[0].retadr = NULL;
3857 status = sys$getdviw
3858 (NO_EFN, 0, &decwdisplay_dsc, items, dvi_iosb, NULL, NULL, NULL);
3860 if ($VMS_STATUS_SUCCESS(status)) {
3861 status = dvi_iosb[0];
3864 if (!$VMS_STATUS_SUCCESS(status)) {
3865 SETERRNO(EVMSERR, status);
3869 /* If it does, then for now assume that we are on a workstation */
3870 /* Now verify that SYS$COMMAND is a terminal */
3871 /* for creating the debugger DECTerm */
3874 items[0].code = DVI$_DEVCLASS;
3875 items[0].bufadr = &devclass;
3876 items[0].retadr = NULL;
3880 status = sys$getdviw
3881 (NO_EFN, 0, &syscommand_dsc, items, dvi_iosb, NULL, NULL, NULL);
3883 if ($VMS_STATUS_SUCCESS(status)) {
3884 status = dvi_iosb[0];
3887 if (!$VMS_STATUS_SUCCESS(status)) {
3888 SETERRNO(EVMSERR, status);
3892 if (devclass == DC$_TERM) {
3899 /* If we are on a DECTerm, we can pretend to fork xterms when requested */
3900 static PerlIO * create_forked_xterm(pTHX_ const char *cmd, const char *mode)
3905 char device_name[65];
3906 unsigned short device_name_len;
3907 struct dsc$descriptor_s customization_dsc;
3908 struct dsc$descriptor_s device_name_dsc;
3910 char customization[200];
3914 unsigned short p_chan;
3916 unsigned short iosb[4];
3917 const char * cust_str =
3918 "DECW$TERMINAL.iconName:\tPerl Dbg\nDECW$TERMINAL.title:\t%40s\n";
3919 struct dsc$descriptor_s d_mbx1 = {sizeof mbx1, DSC$K_DTYPE_T,
3920 DSC$K_CLASS_S, mbx1};
3922 /* LIB$FIND_IMAGE_SIGNAL needs a handler */
3923 /*---------------------------------------*/
3924 VAXC$ESTABLISH((__vms_handler)lib$sig_to_ret);
3927 /* Make sure that this is from the Perl debugger */
3928 ret_char = strstr(cmd," xterm ");
3929 if (ret_char == NULL)
3931 cptr = ret_char + 7;
3932 ret_char = strstr(cmd,"tty");
3933 if (ret_char == NULL)
3935 ret_char = strstr(cmd,"sleep");
3936 if (ret_char == NULL)
3939 if (decw_term_port == 0) {
3940 $DESCRIPTOR(filename1_dsc, "DECW$TERMINALSHR12");
3941 $DESCRIPTOR(filename2_dsc, "DECW$TERMINALSHR");
3942 $DESCRIPTOR(decw_term_port_dsc, "DECW$TERM_PORT");
3944 status = lib$find_image_symbol
3946 &decw_term_port_dsc,
3947 (void *)&decw_term_port,
3951 /* Try again with the other image name */
3952 if (!$VMS_STATUS_SUCCESS(status)) {
3954 status = lib$find_image_symbol
3956 &decw_term_port_dsc,
3957 (void *)&decw_term_port,
3966 /* No decw$term_port, give it up */
3967 if (!$VMS_STATUS_SUCCESS(status))
3970 /* Are we on a workstation? */
3971 /* to do: capture the rows / columns and pass their properties */
3972 ret_stat = vms_is_syscommand_xterm();
3976 /* Make the title: */
3977 ret_char = strstr(cptr,"-title");
3978 if (ret_char != NULL) {
3979 while ((*cptr != 0) && (*cptr != '\"')) {
3985 while ((*cptr != 0) && (*cptr != '\"')) {
3998 strcpy(title,"Perl Debug DECTerm");
4000 sprintf(customization, cust_str, title);
4002 customization_dsc.dsc$a_pointer = customization;
4003 customization_dsc.dsc$w_length = strlen(customization);
4004 customization_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4005 customization_dsc.dsc$b_class = DSC$K_CLASS_S;
4007 device_name_dsc.dsc$a_pointer = device_name;
4008 device_name_dsc.dsc$w_length = sizeof device_name -1;
4009 device_name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
4010 device_name_dsc.dsc$b_class = DSC$K_CLASS_S;
4012 device_name_len = 0;
4014 /* Try to create the window */
4015 status = (*decw_term_port)
4024 if (!$VMS_STATUS_SUCCESS(status)) {
4025 SETERRNO(EVMSERR, status);
4029 device_name[device_name_len] = '\0';
4031 /* Need to set this up to look like a pipe for cleanup */
4033 status = lib$get_vm(&n, &info);
4034 if (!$VMS_STATUS_SUCCESS(status)) {
4035 SETERRNO(ENOMEM, status);
4041 info->completion = 0;
4042 info->closing = FALSE;
4049 info->in_done = TRUE;
4050 info->out_done = TRUE;
4051 info->err_done = TRUE;
4053 /* Assign a channel on this so that it will persist, and not login */
4054 /* We stash this channel in the info structure for reference. */
4055 /* The created xterm self destructs when the last channel is removed */
4056 /* and it appears that perl5db.pl (perl debugger) does this routinely */
4057 /* So leave this assigned. */
4058 device_name_dsc.dsc$w_length = device_name_len;
4059 status = sys$assign(&device_name_dsc,&info->xchan,0,0);
4060 if (!$VMS_STATUS_SUCCESS(status)) {
4061 SETERRNO(EVMSERR, status);
4064 info->xchan_valid = 1;
4066 /* Now create a mailbox to be read by the application */
4068 create_mbx(&p_chan, &d_mbx1);
4070 /* write the name of the created terminal to the mailbox */
4071 status = sys$qiow(NO_EFN, p_chan, IO$_WRITEVBLK|IO$M_NOW,
4072 iosb, NULL, NULL, device_name, device_name_len, 0, 0, 0, 0);
4074 if (!$VMS_STATUS_SUCCESS(status)) {
4075 SETERRNO(EVMSERR, status);
4079 info->fp = PerlIO_open(mbx1, mode);
4081 /* Done with this channel */
4084 /* If any errors, then clean up */
4087 _ckvmssts_noperl(lib$free_vm(&n, &info));
4095 static I32 my_pclose_pinfo(pTHX_ pInfo info);
4098 safe_popen(pTHX_ const char *cmd, const char *in_mode, int *psts)
4100 static int handler_set_up = FALSE;
4102 unsigned long int sts, flags = CLI$M_NOWAIT;
4103 /* The use of a GLOBAL table (as was done previously) rendered
4104 * Perl's qx() or `` unusable from a C<$ SET SYMBOL/SCOPE=NOGLOBAL> DCL
4105 * environment. Hence we've switched to LOCAL symbol table.
4107 unsigned int table = LIB$K_CLI_LOCAL_SYM;
4109 char *p, mode[10], symbol[MAX_DCL_SYMBOL+1], *vmspipe;
4110 char *in, *out, *err, mbx[512];
4112 char tfilebuf[NAM$C_MAXRSS+1];
4114 char cmd_sym_name[20];
4115 struct dsc$descriptor_s d_symbol= {0, DSC$K_DTYPE_T,
4116 DSC$K_CLASS_S, symbol};
4117 struct dsc$descriptor_s vmspipedsc = {0, DSC$K_DTYPE_T,
4119 struct dsc$descriptor_s d_sym_cmd = {0, DSC$K_DTYPE_T,
4120 DSC$K_CLASS_S, cmd_sym_name};
4121 struct dsc$descriptor_s *vmscmd;
4122 $DESCRIPTOR(d_sym_in ,"PERL_POPEN_IN");
4123 $DESCRIPTOR(d_sym_out,"PERL_POPEN_OUT");
4124 $DESCRIPTOR(d_sym_err,"PERL_POPEN_ERR");
4126 /* Check here for Xterm create request. This means looking for
4127 * "3>&1 xterm\b" and "\btty 1>&3\b$" in the command, and that it
4128 * is possible to create an xterm.
4130 if (*in_mode == 'r') {
4133 #if defined(PERL_IMPLICIT_CONTEXT)
4134 /* Can not fork an xterm with a NULL context */
4135 /* This probably could never happen */
4139 xterm_fd = create_forked_xterm(aTHX_ cmd, in_mode);
4140 if (xterm_fd != NULL)
4144 if (!head_PLOC) store_pipelocs(aTHX); /* at least TRY to use a static vmspipe file */
4146 /* once-per-program initialization...
4147 note that the SETAST calls and the dual test of pipe_ef
4148 makes sure that only the FIRST thread through here does
4149 the initialization...all other threads wait until it's
4152 Yeah, uglier than a pthread call, it's got all the stuff inline
4153 rather than in a separate routine.
4157 _ckvmssts_noperl(sys$setast(0));
4159 unsigned long int pidcode = JPI$_PID;
4160 $DESCRIPTOR(d_delay, RETRY_DELAY);
4161 _ckvmssts_noperl(lib$get_ef(&pipe_ef));
4162 _ckvmssts_noperl(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4163 _ckvmssts_noperl(sys$bintim(&d_delay, delaytime));
4165 if (!handler_set_up) {
4166 _ckvmssts_noperl(sys$dclexh(&pipe_exitblock));
4167 handler_set_up = TRUE;
4169 _ckvmssts_noperl(sys$setast(1));
4172 /* see if we can find a VMSPIPE.COM */
4175 vmspipe = find_vmspipe(aTHX);
4177 vmspipedsc.dsc$w_length = my_strlcpy(tfilebuf+1, vmspipe, sizeof(tfilebuf)-1) + 1;
4178 } else { /* uh, oh...we're in tempfile hell */
4179 tpipe = vmspipe_tempfile(aTHX);
4180 if (!tpipe) { /* a fish popular in Boston */
4181 if (ckWARN(WARN_PIPE)) {
4182 Perl_warner(aTHX_ packWARN(WARN_PIPE),"unable to find VMSPIPE.COM for i/o piping");
4186 fgetname(tpipe,tfilebuf+1,1);
4187 vmspipedsc.dsc$w_length = strlen(tfilebuf);
4189 vmspipedsc.dsc$a_pointer = tfilebuf;
4191 sts = setup_cmddsc(aTHX_ cmd,0,0,&vmscmd);
4194 case RMS$_FNF: case RMS$_DNF:
4195 set_errno(ENOENT); break;
4197 set_errno(ENOTDIR); break;
4199 set_errno(ENODEV); break;
4201 set_errno(EACCES); break;
4203 set_errno(EINVAL); break;
4204 case CLI$_BUFOVF: case RMS$_RTB: case CLI$_TKNOVF: case CLI$_RSLOVF:
4205 set_errno(E2BIG); break;
4206 case LIB$_INVARG: case LIB$_INVSTRDES: case SS$_ACCVIO: /* shouldn't happen */
4207 _ckvmssts_noperl(sts); /* fall through */
4208 default: /* SS$_DUPLNAM, SS$_CLI, resource exhaustion, etc. */
4211 set_vaxc_errno(sts);
4212 if (*in_mode != 'n' && ckWARN(WARN_PIPE)) {
4213 Perl_warner(aTHX_ packWARN(WARN_PIPE),"Can't pipe \"%*s\": %s", strlen(cmd), cmd, Strerror(errno));
4219 _ckvmssts_noperl(lib$get_vm(&n, &info));
4221 my_strlcpy(mode, in_mode, sizeof(mode));
4224 info->completion = 0;
4225 info->closing = FALSE;
4232 info->in_done = TRUE;
4233 info->out_done = TRUE;
4234 info->err_done = TRUE;
4236 info->xchan_valid = 0;
4238 in = (char *)PerlMem_malloc(VMS_MAXRSS);
4239 if (in == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4240 out = (char *)PerlMem_malloc(VMS_MAXRSS);
4241 if (out == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4242 err = (char *)PerlMem_malloc(VMS_MAXRSS);
4243 if (err == NULL) _ckvmssts_noperl(SS$_INSFMEM);
4245 in[0] = out[0] = err[0] = '\0';
4247 if ((p = strchr(mode,'F')) != NULL) { /* F -> use FILE* */
4251 if ((p = strchr(mode,'W')) != NULL) { /* W -> wait for completion */
4256 if (*mode == 'r') { /* piping from subroutine */
4258 info->out = pipe_infromchild_setup(aTHX_ mbx,out);
4260 info->out->pipe_done = &info->out_done;
4261 info->out_done = FALSE;
4262 info->out->info = info;
4264 if (!info->useFILE) {
4265 info->fp = PerlIO_open(mbx, mode);
4267 info->fp = (PerlIO *) freopen(mbx, mode, stdin);
4268 Perl_vmssetuserlnm(aTHX_ "SYS$INPUT",mbx);
4271 if (!info->fp && info->out) {
4272 sys$cancel(info->out->chan_out);
4274 while (!info->out_done) {
4276 _ckvmssts_noperl(sys$setast(0));
4277 done = info->out_done;
4278 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4279 _ckvmssts_noperl(sys$setast(1));
4280 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4283 if (info->out->buf) {
4284 n = info->out->bufsize * sizeof(char);
4285 _ckvmssts_noperl(lib$free_vm(&n, &info->out->buf));
4288 _ckvmssts_noperl(lib$free_vm(&n, &info->out));
4290 _ckvmssts_noperl(lib$free_vm(&n, &info));
4295 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4297 info->err->pipe_done = &info->err_done;
4298 info->err_done = FALSE;
4299 info->err->info = info;
4302 } else if (*mode == 'w') { /* piping to subroutine */
4304 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4306 info->out->pipe_done = &info->out_done;
4307 info->out_done = FALSE;
4308 info->out->info = info;
4311 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4313 info->err->pipe_done = &info->err_done;
4314 info->err_done = FALSE;
4315 info->err->info = info;
4318 info->in = pipe_tochild_setup(aTHX_ in,mbx);
4319 if (!info->useFILE) {
4320 info->fp = PerlIO_open(mbx, mode);
4322 info->fp = (PerlIO *) freopen(mbx, mode, stdout);
4323 Perl_vmssetuserlnm(aTHX_ "SYS$OUTPUT",mbx);
4327 info->in->pipe_done = &info->in_done;
4328 info->in_done = FALSE;
4329 info->in->info = info;
4333 if (!info->fp && info->in) {
4335 _ckvmssts_noperl(sys$qiow(0,info->in->chan_in, IO$_WRITEOF, 0,
4336 0, 0, 0, 0, 0, 0, 0, 0));
4338 while (!info->in_done) {
4340 _ckvmssts_noperl(sys$setast(0));
4341 done = info->in_done;
4342 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4343 _ckvmssts_noperl(sys$setast(1));
4344 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4347 if (info->in->buf) {
4348 n = info->in->bufsize * sizeof(char);
4349 _ckvmssts_noperl(lib$free_vm(&n, &info->in->buf));
4352 _ckvmssts_noperl(lib$free_vm(&n, &info->in));
4354 _ckvmssts_noperl(lib$free_vm(&n, &info));
4360 } else if (*mode == 'n') { /* separate subprocess, no Perl i/o */
4361 info->out = pipe_mbxtofd_setup(aTHX_ fileno(stdout), out);
4363 info->out->pipe_done = &info->out_done;
4364 info->out_done = FALSE;
4365 info->out->info = info;
4368 info->err = pipe_mbxtofd_setup(aTHX_ fileno(stderr), err);
4370 info->err->pipe_done = &info->err_done;
4371 info->err_done = FALSE;
4372 info->err->info = info;
4376 d_symbol.dsc$w_length = my_strlcpy(symbol, in, sizeof(symbol));
4377 _ckvmssts_noperl(lib$set_symbol(&d_sym_in, &d_symbol, &table));
4379 d_symbol.dsc$w_length = my_strlcpy(symbol, err, sizeof(symbol));
4380 _ckvmssts_noperl(lib$set_symbol(&d_sym_err, &d_symbol, &table));
4382 d_symbol.dsc$w_length = my_strlcpy(symbol, out, sizeof(symbol));
4383 _ckvmssts_noperl(lib$set_symbol(&d_sym_out, &d_symbol, &table));
4385 /* Done with the names for the pipes */
4390 p = vmscmd->dsc$a_pointer;
4391 while (*p == ' ' || *p == '\t') p++; /* remove leading whitespace */
4392 if (*p == '$') p++; /* remove leading $ */
4393 while (*p == ' ' || *p == '\t') p++;
4395 for (j = 0; j < 4; j++) {
4396 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4397 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4399 d_symbol.dsc$w_length = my_strlcpy(symbol, p, sizeof(symbol));
4400 _ckvmssts_noperl(lib$set_symbol(&d_sym_cmd, &d_symbol, &table));
4402 if (strlen(p) > MAX_DCL_SYMBOL) {
4403 p += MAX_DCL_SYMBOL;
4408 _ckvmssts_noperl(sys$setast(0));
4409 info->next=open_pipes; /* prepend to list */
4411 _ckvmssts_noperl(sys$setast(1));
4412 /* Omit arg 2 (input file) so the child will get the parent's SYS$INPUT
4413 * and SYS$COMMAND. vmspipe.com will redefine SYS$INPUT, but we'll still
4414 * have SYS$COMMAND if we need it.
4416 _ckvmssts_noperl(lib$spawn(&vmspipedsc, 0, &nl_desc, &flags,
4417 0, &info->pid, &info->completion,
4418 0, popen_completion_ast,info,0,0,0));
4420 /* if we were using a tempfile, close it now */
4422 if (tpipe) fclose(tpipe);
4424 /* once the subprocess is spawned, it has copied the symbols and
4425 we can get rid of ours */
4427 for (j = 0; j < 4; j++) {
4428 sprintf(cmd_sym_name,"PERL_POPEN_CMD%d",j);
4429 d_sym_cmd.dsc$w_length = strlen(cmd_sym_name);
4430 _ckvmssts_noperl(lib$delete_symbol(&d_sym_cmd, &table));
4432 _ckvmssts_noperl(lib$delete_symbol(&d_sym_in, &table));
4433 _ckvmssts_noperl(lib$delete_symbol(&d_sym_err, &table));
4434 _ckvmssts_noperl(lib$delete_symbol(&d_sym_out, &table));
4435 vms_execfree(vmscmd);
4437 #ifdef PERL_IMPLICIT_CONTEXT
4440 PL_forkprocess = info->pid;
4447 _ckvmssts_noperl(sys$setast(0));
4449 if (!done) _ckvmssts_noperl(sys$clref(pipe_ef));
4450 _ckvmssts_noperl(sys$setast(1));
4451 if (!done) _ckvmssts_noperl(sys$waitfr(pipe_ef));
4453 *psts = info->completion;
4454 /* Caller thinks it is open and tries to close it. */
4455 /* This causes some problems, as it changes the error status */
4456 /* my_pclose(info->fp); */
4458 /* If we did not have a file pointer open, then we have to */
4459 /* clean up here or eventually we will run out of something */
4461 if (info->fp == NULL) {
4462 my_pclose_pinfo(aTHX_ info);
4470 } /* end of safe_popen */
4473 /*{{{ PerlIO *my_popen(char *cmd, char *mode)*/
4475 Perl_my_popen(pTHX_ const char *cmd, const char *mode)
4479 TAINT_PROPER("popen");
4480 PERL_FLUSHALL_FOR_CHILD;
4481 return safe_popen(aTHX_ cmd,mode,&sts);
4487 /* Routine to close and cleanup a pipe info structure */
4489 static I32 my_pclose_pinfo(pTHX_ pInfo info) {
4491 unsigned long int retsts;
4495 /* If we were writing to a subprocess, insure that someone reading from
4496 * the mailbox gets an EOF. It looks like a simple fclose() doesn't
4497 * produce an EOF record in the mailbox.
4499 * well, at least sometimes it *does*, so we have to watch out for
4500 * the first EOF closing the pipe (and DASSGN'ing the channel)...
4504 #if defined(USE_ITHREADS)
4508 && PL_perlio_fd_refcnt
4511 PerlIO_flush(info->fp);
4513 fflush((FILE *)info->fp);
4516 _ckvmssts(sys$setast(0));
4517 info->closing = TRUE;
4518 done = info->done && info->in_done && info->out_done && info->err_done;
4519 /* hanging on write to Perl's input? cancel it */
4520 if (info->mode == 'r' && info->out && !info->out_done) {
4521 if (info->out->chan_out) {
4522 _ckvmssts(sys$cancel(info->out->chan_out));
4523 if (!info->out->chan_in) { /* EOF generation, need AST */
4524 _ckvmssts(sys$dclast(pipe_infromchild_ast,info->out,0));
4528 if (info->in && !info->in_done && !info->in->shut_on_empty) /* EOF if hasn't had one yet */
4529 _ckvmssts(sys$qio(0,info->in->chan_in,IO$_WRITEOF,0,0,0,
4531 _ckvmssts(sys$setast(1));
4534 #if defined(USE_ITHREADS)
4538 && PL_perlio_fd_refcnt
4541 PerlIO_close(info->fp);
4543 fclose((FILE *)info->fp);
4546 we have to wait until subprocess completes, but ALSO wait until all
4547 the i/o completes...otherwise we'll be freeing the "info" structure
4548 that the i/o ASTs could still be using...
4552 _ckvmssts(sys$setast(0));
4553 done = info->done && info->in_done && info->out_done && info->err_done;
4554 if (!done) _ckvmssts(sys$clref(pipe_ef));
4555 _ckvmssts(sys$setast(1));
4556 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4558 retsts = info->completion;
4560 /* remove from list of open pipes */
4561 _ckvmssts(sys$setast(0));
4563 for (next = open_pipes; next != NULL; last = next, next = next->next) {
4569 last->next = info->next;
4571 open_pipes = info->next;
4572 _ckvmssts(sys$setast(1));
4574 /* free buffers and structures */
4577 if (info->in->buf) {
4578 n = info->in->bufsize * sizeof(char);
4579 _ckvmssts(lib$free_vm(&n, &info->in->buf));
4582 _ckvmssts(lib$free_vm(&n, &info->in));
4585 if (info->out->buf) {
4586 n = info->out->bufsize * sizeof(char);
4587 _ckvmssts(lib$free_vm(&n, &info->out->buf));
4590 _ckvmssts(lib$free_vm(&n, &info->out));
4593 if (info->err->buf) {
4594 n = info->err->bufsize * sizeof(char);
4595 _ckvmssts(lib$free_vm(&n, &info->err->buf));
4598 _ckvmssts(lib$free_vm(&n, &info->err));
4601 _ckvmssts(lib$free_vm(&n, &info));
4607 /*{{{ I32 my_pclose(PerlIO *fp)*/
4608 I32 Perl_my_pclose(pTHX_ PerlIO *fp)
4610 pInfo info, last = NULL;
4613 /* Fixme - need ast and mutex protection here */
4614 for (info = open_pipes; info != NULL; last = info, info = info->next)
4615 if (info->fp == fp) break;
4617 if (info == NULL) { /* no such pipe open */
4618 set_errno(ECHILD); /* quoth POSIX */
4619 set_vaxc_errno(SS$_NONEXPR);
4623 ret_status = my_pclose_pinfo(aTHX_ info);
4627 } /* end of my_pclose() */
4629 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4630 /* Roll our own prototype because we want this regardless of whether
4631 * _VMS_WAIT is defined.
4637 __pid_t __vms_waitpid( __pid_t __pid, int *__stat_loc, int __options );
4643 /* sort-of waitpid; special handling of pipe clean-up for subprocesses
4644 created with popen(); otherwise partially emulate waitpid() unless
4645 we have a suitable one from the CRTL that came with VMS 7.2 and later.
4646 Also check processes not considered by the CRTL waitpid().
4648 /*{{{Pid_t my_waitpid(Pid_t pid, int *statusp, int flags)*/
4650 Perl_my_waitpid(pTHX_ Pid_t pid, int *statusp, int flags)
4657 if (statusp) *statusp = 0;
4659 for (info = open_pipes; info != NULL; info = info->next)
4660 if (info->pid == pid) break;
4662 if (info != NULL) { /* we know about this child */
4663 while (!info->done) {
4664 _ckvmssts(sys$setast(0));
4666 if (!done) _ckvmssts(sys$clref(pipe_ef));
4667 _ckvmssts(sys$setast(1));
4668 if (!done) _ckvmssts(sys$waitfr(pipe_ef));
4671 if (statusp) *statusp = info->completion;
4675 /* child that already terminated? */
4677 for (j = 0; j < NKEEPCLOSED && j < closed_num; j++) {
4678 if (closed_list[j].pid == pid) {
4679 if (statusp) *statusp = closed_list[j].completion;
4684 /* fall through if this child is not one of our own pipe children */
4686 #if defined(__CRTL_VER) && __CRTL_VER >= 70200000
4688 /* waitpid() became available in the CRTL as of VMS 7.0, but only
4689 * in 7.2 did we get a version that fills in the VMS completion
4690 * status as Perl has always tried to do.
4693 sts = __vms_waitpid( pid, statusp, flags );
4695 if ( sts == 0 || !(sts == -1 && errno == ECHILD) )
4698 /* If the real waitpid tells us the child does not exist, we
4699 * fall through here to implement waiting for a child that
4700 * was created by some means other than exec() (say, spawned
4701 * from DCL) or to wait for a process that is not a subprocess
4702 * of the current process.
4705 #endif /* defined(__CRTL_VER) && __CRTL_VER >= 70200000 */
4708 $DESCRIPTOR(intdsc,"0 00:00:01");
4709 unsigned long int ownercode = JPI$_OWNER, ownerpid;
4710 unsigned long int pidcode = JPI$_PID, mypid;
4711 unsigned long int interval[2];
4712 unsigned int jpi_iosb[2];
4713 struct itmlst_3 jpilist[2] = {
4714 {sizeof(ownerpid), JPI$_OWNER, &ownerpid, 0},
4719 /* Sorry folks, we don't presently implement rooting around for
4720 the first child we can find, and we definitely don't want to
4721 pass a pid of -1 to $getjpi, where it is a wildcard operation.
4727 /* Get the owner of the child so I can warn if it's not mine. If the
4728 * process doesn't exist or I don't have the privs to look at it,
4729 * I can go home early.
4731 sts = sys$getjpiw(0,&pid,NULL,&jpilist,&jpi_iosb,NULL,NULL);
4732 if (sts & 1) sts = jpi_iosb[0];
4744 set_vaxc_errno(sts);
4748 if (ckWARN(WARN_EXEC)) {
4749 /* remind folks they are asking for non-standard waitpid behavior */
4750 _ckvmssts(lib$getjpi(&pidcode,0,0,&mypid,0,0));
4751 if (ownerpid != mypid)
4752 Perl_warner(aTHX_ packWARN(WARN_EXEC),
4753 "waitpid: process %x is not a child of process %x",
4757 /* simply check on it once a second until it's not there anymore. */
4759 _ckvmssts(sys$bintim(&intdsc,interval));
4760 while ((sts=lib$getjpi(&ownercode,&pid,0,&ownerpid,0,0)) & 1) {
4761 _ckvmssts(sys$schdwk(0,0,interval,0));
4762 _ckvmssts(sys$hiber());
4764 if (sts == SS$_NONEXPR) sts = SS$_NORMAL;
4769 } /* end of waitpid() */
4774 /*{{{ char *my_gconvert(double val, int ndig, int trail, char *buf) */
4776 my_gconvert(double val, int ndig, int trail, char *buf)
4778 static char __gcvtbuf[DBL_DIG+1];
4781 loc = buf ? buf : __gcvtbuf;
4783 #ifndef __DECC /* VAXCRTL gcvt uses E format for numbers < 1 */
4785 sprintf(loc,"%.*g",ndig,val);
4791 if (!buf && ndig > DBL_DIG) ndig = DBL_DIG;
4792 return gcvt(val,ndig,loc);
4795 loc[0] = '0'; loc[1] = '\0';
4802 #if defined(__VAX) || !defined(NAML$C_MAXRSS)
4803 static int rms_free_search_context(struct FAB * fab)
4807 nam = fab->fab$l_nam;
4808 nam->nam$b_nop |= NAM$M_SYNCHK;
4809 nam->nam$l_rlf = NULL;
4811 return sys$parse(fab, NULL, NULL);
4814 #define rms_setup_nam(nam) struct NAM nam = cc$rms_nam
4815 #define rms_clear_nam_nop(nam) nam.nam$b_nop = 0;
4816 #define rms_set_nam_nop(nam, opt) nam.nam$b_nop |= (opt)
4817 #define rms_set_nam_fnb(nam, opt) nam.nam$l_fnb |= (opt)
4818 #define rms_is_nam_fnb(nam, opt) (nam.nam$l_fnb & (opt))
4819 #define rms_nam_esll(nam) nam.nam$b_esl
4820 #define rms_nam_esl(nam) nam.nam$b_esl
4821 #define rms_nam_name(nam) nam.nam$l_name
4822 #define rms_nam_namel(nam) nam.nam$l_name
4823 #define rms_nam_type(nam) nam.nam$l_type
4824 #define rms_nam_typel(nam) nam.nam$l_type
4825 #define rms_nam_ver(nam) nam.nam$l_ver
4826 #define rms_nam_verl(nam) nam.nam$l_ver
4827 #define rms_nam_rsll(nam) nam.nam$b_rsl
4828 #define rms_nam_rsl(nam) nam.nam$b_rsl
4829 #define rms_bind_fab_nam(fab, nam) fab.fab$l_nam = &nam
4830 #define rms_set_fna(fab, nam, name, size) \
4831 { fab.fab$b_fns = size; fab.fab$l_fna = name; }
4832 #define rms_get_fna(fab, nam) fab.fab$l_fna
4833 #define rms_set_dna(fab, nam, name, size) \
4834 { fab.fab$b_dns = size; fab.fab$l_dna = name; }
4835 #define rms_nam_dns(fab, nam) fab.fab$b_dns
4836 #define rms_set_esa(nam, name, size) \
4837 { nam.nam$b_ess = size; nam.nam$l_esa = name; }
4838 #define rms_set_esal(nam, s_name, s_size, l_name, l_size) \
4839 { nam.nam$l_esa = s_name; nam.nam$b_ess = s_size;}
4840 #define rms_set_rsa(nam, name, size) \
4841 { nam.nam$l_rsa = name; nam.nam$b_rss = size; }
4842 #define rms_set_rsal(nam, s_name, s_size, l_name, l_size) \
4843 { nam.nam$l_rsa = s_name; nam.nam$b_rss = s_size; }
4844 #define rms_nam_name_type_l_size(nam) \
4845 (nam.nam$b_name + nam.nam$b_type)
4847 static int rms_free_search_context(struct FAB * fab)