diff options
Diffstat (limited to 'vms/gawkmisc.vms')
-rw-r--r-- | vms/gawkmisc.vms | 459 |
1 files changed, 449 insertions, 10 deletions
diff --git a/vms/gawkmisc.vms b/vms/gawkmisc.vms index cbc59cd7..046c5167 100644 --- a/vms/gawkmisc.vms +++ b/vms/gawkmisc.vms @@ -23,30 +23,446 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> + +#include <descrip.h> +#include <dvidef.h> +#include <efndef.h> +#include <fscndef.h> +#include <stsdef.h> +#include <time.h> +#include <lnmdef.h> + + +#pragma member_alignment save +#pragma nomember_alignment longword +struct item_list_3 { + unsigned short len; + unsigned short code; + void * bufadr; + unsigned short * retlen; +}; + +struct filescan_itmlst_2 { + unsigned short length; + unsigned short itmcode; + char * component; +}; + +#pragma member_alignment + +int SYS$GETDVIW( + unsigned long efn, + unsigned short chan, + const struct dsc$descriptor_s * devnam, + const struct item_list_3 * itmlst, + void * iosb, + void (* astadr)(unsigned long), + unsigned long astprm, + void * nullarg); + +int SYS$FILESCAN( + const struct dsc$descriptor_s * srcstr, + struct filescan_itmlst_2 * valuelist, + unsigned long * fldflags, + struct dsc$descriptor_s *auxout, + unsigned short * retlen); + +int SYS$TRNLNM( + const unsigned long * attr, + const struct dsc$descriptor_s * table_dsc, + struct dsc$descriptor_s * name_dsc, + const unsigned char * acmode, + const struct item_list_3 * item_list); + char quote = '\''; char *defpath = DEFPATH; char *deflibpath = DEFLIBPATH; char envsep = ','; +#define VMS_NAME_LEN 1 +static char vms_name[VMS_NAME_LEN+1]; + +/* Take all the fun out of simply looking up a logical name */ +static int sys_trnlnm + (const char * logname, + char * value, + int value_len) +{ + const $DESCRIPTOR(table_dsc, "LNM$FILE_DEV"); + const unsigned long attr = LNM$M_CASE_BLIND; + struct dsc$descriptor_s name_dsc; + int status; + unsigned short result; + struct item_list_3 itlst[2]; + + itlst[0].len = value_len; + itlst[0].code = LNM$_STRING; + itlst[0].bufadr = value; + itlst[0].retlen = &result; + + itlst[1].len = 0; + itlst[1].code = 0; + + name_dsc.dsc$w_length = strlen(logname); + name_dsc.dsc$a_pointer = (char *)logname; + name_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + name_dsc.dsc$b_class = DSC$K_CLASS_S; + + status = SYS$TRNLNM(&attr, &table_dsc, &name_dsc, 0, itlst); + + if ($VMS_STATUS_SUCCESS(status)) { + + /* Null terminate and return the string */ + value[result] = '\0'; + } + + return status; +} + /* gawk_name --- pull out the "gawk" part from how the OS called us */ +/* You would not think that this should be a such a problem, but + * VMS extended file specifications are tricky to parse, and we have + * to tell the difference between a CRTL generated argv[0] and a + * passed exec() argv[0] and handle both cases. + */ + char * gawk_name(filespec) const char *filespec; { - char *p, *q; + int status; + int result; + char * shell; + int lcname = 0; + + /* If the path name starts with a /, then it is an absolute path + * that may have been generated by the CRTL instead of the command + * name. If it is the device name between the slashes, then this + * was likely from the run command and needs to be fixed up. + * If the DECC$POSIX_COMPLIANT_PATHNAMES is set to 2, then it is + * the DISK$VOLUME that will be present, and it will still need to + * be fixed. + */ + + if (filespec[0] == '/') { + char * nextslash; + int length; + struct item_list_3 itemlist[3]; + unsigned short dvi_iosb[4]; + char alldevnam[64]; + unsigned short alldevnam_len; + struct dsc$descriptor_s devname_dsc; + char diskvolnam[256]; + unsigned short diskvolnam_len; + + /* Get some information about the disk */ + /*--------------------------------------*/ + itemlist[0].len = (sizeof alldevnam) - 1; + itemlist[0].code = DVI$_ALLDEVNAM; + itemlist[0].bufadr = alldevnam; + itemlist[0].retlen = &alldevnam_len; + itemlist[1].len = (sizeof diskvolnam) - 1 - 5; + itemlist[1].code = DVI$_VOLNAM; + itemlist[1].bufadr = &diskvolnam[5]; + itemlist[1].retlen = &diskvolnam_len; + itemlist[2].len = 0; + itemlist[2].code = 0; + + /* Add the prefix for the volume name. */ + /* SYS$GETDVI will append the volume name to this */ + strcpy(diskvolnam,"DISK$"); + + nextslash = strchr(&filespec[1], '/'); + if (nextslash != NULL) { + length = nextslash - filespec - 1; + + /* DECC requires a cast here */ + devname_dsc.dsc$a_pointer = (char *)&filespec[1]; + devname_dsc.dsc$w_length = length; + devname_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + devname_dsc.dsc$b_class = DSC$K_CLASS_S; + + status = SYS$GETDVIW( + EFN$C_ENF, + 0, + &devname_dsc, + itemlist, + dvi_iosb, + NULL, 0, 0); + if (!$VMS_STATUS_SUCCESS(status)) { + /* If the sys$getdviw fails, then this path + * was passed by an exec() program and not + * from DCL, so do nothing. + * An example is "/tmp/program" where tmp: + * does not exist + */ + result = 0; + } else if (!$VMS_STATUS_SUCCESS(dvi_iosb[0])) { + result = 0; + } else { + char * devnam; + int devnam_len; + char argv_dev[64]; + + /* Null terminate the returned alldevnam */ + alldevnam[alldevnam_len] = 0; + devnam = alldevnam; + devnam_len = alldevnam_len; + + /* Need to skip past any leading underscore */ + if (devnam[0] == '_') { + devnam++; + devnam_len--; + } + + /* And remove the trailing colon */ + if (devnam[devnam_len - 1] == ':') { + devnam_len--; + devnam[devnam_len] = 0; + } + + /* Null terminate the returned volnam */ + diskvolnam_len += 5; + diskvolnam[diskvolnam_len] = 0; + + /* Check first for normal CRTL behavior */ + if (devnam_len == length) { + strncpy(vms_name, &filespec[1], length); + vms_name[length] = 0; + result = (strcasecmp(devnam, vms_name) == 0); + } + + /* If we have not got a match check for + * POSIX Compliant behavior. To be more + * accurate, we could also check to see + * if that feature is active. + */ + if ((result == 0) && + (diskvolnam_len == length)) { + int cmp; + strncpy(vms_name, &filespec[1], length); + vms_name[length] = 0; + cmp = strcasecmp(diskvolnam, vms_name); + result = (cmp == 0); + } + } + } + } else { + /* The path did not start with a slash, so it could be VMS + * format. If it is vms format, it has a volume/device in + * it as it must be an absolute path + */ + struct dsc$descriptor_s path_desc; + int status; + unsigned long field_flags; + struct filescan_itmlst_2 item_list[5]; + char * volume; + char * name; + int name_len; + char * ext; + + /* DECC requires a cast here */ + path_desc.dsc$a_pointer = (char *)filespec; + path_desc.dsc$w_length = strlen(filespec); + path_desc.dsc$b_dtype = DSC$K_DTYPE_T; + path_desc.dsc$b_class = DSC$K_CLASS_S; + + /* Don't actually need to initialize anything buf itmcode */ + /* I just do not like uninitialized input values */ + + /* Sanity check, this must be the same length as input */ + item_list[0].itmcode = FSCN$_FILESPEC; + item_list[0].length = 0; + item_list[0].component = NULL; + + /* If the device is present, then it if a VMS spec */ + item_list[1].itmcode = FSCN$_DEVICE; + item_list[1].length = 0; + item_list[1].component = NULL; + + /* we need the program name and type */ + item_list[2].itmcode = FSCN$_NAME; + item_list[2].length = 0; + item_list[2].component = NULL; + + item_list[3].itmcode = FSCN$_TYPE; + item_list[3].length = 0; + item_list[3].component = NULL; + + /* End the list */ + item_list[4].itmcode = 0; + item_list[4].length = 0; + item_list[4].component = NULL; + + status = SYS$FILESCAN( + (const struct dsc$descriptor_s *)&path_desc, + item_list, &field_flags, NULL, NULL); + + if ($VMS_STATUS_SUCCESS(status) && + (item_list[0].length == path_desc.dsc$w_length) && + (item_list[1].length != 0)) { + + char * dollar; + int keep_ext; + int i; + + /* We need the filescan to be successful, + * same length as input, and a volume to be present. + * + * We will assume that we only get to this path on + * a version of VMS that does not support the EFS + * character set. + * + * There may be a xxx$ prefix on the image name. + * Linux programs do not handle that well, so + * strip the prefix. + */ + name = item_list[2].component; + name_len = item_list[2].length; + dollar = strrchr(name, '$'); + if (dollar != NULL) { + dollar++; + name_len = name_len - (dollar - name); + name = dollar; + } + + strncpy(vms_name, name, name_len); + vms_name[name_len] = 0; + + /* We only keep the extension if it is not ".exe" */ + keep_ext = 0; + ext = item_list[3].component; + + if (item_list[3].length != 1) { + if (item_list[3].length != 4) { + keep_ext = 1; + } else { + int x; + x = strncmp(ext, ".exe", 4); + if (x != 0) { + keep_ext = 1; + } + } + } + + if (keep_ext == 1) { + strncpy(&vms_name[name_len], + ext, item_list[3].length); + } + } + } - /* "device:[root.][directory.subdir]GAWK.EXE;n" -> "GAWK" */ - p = strrchr(filespec, ']'); /* directory punctuation */ - q = strrchr(filespec, '>'); /* alternate <international> punct */ + if (result) { + char * lastslash; + char * dollar; + char * dotexe; + char * lastdot; + char * extension; + + /* This means it is probably the name from a DCL command + * Find the last slash which separates the file from the + * path. + */ + lastslash = strrchr(filespec, '/'); + + if (lastslash != NULL) { + int i; + + lastslash++; + + /* There may be a xxx$ prefix on the image name. */ + /* Linux programs do not handle that well, so */ + /* strip the prefix */ + dollar = strrchr(lastslash, '$'); + + if (dollar != NULL) { + dollar++; + lastslash = dollar; + } + + strcpy(vms_name, lastslash); + + /* In UNIX mode + EFS character set, there should + * not be a version present, as it is not possible + * when parsing to tell if it is a version or part + * of the UNIX filename as UNIX programs use numeric + * extensions for many reasons. + */ + + lastdot = strrchr(vms_name, '.'); + if (lastdot != NULL) { + int i; + + i = 1; + while (isdigit(lastdot[i])) { + i++; + } + if (lastdot[i] == 0) { + *lastdot = 0; + } + } + + /* Find the .exe on the name (case insenstive) + * and toss it + */ + dotexe = strrchr(vms_name, '.'); + if (dotexe != NULL) { + if ((dotexe[1] == 'e' || dotexe[1] == 'E') && + (dotexe[2] == 'x' || dotexe[2] == 'X') && + (dotexe[3] == 'e' || dotexe[3] == 'E') && + (dotexe[4] == 0)) { + + *dotexe = 0; + } else { + /* Also need to handle a null + * extension because of a CRTL bug. + */ + if (dotexe[1] == 0) { + *dotexe = 0; + } + } + } + + } else { + /* There is no way that the code should ever get here + * As we already verified that the '/' was present + */ + fprintf(stderr, + "Sanity failure somewhere we lost a '/'\n"); + } + } else { + /* No changes needed */ + strncpy(vms_name, filespec, VMS_NAME_LEN); + vms_name[VMS_NAME_LEN] = 0; + } - if (p == NULL || q > p) - p = q; - p = strdup(p == NULL ? filespec : (p + 1)); - if ((q = strrchr(p, '.')) != NULL) - *q = '\0'; /* strip .typ;vers */ - return p; + /* + * The above fixes up the name, but for the DCL shell + * may leave it in upper case, which messes up the self tests. + * force it to lower case here. + */ + shell = getenv("SHELL"); + if (shell != NULL) { + if (strcmp(shell, "DCL") == 0) { + lcname = 1; + } + } else { + lcname = 1; + } + if (lcname == 1) { + int i = 0; + while (vms_name[i] != 0) { + vms_name[i] = tolower(vms_name[i]); + i++; + } + } + return vms_name; } /* os_arg_fixup --- fixup the command line */ @@ -56,7 +472,24 @@ os_arg_fixup(argcp, argvp) int *argcp; char ***argvp; { + char *tz_rule; + int status; + (void) vms_arg_fixup(argcp, argvp); + + /* Fix up the time zone */ + /* For some reason it gets trashed */ + tz_rule = malloc(1024); + status = sys_trnlnm("TZ", tz_rule, 1024); + if ($VMS_STATUS_SUCCESS(status)) { + setenv("TZ", tz_rule, 1); + } else { + status = sys_trnlnm("SYS$TIMEZONE_RULE", tz_rule, 1024); + if ($VMS_STATUS_SUCCESS(status)) { + setenv("TZ", tz_rule, 1); + } + } + free(tz_rule); } /* os_devopen --- open special per-OS devices */ @@ -208,11 +641,17 @@ files_are_same(char *newfile, SRCFILE *oldfile) f2 = &oldfile->sbuf; /* compare device string */ +#ifdef _USE_STD_STAT + return (f1->st_dev == f2->st_dev + /* and 48-bit file id cookie */ + && f1->st_ino == f2->st_ino); + #else return (strcmp(f1->st_dev, f2->st_dev) == 0 /* and 48-bit file id cookie stored in 3 short ints */ && f1->st_ino[0] == f2->st_ino[0] && f1->st_ino[1] == f2->st_ino[1] && f1->st_ino[2] == f2->st_ino[2]); +#endif } int |