From b6f45ddc5301b7d7f6472e38a475716ff1414186 Mon Sep 17 00:00:00 2001 From: Paul Smith Date: Mon, 16 Nov 2009 02:31:23 +0000 Subject: [PATCH] Add VMS enhancements from Hartmut Becker. --- ChangeLog | 30 +++++++++++ arscan.c | 26 ++++++++- config.h-vms.template | 5 +- dir.c | 23 ++++++-- job.h | 1 + main.c | 13 ++--- readme.vms | 95 +++++++++++++++++++++++++++++--- vmsfunctions.c | 5 ++ vmsify.c | 22 +++++--- vmsjobs.c | 123 ++++++++++++++++++++++++++++-------------- 10 files changed, 271 insertions(+), 72 deletions(-) diff --git a/ChangeLog b/ChangeLog index e8c89d13..b5f32f29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,33 @@ +2009-11-15 Paul Smith + + Patches for VMS provided by Hartmut Becker + + * vmsjobs.c (ctrlYPressed) [VMS]: Deal with CTRL-Y. + (vmsHandleChildTerm) [VMS]: Ditto. + (astYHandler) [VMS]: Ditto. + (tryToSetupYAst) [VMS]: Ditto. + (child_execute_job) [VMS]: Ditto. + + * vmsify.c (trnlog) [VMS]: Fix const errors. + (vmsify) [VMS]: Ditto. + + * readme.vms [VMS]: Update with notes for 3.82. + + * job.h (comname) [VMS]: Remember the temporary command filename + + * dir.c (vmsify) [VMS]: Fix const errors. + (vms_hash) [VMS]: Ditto. + (vmsstat_dir) [VMS]: Ditto. + (find_directory) [VMS]: Fix case-insensitive option for VMS + (dir_contents_file_exists_p) [VMS]: Ditto. + (file_impossible) [VMS]: Ditto. + + * config.h-vms.template (HAVE_FDOPEN) [VMS]: Have it. + (HAVE_STRCASECMP) [VMS]: Ditto. + + * arscan.c (VMS_get_member_info) [VMS]: Fix timezone computation. + (ar_scan) [VMS]: Fix const error. + 2009-11-12 Boris Kolpackov * vpath.c (vpath_search, selective_vpath_search): Add index arguments diff --git a/arscan.c b/arscan.c index 782786ca..771e394e 100644 --- a/arscan.c +++ b/arscan.c @@ -81,7 +81,28 @@ VMS_get_member_info (struct dsc$descriptor_s *module, unsigned long *rfa) * but that decc$fix_time() isn't documented to work this way. Let me * know if this causes problems in other VMS environments. */ - val = decc$fix_time (&mhd->mhd$l_datim) + timezone - daylight*3600; + { + /* Modified by M. Gehre at 11-JAN-2008 because old formula is wrong: + * val = decc$fix_time (&mhd->mhd$l_datim) + timezone - daylight*3600; + * a) daylight specifies, if the timezone has daylight saving enabled, not + * if it is active + * b) what we need is the information, if daylight saving was active, if + * the library module was replaced. This information we get using the + * localtime function + */ + + struct tm *tmp; + + /* Conversion from VMS time to C time */ + val = decc$fix_time (&mhd->mhd$l_datim); + + /* + * Conversion from local time (stored in library) to GMT (needed for gmake) + * Note: The tm_gmtoff element is a VMS extension to the ANSI standard. + */ + tmp = localtime (&val); + val -= tmp->tm_gmtoff; + } #endif for (i = 0; i < module->dsc$w_length; i++) @@ -155,7 +176,8 @@ ar_scan (const char *archive, ar_member_func_t function, const void *arg) return -2; } - libdesc.dsc$a_pointer = archive; + /* there is no such descriptor with "const char *dsc$a_pointer" */ + libdesc.dsc$a_pointer = (char *)archive; libdesc.dsc$w_length = strlen (archive); status = lbr$open (&VMS_lib_idx, &libdesc, 0, 0, 0, 0, 0); diff --git a/config.h-vms.template b/config.h-vms.template index 9811d6c5..68af4ec7 100644 --- a/config.h-vms.template +++ b/config.h-vms.template @@ -76,6 +76,9 @@ this program. If not, see . */ /* Define to 1 if you don't have vprintf but do have _doprnt. */ /* #undef HAVE_DOPRNT */ +/* Define to 1 if you have the fdopen function. */ +#define HAVE_FDOPEN 1 + /* Define to 1 if your system has a working fnmatch function. */ /* #undef HAVE_FNMATCH */ @@ -289,7 +292,7 @@ this program. If not, see . */ /* #undef HAVE_SOCKET */ /* Define to 1 if you have the strcasecmp function. */ -/* #undef HAVE_STRCASECMP */ +#define HAVE_STRCASECMP 1 /* Define to 1 if you have the strcmpi function. */ /* #undef HAVE_STRCMPI */ diff --git a/dir.c b/dir.c index 9c92fa07..e127fc12 100644 --- a/dir.c +++ b/dir.c @@ -23,7 +23,8 @@ this program. If not, see . */ # include # define NAMLEN(dirent) strlen((dirent)->d_name) # ifdef VMS -char *vmsify (char *name, int type); +/* its prototype is in vmsdir.h, which is not needed for HAVE_DIRENT_H */ +const char *vmsify (const char *name, int type); # endif #else # define dirent direct @@ -145,7 +146,7 @@ downcase (const char *filename) #ifdef VMS static int -vms_hash (char *name) +vms_hash (const char *name) { int h = 0; int g; @@ -171,7 +172,7 @@ vms_hash (char *name) /* fake stat entry for a directory */ static int -vmsstat_dir (char *name, struct stat *st) +vmsstat_dir (const char *name, struct stat *st) { char *s; int h; @@ -184,6 +185,7 @@ vmsstat_dir (char *name, struct stat *st) s = strchr (name, ':'); /* find device */ if (s) { + /* to keep the compiler happy we said "const char *name", now we cheat */ *s++ = 0; st->st_dev = (char *)vms_hash (name); h = vms_hash (s); @@ -192,8 +194,7 @@ vmsstat_dir (char *name, struct stat *st) else { st->st_dev = 0; - s = name; - h = vms_hash (s); + h = vms_hash (name); } st->st_ino[0] = h & 0xff; @@ -449,7 +450,11 @@ find_directory (const char *name) p = name + strlen (name); dir = xmalloc (sizeof (struct directory)); +#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) + dir->name = strcache_add_len (downcase(name), p - name); +#else dir->name = strcache_add_len (name, p - name); +#endif hash_insert_at (&directories, dir, dir_slot); /* The directory is not in the name hash table. Find its device and inode numbers, and look it up by them. */ @@ -706,7 +711,11 @@ dir_contents_file_exists_p (struct directory_contents *dir, #endif { df = xmalloc (sizeof (struct dirfile)); +#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) + df->name = strcache_add_len (downcase(d->d_name), len); +#else df->name = strcache_add_len (d->d_name, len); +#endif df->length = len; df->impossible = 0; hash_insert_at (&dir->dirfiles, df, dirfile_slot); @@ -880,7 +889,11 @@ file_impossible (const char *filename) new = xmalloc (sizeof (struct dirfile)); new->length = strlen (filename); +#if defined(HAVE_CASE_INSENSITIVE_FS) && defined(VMS) + new->name = strcache_add_len (downcase(filename), new->length); +#else new->name = strcache_add_len (filename, new->length); +#endif new->impossible = 1; hash_insert (&dir->contents->dirfiles, new); } diff --git a/job.h b/job.h index 89472514..4664e750 100644 --- a/job.h +++ b/job.h @@ -53,6 +53,7 @@ struct child #ifdef VMS int efn; /* Completion event flag number */ int cstatus; /* Completion status */ + char *comname; /* Temporary command file name */ #endif char *sh_batch_file; /* Script file for shell commands */ unsigned int remote:1; /* Nonzero if executing remotely. */ diff --git a/main.c b/main.c index babf21d3..f45f6086 100644 --- a/main.c +++ b/main.c @@ -1127,20 +1127,17 @@ main (int argc, char **argv, char **envp) /* Set up .FEATURES */ define_variable_cname (".FEATURES", "target-specific order-only second-expansion else-if" - "shortest-stem undefine", - o_default, 0); + "shortest-stem undefine" #ifndef NO_ARCHIVES - do_variable_definition (NILF, ".FEATURES", "archives", - o_default, f_append, 0); + "archives" #endif #ifdef MAKE_JOBSERVER - do_variable_definition (NILF, ".FEATURES", "jobserver", - o_default, f_append, 0); + "jobserver" #endif #ifdef MAKE_SYMLINKS - do_variable_definition (NILF, ".FEATURES", "check-symlink", - o_default, f_append, 0); + "check-symlink" #endif + , o_default, 0); /* Read in variables from the environment. It is important that this be done before $(MAKE) is figured out so its definitions will not be diff --git a/readme.vms b/readme.vms index be11778d..5a843748 100644 --- a/readme.vms +++ b/readme.vms @@ -1,16 +1,13 @@ This is the VMS version of GNU Make, updated by Hartmut Becker -Changes are based on GNU make 3.80. Latest changes are for OpenVMS/I64 -and new VMS CRTLs. +Changes are based on GNU make 3.82. -This version was tested on OpenVMS/I64 V8.2 (field test) with hp C -X7.1-024 OpenVMS/Alpha V7.3-2 with Compaq C V6.5-001 and OpenVMS/VAX 7.1 -with Compaq C V6.2-003 There are still some warning and informational -message issued by the compilers. +This version was built and tested on OpenVMS V7.3 (VAX), V7.3-2 (Alpha) and +V8.3-1H1 (I64). Build instructions Make a 1st version - $ @makefile.com + $ @makefile.com ! ignore any compiler and/or linker warning $ rena make.exe 1st-make.exe Use the 1st version to generate a 2nd version $ mc sys$disk:[]1st-make clean @@ -20,7 +17,89 @@ Verify your 2nd version $ mc sys$disk:[]2nd-make clean $ mc sys$disk:[]2nd-make -Changes: +Changes (3.81.90) + +Michael Gehre (at VISTEC-SEMI dot COM) supplied a fix for a problem with +timestamps of object modules in OLBs. The timestamps were not correctly +adjusted to GMT based time, if the local VMS time was using a daylight saving +algorithm and if daylight saving was switched off. + +John Eisenbraun (at HP dot COM) supplied fixes and and an enhancement to append +output redirection in action lines. + +Rework of ctrl+c and ctrl+y handling. + +Fix a problem with cached strings, which showed on case-insensitive file +systems. + +Build fixes for const-ified code in VMS specific sources. + +Build notes: +- Try to avoid HP C V7.2-001, which has an incompatible change +how __STDC__ is defined. This results at least in compile time warnings. + +- On V8.3-1H1, if you press Ctrl+C you may see a traceback, starting with +%SYSTEM-F-CONTROLC, operation completed under CTRL/C +%TRACE-F-TRACEBACK, symbolic stack dump follows +image module routine line rel PC abs PC + +DECC$SHR C$SIGNAL gsignal 27991 0000000000001180 +FFFFFFFF84AB2DA0 +DECC$SHR C$SIGNAL raise 28048 0000000000001280 +FFFFFFFF84AB2EA0 +DECC$SHR C$SIGPENDING decc$$deliver_signals + 12475 0000000000000890 +FFFFFFFF84C13690 +... +This looks like an incompatibility to the Alpha and VAX behavior, so it looks +like a problem in I64 VMS version(s). + +- There is no clean build on VAX. In the environment I tested, I had to use GNU +make's alloca which produced a couple of compile time warnings. It seems too +much effort to work on a clean build on VAX. + +A note on appending the redirected output. With this change, a simple mechanism +is implemented to make ">>" work in action lines. In VMS there is no simple +feature like ">>" to have DCL command or program output redirected and appended +to a file. GNU make for VMS already implements the redirection of output. If +such a redirection is detected, an ">" on the action line, GNU make creates a +DCL command procedure to execute the action and to redirect its output. Based +on that, now ">>" is also recognized and a similar but different command +procedure is created to implement the append. The main idea here is to create a +temporary file which collects the output and which is appended to the wanted +output file. Then the temporary file is deleted. This is all done in the +command procedure to keep changes in make small and simple. This obviously has +some limitations but it seems good enough compared with the current ">" +implementation. (And in my opinion, redirection is not really what GNU make has +to do.) With this approach, it may happen that the temporary file is not yet +appended and is left in SYS$SCRATCH. The temporary file names look like +"CMDxxxxx.". Any time the created command procedure can not complete, this +happens. Pressing Ctrl+Y to abort make is one case. In case of Ctrl+Y the +associated command procedure is left in SYS$SCRATCH as well. Its name is +CMDxxxxx.COM. + +Change in the Ctrl+Y handling + +Ctrl+Y was: The CtrlY handler called $forcex for the current child. + +Ctrl+Y changed: The CtrlY handler uses $delprc to delete all children. This way +also actions with DCL commands will be stopped. As before Ctrl+Y then sends +SIGQUIT to itself, which is handled in common code. + +Change in deleteing temporary command files + +Temporary command files were deleted in the main line, after returning from the +vms child termination handler. If Ctrl+C was pressed, the handler is called but +did not return to main line. + +Now, temporary command files are deleted in the vms child termination +handler. That deletes the them even if a Ctrl+C was pressed. + +The behavior of pressing Ctrl+C is not changed. It still has only an effect, +after the current action is terminated. If that doesn't happen or takes too +long, Ctrl+Y should be used instead. + +Changes (3.80) . In default.c define variable ARCH as IA64 for VMS on Itanium systems. diff --git a/vmsfunctions.c b/vmsfunctions.c index 9ff543fe..e100826e 100644 --- a/vmsfunctions.c +++ b/vmsfunctions.c @@ -139,6 +139,10 @@ getwd (char *cwd) return (getcwd (buf, 512)); } +#if 0 +/* + * Is this used? I don't see any reference, so I suggest to remove it. + */ int vms_stat (char *name, struct stat *buf) { @@ -235,6 +239,7 @@ vms_stat (char *name, struct stat *buf) return 0; } +#endif char * cvt_time (unsigned long tval) diff --git a/vmsify.c b/vmsify.c index 628ac6d9..178fc515 100644 --- a/vmsify.c +++ b/vmsify.c @@ -120,7 +120,11 @@ trnlog (const char *name) struct dsc$descriptor_s name_dsc; char *s; - INIT_DSC_CSTRING (name_dsc, name); + /* + * the string isn't changed, but there is no string descriptor with + * "const char *dsc$a_pointer" + */ + INIT_DSC_CSTRING (name_dsc, (char *)name); stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc); @@ -227,6 +231,9 @@ vmsify (const char *name, int type) char *vptr; int as_dir; int count; + const char *s; + const char *s1; + const char *s2; if (name == 0) return 0; @@ -239,8 +246,8 @@ vmsify (const char *name, int type) if (t != 0) { - const char *s1; - const char *s2; +// const char *s1; +// const char *s2; if (type == 1) { @@ -272,8 +279,9 @@ vmsify (const char *name, int type) if (t != 0) { - const char *s; - const char *s1 = strchr (t+1, '['); +// const char *s; +// const char *s1 = strchr (t+1, '['); + s1 = strchr (t+1, '['); if (s1 == 0) { strcpy (vmsname, name); @@ -388,8 +396,8 @@ vmsify (const char *name, int type) case 3: /* '//' at start */ { - const char *s; - const char *s1; +// const char *s; +// const char *s1; char *vp; while (*fptr == '/') /* collapse all '/' */ fptr++; diff --git a/vmsjobs.c b/vmsjobs.c index 71492a8d..3cba00b8 100644 --- a/vmsjobs.c +++ b/vmsjobs.c @@ -110,8 +110,11 @@ vms_handle_apos (char *p) return p; } -/* This is called as an AST when a child process dies (it won't get - interrupted by anything except a higher level AST). +static int ctrlYPressed= 0; +/* This is called at main or AST level. It is at AST level for DONTWAITFORCHILD + and at main level otherwise. In any case it is called when a child process + terminated. At AST level it won't get interrupted by anything except a + inner mode level AST. */ int vmsHandleChildTerm(struct child *child) @@ -123,6 +126,12 @@ vmsHandleChildTerm(struct child *child) vms_jobsefnmask &= ~(1 << (child->efn - 32)); lib$free_ef(&child->efn); + if (child->comname) + { + if (!ISDB (DB_JOBS)&&!ctrlYPressed) + unlink (child->comname); + free (child->comname); + } (void) sigblock (fatal_signal_mask); @@ -219,8 +228,7 @@ vmsHandleChildTerm(struct child *child) static int ctrlMask= LIB$M_CLI_CTRLY; static int oldCtrlMask; static int setupYAstTried= 0; -static int pidToAbort= 0; -static int chan= 0; +static unsigned short int chan= 0; static void reEnableAst(void) @@ -228,14 +236,15 @@ reEnableAst(void) lib$enable_ctrl (&oldCtrlMask,0); } -static void -astHandler (void) +static int +astYHandler (void) { - if (pidToAbort) { - sys$forcex (&pidToAbort, 0, SS$_ABORT); - pidToAbort= 0; - } + struct child *c; + for (c = children; c != 0; c = c->next) + sys$delprc (&c->pid, 0, 0); + ctrlYPressed= 1; kill (getpid(),SIGQUIT); + return SS$_NORMAL; } static void @@ -247,32 +256,28 @@ tryToSetupYAst(void) short int status, count; int dvi; } iosb; + unsigned short int loc_chan; setupYAstTried++; - if (!chan) { - status= sys$assign(&inputDsc,&chan,0,0); + if (chan) + loc_chan= chan; + else { + status= sys$assign(&inputDsc,&loc_chan,0,0); if (!(status&SS$_NORMAL)) { lib$signal(status); return; } } - status= sys$qiow (0, chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0, - astHandler,0,0,0,0,0); - if (status==SS$_NORMAL) - status= iosb.status; - if (status==SS$_ILLIOFUNC || status==SS$_NOPRIV) { - sys$dassgn(chan); -#ifdef CTRLY_ENABLED_ANYWAY - fprintf (stderr, - _("-warning, CTRL-Y will leave sub-process(es) around.\n")); -#else - return; -#endif - } - else if (!(status&SS$_NORMAL)) { - sys$dassgn(chan); - lib$signal(status); + status= sys$qiow (0, loc_chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0, + astYHandler,0,0,0,0,0); + if (status==SS$_NORMAL) + status= iosb.status; + if (status!=SS$_NORMAL) { + if (!chan) + sys$dassgn(loc_chan); + if (status!=SS$_ILLIOFUNC && status!=SS$_NOPRIV) + lib$signal(status); return; } @@ -287,6 +292,8 @@ tryToSetupYAst(void) lib$signal(status); return; } + if (!chan) + chan = loc_chan; } int @@ -299,13 +306,14 @@ child_execute_job (char *argv, struct child *child) static struct dsc$descriptor_s ofiledsc; static struct dsc$descriptor_s efiledsc; int have_redirection = 0; + int have_append = 0; int have_newline = 0; int spflags = CLI$M_NOWAIT; int status; char *cmd = alloca (strlen (argv) + 512), *p, *q; char ifile[256], ofile[256], efile[256]; - char *comname = 0; + int comnamelen; char procname[100]; int in_string; @@ -314,6 +322,7 @@ child_execute_job (char *argv, struct child *child) ifile[0] = 0; ofile[0] = 0; efile[0] = 0; + child->comname = NULL; DB (DB_JOBS, ("child_execute_job (%s)\n", argv)); @@ -383,6 +392,11 @@ child_execute_job (char *argv, struct child *child) } else { + if (*(p+1) == '>') + { + have_append = 1; + p += 1; + } p = vms_redirect (&ofiledsc, ofile, p); } *q = ' '; @@ -481,9 +495,10 @@ child_execute_job (char *argv, struct child *child) return 0; } - outfile = open_tmpfile (&comname, "sys$scratch:CMDXXXXXX.COM"); + outfile = open_tmpfile (&child->comname, "sys$scratch:CMDXXXXXX.COM"); if (outfile == 0) pfatal_with_name (_("fopen (temporary file)")); + comnamelen = strlen (child->comname); if (ifile[0]) { @@ -501,9 +516,19 @@ child_execute_job (char *argv, struct child *child) if (ofile[0]) { - fprintf (outfile, "$ define sys$output %s\n", ofile); - DB (DB_JOBS, (_("Redirected output to %s\n"), ofile)); - ofiledsc.dsc$w_length = 0; + if (have_append) + { + fprintf (outfile, "$ set noon\n"); + fprintf (outfile, "$ define sys$output %.*s\n", comnamelen-3, child->comname); + DB (DB_JOBS, (_("Append output to %s\n"), ofile)); + ofiledsc.dsc$w_length = 0; + } + else + { + fprintf (outfile, "$ define sys$output %s\n", ofile); + DB (DB_JOBS, (_("Redirected output to %s\n"), ofile)); + ofiledsc.dsc$w_length = 0; + } } p = sep = q = cmd; @@ -558,12 +583,25 @@ child_execute_job (char *argv, struct child *child) } } - fwrite (p, 1, q - p, outfile); + if (*p) + { + fwrite (p, 1, --q - p, outfile); fputc ('\n', outfile); + } + + if (have_append) + { + fprintf (outfile, "$ deassign sys$output ! 'f$verify(0)\n"); + fprintf (outfile, "$ append:=append\n"); + fprintf (outfile, "$ delete:=delete\n"); + fprintf (outfile, "$ append/new %.*s %s\n", comnamelen-3, child->comname, ofile); + fprintf (outfile, "$ delete %.*s;*\n", comnamelen-3, child->comname); + DB (DB_JOBS, (_("Append %.*s and cleanup\n"), comnamelen-3, child->comname)); + } fclose (outfile); - sprintf (cmd, "$ @%s", comname); + sprintf (cmd, "$ @%s", child->comname); DB (DB_JOBS, (_("Executing %s instead\n"), cmd)); } @@ -578,7 +616,15 @@ child_execute_job (char *argv, struct child *child) { status = lib$get_ef ((unsigned long *)&child->efn); if (!(status & 1)) - return 0; + { + if (child->comname) + { + if (!ISDB (DB_JOBS)) + unlink (child->comname); + free (child->comname); + } + return 0; + } } sys$clref (child->efn); @@ -647,9 +693,7 @@ child_execute_job (char *argv, struct child *child) 0, 0, 0); if (status & 1) { - pidToAbort= child->pid; status= sys$waitfr (child->efn); - pidToAbort= 0; vmsHandleChildTerm(child); } #else @@ -677,8 +721,5 @@ child_execute_job (char *argv, struct child *child) } } - if (comname && !ISDB (DB_JOBS)) - unlink (comname); - return (status & 1); }