Add VMS enhancements from Hartmut Becker.

This commit is contained in:
Paul Smith 2009-11-16 02:31:23 +00:00
parent fe43fa9de3
commit b6f45ddc53
10 changed files with 271 additions and 72 deletions

View file

@ -1,3 +1,33 @@
2009-11-15 Paul Smith <psmith@gnu.org>
Patches for VMS provided by Hartmut Becker <Hartmut.Becker@hp.com>
* 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 <boris@codesynthesis.com>
* vpath.c (vpath_search, selective_vpath_search): Add index arguments

View file

@ -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);

View file

@ -76,6 +76,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
/* 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 <http://www.gnu.org/licenses/>. */
/* #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 */

23
dir.c
View file

@ -23,7 +23,8 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
# include <dirent.h>
# 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);
}

1
job.h
View file

@ -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. */

13
main.c
View file

@ -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

View file

@ -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.

View file

@ -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)

View file

@ -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++;

123
vmsjobs.c
View file

@ -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);
}