summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ar.c126
-rw-r--r--commands.c22
-rw-r--r--commands.h8
-rw-r--r--compatMakefile2
-rw-r--r--config.h-vms.template292
-rw-r--r--default.c114
-rw-r--r--dep.h13
-rw-r--r--dir.c192
-rw-r--r--expand.c3
-rw-r--r--file.c55
-rw-r--r--filedef.h120
-rw-r--r--function.c98
-rw-r--r--implicit.c13
-rw-r--r--job.c368
-rw-r--r--job.h27
-rw-r--r--main.c49
-rw-r--r--make.h121
-rw-r--r--makefile.com34
-rw-r--r--makefile.vms121
-rw-r--r--misc.c4
-rw-r--r--read.c103
-rw-r--r--readme.vms62
-rw-r--r--remake.c52
-rw-r--r--remote-stub.c2
-rw-r--r--rule.c21
-rw-r--r--rule.h4
-rw-r--r--variable.c10
-rw-r--r--variable.h57
-rw-r--r--vmsdir.h40
-rw-r--r--vmsfunctions.c234
-rw-r--r--vmsify.c925
-rw-r--r--vpath.c4
32 files changed, 3068 insertions, 228 deletions
diff --git a/ar.c b/ar.c
index 63fcd34..117e11b 100644
--- a/ar.c
+++ b/ar.c
@@ -20,14 +20,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef NO_ARCHIVES
-#include "file.h"
+#include "filedef.h"
#include "dep.h"
#include <fnmatch.h>
/* Defined in arscan.c. */
-extern long int ar_scan ();
-extern int ar_member_touch ();
-extern int ar_name_equal ();
+extern long int ar_scan PARAMS ((char *archive, long int (*function) (), long int arg));
+extern int ar_member_touch PARAMS ((char *arname, char *memname));
+extern int ar_name_equal PARAMS ((char *name, char *mem, int truncated));
/* Return nonzero if NAME is an archive-member reference, zero if not.
@@ -67,8 +67,113 @@ ar_parse_name (name, arname_p, memname_p)
if (memname_p != 0)
*memname_p = savestring (p + 1, end - (p + 1));
}
+
+#ifdef VMS
+#include <lbrdef.h>
+#include <mhddef.h>
+#include <credef.h>
+#include <descrip.h>
+#include <ctype.h>
+#if __DECC
+#include <lbr$routines.h>
+#endif
+
+#define uppercasify(str) {char *str1; for (str1 = str; *str1; str1++) *str1 = _toupper(*str1);}
+
+#define LBR$_KEYNOTFND 2527330 /* This isn't in any .h file anywhere so I got it from a MACRO library */
+
+time_t
+ar_member_date (name)
+ char *name;
+{
+ static char *arname;
+ static char *memname;
+ char *p,*q;
+ long int val;
+ static struct {
+ struct mhddef mhd;
+ struct credef cre;
+ char garbage[256];
+ } buf;
+ int func=LBR$C_READ,
+ type=LBR$C_TYP_OBJ,
+ rfa[2],
+ lidx,
+ status;
+ $DESCRIPTOR(bufdesc,(char *)&buf);
+ $DESCRIPTOR(libdesc,arname);
+ $DESCRIPTOR(moddesc,memname);
+
+ /* This "file" is an archive member. */
+ p = index (name, '(');
+ arname = savestring (name, p - name);
+ val = strlen (p) - 2;
+/*
+ if (val > 15)
+ val = 15;
+*/
+ memname = savestring (p + 1, val);
+#ifdef OLDWAY
+ p = rindex (memname, ')');
+ if (p != 0) {
+ q = rindex(p,'.');
+ if (q)
+ *q = '\0'; /* to get rid of extension */
+ }
+#endif
+
+ q = rindex(memname,'.');
+ if (q)
+ *q = '\0'; /* to get rid of extension */
+
+ uppercasify(memname);
+
+ /* Make sure we know the modtime of the archive itself because
+ we are likely to be called just before commands to remake a
+ member are run, and they will change the archive itself. */
+ (void) f_mtime (enter_file (arname));
+
+ libdesc.dsc$a_pointer = arname;
+ libdesc.dsc$w_length = strlen(arname);
+ moddesc.dsc$a_pointer = memname;
+ moddesc.dsc$w_length = strlen(memname);
+
+ if (!((status = lbr$ini_control(&lidx,&func,&type,0)) & 1)) {
+ printf("Error in lbr$ini_control, %d\n",status);
+ return(-1);
+ }
+
+ if (!((status = lbr$open(&lidx,&libdesc,0,0,0,0,0)) & 1)) {
+ printf("Error opening library %s to lookup member %s, %d\n",arname, memname ,status);
+ return(-1);
+ }
+
+ if (!((status = lbr$lookup_key(&lidx,&moddesc,rfa)) & 1)) {
+ if (status != LBR$_KEYNOTFND)
+ printf("Error looking up module %s in library %s, %d\n",memname, arname ,status);
+ lbr$close(&lidx);
+ return(-1);
+ }
+
+ if (!((status = lbr$set_module(&lidx,rfa,&bufdesc,&bufdesc,0)) & 1)) {
+ printf("Error getting module info, %d\n",status);
+ lbr$close(&lidx);
+ return(-1);
+ }
+
+ lbr$close(&lidx);
+
+ val = SHELL$FIX_TIME(&buf.mhd.mhd$l_datim);
+
+ free (arname);
+ free (memname);
+ return (val <= 0 ? (time_t) -1 : (time_t) val);
+}
+
+#else
-static long int ar_member_date_1 ();
+static long int ar_member_date_1 PARAMS ((int desc, char *mem, int truncated, long int hdrpos,
+ long int datapos, long int size, long int date, int uid, int gid, int mode, char *name));
/* Return the modtime of NAME. */
@@ -127,9 +232,19 @@ ar_member_date_1 (desc, mem, truncated,
{
return ar_name_equal (name, mem, truncated) ? date : 0;
}
+#endif /* !VMS */
/* Set the archive-member NAME's modtime to now. */
+#ifdef VMS
+int
+ar_touch (name)
+ char *name;
+{
+ error ("touch archive member is not available on VMS");
+ return -1;
+}
+#else
int
ar_touch (name)
char *name;
@@ -182,6 +297,7 @@ ar_touch (name)
return val;
}
+#endif /* !VMS */
/* State of an `ar_glob' run, passed to `ar_glob_match'. */
diff --git a/commands.c b/commands.c
index 97ccbb1..1a4372f 100644
--- a/commands.c
+++ b/commands.c
@@ -18,12 +18,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
#include "dep.h"
-#include "commands.h"
-#include "file.h"
+#include "filedef.h"
#include "variable.h"
#include "job.h"
+#include "commands.h"
-extern int remote_kill ();
+extern int remote_kill PARAMS ((int id, int sig));
#ifndef HAVE_UNISTD_H
extern int getpid ();
@@ -154,8 +154,11 @@ set_file_variables (file)
bcopy (c, cp, len);
cp += len;
+#if VMS
+ *cp++ = ',';
+#else
*cp++ = ' ';
-
+#endif
if (! d->changed)
qmark_len -= len + 1; /* Don't space in $? for this one. */
}
@@ -193,13 +196,20 @@ set_file_variables (file)
bcopy (c, cp, len);
cp += len;
+#if VMS
+ *cp++ = ',';
+#else
*cp++ = ' ';
-
+#endif
if (d->changed)
{
bcopy (c, qp, len);
qp += len;
+#if VMS
+ *qp++ = ',';
+#else
*qp++ = ' ';
+#endif
}
}
@@ -413,7 +423,7 @@ fatal_error_signal (sig)
if (sig == SIGQUIT)
/* We don't want to send ourselves SIGQUIT, because it will
cause a core dump. Just exit instead. */
- exit (1);
+ exit (EXIT_FAILURE);
/* Signal the same code; this time it will really be fatal. The signal
will be unblocked when we return and arrive then to kill us. */
diff --git a/commands.h b/commands.h
index 31de16a..c55fa67 100644
--- a/commands.h
+++ b/commands.h
@@ -36,7 +36,7 @@ struct commands
#define COMMANDS_SILENT 2 /* Silent: @. */
#define COMMANDS_NOERROR 4 /* No errors: -. */
-extern void execute_file_commands ();
-extern void print_commands ();
-extern void delete_child_targets ();
-extern void chop_commands ();
+extern void execute_file_commands PARAMS ((struct file *file));
+extern void print_commands PARAMS ((struct commands *cmds));
+extern void delete_child_targets PARAMS ((struct child *child));
+extern void chop_commands PARAMS ((struct commands *cmds));
diff --git a/compatMakefile b/compatMakefile
index dd70ded..0755b0b 100644
--- a/compatMakefile
+++ b/compatMakefile
@@ -122,7 +122,7 @@ srcs = $(srcdir)/commands.c $(srcdir)/job.c $(srcdir)/dir.c \
$(srcdir)/ar.c $(srcdir)/arscan.c \
$(srcdir)/signame.c $(srcdir)/signame.h \
$(srcdir)/getopt.c $(srcdir)/getopt1.c $(srcdir)/getopt.h \
- $(srcdir)/commands.h $(srcdir)/dep.h $(srcdir)/file.h \
+ $(srcdir)/commands.h $(srcdir)/dep.h $(srcdir)/filedef.h \
$(srcdir)/job.h $(srcdir)/make.h $(srcdir)/rule.h \
$(srcdir)/variable.h $(ALLOCA_SRC) $(srcdir)/config.h.in
diff --git a/config.h-vms.template b/config.h-vms.template
new file mode 100644
index 0000000..7211919
--- /dev/null
+++ b/config.h-vms.template
@@ -0,0 +1,292 @@
+/* config.h-vms. Generated by hand by Klaus Kämpf <kkaempf@didymus.rmi.de> */
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define if using alloca.c. */
+/* #undef C_ALLOCA */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define for DGUX with <sys/dg_sys_info.h>. */
+/* #undef DGUX */
+
+/* Define if the `getloadavg' function needs to be run setuid or setgid. */
+/* #undef GETLOADAVG_PRIVILEGED 1 */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define if you have alloca, as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+/* #undef HAVE_ALLOCA_H 1 */
+
+/* Define if you don't have vprintf but do have _doprnt. */
+/* #undef HAVE_DOPRNT */
+
+/* Define if your system has its own `getloadavg' function. */
+/* #undef HAVE_GETLOADAVG */
+
+/* Define if you have the getmntent function. */
+/* #undef HAVE_GETMNTENT */
+
+/* Define if the `long double' type works. */
+/* #undef HAVE_LONG_DOUBLE */
+
+/* Define if you support file names longer than 14 characters. */
+#define HAVE_LONG_FILE_NAMES 1
+
+/* Define if you have a working `mmap' system call. */
+/* #undef HAVE_MMAP */
+
+/* Define if system calls automatically restart after interruption
+ by a signal. */
+/* #undef HAVE_RESTARTABLE_SYSCALLS */
+
+/* Define if your struct stat has st_blksize. */
+/* #undef HAVE_ST_BLKSIZE */
+
+/* Define if your struct stat has st_blocks. */
+/* #undef HAVE_ST_BLOCKS */
+
+/* Define if you have the strcoll function and it is properly defined. */
+/* #undef HAVE_STRCOLL 1 */
+
+/* Define if your struct stat has st_rdev. */
+/* #undef HAVE_ST_RDEV */
+
+/* Define if you have the strftime function. */
+/* #undef HAVE_STRFTIME */
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+/* #undef HAVE_SYS_WAIT_H 1 */
+
+/* Define if your struct tm has tm_zone. */
+/* #undef HAVE_TM_ZONE */
+
+/* Define if you don't have tm_zone but do have the external array
+ tzname. */
+/* #undef HAVE_TZNAME */
+
+/* Define if you have <unistd.h>. */
+#ifdef __DECC
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define if utime(file, NULL) sets file's timestamp to the present. */
+/* #undef HAVE_UTIME_NULL */
+
+/* Define if you have <vfork.h>. */
+/* #undef HAVE_VFORK_H 1 */
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF 1
+
+/* Define if you have the wait3 system call. */
+/* #undef HAVE_WAIT3 1 */
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define if your struct nlist has an n_un member. */
+/* #undef NLIST_NAME_UNION */
+
+/* Define if you have <nlist.h>. */
+/* #undef NLIST_STRUCT 1 */
+
+/* Define if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#define pid_t int
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* Define if the setvbuf function takes the buffering type as its second
+ argument and the buffer pointer as the third, as on System V
+ before release 3. */
+/* #undef SETVBUF_REVERSED 1 */
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */
+/* #undef STAT_MACROS_BROKEN */
+
+/* Define if you have the ANSI C header files. */
+/* #undef STDC_HEADERS */
+
+/* Define on System V Release 4. */
+/* #undef SVR4 */
+
+/* Define if `sys_siglist' is declared by <signal.h>. */
+/* #undef SYS_SIGLIST_DECLARED */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#define uid_t int
+
+/* Define for Encore UMAX. */
+/* #undef UMAX */
+
+/* Define for Encore UMAX 4.3 that has <inq_status/cpustats.h>
+ instead of <sys/cpustats.h>. */
+/* #undef UMAX4_3 */
+
+/* Define vfork as fork if vfork does not work. */
+/* #undef vfork */
+
+/* Define to the name of the SCCS `get' command. */
+/* #undef SCCS_GET "/usr/sccs/get" */
+
+/* Define this if the SCCS `get' command understands the `-G<file>' option. */
+/* #undef SCCS_GET_MINUS_G 1 */
+
+/* Define this if the C library defines the variable `sys_siglist'. */
+/* #undefine HAVE_SYS_SIGLIST 1 */
+
+/* Define this if the C library defines the variable `_sys_siglist'. */
+/* #undef HAVE__SYS_SIGLIST */
+
+/* Define this if you have the `union wait' type in <sys/wait.h>. */
+/* #undef HAVE_UNION_WAIT */
+
+/* Define this if the POSIX.1 call `sysconf (_SC_OPEN_MAX)' works properly. */
+/* #undef HAVE_SYSCONF_OPEN_MAX */
+
+/* Define if you have the dup2 function. */
+#define HAVE_DUP2 1
+
+/* Define if you have the getcwd function. */
+#define HAVE_GETCWD 1
+
+/* Define if you have the getdtablesize function. */
+/* #undef HAVE_GETDTABLESIZE 1 */
+
+/* Define if you have the getgroups function. */
+/* #undef HAVE_GETGROUPS 1 */
+
+/* Define if you have the mktemp function. */
+#define HAVE_MKTEMP 1
+
+/* Define if you have the psignal function. */
+/* #undef HAVE_PSIGNAL 1 */
+
+/* Define if you have the setegid function. */
+/* #undef HAVE_SETEGID 1 */
+
+/* Define if you have the seteuid function. */
+/* #undef HAVE_SETEUID 1 */
+
+/* Define if you have the setlinebuf function. */
+/* #undef HAVE_SETLINEBUF 1 */
+
+/* Define if you have the setregid function. */
+/* #undefine HAVE_SETREGID 1 */
+
+/* Define if you have the setreuid function. */
+/* #define HAVE_SETREUID 1 */
+
+/* Define if you have the sigsetmask function. */
+#define HAVE_SIGSETMASK 1
+
+/* Define if you have the strerror function. */
+#define HAVE_STRERROR 1
+
+/* Define if you have the strsignal function. */
+/* #undef HAVE_STRSIGNAL */
+
+/* Define if you have the wait3 function. */
+/* #define HAVE_WAIT3 1 */
+
+/* Define if you have the waitpid function. */
+/* #undef HAVE_WAITPID 1 */
+
+/* Define if you have the <dirent.h> header file. */
+/* #unddef HAVE_DIRENT_H 1 */
+
+/* Define if you have the <fcntl.h> header file. */
+#ifdef __DECC
+#define HAVE_FCNTL_H 1
+#endif
+
+/* Define if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <mach/mach.h> header file. */
+/* #undef HAVE_MACH_MACH_H */
+
+/* Define if you have the <memory.h> header file. */
+/* #undef HAVE_MEMORY_H 1 */
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <pwd.h> header file. */
+/* #undef HAVE_PWD_H */
+
+/* Define if you have the <sys/dir.h> header file. */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/param.h> header file. */
+/* #undef HAVE_SYS_PARAM_H 1 */
+
+/* Define if you have the <sys/timeb.h> header file. */
+#define HAVE_SYS_TIMEB_H 1
+
+/* Define if you have the <sys/wait.h> header file. */
+/* #undef HAVE_SYS_WAIT_H 1 */
+
+/* Define if you have the dgc library (-ldgc). */
+/* #undef HAVE_LIBDGC */
+
+/* Define if you have the sun library (-lsun). */
+/* #undef HAVE_LIBSUN */
+
+/* VMS specific */
+
+#define HAVE_VMSDIR_H 1
+#define HAVE_STDLIB_H 1
+#define INCLUDEDIR "sys$sysroot:[syslib]"
+#define LIBDIR "sys$sysroot:[syslib]"
+
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef PARAMS
+#define PARAMS(protos) protos
+#else /* Not C++ or ANSI C. */
+#undef PARAMS
+#define PARAMS(protos) ()
+#endif /* C++ or ANSI C. */
+
diff --git a/default.c b/default.c
index 7c487d1..5f5d2b5 100644
--- a/default.c
+++ b/default.c
@@ -19,7 +19,8 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
#include "rule.h"
#include "dep.h"
-#include "file.h"
+#include "filedef.h"
+#include "job.h"
#include "commands.h"
#include "variable.h"
@@ -35,9 +36,15 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
a `.c' or `.p' or ... file rather than from a .s file. */
static char default_suffixes[]
+#ifdef VMS
+ = ".exe .olb .ln .obj .c .cc .pas .p .for .f .r .y .l .mar \
+.mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \
+.w .ch .cweb .web .com .sh .elc .el";
+#else
= ".out .a .ln .o .c .cc .C .p .f .F .r .y .l .s .S \
.mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \
.w .ch .web .sh .elc .el";
+#endif
static struct pspec default_pattern_rules[] =
{
@@ -47,9 +54,13 @@ static struct pspec default_pattern_rules[] =
/* The X.out rules are only in BSD's default set because
BSD Make has no null-suffix rules, so `foo.out' and
`foo' are the same thing. */
+#ifdef VMS
+ { "%.exe", "%",
+ "copy $< $@" },
+#else
{ "%.out", "%",
"@rm -f $@ \n cp $< $@" },
-
+#endif
/* Syntax is "ctangle foo.w foo.ch foo.c". */
{ "%.c", "%.w %.ch",
"$(CTANGLE) $^ $@" },
@@ -61,6 +72,20 @@ static struct pspec default_pattern_rules[] =
static struct pspec default_terminal_rules[] =
{
+#ifdef VMS
+ /* RCS. */
+ { "%", "%$$5lv", /* Multinet style */
+ "if f$$search($@) .nes. \"\" then +$(CHECKOUT,v)" },
+ { "%", "[.$$rcs]%$$5lv", /* Multinet style */
+ "if f$$search($@) .nes. \"\" then +$(CHECKOUT,v)" },
+ { "%", "%_v", /* Normal style */
+ "if f$$search($@) .nes. \"\" then +$(CHECKOUT,v)" },
+ { "%", "[.rcs]%_v", /* Normal style */
+ "if f$$search($@) .nes. \"\" then +$(CHECKOUT,v)" },
+
+ /* SCCS. */
+ /* ain't no SCCS on vms */
+#else
/* RCS. */
{ "%", "%,v",
"$(CHECKOUT,v)" },
@@ -72,12 +97,53 @@ static struct pspec default_terminal_rules[] =
"$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" },
{ "%", "SCCS/s.%",
"$(GET) $(GFLAGS) $(SCCS_OUTPUT_OPTION) $<" },
-
+#endif /* !VMS */
{ 0, 0, 0 }
};
static char *default_suffix_rules[] =
{
+#ifdef VMS
+ ".obj.exe",
+ "$(LINK.obj) $^ $(LOADLIBES) $(LDLIBS) /exe=$@",
+ ".mar.exe",
+ "$(LINK.mar) $^ $(LOADLIBES) $(LDLIBS) /exe=$@",
+ ".c.exe",
+ "$(COMPILE.c) $^ \n $(LINK.obj) $(subst .c,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@",
+ ".cc.exe",
+ "$(COMPILE.cc) $^ \n $(LINK.obj) $(subst .cc,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@",
+ ".for.exe",
+ "$(COMPILE.for) $^ \n $(LINK.obj) $(subst .for,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@",
+ ".pas.exe",
+ "$(COMPILE.pas) $^ \n $(LINK.obj) $(subst .pas,.obj,$^) $(LOADLIBES) $(LDLIBS) /exe=$@",
+
+ ".com",
+ "copy $< >$@",
+
+ ".mar.obj",
+ "$(COMPILE.mar) /obj=$@ $<",
+ ".c.obj",
+ "$(COMPILE.c) /obj=$@ $<",
+ ".cc.obj",
+ "$(COMPILE.cc) /obj=$@ $<",
+ ".for.obj",
+ "$(COMPILE.for) /obj=$@ $<",
+ ".pas.obj",
+ "$(COMPILE.pas) /obj=$@ $<",
+
+ ".y.c",
+ "$(YACC.y) $< \n rename y_tab.c $@",
+ ".l.c",
+ "$(LEX.l) $< \n rename lexyy.c $@",
+
+ ".texinfo.info",
+ "$(MAKEINFO) $<",
+
+ ".tex.dvi",
+ "$(TEX) $<",
+
+#else /* ! VMS */
+
".o",
"$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@",
".s",
@@ -195,11 +261,52 @@ static char *default_suffix_rules[] =
".web.tex",
"$(WEAVE) $<",
+#endif /* !VMS */
+
0, 0,
};
static char *default_variables[] =
{
+#ifdef VMS
+ "AR", "library/obj",
+ "ARFLAGS", "/replace",
+ "AS", "macro",
+ "CC", "cc",
+ "C++", "gcc/plus",
+ "CXX", "gcc/plus",
+ "CO", "co",
+ "CPP", "$(CC) /preprocess_only",
+ "FC", "fortran",
+ /* System V uses these, so explicit rules using them should work.
+ However, there is no way to make implicit rules use them and FC. */
+ "F77", "$(FC)",
+ "F77FLAGS", "$(FFLAGS)",
+ "LD", "link",
+ "LEX", "lex",
+ "PC", "pascal",
+ "YACC", "yacc", /* Or "bison -y" */
+ "MAKEINFO", "makeinfo",
+ "TEX", "tex",
+ "TEXINDEX", "texindex",
+
+ "RM", "delete/nolog",
+
+ "LINK.obj", "$(LD) $(LDFLAGS)",
+ "COMPILE.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
+ "COMPILE.cc", "$(C++) $(C++FLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c",
+ "YACC.y", "$(YACC) $(YFLAGS)",
+ "LEX.l", "$(LEX) $(LFLAGS)",
+ "COMPILE.for", "$(FC) $(FFLAGS) $(TARGET_ARCH)",
+ "COMPILE.pas", "$(PC) $(PFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
+ "COMPILE.mar", "$(AS) $(ASFLAGS) $(TARGET_MACH)",
+ "LINT.c", "$(LINT) $(LINTFLAGS) $(CPPFLAGS) $(TARGET_ARCH)",
+
+ "MV", "rename/new_version",
+ "CP", "copy",
+
+#else /* !VMS */
+
"AR", "ar",
"ARFLAGS", "rv",
"AS", "as",
@@ -310,6 +417,7 @@ static char *default_variables[] =
"SCCS_OUTPUT_OPTION", "-G$@",
#endif
+#endif /* !VMS */
0, 0
};
diff --git a/dep.h b/dep.h
index 244cde2..550c68a 100644
--- a/dep.h
+++ b/dep.h
@@ -40,11 +40,16 @@ struct nameseq
};
-extern struct nameseq *multi_glob (), *parse_file_seq ();
-extern char *tilde_expand ();
+extern struct nameseq *multi_glob PARAMS ((struct nameseq *chain, unsigned int size));
+#ifdef VMS
+extern struct nameseq *parse_file_seq ();
+#else
+extern struct nameseq *parse_file_seq PARAMS ((char **stringp, char stopchar, unsigned int size, int strip));
+#endif
+extern char *tilde_expand PARAMS ((char *name));
#ifndef NO_ARCHIVES
-extern struct nameseq *ar_glob ();
+extern struct nameseq *ar_glob PARAMS ((char *arname, char *member_pattern, unsigned int size));
#endif
#ifndef iAPX286
@@ -54,7 +59,7 @@ extern struct nameseq *ar_glob ();
extern char *dep_name ();
#endif
-extern struct dep *read_all_makefiles ();
+extern struct dep *read_all_makefiles PARAMS ((char **makefiles));
/* Flag bits for the second argument to `read_makefile'.
These flags are saved in the `changed' field of each
diff --git a/dir.c b/dir.c
index ba2acc5..969f52a 100644
--- a/dir.c
+++ b/dir.c
@@ -33,6 +33,9 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
# ifdef HAVE_NDIR_H
# include <ndir.h>
# endif
+# ifdef HAVE_VMSDIR_H
+# include "vmsdir.h"
+# endif /* HAVE_VMSDIR_H */
#endif
/* In GNU systems, <dirent.h> defines this macro for us. */
@@ -92,7 +95,63 @@ dosify (filename)
*df = 0;
return dos_filename;
}
-#endif
+#endif /* __MSDOS__ */
+
+#ifdef VMS
+
+static int
+vms_hash (name)
+ char *name;
+{
+ int h = 0;
+ int g;
+
+ while (*name)
+ {
+ h = (h << 4) + *name++;
+ g = h & 0xf0000000;
+ if (g)
+ {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ return h;
+}
+
+/* fake stat entry for a directory */
+static int
+vmsstat_dir (name, st)
+ char *name;
+ struct stat *st;
+{
+ char *s;
+ int h;
+ DIR *dir;
+
+ dir = opendir (name);
+ if (dir == 0)
+ return -1;
+ closedir (dir);
+ s = strchr (name, ':'); /* find device */
+ if (s)
+ {
+ *s++ = 0;
+ st->st_dev = (char *)vms_hash (name);
+ }
+ else
+ {
+ st->st_dev = 0;
+ s = name;
+ }
+ h = vms_hash (s);
+ st->st_ino[0] = h & 0xff;
+ st->st_ino[1] = h & 0xff00;
+ st->st_ino[2] = h >> 16;
+
+ return 0;
+}
+#endif /* VMS */
/* Hash table of directories. */
@@ -104,8 +163,12 @@ struct directory_contents
{
struct directory_contents *next;
- int dev, ino; /* Device and inode numbers of this dir. */
-
+ dev_t dev; /* Device and inode numbers of this dir. */
+#ifdef VMS
+ ino_t ino[3];
+#else
+ ino_t ino;
+#endif
struct dirfile **files; /* Files in this directory. */
DIR *dirstream; /* Stream reading this directory. */
};
@@ -149,7 +212,8 @@ struct dirfile
#define DIRFILE_BUCKETS 107
#endif
-static int dir_contents_file_exists_p ();
+static int dir_contents_file_exists_p PARAMS ((struct directory_contents *dir, char *filename));
+static struct directory *find_directory PARAMS ((char *name));
/* Find the directory named NAME and return its `struct directory'. */
@@ -160,6 +224,12 @@ find_directory (name)
register unsigned int hash = 0;
register char *p;
register struct directory *dir;
+#ifdef VMS
+ if ((*name == '.') && (*(name+1) == 0))
+ name = "[]";
+ else
+ name = vmsify (name,1);
+#endif
for (p = name; *p != '\0'; ++p)
HASH (hash, *p);
@@ -183,21 +253,41 @@ find_directory (name)
/* The directory is not in the name hash table.
Find its device and inode numbers, and look it up by them. */
+#ifdef VMS
+ if (vmsstat_dir (name, &st) < 0)
+#else
if (stat (name, &st) < 0)
+#endif
+ {
/* Couldn't stat the directory. Mark this by
setting the `contents' member to a nil pointer. */
- dir->contents = 0;
+ dir->contents = 0;
+ }
else
{
/* Search the contents hash table; device and inode are the key. */
struct directory_contents *dc;
+#ifdef VMS
+ hash = ((unsigned int) st.st_dev << 16)
+ | ((unsigned int) st.st_ino[0]
+ + (unsigned int) st.st_ino[1]
+ + (unsigned int) st.st_ino[2]);
+#else
hash = ((unsigned int) st.st_dev << 16) | (unsigned int) st.st_ino;
+#endif
hash %= DIRECTORY_BUCKETS;
for (dc = directories_contents[hash]; dc != 0; dc = dc->next)
- if (dc->dev == st.st_dev && dc->ino == st.st_ino)
+ if (dc->dev == st.st_dev
+#ifdef VMS
+ && dc->ino[0] == st.st_ino[0]
+ && dc->ino[1] == st.st_ino[1]
+ && dc->ino[2] == st.st_ino[2])
+#else
+ && dc->ino == st.st_ino)
+#endif
break;
if (dc == 0)
@@ -209,15 +299,23 @@ find_directory (name)
/* Enter it in the contents hash table. */
dc->dev = st.st_dev;
+#ifdef VMS
+ dc->ino[0] = st.st_ino[0];
+ dc->ino[1] = st.st_ino[1];
+ dc->ino[2] = st.st_ino[2];
+#else
dc->ino = st.st_ino;
+#endif
dc->next = directories_contents[hash];
directories_contents[hash] = dc;
dc->dirstream = opendir (name);
if (dc->dirstream == 0)
+ {
/* Couldn't open the directory. Mark this by
setting the `files' member to a nil pointer. */
- dc->files = 0;
+ dc->files = 0;
+ }
else
{
/* Allocate an array of buckets for files and zero it. */
@@ -257,19 +355,26 @@ dir_contents_file_exists_p (dir, filename)
register struct dirent *d;
if (dir == 0 || dir->files == 0)
+ {
/* The directory could not be stat'd or opened. */
- return 0;
-
+ return 0;
+ }
#ifdef __MSDOS__
filename = dosify (filename);
#endif
+#ifdef VMS
+ filename = vmsify (filename,0);
+#endif
+
hash = 0;
if (filename != 0)
{
if (*filename == '\0')
+ {
/* Checking if the directory exists. */
- return 1;
+ return 1;
+ }
for (p = filename; *p != '\0'; ++p)
HASH (hash, *p);
@@ -278,16 +383,22 @@ dir_contents_file_exists_p (dir, filename)
/* Search the list of hashed files. */
for (df = dir->files[hash]; df != 0; df = df->next)
- if (streq (df->name, filename))
- return !df->impossible;
+ {
+ if (streq (df->name, filename))
+ {
+ return !df->impossible;
+ }
+ }
}
/* The file was not found in the hashed list.
Try to read the directory further. */
if (dir->dirstream == 0)
+ {
/* The directory has been all read in. */
- return 0;
+ return 0;
+ }
while ((d = readdir (dir->dirstream)) != 0)
{
@@ -309,11 +420,12 @@ dir_contents_file_exists_p (dir, filename)
dir->files[newhash] = df;
df->name = savestring (d->d_name, len);
df->impossible = 0;
-
/* Check if the name matches the one we're searching for. */
if (filename != 0
&& newhash == hash && streq (d->d_name, filename))
- return 1;
+ {
+ return 1;
+ }
}
/* If the directory has been completely read in,
@@ -324,7 +436,6 @@ dir_contents_file_exists_p (dir, filename)
closedir (dir->dirstream);
dir->dirstream = 0;
}
-
return 0;
}
@@ -355,9 +466,16 @@ file_exists_p (name)
return ar_member_date (name) != (time_t) -1;
#endif
+#ifdef VMS
+ dirend = rindex (name, ']');
+ dirend++;
+ if (dirend == (char *)1)
+ return dir_file_exists_p ("[]", name);
+#else
dirend = rindex (name, '/');
if (dirend == 0)
return dir_file_exists_p (".", name);
+#endif
dirname = (char *) alloca (dirend - name + 1);
bcopy (name, dirname, dirend - name);
@@ -379,9 +497,16 @@ file_impossible (filename)
register struct directory *dir;
register struct dirfile *new;
+#ifdef VMS
+ dirend = rindex (p, ']');
+ dirend++;
+ if (dirend == (char *)1)
+ dir = find_directory ("[]");
+#else
dirend = rindex (p, '/');
if (dirend == 0)
dir = find_directory (".");
+#endif
else
{
char *dirname = (char *) alloca (dirend - p + 1);
@@ -401,7 +526,13 @@ file_impossible (filename)
structure for it, but leave it out of the contents hash table. */
dir->contents = (struct directory_contents *)
xmalloc (sizeof (struct directory_contents));
+#ifdef VMS
+ dir->contents->dev = 0;
+ dir->contents->ino[0] = dir->contents->ino[1] =
+ dir->contents->ino[2] = 0;
+#else
dir->contents->dev = dir->contents->ino = 0;
+#endif
dir->contents->files = 0;
dir->contents->dirstream = 0;
}
@@ -436,9 +567,15 @@ file_impossible_p (filename)
register struct directory_contents *dir;
register struct dirfile *next;
+#ifdef VMS
+ dirend = rindex (filename, ']');
+ if (dirend == 0)
+ dir = find_directory ("[]")->contents;
+#else
dirend = rindex (filename, '/');
if (dirend == 0)
dir = find_directory (".")->contents;
+#endif
else
{
char *dirname = (char *) alloca (dirend - filename + 1);
@@ -455,6 +592,9 @@ file_impossible_p (filename)
#ifdef __MSDOS__
p = filename = dosify (p);
#endif
+#ifdef VMS
+ p = filename = vmsify (p, 1);
+#endif
for (hash = 0; *p != '\0'; ++p)
HASH (hash, *p);
@@ -495,8 +635,15 @@ print_dir_data_base ()
if (dir->contents == 0)
printf ("# %s: could not be stat'd.\n", dir->name);
else if (dir->contents->files == 0)
+#ifdef VMS
+ printf ("# %s (device %d, inode [%d,%d,%d]): could not be opened.\n",
+ dir->name, dir->contents->dev,
+ dir->contents->ino[0], dir->contents->ino[1],
+ dir->contents->ino[2]);
+#else
printf ("# %s (device %d, inode %d): could not be opened.\n",
dir->name, dir->contents->dev, dir->contents->ino);
+#endif
else
{
register unsigned int f = 0, im = 0;
@@ -508,8 +655,15 @@ print_dir_data_base ()
++im;
else
++f;
+#ifdef VMS
+ printf ("# %s (device %d, inode [%d,%d,%d]): ",
+ dir->name, dir->contents->dev,
+ dir->contents->ino[0], dir->contents->ino[1],
+ dir->contents->ino[2]);
+#else
printf ("# %s (device %d, inode %d): ",
dir->name, dir->contents->dev, dir->contents->ino);
+#endif
if (f == 0)
fputs ("No", stdout);
else
@@ -557,15 +711,15 @@ struct dirstream
};
/* Forward declarations. */
-static __ptr_t open_dirstream __P ((const char *));
-static struct dirent *read_dirstream __P ((__ptr_t));
+static __ptr_t open_dirstream PARAMS ((const char *));
+static struct dirent *read_dirstream PARAMS ((__ptr_t));
static __ptr_t
open_dirstream (directory)
const char *directory;
{
struct dirstream *new;
- struct directory *dir = find_directory (directory);
+ struct directory *dir = find_directory ((char *)directory);
if (dir->contents == 0 || dir->contents->files == 0)
/* DIR->contents is nil if the directory could not be stat'd.
diff --git a/expand.c b/expand.c
index 7348fb2..5f46ac2 100644
--- a/expand.c
+++ b/expand.c
@@ -17,8 +17,9 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
+#include "filedef.h"
+#include "job.h"
#include "commands.h"
-#include "file.h"
#include "variable.h"
/* The next two describe the variable output buffer.
diff --git a/file.c b/file.c
index f81c9b9..5bf4708 100644
--- a/file.c
+++ b/file.c
@@ -17,9 +17,10 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
-#include "commands.h"
#include "dep.h"
-#include "file.h"
+#include "filedef.h"
+#include "job.h"
+#include "commands.h"
#include "variable.h"
#include <assert.h>
@@ -55,6 +56,10 @@ lookup_file (name)
/* This is also done in parse_file_seq, so this is redundant
for names read from makefiles. It is here for names passed
on the command line. */
+#ifdef VMS
+ while (name[0] == '[' && name[1] == ']' && name[2] != '\0')
+ name += 2;
+#endif
while (name[0] == '.' && name[1] == '/' && name[2] != '\0')
{
name += 2;
@@ -65,7 +70,11 @@ lookup_file (name)
if (*name == '\0')
/* It was all slashes after a dot. */
+#ifdef VMS
+ name = "[]";
+#else
name = "./";
+#endif
hashval = 0;
for (n = name; *n != '\0'; ++n)
@@ -73,8 +82,12 @@ lookup_file (name)
hashval %= FILE_BUCKETS;
for (f = files[hashval]; f != 0; f = f->next)
- if (streq (f->name, name))
- return f;
+ {
+ if (streq (f->name, name))
+ {
+ return f;
+ }
+ }
return 0;
}
@@ -85,10 +98,26 @@ enter_file (name)
register struct file *f, *new;
register char *n;
register unsigned int hashval;
+#ifdef VMS
+ char *lname, *ln;
+#endif
if (*name == '\0')
abort ();
+#ifdef VMS
+ lname = (char *)malloc (strlen (name) + 1);
+ for (n = name, ln = lname; *n != '\0'; ++n, ++ln)
+ {
+ if (isupper(*n))
+ *ln = tolower(*n);
+ else
+ *ln = *n;
+ }
+ *ln = 0;
+ name = lname;
+#endif
+
hashval = 0;
for (n = name; *n != '\0'; ++n)
HASH (hashval, *n);
@@ -99,7 +128,12 @@ enter_file (name)
break;
if (f != 0 && !f->double_colon)
- return f;
+ {
+#ifdef VMS
+ free(lname);
+#endif
+ return f;
+ }
new = (struct file *) xmalloc (sizeof (struct file));
bzero ((char *) new, sizeof (struct file));
@@ -477,7 +511,9 @@ print_file (f)
struct file *f;
{
register struct dep *d;
-
+#ifdef VMS
+ extern char *cvt_time PARAMS ((unsigned long));
+#endif
putchar ('\n');
if (!f->is_target)
puts ("# Not a target:");
@@ -513,8 +549,13 @@ print_file (f)
else if (f->last_mtime == (time_t) -1)
puts ("# File does not exist.");
else
+#ifdef VMS
+ printf ("# Last modified %.24s (%0lx)\n",
+ cvt_time(f->last_mtime), (unsigned long) f->last_mtime);
+#else
printf ("# Last modified %.24s (%ld)\n",
ctime (&f->last_mtime), (long int) f->last_mtime);
+#endif
printf ("# File has%s been updated.\n",
f->updated ? "" : " not");
switch (f->command_state)
@@ -601,3 +642,5 @@ print_file_data_base ()
#endif
}
}
+
+/* EOF */
diff --git a/filedef.h b/filedef.h
new file mode 100644
index 0000000..6070ecb
--- /dev/null
+++ b/filedef.h
@@ -0,0 +1,120 @@
+/* Definition of target file data structures for GNU Make.
+Copyright (C) 1988, 89, 90, 91, 92, 93, 94 Free Software Foundation, Inc.
+This file is part of GNU Make.
+
+GNU Make is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Make is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Make; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Structure that represents the info on one file
+ that the makefile says how to make.
+ All of these are chained together through `next'. */
+
+struct file
+ {
+ struct file *next;
+ char *name;
+ struct dep *deps;
+ struct commands *cmds; /* Commands to execute for this target. */
+ int command_flags; /* Flags OR'd in for cmds; see commands.h. */
+ char *stem; /* Implicit stem, if an implicit
+ rule has been used */
+ struct dep *also_make; /* Targets that are made by making this. */
+ time_t last_mtime; /* File's modtime, if already known. */
+ struct file *prev; /* Previous entry for same file name;
+ used when there are multiple double-colon
+ entries for the same file. */
+
+ /* File that this file was renamed to. After any time that a
+ file could be renamed, call `check_renamed' (below). */
+ struct file *renamed;
+
+ /* List of variable sets used for this file. */
+ struct variable_set_list *variables;
+
+ /* Immediate dependent that caused this target to be remade,
+ or nil if there isn't one. */
+ struct file *parent;
+
+ /* For a double-colon entry, this is the first double-colon entry for
+ the same file. Otherwise this is null. */
+ struct file *double_colon;
+
+ short int update_status; /* Status of the last attempt to update,
+ or -1 if none has been made. */
+
+ enum /* State of the commands. */
+ { /* Note: It is important that cs_not_started be zero. */
+ cs_not_started, /* Not yet started. */
+ cs_deps_running, /* Dep commands running. */
+ cs_running, /* Commands running. */
+ cs_finished /* Commands finished. */
+ } command_state ENUM_BITFIELD (2);
+
+ unsigned int precious:1; /* Non-0 means don't delete file on quit */
+ unsigned int tried_implicit:1; /* Nonzero if have searched
+ for implicit rule for making
+ this file; don't search again. */
+ unsigned int updating:1; /* Nonzero while updating deps of this file */
+ unsigned int updated:1; /* Nonzero if this file has been remade. */
+ unsigned int is_target:1; /* Nonzero if file is described as target. */
+ unsigned int cmd_target:1; /* Nonzero if file was given on cmd line. */
+ unsigned int phony:1; /* Nonzero if this is a phony file
+ i.e., a dependency of .PHONY. */
+ unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */
+ /* Nonzero, for an intermediate file,
+ means remove_intermediates should not delete it. */
+ unsigned int secondary:1;
+ unsigned int dontcare:1; /* Nonzero if no complaint is to be made if
+ this target cannot be remade. */
+ };
+
+/* Number of intermediate files entered. */
+
+extern unsigned int num_intermediates;
+
+extern struct file *default_goal_file, *suffix_file, *default_file;
+
+
+extern struct file *lookup_file (), *enter_file ();
+extern void remove_intermediates (), snap_deps ();
+extern void rename_file (), file_hash_enter ();
+extern void set_command_state ();
+
+
+/* Return the mtime of file F (a struct file *), caching it.
+ The value is -1 if the file does not exist. */
+#define file_mtime(f) file_mtime_1 ((f), 1)
+/* Return the mtime of file F (a struct file *), caching it.
+ Don't search using vpath for the file--if it doesn't actually exist,
+ we don't find it.
+ The value is -1 if the file does not exist. */
+#define file_mtime_no_search(f) file_mtime_1 ((f), 0)
+extern time_t f_mtime ();
+#define file_mtime_1(f, v) \
+ ((f)->last_mtime != (time_t) 0 ? (f)->last_mtime : f_mtime ((f), v))
+
+/* Modtime value to use for `infinitely new'. We used to get the current time
+ from the system and use that whenever we wanted `new'. But that causes
+ trouble when the machine running make and the machine holding a file have
+ different ideas about what time it is; and can also lose for `force'
+ targets, which need to be considered newer than anything that depends on
+ them, even if said dependents' modtimes are in the future.
+
+ NOTE: This assumes 32-bit `time_t's, but I cannot think of a portable way
+ to produce the largest representable integer of a given signed type. */
+#define NEW_MTIME ((time_t) 0x7fffffff)
+
+
+#define check_renamed(file) \
+ while ((file)->renamed != 0) (file) = (file)->renamed /* No ; here. */
diff --git a/function.c b/function.c
index e5b46d7..1886f75 100644
--- a/function.c
+++ b/function.c
@@ -17,17 +17,18 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
+#include "filedef.h"
#include "variable.h"
#include "dep.h"
-#include "commands.h"
#include "job.h"
+#include "commands.h"
#ifdef __MSDOS__
#include <process.h>
#include <fcntl.h>
#endif
-static char *string_glob ();
+static char *string_glob PARAMS ((char *line));
/* Store into VARIABLE_BUFFER at O the result of scanning TEXT and replacing
each occurrence of SUBST with REPLACE. TEXT is null-terminated. SLEN is
@@ -35,7 +36,7 @@ static char *string_glob ();
nonzero, substitutions are done only on matches which are complete
whitespace-delimited words. If SUFFIX_ONLY is nonzero, substitutions are
done only at the ends of whitespace-delimited words. */
-
+
char *
subst_expand (o, text, subst, replace, slen, rlen, by_word, suffix_only)
char *o;
@@ -337,7 +338,8 @@ expand_function (o, function, text, end)
default:
abort ();
break;
-
+
+#ifndef VMS /* not supported for vms yet */
case function_shell:
{
char **argv, **envp;
@@ -349,12 +351,13 @@ expand_function (o, function, text, end)
text = expand_argument (text, end);
/* Construct the argument list. */
- argv = construct_command_argv (text, (char *) NULL, (struct file *) 0);
+ argv = construct_command_argv (text,
+ (char **) NULL, (struct file *) 0);
if (argv == 0)
break;
/* Using a target environment for `shell' loses in cases like:
- export var = $(shell echo foobie)
+ export var = $(shell echo foobie)
because target_environment hits a loop trying to expand $(var)
to put it in the environment. This is even more confusing when
var was not explicitly exported, but just appeared in the
@@ -498,7 +501,7 @@ expand_function (o, function, text, end)
unsigned int maxlen = 200;
int cc;
char *buffer;
-
+
strcpy (tmp_output, "shXXXXXX");
mktemp (tmp_output);
child_stdout = open (tmp_output,
@@ -509,9 +512,9 @@ expand_function (o, function, text, end)
dup2 (save_stdout, 1);
close (child_stdout);
close (save_stdout);
-
+
child_stdout = open (tmp_output, O_RDONLY|O_TEXT, 0644);
-
+
buffer = xmalloc (maxlen);
i = 0;
do
@@ -521,15 +524,15 @@ expand_function (o, function, text, end)
maxlen += 512;
buffer = (char *) xrealloc (buffer, maxlen + 1);
}
-
+
cc = read (child_stdout, &buffer[i], maxlen - i);
if (cc > 0)
i += cc;
} while (cc > 0);
-
+
close (child_stdout);
unlink (tmp_output);
-
+
if (i > 0)
{
if (buffer[i - 1] == '\n')
@@ -548,6 +551,7 @@ expand_function (o, function, text, end)
free (text);
break;
}
+#endif /* !VMS */
case function_origin:
/* Expand the argument. */
@@ -590,7 +594,7 @@ expand_function (o, function, text, end)
free (text);
break;
-
+
case function_sort:
/* Expand the argument. */
text = expand_argument (text, end);
@@ -610,7 +614,7 @@ expand_function (o, function, text, end)
nwords *= 2;
words = (char **) xrealloc ((char *) words,
nwords * sizeof (char *));
- }
+ }
words[wordi++] = savestring (p, len);
}
@@ -640,7 +644,7 @@ expand_function (o, function, text, end)
free (text);
break;
-
+
case function_foreach:
{
/* Get three comma-separated arguments but
@@ -733,7 +737,7 @@ expand_function (o, function, text, end)
if (p == end)
BADARGS (function == function_filter ? "filter" : "filter-out");
p2 = expand_argument (text, p);
-
+
text = expand_argument (p + 1, end);
/* Chop TEXT up into words and then run each pattern through. */
@@ -792,7 +796,7 @@ expand_function (o, function, text, end)
free (text);
}
break;
-
+
case function_patsubst:
/* Get three comma-separated arguments and expand each one. */
count = 0;
@@ -825,9 +829,9 @@ expand_function (o, function, text, end)
text = expand_argument (text, p2);
p3 = expand_argument (p2 + 1, p);
p2 = expand_argument (p + 1, end);
-
+
o = patsubst_expand (o, p2, text, p3, (char *) 0, (char *) 0);
-
+
free (text);
free (p3);
free (p2);
@@ -850,7 +854,7 @@ expand_function (o, function, text, end)
text = expand_argument (text, p);
p = expand_argument (p + 1, end);
-
+
{
/* Write each word of the first argument directly followed
by the corresponding word of the second argument.
@@ -866,11 +870,11 @@ expand_function (o, function, text, end)
tp = find_next_token (&p2, &tlen);
if (tp != 0)
o = variable_buffer_output (o, tp, tlen);
-
+
pp = find_next_token (&p3, &plen);
if (pp != 0)
o = variable_buffer_output (o, pp, plen);
-
+
if (tp != 0 || pp != 0)
{
o = variable_buffer_output (o, " ", 1);
@@ -882,11 +886,11 @@ expand_function (o, function, text, end)
/* Kill the last blank. */
--o;
}
-
+
free (text);
free (p);
break;
-
+
case function_strip:
/* Expand the argument. */
text = expand_argument (text, end);
@@ -901,19 +905,19 @@ expand_function (o, function, text, end)
if (doneany)
/* Kill the last space. */
--o;
-
+
free (text);
break;
-
+
case function_wildcard:
text = expand_argument (text, end);
-
+
p = string_glob (text);
o = variable_buffer_output (o, p, strlen (p));
-
+
free (text);
break;
-
+
case function_subst:
/* Get three comma-separated arguments and expand each one. */
count = 0;
@@ -946,14 +950,14 @@ expand_function (o, function, text, end)
text = expand_argument (text, p2);
p3 = expand_argument (p2 + 1, p);
p2 = expand_argument (p + 1, end);
-
+
o = subst_expand (o, p2, text, p3, strlen (text), strlen (p3), 0, 0);
-
+
free (text);
free (p3);
free (p2);
break;
-
+
case function_firstword:
/* Expand the argument. */
text = expand_argument (text, end);
@@ -963,10 +967,10 @@ expand_function (o, function, text, end)
p = find_next_token (&p2, &i);
if (p != 0)
o = variable_buffer_output (o, p, i);
-
+
free (text);
break;
-
+
case function_word:
/* Get two comma-separated arguments and expand each one. */
count = 0;
@@ -1058,11 +1062,11 @@ index argument");
i = strlen (text);
if (sindex (p, 0, text, i) != 0)
o = variable_buffer_output (o, text, i);
-
+
free (p);
free (text);
break;
-
+
case function_addsuffix:
case function_addprefix:
/* Get two comma-separated arguments and expand each one. */
@@ -1082,7 +1086,7 @@ index argument");
i = strlen (text);
p2 = expand_argument (p + 1, end);
-
+
p3 = p2;
while ((p = find_next_token (&p3, &len)) != 0)
{
@@ -1097,11 +1101,11 @@ index argument");
if (doneany)
/* Kill last space. */
--o;
-
+
free (p2);
free (text);
break;
-
+
case function_dir:
case function_basename:
/* Expand the argument. */
@@ -1111,7 +1115,11 @@ index argument");
while ((p2 = find_next_token (&p3, &len)) != 0)
{
p = p2 + len;
+#ifdef VMS
+ while (p >= p2 && *p != (function == function_dir ? ']' : '.'))
+#else
while (p >= p2 && *p != (function == function_dir ? '/' : '.'))
+#endif
--p;
if (p >= p2)
{
@@ -1120,7 +1128,11 @@ index argument");
o = variable_buffer_output (o, p2, p - p2);
}
else if (function == function_dir)
+#ifdef VMS
+ o = variable_buffer_output (o, "[]", 2);
+#else
o = variable_buffer_output (o, "./", 2);
+#endif
else
/* The entire name is the basename. */
o = variable_buffer_output (o, p2, len);
@@ -1131,10 +1143,10 @@ index argument");
if (doneany)
/* Kill last space. */
--o;
-
+
free (text);
break;
-
+
case function_notdir:
case function_suffix:
/* Expand the argument. */
@@ -1144,7 +1156,11 @@ index argument");
while ((p2 = find_next_token (&p3, &len)) != 0)
{
p = p2 + len;
+#ifdef VMS
+ while (p >= p2 && *p != (function == function_notdir ? ']' : '.'))
+#else
while (p >= p2 && *p != (function == function_notdir ? '/' : '.'))
+#endif
--p;
if (p >= p2)
{
diff --git a/implicit.c b/implicit.c
index 947ab4a..2ccf354 100644
--- a/implicit.c
+++ b/implicit.c
@@ -19,9 +19,10 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
#include "rule.h"
#include "dep.h"
-#include "file.h"
+#include "filedef.h"
-static int pattern_search ();
+static int pattern_search PARAMS ((struct file *file, int archive, unsigned int depth,
+ unsigned int recursions));
/* For a FILE which has no commands specified, try to figure out some
from the implicit pattern rules.
@@ -162,7 +163,11 @@ pattern_search (file, archive, depth, recursions)
/* Set LASTSLASH to point at the last slash in FILENAME
but not counting any slash at the end. (foo/bar/ counts as
bar/ in directory foo/, not empty in directory foo/bar/.) */
+#ifdef VMS
+ lastslash = rindex (filename, ']');
+#else
lastslash = rindex (filename, '/');
+#endif
if (lastslash != 0 && lastslash[1] == '\0')
lastslash = 0;
}
@@ -210,7 +215,11 @@ pattern_search (file, archive, depth, recursions)
/* Set CHECK_LASTSLASH if FILENAME contains a directory
prefix and the target pattern does not contain a slash. */
+#ifdef VMS
+ check_lastslash = lastslash != 0 && index (target, ']') == 0;
+#else
check_lastslash = lastslash != 0 && index (target, '/') == 0;
+#endif
if (check_lastslash)
{
/* In that case, don't include the
diff --git a/job.c b/job.c
index e5d4d1c..90ae9d9 100644
--- a/job.c
+++ b/job.c
@@ -18,9 +18,9 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
-#include "commands.h"
#include "job.h"
-#include "file.h"
+#include "filedef.h"
+#include "commands.h"
#include "variable.h"
#include <assert.h>
@@ -36,6 +36,13 @@ static char *dos_bename;
static int dos_batch_file;
#endif /* MSDOS. */
+#ifdef VMS
+#include <time.h>
+#include <processes.h>
+#include <starlet.h>
+#include <lib$routines.h>
+#endif
+
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else
@@ -102,22 +109,40 @@ extern int wait ();
#endif /* Don't have `union wait'. */
+#ifdef VMS
+static int vms_jobsefnmask=0;
+#endif /* !VMS */
#ifndef HAVE_UNISTD_H
extern int dup2 ();
extern int execve ();
extern void _exit ();
-extern int geteuid (), getegid ();
-extern int setgid (), getgid ();
+#ifndef VMS
+extern int geteuid ();
+extern int getegid ();
+extern int setgid ();
+extern int getgid ();
+#endif
#endif
-extern int getloadavg ();
-extern int start_remote_job_p ();
-extern int start_remote_job (), remote_status ();
-
-RETSIGTYPE child_handler ();
-static void free_child (), start_job_command ();
-static int load_too_high (), job_next_command ();
+extern char *allocated_variable_expand_for_file PARAMS ((char *line, struct file *file));
+
+extern int getloadavg PARAMS ((double loadavg[], int nelem));
+extern int start_remote_job PARAMS ((char **argv, char **envp, int stdin_fd,
+ int *is_remote, int *id_ptr, int *used_stdin));
+extern int start_remote_job_p PARAMS ((void));
+extern int remote_status PARAMS ((int *exit_code_ptr, int *signal_ptr,
+ int *coredump_ptr, int block));
+
+RETSIGTYPE child_handler PARAMS ((int));
+static void free_child PARAMS ((struct child *));
+static void start_job_command PARAMS ((struct child *child));
+static int load_too_high PARAMS ((void));
+static int job_next_command PARAMS ((struct child *));
+static int start_waiting_job PARAMS ((struct child *));
+#ifdef VMS
+static void vmsWaitForChildren PARAMS ((int *));
+#endif
/* Chain of all live (or recently deceased) children. */
@@ -148,6 +173,10 @@ child_error (target_name, exit_code, exit_sig, coredump, ignored)
if (ignored && silent_flag)
return;
+#ifdef VMS
+ if (!(exit_code & 1))
+ error("*** [%s] Error 0x%x%s", target_name, exit_code, ((ignored)? " (ignored)" : ""));
+#else
if (exit_sig == 0)
error (ignored ? "[%s] Error %d (ignored)" :
"*** [%s] Error %d",
@@ -156,10 +185,31 @@ child_error (target_name, exit_code, exit_sig, coredump, ignored)
error ("*** [%s] %s%s",
target_name, strsignal (exit_sig),
coredump ? " (core dumped)" : "");
+#endif
}
static unsigned int dead_children = 0;
+#ifdef VMS
+/* Wait for nchildren children to terminate */
+static void
+vmsWaitForChildren(int *status)
+{
+ while (1)
+ {
+ if (!vms_jobsefnmask)
+ {
+ *status = 0;
+ return;
+ }
+
+ *status = sys$wflor (32, vms_jobsefnmask);
+ }
+ return;
+}
+#endif
+
+
/* Notice that a child died.
reap_children should be called when convenient. */
RETSIGTYPE
@@ -215,7 +265,7 @@ reap_children (block, err)
and we might print the "Waiting for unfinished jobs" message above
when not necessary. */
- if (dead_children != 0)
+ if (dead_children > 0)
--dead_children;
any_remote = 0;
@@ -228,6 +278,9 @@ reap_children (block, err)
printf ("Live child 0x%08lx PID %d%s\n",
(unsigned long int) c,
c->pid, c->remote ? " (remote)" : "");
+#ifdef VMS
+ break;
+#endif
}
/* First, check for remote children. */
@@ -235,6 +288,7 @@ reap_children (block, err)
pid = remote_status (&exit_code, &exit_sig, &coredump, 0);
else
pid = 0;
+
if (pid < 0)
{
remote_status_lose:
@@ -251,19 +305,24 @@ reap_children (block, err)
if (any_local)
{
-#ifdef WAIT_NOHANG
+#ifdef VMS
+ vmsWaitForChildren (&status);
+ pid = c->pid;
+#else
+#ifdef WAIT_NOHANG
if (!block)
pid = WAIT_NOHANG (&status);
else
#endif
pid = wait (&status);
+#endif /* !VMS */
}
else
pid = 0;
if (pid < 0)
{
-#ifdef EINTR
+#ifdef EINTR
if (errno == EINTR)
continue;
#endif
@@ -442,7 +501,8 @@ reap_children (block, err)
free_child (c);
/* There is now another slot open. */
- --job_slots_used;
+ if (job_slots_used > 0)
+ --job_slots_used;
/* If the job failed, and the -k flag was not given, die,
unless we are already in the process of dying. */
@@ -453,6 +513,7 @@ reap_children (block, err)
/* Only block for one child. */
block = 0;
}
+ return;
}
/* Free the storage allocated for CHILD. */
@@ -514,7 +575,11 @@ start_job_command (child)
static int bad_stdin = -1;
register char *p;
int flags;
+#ifdef VMS
+ char *argv;
+#else
char **argv;
+#endif
/* Combine the flags parsed for the line itself with
the flags specified globally for this target. */
@@ -523,6 +588,7 @@ start_job_command (child)
p = child->command_ptr;
child->noerror = flags & COMMANDS_NOERROR;
+
while (*p != '\0')
{
if (*p == '@')
@@ -553,8 +619,12 @@ start_job_command (child)
/* Figure out an argument list from this command line. */
{
- char *end;
+ char *end = 0;
+#ifdef VMS
+ argv = p;
+#else
argv = construct_command_argv (p, &end, child->file);
+#endif
if (end == NULL)
child->command_ptr = NULL;
else
@@ -568,8 +638,10 @@ start_job_command (child)
{
/* Go on to the next command. It might be the recursive one.
We construct ARGV only to find the end of the command line. */
+#ifndef VMS
free (argv[0]);
free ((char *) argv);
+#endif
argv = 0;
}
@@ -608,8 +680,10 @@ start_job_command (child)
if (just_print_flag && !(flags & COMMANDS_RECURSE))
{
+#ifndef VMS
free (argv[0]);
free ((char *) argv);
+#endif
goto next_command;
}
@@ -618,6 +692,8 @@ start_job_command (child)
fflush (stdout);
fflush (stderr);
+#ifndef VMS
+
/* Set up a bad standard input that reads from a broken pipe. */
if (bad_stdin == -1)
@@ -652,6 +728,8 @@ start_job_command (child)
if (child->good_stdin)
good_stdin_used = 1;
+#endif /* !VMS */
+
child->deleted = 0;
/* Set up the environment for the child. */
@@ -660,6 +738,7 @@ start_job_command (child)
#ifndef __MSDOS__
+#ifndef VMS
/* start_waiting_job has set CHILD->remote if we can start a remote job. */
if (child->remote)
{
@@ -680,6 +759,7 @@ start_job_command (child)
}
}
else
+#endif /* !VMS */
{
/* Fork the child process. */
@@ -694,6 +774,17 @@ start_job_command (child)
#endif
child->remote = 0;
+
+#ifdef VMS
+
+ if (!child_execute_job (argv, child)) {
+ /* Fork failed! */
+ perror_with_name ("vfork", "");
+ goto error;
+ }
+
+#else
+
parent_environ = environ;
child->pid = vfork ();
environ = parent_environ; /* Restore value child may have clobbered. */
@@ -711,9 +802,11 @@ start_job_command (child)
perror_with_name ("vfork", "");
goto error;
}
+#endif /* !VMS */
}
#else /* MSDOS. */
+
dos_status = spawnvpe (P_WAIT, argv[0], argv, child->environment);
++dead_children;
child->pid = dos_pid++;
@@ -735,15 +828,17 @@ start_job_command (child)
set_command_state (child->file, cs_running);
/* Free the storage used by the child's argument list. */
-
+#ifndef VMS
free (argv[0]);
free ((char *) argv);
+#endif
return;
error:
child->file->update_status = 2;
notice_finished_file (child->file);
+ return;
}
/* Try to start a child running.
@@ -949,13 +1044,15 @@ new_job (file)
/* The job is now primed. Start it running.
(This will notice if there are in fact no commands.) */
- start_waiting_job (c);
+ (void)start_waiting_job (c);
if (job_slots == 1)
/* Since there is only one job slot, make things run linearly.
Wait for the child to die, setting the state to `cs_finished'. */
while (file->command_state == cs_running)
reap_children (1, 0);
+
+ return;
}
/* Move CHILD's pointers to the next command for it to execute.
@@ -984,10 +1081,9 @@ job_next_command (child)
static int
load_too_high ()
{
-#ifdef __MSDOS__
+#if defined(__MSDOS__) || defined(VMS)
return 1;
#else
- extern int getloadavg ();
double load;
if (max_load_average < 0)
@@ -1036,10 +1132,226 @@ start_waiting_jobs ()
/* Try to start that job. We break out of the loop as soon
as start_waiting_job puts one back on the waiting list. */
- } while (start_waiting_job (job) && waiting_jobs != 0);
+ }
+ while (start_waiting_job (job) && waiting_jobs != 0);
+
+ return;
}
-/* Replace the current process with one executing the command in ARGV.
+#ifdef VMS
+#include <descrip.h>
+#include <clidef.h>
+
+/* This is called as an AST when a child process dies (it won't get
+ interrupted by anything except a higher level AST).
+*/
+int vmsHandleChildTerm(struct child *child)
+{
+ int status;
+ register struct child *lastc, *c;
+ int child_failed;
+
+ vms_jobsefnmask &= ~(1 << (child->efn - 32));
+
+ lib$free_ef(&child->efn);
+
+ (void) sigblock (fatal_signal_mask);
+
+ child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));
+
+ /* Search for a child matching the deceased one. */
+ lastc = 0;
+#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
+ for (c = children; c != 0 && c != child; lastc = c, c = c->next);
+#else
+ c = child;
+#endif
+
+ if (child_failed && !c->noerror && !ignore_errors_flag)
+ {
+ /* The commands failed. Write an error message,
+ delete non-precious targets, and abort. */
+ child_error (c->file->name, c->cstatus, 0, 0, 0);
+ c->file->update_status = 1;
+ delete_child_targets (c);
+ }
+ else
+ {
+ if (child_failed)
+ {
+ /* The commands failed, but we don't care. */
+ child_error (c->file->name, c->cstatus, 0, 0, 1);
+ child_failed = 0;
+ }
+
+#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
+ /* If there are more commands to run, try to start them. */
+ start_job (c);
+
+ switch (c->file->command_state)
+ {
+ case cs_running:
+ /* Successfully started. */
+ break;
+
+ case cs_finished:
+ if (c->file->update_status != 0) {
+ /* We failed to start the commands. */
+ delete_child_targets (c);
+ }
+ break;
+
+ default:
+ error ("internal error: `%s' command_state \
+%d in child_handler", c->file->name);
+ abort ();
+ break;
+ }
+#endif /* RECURSIVEJOBS */
+ }
+
+ /* Set the state flag to say the commands have finished. */
+ c->file->command_state = cs_finished;
+ notice_finished_file (c->file);
+
+#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */
+ /* Remove the child from the chain and free it. */
+ if (lastc == 0)
+ children = c->next;
+ else
+ lastc->next = c->next;
+ free_child (c);
+#endif /* RECURSIVEJOBS */
+
+ /* There is now another slot open. */
+ if (job_slots_used > 0)
+ --job_slots_used;
+
+ /* If the job failed, and the -k flag was not given, die. */
+ if (child_failed && !keep_going_flag)
+ die (EXIT_FAILURE);
+
+ (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
+
+ return 1;
+}
+
+/* VMS:
+ Spawn a process executing the command in ARGV and return its pid. */
+
+#define MAXCMDLEN 200
+
+int
+child_execute_job (argv, child)
+ char *argv;
+ struct child *child;
+{
+ int i;
+ static struct dsc$descriptor_s cmddsc;
+#ifndef DONTWAITFORCHILD
+ int spflags = 0;
+#else
+ int spflags = CLI$M_NOWAIT;
+#endif
+ int status;
+ char cmd[4096],*p,*c;
+ char comname[50];
+
+/* Remove backslashes */
+ for (p = argv, c = cmd; *p; p++,c++)
+ {
+ if (*p == '\\') p++;
+ *c = *p;
+ }
+ *c = *p;
+
+ /* check for maximum dcl length and create *.com file if neccesary */
+
+ comname[0] = '\0';
+
+ if (strlen (cmd) > MAXCMDLEN)
+ {
+ FILE *outfile;
+ char tmp;
+
+ strcpy (comname, "sys$scratch:CMDXXXXXX.COM");
+ (void) mktemp (comname);
+
+ outfile = fopen (comname, "w");
+ if (outfile == 0)
+ pfatal_with_name (comname);
+
+ fprintf (outfile, "$ ");
+ c = cmd;
+
+ while (c)
+ {
+ p = strchr (c, ',');
+ if ((p == NULL) || (p-c > MAXCMDLEN))
+ p = strchr (c, ' ');
+ if (p != NULL)
+ {
+ p++;
+ tmp = *p;
+ *p = '\0';
+ }
+ else
+ tmp = '\0';
+ fprintf (outfile, "%s%s\n", c, (tmp == '\0')?"":" -");
+ if (p != NULL)
+ *p = tmp;
+ c = p;
+ }
+
+ fclose (outfile);
+
+ sprintf (cmd, "$ @%s", comname);
+
+ if (debug_flag)
+ printf ("Executing %s instead\n", cmd);
+ }
+
+ cmddsc.dsc$w_length = strlen(cmd);
+ cmddsc.dsc$a_pointer = cmd;
+ cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ cmddsc.dsc$b_class = DSC$K_CLASS_S;
+
+ child->efn = 0;
+ while (child->efn < 32 || child->efn > 63)
+ {
+ status = lib$get_ef(&child->efn);
+ if (!(status & 1))
+ return 0;
+ }
+
+ sys$clref(child->efn);
+
+ vms_jobsefnmask |= (1 << (child->efn - 32));
+
+#ifndef DONTWAITFORCHILD
+ status = lib$spawn(&cmddsc,0,0,&spflags,0,&child->pid,&child->cstatus,
+ &child->efn,0,0);
+ vmsHandleChildTerm(child);
+#else
+ status = lib$spawn(&cmddsc,0,0,&spflags,0,&child->pid,&child->cstatus,
+ &child->efn,vmsHandleChildTerm,child);
+#endif
+
+ if (!(status & 1))
+ {
+ printf("Error spawning, %d\n",status);
+ fflush(stdout);
+ }
+
+ unlink (comname);
+
+ return (status & 1);
+}
+
+#else /* !VMS */
+
+/* UNIX:
+ Replace the current process with one executing the command in ARGV.
STDIN_FD and STDOUT_FD are used as the process's stdin and stdout; ENVP is
the environment of the new program. This function does not return. */
@@ -1060,6 +1372,7 @@ child_execute_job (stdin_fd, stdout_fd, argv, envp)
/* Run the command. */
exec_command (argv, envp);
}
+#endif /* !VMS */
/* Replace the current process with one running the command in ARGV,
with environment ENVP. This function does not return. */
@@ -1068,6 +1381,12 @@ void
exec_command (argv, envp)
char **argv, **envp;
{
+#ifdef VMS
+ /* Run the program. */
+ execve (argv[0], argv, envp);
+ perror_with_name ("execve: ", argv[0]);
+ _exit (EXIT_FAILURE);
+#else
/* Be the user, permanently. */
child_access ();
@@ -1119,8 +1438,10 @@ exec_command (argv, envp)
}
_exit (127);
+#endif /* !VMS */
}
+#ifndef VMS
/* Figure out the argument list necessary to run LINE as a command. Try to
avoid using a shell. This routine handles only ' quoting, and " quoting
when no backslash, $ or ` characters are seen in the quotes. Starting
@@ -1364,7 +1685,7 @@ construct_command_argv_internal (line, restp, shell, ifs)
{
/* Free the old argument list we were working on. */
free (new_argv[0]);
- free (new_argv);
+ free ((void *)new_argv);
}
#ifdef __MSDOS__
@@ -1496,6 +1817,7 @@ construct_command_argv (line, restp, file)
return argv;
}
+#endif /* !VMS */
#ifndef HAVE_DUP2
int
diff --git a/job.h b/job.h
index 572bb33..82814aa 100644
--- a/job.h
+++ b/job.h
@@ -16,6 +16,9 @@ You should have received a copy of the GNU General Public License
along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+#ifndef SEEN_JOB_H
+#define SEEN_JOB_H
+
/* Structure describing a running or dead child process. */
struct child
@@ -31,6 +34,10 @@ struct child
char *command_ptr; /* Ptr into command_lines[command_line]. */
pid_t pid; /* Child process's ID number. */
+#ifdef VMS
+ int efn; /* Completion event flag number */
+ int cstatus; /* Completion status */
+#endif
unsigned int remote:1; /* Nonzero if executing remotely. */
unsigned int noerror:1; /* Nonzero if commands contained a `-'. */
@@ -41,18 +48,22 @@ struct child
extern struct child *children;
-extern void new_job ();
-extern void reap_children ();
-extern void start_waiting_jobs ();
+extern void new_job PARAMS ((struct file *file));
+extern void reap_children PARAMS ((int block, int err));
+extern void start_waiting_jobs PARAMS ((void));
-extern char **construct_command_argv ();
-extern void child_execute_job ();
-extern void exec_command ();
+extern char **construct_command_argv PARAMS ((char *line, char **restp, struct file *file));
+#ifdef VMS
+extern int child_execute_job PARAMS ((char *argv, struct child *child));
+#else
+extern void child_execute_job PARAMS ((int stdin_fd, int stdout_fd, char **argv, char **envp));
+#endif
+extern void exec_command PARAMS ((char **argv, char **envp));
extern unsigned int job_slots_used;
#ifdef POSIX
-extern void unblock_sigs ();
+extern void unblock_sigs PARAMS ((void));
#else
#ifdef HAVE_SIGSETMASK
extern int fatal_signal_mask;
@@ -61,3 +72,5 @@ extern int fatal_signal_mask;
#define unblock_sigs()
#endif
#endif
+
+#endif /* SEEN_JOB_H */
diff --git a/main.c b/main.c
index a03397f..efbd70e 100644
--- a/main.c
+++ b/main.c
@@ -17,20 +17,23 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
-#include "commands.h"
#include "dep.h"
-#include "file.h"
+#include "filedef.h"
#include "variable.h"
#include "job.h"
+#include "commands.h"
#include "getopt.h"
#include <assert.h>
+extern void init_dir PARAMS ((void));
+extern RETSIGTYPE fatal_error_signal PARAMS ((int sig));
+extern RETSIGTYPE child_handler PARAMS ((int sig));
-extern void print_variable_data_base ();
-extern void print_dir_data_base ();
-extern void print_rule_data_base ();
-extern void print_file_data_base ();
-extern void print_vpath_data_base ();
+extern void print_variable_data_base PARAMS ((void));
+extern void print_dir_data_base PARAMS ((void));
+extern void print_rule_data_base PARAMS ((void));
+extern void print_file_data_base PARAMS ((void));
+extern void print_vpath_data_base PARAMS ((void));
#ifndef HAVE_UNISTD_H
extern int chdir ();
@@ -43,10 +46,12 @@ extern double atof ();
#endif
extern char *mktemp ();
-static void print_data_base (), print_version ();
-static void decode_switches (), decode_env_switches ();
-static void define_makeflags ();
-static char *quote_as_word ();
+static void print_data_base PARAMS((void));
+static void print_version PARAMS ((void));
+static void decode_switches PARAMS ((int argc, char **argv, int env));
+static void decode_env_switches PARAMS ((char *envar, unsigned int len));
+static void define_makeflags PARAMS ((int all, int makefile));
+static char *quote_as_word PARAMS ((char *out, char *in, int double_dollars));
/* The structure that describes an accepted command switch. */
@@ -415,7 +420,6 @@ main (argc, argv, envp)
char **argv;
char **envp;
{
- extern RETSIGTYPE fatal_error_signal (), child_handler ();
register struct file *f;
register unsigned int i;
char **p;
@@ -486,7 +490,11 @@ main (argc, argv, envp)
program = "make";
else
{
+#ifdef VMS
+ program = rindex (argv[0], ']');
+#else
program = rindex (argv[0], '/');
+#endif
#ifdef __MSDOS__
if (program == 0)
program = rindex (argv[0], '\\');
@@ -560,7 +568,7 @@ main (argc, argv, envp)
if (print_version_flag)
die (0);
-#ifndef __MSDOS__
+#if !defined(__MSDOS__) && !defined(VMS)
/* Set the "MAKE_COMMAND" variable to the name we were invoked with.
(If it is a relative pathname with a slash, prepend our directory name
so the result will run the same program regardless of the current dir.
@@ -699,7 +707,12 @@ main (argc, argv, envp)
/* Make a unique filename. */
#ifdef HAVE_MKTEMP
+
+#ifdef VMS
+ static char name[] = "sys$scratch:GmXXXXXX";
+#else
static char name[] = "/tmp/GmXXXXXX";
+#endif
(void) mktemp (name);
#else
static char name[L_tmpnam];
@@ -1101,15 +1114,15 @@ main (argc, argv, envp)
/* Nothing happened. */
case 0:
/* Updated successfully. */
- status = 0;
+ status = EXIT_SUCCESS;
break;
case 2:
/* Updating failed. */
- status = 2;
+ status = EXIT_FAILURE;
break;
case 1:
/* We are under -q and would run some commands. */
- status = 1;
+ status = EXIT_FAILURE;
break;
default:
abort ();
@@ -1589,7 +1602,11 @@ quote_as_word (out, in, double_dollars)
{
while (*in != '\0')
{
+#ifdef VMS
+ if (index ("^;'\"*?$<>(){}|&~`\\ \t\r\n\f\v", *in) != 0)
+#else
if (index ("^;'\"*?[]$<>(){}|&~`\\ \t\r\n\f\v", *in) != 0)
+#endif
*out++ = '\\';
if (double_dollars && *in == '$')
*out++ = '$';
diff --git a/make.h b/make.h
index b44c339..04bc1e9 100644
--- a/make.h
+++ b/make.h
@@ -1,5 +1,5 @@
/* Miscellaneous global declarations and portability cruft for GNU Make.
-Copyright (C) 1988, 89, 90, 91, 92, 93, 94, 95 Free Software Foundation, Inc.
+Copyright (C) 1988,89,90,91,92,93,94,95,96 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify
@@ -28,6 +28,17 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#undef HAVE_CONFIG_H
#define HAVE_CONFIG_H
+
+/* Use prototypes if available. */
+#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
+#undef PARAMS
+#define PARAMS(protos) protos
+#else /* Not C++ or ANSI C. */
+#undef PARAMS
+#define PARAMS(protos) ()
+#endif /* C++ or ANSI C. */
+
+
#ifdef CRAY
/* This must happen before #include <signal.h> so
that the declaration therein is changed. */
@@ -67,9 +78,7 @@ extern int errno;
#endif
/* Some systems define _POSIX_VERSION but are not really POSIX.1. */
-#if (defined (butterfly) || defined (__arm) || \
- (defined (__mips) && defined (_SYSTYPE_SVR3)) || \
- (defined (sequent) && defined (i386)))
+#if (defined (butterfly) || defined (__arm) || (defined (__mips) && defined (_SYSTYPE_SVR3)) || (defined (sequent) && defined (i386)))
#undef POSIX
#endif
@@ -132,7 +141,7 @@ extern char *sys_siglist[];
#define PATH_VAR(var) char var[PATH_MAX]
#else
#define NEED_GET_PATH_MAX
-extern unsigned int get_path_max ();
+extern unsigned int get_path_max PARAMS ((void));
#define GET_PATH_MAX (get_path_max ())
#define PATH_VAR(var) char *var = (char *) alloca (GET_PATH_MAX)
#endif
@@ -153,8 +162,16 @@ extern unsigned int get_path_max ();
#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
#endif
+#ifdef VMS
+#include <stdio.h>
+#include <types.h>
+#include <unixlib.h>
+#include <unixio.h>
+#include <errno.h>
+#include <perror.h>
+#endif
-#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__))
+#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) || defined(VMS))
#include <stdlib.h>
#include <string.h>
#define ANSI_STRING
@@ -170,10 +187,12 @@ extern unsigned int get_path_max ();
#include <memory.h>
#endif
-extern char *malloc (), *realloc ();
-extern void free ();
+extern char *malloc PARAMS ((int));
+extern char *realloc PARAMS ((char *, int));
+extern void free PARAMS ((char *));
-extern void abort (), exit ();
+extern void abort PARAMS ((void));
+extern void exit PARAMS ((int));
#endif /* Standard headers. */
@@ -214,8 +233,8 @@ extern void bcopy ();
/* SCO Xenix has a buggy macro definition in <string.h>. */
#undef strerror
-#ifndef ANSI_STRING
-extern char *strerror ();
+#if !defined(ANSI_STRING) && !defined(__DECC)
+extern char *strerror PARAMS ((int errnum));
#endif
@@ -258,19 +277,30 @@ extern char *alloca ();
#endif
extern void die ();
-extern void message (), fatal (), error ();
+extern void message ();
+extern void fatal ();
+extern void error ();
extern void log_working_directory ();
-extern void makefile_error (), makefile_fatal ();
-extern void pfatal_with_name (), perror_with_name ();
-extern char *savestring (), *concat ();
-extern char *xmalloc (), *xrealloc ();
-extern char *find_next_token (), *next_token (), *end_of_token ();
-extern void collapse_continuations (), remove_comments ();
-extern char *sindex (), *lindex ();
+extern void makefile_error ();
+extern void makefile_fatal ();
+extern void pfatal_with_name ();
+extern void perror_with_name ();
+extern char *savestring ();
+extern char *concat ();
+extern char *xmalloc ();
+extern char *xrealloc ();
+extern char *find_next_token ();
+extern char *next_token ();
+extern char *end_of_token ();
+extern void collapse_continuations ();
+extern void remove_comments ();
+extern char *sindex ();
+extern char *lindex ();
extern int alpha_compare ();
extern void print_spaces ();
extern struct dep *copy_dep_chain ();
-extern char *find_char_unquote (), *find_percent ();
+extern char *find_char_unquote ();
+extern char *find_percent ();
#ifndef NO_ARCHIVES
extern int ar_name ();
@@ -280,16 +310,22 @@ extern time_t ar_member_date ();
#endif
extern void dir_load ();
-extern int dir_file_exists_p (), file_exists_p (), file_impossible_p ();
+extern int dir_file_exists_p ();
+extern int file_exists_p ();
+extern int file_impossible_p ();
extern void file_impossible ();
extern char *dir_name ();
extern void define_default_variables ();
-extern void set_default_suffixes (), install_default_suffix_rules ();
-extern void install_default_implicit_rules (), count_implicit_rule_limits ();
-extern void convert_to_pattern (), create_pattern_rule ();
-
-extern void build_vpath_lists (), construct_vpath_list ();
+extern void set_default_suffixes ();
+extern void install_default_suffix_rules ();
+extern void install_default_implicit_rules ();
+extern void count_implicit_rule_limits ();
+extern void convert_to_pattern ();
+extern void create_pattern_rule ();
+
+extern void build_vpath_lists ();
+extern void construct_vpath_list ();
extern int vpath_search ();
extern void construct_include_path ();
@@ -298,8 +334,9 @@ extern void uniquize_deps ();
extern int update_goal_chain ();
extern void notice_finished_file ();
-extern void user_access (), make_access (), child_access ();
-
+extern void user_access ();
+extern void make_access ();
+extern void child_access ();
#ifdef HAVE_VFORK_H
#include <vfork.h>
@@ -311,12 +348,17 @@ extern void user_access (), make_access (), child_access ();
#if !defined (__GNU_LIBRARY__) && !defined (POSIX) && !defined (_POSIX_VERSION)
extern long int atol ();
+#ifndef VMS
extern long int lseek ();
+#endif
#endif /* Not GNU C library or POSIX. */
#ifdef HAVE_GETCWD
extern char *getcwd ();
+#ifdef VMS
+extern char *getwd PARAMS ((char *));
+#endif
#else
extern char *getwd ();
#define getcwd(buf, len) getwd (buf)
@@ -349,3 +391,26 @@ extern int handling_fatal_signal;
#define DEBUGPR(msg) \
do if (debug_flag) { print_spaces (depth); printf (msg, file->name); \
fflush (stdout); } while (0)
+
+#ifdef VMS
+# ifndef EXIT_FAILURE
+# define EXIT_FAILURE 3
+# endif
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 1
+# endif
+# ifndef EXIT_TROUBLE
+# define EXIT_TROUBLE 2
+# endif
+#else
+# ifndef EXIT_FAILURE
+# define EXIT_FAILURE 2
+# endif
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# ifndef EXIT_TROUBLE
+# define EXIT_TROUBLE 1
+# endif
+#endif
+
diff --git a/makefile.com b/makefile.com
new file mode 100644
index 0000000..cba8fda
--- /dev/null
+++ b/makefile.com
@@ -0,0 +1,34 @@
+$!
+$! Makefile.com - builds GNU Make for VMS
+$!
+$! P1 is non-empty if you want to link with the VAXCRTL library instead
+$! of the shareable executable
+$!
+$ def/nolog sys sys$library:
+$ filelist = "alloca commands default dir expand file function implicit job main misc read remake remote-stub rule signame variable version vmsfunctions vmsify vpath [.glob]glob [.glob]fnmatch getopt getopt1"
+$ copy config.h-vms config.h
+$ n=0
+$ loop:
+$ cfile = f$elem(n," ",filelist)
+$ if cfile .eqs. " " then goto linkit
+$ write sys$output "Compiling ''cfile'..."
+$ call compileit 'cfile' 'p1'
+$ n = n + 1
+$ goto loop
+$ linkit:
+$ if p1 .nes. "" then goto link_using_library
+$ link/exe=make alloca,commands,default,dir,expand,file,function,-
+ implicit,job,main,misc,read,remake,remote-stub,rule,-
+ signame,variable,version,vmsfunctions,vmsify,vpath,-
+ glob,fnmatch,getopt,getopt1
+$ exit
+$ link_using_library:
+$ link/exe=make alloca,commands,default,dir,expand,file,function,-
+ implicit,job,main,misc,read,remake,remote-stub,rule,-
+ signame,variable,version,vmsfunctions,vmsfiy,vpath,-
+ glob,fnmatch,getopt,getopt1,sys$library:vaxcrtl/lib
+$!
+$ compileit : subroutine
+$ cc/include=([],[.glob])/define=("allocated_variable_expand_for_file=alloc_var_expand_for_file","unlink=remove","HAVE_CONFIG_H","VMS","NO_ARCHIVES") 'p1'
+$ exit
+$ endsubroutine : compileit
diff --git a/makefile.vms b/makefile.vms
new file mode 100644
index 0000000..d98afa8
--- /dev/null
+++ b/makefile.vms
@@ -0,0 +1,121 @@
+# Copyright (C) 1988, 1989 Free Software Foundation, Inc.
+# This file is part of GNU Make.
+#
+# VMS extensions from GNU Make 3.60 imported by
+# Klaus Kämpf (kkaempf@didymus.rmi.de)
+#
+# GNU Make is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# GNU Make is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Make; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+CC = cc/warn
+CP = copy
+
+%.obj: %.c
+ $(CC) $(CFLAGS)/obj=$@ $<
+#
+# Makefile for GNU Make
+#
+
+CFLAGS = $(defines) /debug/noopt/include=([],[.glob])
+#LDFLAGS = /deb
+LDFLAGS =
+
+defines = /define=("unlink=remove","HAVE_CONFIG_H","VMS","NO_ARCHIVES","allocated_variable_expand_for_file=alloc_var_expand_for_file")
+
+LOAD_AVG = /define="NO_LDAV"
+
+# If you don't want archive support, comment these out.
+#ARCHIVES = ,ar.obj,arscan.obj
+#ARCHIVES_SRC = ar.c arscan.c
+
+# If your system needs extra libraries loaded in, define them here.
+# System V probably need -lPW for alloca.
+# if on vax, uncomment the following line
+#LOADLIBES = ,c.opt/opt
+LOADLIBES =
+
+# If your system doesn't have alloca, or the one provided is bad,
+# get it from the Emacs distribution and define these.
+ALLOCA = ,alloca.obj
+ALLOCASRC = alloca.c
+
+# If there are remote execution facilities defined,
+# enable them with switches here (see remote-*.c).
+REMOTE =
+
+# Any extra object files your system needs.
+extras = ,signame.obj,remote-stub.obj,vmsfunctions.obj,vmsify.obj
+#,directory.obj
+# as an alternative:
+glob = ,[.glob]glob.obj,[.glob]fnmatch.obj
+getopt = ,getopt.obj,getopt1.obj
+# Directory to install `make' in.
+bindir = []
+# Directory to install the man page in.
+mandir = []
+# Number to put on the man page filename.
+manext = 1
+
+objs = commands.obj,job.obj,dir.obj,file.obj,misc.obj,\
+ main.obj,read.obj,remake.obj,rule.obj,implicit.obj,\
+ default.obj,variable.obj,expand.obj,function.obj,\
+ vpath.obj,version.obj$(ARCHIVES)$(ALLOCA)$(extras)$(getopt)$(glob)
+srcs = commands.c job.c dir.c file.c misc.c \
+ main.c read.c remake.c rule.c implicit.c \
+ default.c variable.c expand.c function.c \
+ vpath.c version.c vmsfunctions.c vmsify.c $(ARCHIVES_SRC) $(ALLOCASRC) \
+ commands.h dep.h filedef.h job.h make.h rule.h variable.h
+
+
+.PHONY: all doc
+all: config.h make.exe
+
+doc: make.info make.dvi
+
+
+make.exe: $(objs)
+ $(LD)$(LDFLAGS)/exe=$@ $^$(LOADLIBES)
+
+.PHONY: clean realclean
+clean:
+ -$(RM) make.exe;,*.obj;*
+
+# Automatically generated dependencies.
+commands.obj: commands.c make.h dep.h commands.h filedef.h variable.h job.h
+job.obj: job.c make.h commands.h job.h filedef.h variable.h
+dir.obj: dir.c make.h
+file.obj: file.c make.h commands.h dep.h filedef.h variable.h
+misc.obj: misc.c make.h dep.h
+main.obj: main.c make.h commands.h dep.h filedef.h variable.h job.h
+read.obj: read.c make.h commands.h dep.h filedef.h variable.h
+remake.obj: remake.c make.h commands.h job.h dep.h filedef.h
+rule.obj: rule.c make.h commands.h dep.h filedef.h variable.h rule.h
+implicit.obj: implicit.c make.h rule.h dep.h filedef.h
+default.obj: default.c make.h rule.h dep.h filedef.h commands.h variable.h
+variable.obj: variable.c make.h commands.h variable.h dep.h filedef.h
+expand.obj: expand.c make.h commands.h filedef.h variable.h
+function.obj: function.c make.h variable.h dep.h commands.h job.h
+vpath.obj: vpath.c make.h filedef.h variable.h
+version.obj: version.c
+arscan.obj: arscan.c
+ar.obj: ar.c make.h filedef.h
+signame.obj: signame.c
+remote-stub.obj: remote-stub.c
+[.glob]glob.obj: [.glob]glob.c
+[.glob]fnmatch.obj: [.glob]fnmatch.c
+getopt.obj: getopt.c
+getopt1.obj: getopt1.c
+
+config.h: config.h-vms
+ $(CP) $< $@
diff --git a/misc.c b/misc.c
index 88dfd60..10fce3a 100644
--- a/misc.c
+++ b/misc.c
@@ -271,7 +271,9 @@ strerror (errnum)
int errnum;
{
extern int errno, sys_nerr;
+#ifndef __DECC
extern char *sys_errlist[];
+#endif
static char buf[] = "Unknown error 12345678901234567890";
if (errno < sys_nerr)
@@ -540,6 +542,7 @@ log_access (flavor)
static void
init_access ()
{
+#ifndef VMS
user_uid = getuid ();
user_gid = getgid ();
@@ -553,6 +556,7 @@ init_access ()
log_access ("Initialized");
current_access = make;
+#endif
}
#endif /* GETLOADAVG_PRIVILEGED */
diff --git a/read.c b/read.c
index edbaf48..95c2169 100644
--- a/read.c
+++ b/read.c
@@ -17,9 +17,10 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
-#include "commands.h"
#include "dep.h"
-#include "file.h"
+#include "filedef.h"
+#include "job.h"
+#include "commands.h"
#include "variable.h"
/* This is POSIX.2, but most systems using -DPOSIX probably don't have it. */
@@ -29,15 +30,11 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "glob/glob.h"
#endif
+#ifndef VMS
#include <pwd.h>
-struct passwd *getpwnam ();
-
-
-static int read_makefile ();
-static unsigned int readline (), do_define ();
-static int conditional_line ();
-static void record_files ();
-
+#else
+struct passwd *getpwnam PARAMS ((char *name));
+#endif
/* A `struct linebuffer' is a structure which holds a line of text.
`readline' reads a line from a stream into a linebuffer
@@ -104,6 +101,18 @@ unsigned int *reading_lineno_ptr;
/* The chain of makefiles read by read_makefile. */
static struct dep *read_makefiles = 0;
+
+static int read_makefile PARAMS ((char *filename, int flags));
+static unsigned int readline PARAMS ((struct linebuffer *linebuffer, FILE *stream,
+ char *filename, unsigned int lineno));
+static unsigned int do_define PARAMS ((char *name, unsigned int namelen, enum variable_origin origin,
+ unsigned int lineno, FILE *infile, char *filename));
+static int conditional_line PARAMS ((char *line, char *filename, unsigned int lineno));
+static void record_files PARAMS ((struct nameseq *filenames, char *pattern, char *pattern_percent,
+ struct dep *deps, unsigned int commands_started, char *commands,
+ unsigned int commands_idx, int two_colon, char *filename,
+ unsigned int lineno, int set_default));
+static char *find_semicolon PARAMS ((char *s));
/* Read in all the makefiles and return the chain of their names. */
@@ -138,6 +147,7 @@ read_all_makefiles (makefiles)
/* Set NAME to the start of next token and LENGTH to its length.
MAKEFILES is updated for finding remaining tokens. */
p = value;
+
while ((name = find_next_token (&p, &length)) != 0)
{
if (*p != '\0')
@@ -176,7 +186,12 @@ read_all_makefiles (makefiles)
if (num_makefiles == 0)
{
static char *default_makefiles[] =
+#if VMS
+ /* all lower case since readdir() (the vms version) 'lowercasifies' */
+ { "makefile.vms", "gnumakefile", "makefile", 0 };
+#else
{ "GNUmakefile", "makefile", "Makefile", 0 };
+#endif
register char **p = default_makefiles;
while (*p != 0 && !file_exists_p (*p))
++p;
@@ -302,7 +317,6 @@ read_makefile (filename, flags)
/* If the makefile wasn't found and it's either a makefile from
the `MAKEFILES' variable or an included makefile,
search the included makefile search path for this makefile. */
-
if (infile == 0 && (flags & RM_INCLUDED) && *filename != '/')
{
register unsigned int i;
@@ -586,7 +600,7 @@ read_makefile (filename, flags)
{
struct nameseq *next = files->next;
char *name = files->name;
- free (files);
+ free ((char *)files);
files = next;
if (! read_makefile (name, (RM_INCLUDED | RM_NO_TILDE
@@ -1303,7 +1317,7 @@ record_files (filenames, pattern, pattern_percent, deps, commands_started,
{
struct dep *nextd = d->next;
free (d->name);
- free (d);
+ free ((char *)d);
d = nextd;
}
f->deps = 0;
@@ -1520,9 +1534,16 @@ parse_file_seq (stringp, stopchar, size, strip)
register char *p = *stringp;
char *q;
char *name;
- char stopchars[2];
+ char stopchars[3];
+
+#ifdef VMS
+ stopchars[0] = ',';
+ stopchars[1] = stopchar;
+ stopchars[2] = '\0';
+#else
stopchars[0] = stopchar;
stopchars[1] = '\0';
+#endif
while (1)
{
@@ -1532,9 +1553,16 @@ parse_file_seq (stringp, stopchar, size, strip)
break;
if (*p == stopchar)
break;
+
/* Yes, find end of next name. */
q = p;
p = find_char_unquote (q, stopchars, 1);
+#ifdef VMS
+ /* convert comma separated list to space separated */
+ if (p && *p == ',')
+ *p =' ';
+#endif
+
#ifdef __MSDOS__
/* For MS-DOS, skip a "C:\...". */
if (stopchar == ':' && p != 0 && p[1] == '\\' && isalpha (p[-1]))
@@ -1544,8 +1572,13 @@ parse_file_seq (stringp, stopchar, size, strip)
p = q + strlen (q);
if (strip)
+#ifdef VMS
+ /* Skip leading `[]'s. */
+ while (p - q > 2 && q[0] == '[' && q[1] == ']')
+#else
/* Skip leading `./'s. */
while (p - q > 2 && q[0] == '.' && q[1] == '/')
+#endif
{
q += 2; /* Skip "./". */
while (q < p && *q == '/')
@@ -1556,10 +1589,40 @@ parse_file_seq (stringp, stopchar, size, strip)
/* Extract the filename just found, and skip it. */
if (q == p)
- /* ".///" was stripped to "". */
+ /* ".///" was stripped to "". */
+#ifdef VMS
+ continue;
+#else
name = savestring ("./", 2);
+#endif
else
+#ifdef VMS
+/* VMS filenames can have a ':' in them but they have to be '\'ed but we need
+ * to remove this '\' before we can use the filename.
+ * Savestring called because q may be read-only string constant.
+ */
+ {
+ char *qbase = savestring(q, strlen(q));
+ char *pbase = qbase + (p-q);
+ char *q1 = qbase;
+ char *q2 = q1;
+ char *p1 = pbase;
+
+ while (q1 != pbase)
+ {
+ if (*q1 == '\\' && *(q1+1) == ':')
+ {
+ q1++;
+ p1--;
+ }
+ *q2++ = *q1++;
+ }
+ name = savestring (qbase, p1 - qbase);
+ free (qbase);
+ }
+#else
name = savestring (q, p - q);
+#endif
/* Add it to the front of the chain. */
new1 = (struct nameseq *) xmalloc (size);
@@ -1787,8 +1850,11 @@ construct_include_path (arg_dirs)
char **arg_dirs;
{
register unsigned int i;
+#ifdef VAXC /* just don't ask ... */
+ stat_t stbuf;
+#else
struct stat stbuf;
-
+#endif
/* Table to hold the dirs. */
register unsigned int defsize = (sizeof (default_include_directories)
@@ -1860,6 +1926,7 @@ char *
tilde_expand (name)
char *name;
{
+#ifndef VMS
if (name[1] == '/' || name[1] == '\0')
{
extern char *getenv ();
@@ -1919,7 +1986,7 @@ tilde_expand (name)
else if (userend != 0)
*userend = '/';
}
-
+#endif /* !VMS */
return 0;
}
@@ -2037,7 +2104,7 @@ multi_glob (chain, size)
}
globfree (&gl);
free (old->name);
- free (old);
+ free ((char *)old);
break;
}
diff --git a/readme.vms b/readme.vms
new file mode 100644
index 0000000..f54be73
--- /dev/null
+++ b/readme.vms
@@ -0,0 +1,62 @@
+This is the VMS port of GNU Make version 3.74.
+
+It is based on the VMS port of GNU Make 3.60 by Mike Moretti.
+
+This port was done by Klaus Kämpf (kkaempf@didymus.rmi.de)
+
+To build Make, simply type @makefile. This should compile all the
+necessary files and link Make.
+There is also a file called makefile.vms. If you already have GNU
+Make 3.74 built you can just use Make with this makefile to rebuild.
+
+Here are some notes about GNU Make for VMS:
+
+Libraries are not supported. They were in GNU Make 3.60 but somehow I didn't
+care porting the code. If there is enough interest, I'll do it at some
+later time.
+
+The variable $^ separates files with commas instead of spaces (It's the
+natural thing to do for VMS).
+
+See defaults.c for VMS default suffixes and my definitions for default
+rules and variables.
+
+The shell function is not implemented yet.
+
+Load average routines haven't been implemented for VMS yet.
+
+The default include directory for including other makefiles is
+SYS$SYSROOT:[SYSLIB] (I don't remember why I didn't just use
+SYS$LIBRARY: instead; maybe it wouldn't work that way).
+
+The default makefiles make looks for are: makefile.vms, gnumakefile, makefile.,
+and gnumakefile. .
+
+The stat() function and handling of time stamps in VMS is broken, so I
+replaced it with a hack in vmsfunctions.c. I will provide a full rewrite
+somewhere in the future. Be warned, the time resolution inside make is
+less than what vms provides. This might be a problem on the faster Alphas.
+
+You can use a : in a filename only if you preceed it with a backslash ('\').
+E.g.- hobbes\:[bogas.files]
+
+None of the stuff in vpath.c has been implemented yet.
+
+Make ignores success, informational, or warning errors (-S-, -I-, or -W-).
+But it will stop on -E- and -F- errors. (unless you do something to override
+this in your makefile, or whatever).
+
+Remote stuff isn't implemented yet.
+
+Multiple line DCL commands, such as "if" statements, must be put inside
+command files. You can run a command file by using \@.
+
+
+VMS changes made for 3.74.3
+
+Lots of default settings are adapted for VMS. See default.c.
+
+Long command lines are now converted to command files.
+
+Comma (',') as a separator is now allowed. See makefile.vms for an example.
+
diff --git a/remake.c b/remake.c
index 7245531..befb7ad 100644
--- a/remake.c
+++ b/remake.c
@@ -17,10 +17,10 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
-#include "commands.h"
+#include "filedef.h"
#include "job.h"
+#include "commands.h"
#include "dep.h"
-#include "file.h"
#include <assert.h>
#ifdef HAVE_FCNTL_H
@@ -29,17 +29,30 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <sys/file.h>
#endif
-extern int try_implicit_rule ();
+#ifdef VMS
+#include <starlet.h>
+#endif
+
+extern int try_implicit_rule PARAMS ((struct file *file, unsigned int depth));
/* Incremented when a command is started (under -n, when one would be). */
unsigned int commands_started = 0;
-static int update_file (), update_file_1 (), check_dep (), touch_file ();
-static void remake_file ();
-static time_t name_mtime ();
-static int library_search ();
-extern time_t f_mtime ();
+static int update_file PARAMS ((struct file *file, unsigned int depth));
+static int update_file_1 PARAMS ((struct file *file, unsigned int depth));
+static int check_dep PARAMS ((struct file *file, unsigned int depth, time_t this_mtime, int *must_make_ptr));
+static int touch_file PARAMS ((struct file *file));
+static void remake_file PARAMS ((struct file *file));
+static time_t name_mtime PARAMS ((char *name));
+static int library_search PARAMS ((char **lib, time_t *mtime_ptr));
+
+extern time_t f_mtime PARAMS ((struct file *file, int search));
+
+#ifdef VMS
+extern int vms_stat PARAMS ((char *name, struct stat *buf));
+#endif
+
/* Remake all the goals in the `struct dep' chain GOALS. Return -1 if nothing
was done, 0 if all goals were updated successfully, or 1 if a goal failed.
@@ -100,6 +113,7 @@ update_goal_chain (goals, makefiles)
/* Iterate over all double-colon entries for this file. */
struct file *file = g->file;
int stop, any_not_updated = 0;
+
for (file = g->file->double_colon ? g->file->double_colon : g->file;
file != NULL;
file = file->prev)
@@ -108,7 +122,6 @@ update_goal_chain (goals, makefiles)
int x;
time_t mtime = MTIME (file);
check_renamed (file);
-
if (makefiles)
{
if (file->cmd_target)
@@ -229,7 +242,6 @@ update_goal_chain (goals, makefiles)
just_print_flag = n;
job_slots = j;
}
-
return status;
}
@@ -1015,12 +1027,28 @@ f_mtime (file, search)
unrecoverably absent. */
static time_t now;
+#ifdef VMS
+ /* Handle vms 64bit to 32bit time hack introduced in vms_stat() ... */
+ static unsigned long vms_now[2]; /* assumes 32 bit long ! */
+ static int vms_now_set = 0;
+
+ if (!vms_now_set)
+ {
+ sys$gettim(vms_now);
+ now = ((vms_now[0]>>24) & 0xff) + ((vms_now[1]<<8) & 0xffffff00);
+ vms_now_set = 1;
+ }
+#endif
if (mtime > now && ! file->updated)
{
/* This file's time appears to be in the future.
Update our concept of the present, and compare again. */
+#ifndef VMS
extern time_t time ();
if (mtime > time (&now))
+#else
+ if ((mtime != -1) && (mtime > now))
+#endif
{
error ("*** File `%s' has modification time in the future",
file->name);
@@ -1050,7 +1078,11 @@ name_mtime (name)
{
struct stat st;
+#ifdef VMS
+ if (vms_stat (name, &st) < 0)
+#else
if (stat (name, &st) < 0)
+#endif
return (time_t) -1;
return (time_t) st.st_mtime;
diff --git a/remote-stub.c b/remote-stub.c
index 24a860b..439c35e 100644
--- a/remote-stub.c
+++ b/remote-stub.c
@@ -17,6 +17,8 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
+#include "filedef.h"
+#include "job.h"
#include "commands.h"
diff --git a/rule.c b/rule.c
index b69212d..d38cf54 100644
--- a/rule.c
+++ b/rule.c
@@ -17,13 +17,14 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
-#include "commands.h"
#include "dep.h"
-#include "file.h"
+#include "filedef.h"
+#include "job.h"
+#include "commands.h"
#include "variable.h"
#include "rule.h"
-static void freerule ();
+static void freerule PARAMS ((struct rule *rule, struct rule *lastrule));
/* Chain of all pattern rules. */
@@ -96,9 +97,13 @@ count_implicit_rule_limits ()
for (dep = rule->deps; dep != 0; dep = dep->next)
{
unsigned int len = strlen (dep->name);
+
+#ifdef VMS
+ char *p = rindex (dep->name, ']');
+#else
char *p = rindex (dep->name, '/');
+#endif
char *p2 = p != 0 ? index (dep->name, '%') : 0;
-
ndeps++;
if (len > max_pattern_dep_length)
@@ -125,7 +130,11 @@ count_implicit_rule_limits ()
nonexistent subdirectory. */
dep->changed = !dir_file_exists_p (name, "");
+#ifdef VMS
+ if (dep->changed && *name == ']')
+#else
if (dep->changed && *name == '/')
+#endif
{
/* The name is absolute and the directory does not exist.
This rule can never possibly match, since this dependency
@@ -173,7 +182,11 @@ convert_suffix_rule (target, source, cmds)
/* Special case: TARGET being nil means we are defining a
`.X.a' suffix rule; the target pattern is always `(%.o)'. */
{
+#ifdef VMS
+ targname = savestring ("(%.obj)", 7);
+#else
targname = savestring ("(%.o)", 5);
+#endif
targpercent = targname + 1;
}
else
diff --git a/rule.h b/rule.h
index 75d43d6..9c6b1b0 100644
--- a/rule.h
+++ b/rule.h
@@ -49,5 +49,5 @@ extern struct file *suffix_file;
extern unsigned int maxsuffix;
-extern void install_pattern_rule ();
-int new_pattern_rule ();
+extern void install_pattern_rule PARAMS ((struct pspec *p, int terminal));
+extern int new_pattern_rule PARAMS ((struct rule *rule, int override));
diff --git a/variable.c b/variable.c
index 319826f..a414516 100644
--- a/variable.c
+++ b/variable.c
@@ -17,10 +17,11 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
+#include "dep.h"
+#include "filedef.h"
+#include "job.h"
#include "commands.h"
#include "variable.h"
-#include "dep.h"
-#include "file.h"
/* Hash table of all global variable definitions. */
@@ -39,6 +40,11 @@ static struct variable_set global_variable_set
static struct variable_set_list global_setlist
= { 0, &global_variable_set };
struct variable_set_list *current_variable_set_list = &global_setlist;
+
+static struct variable *define_variable_in_set PARAMS ((char *name, unsigned int length,
+ char *value, enum variable_origin origin,
+ int recursive, struct variable_set *set));
+
/* Implement variables. */
diff --git a/variable.h b/variable.h
index 8096179..79d9739 100644
--- a/variable.h
+++ b/variable.h
@@ -70,31 +70,40 @@ struct variable_set_list
extern struct variable_set_list *current_variable_set_list;
-
-extern void push_new_variable_scope (), pop_variable_scope ();
-
-extern int handle_function ();
-
-extern char *variable_buffer_output ();
-extern char *variable_expand (), *variable_expand_for_file ();
-extern char *allocated_variable_expand_for_file ();
+/* expand.c */
+extern char *variable_buffer_output PARAMS ((char *ptr, char *string, unsigned int length));
+extern char *variable_expand PARAMS ((char *line));
+extern char *variable_expand_for_file PARAMS ((char *line, struct file *file));
+extern char *allocated_variable_expand_for_file PARAMS ((char *line, struct file *file));
#define allocated_variable_expand(line) \
allocated_variable_expand_for_file (line, (struct file *) 0)
-extern char *expand_argument ();
-
-extern void define_automatic_variables ();
-extern void initialize_file_variables ();
-extern void print_file_variables ();
-
-extern void merge_variable_set_lists ();
-
-extern struct variable *try_variable_definition ();
-
-extern struct variable *lookup_variable (), *define_variable ();
-extern struct variable *define_variable_for_file ();
-
-extern int pattern_matches ();
-extern char *subst_expand (), *patsubst_expand (), *recursively_expand ();
+extern char *expand_argument PARAMS ((char *str, char *end));
+
+/* function.c */
+extern int handle_function PARAMS ((char **op, char **stringp));
+extern int pattern_matches PARAMS ((char *pattern, char *percent, char *word));
+extern char *subst_expand PARAMS ((char *o, char *text, char *subst, char *replace,
+ unsigned int slen, unsigned int rlen, int by_word, int suffix_only));
+extern char *patsubst_expand PARAMS ((char *o, char *text, char *pattern, char *replace,
+ char *pattern_percent, char *replace_percent));
+
+/* expand.c */
+extern char *recursively_expand PARAMS ((struct variable *v));
+
+/* variable.c */
+extern void push_new_variable_scope PARAMS ((void));
+extern void pop_variable_scope PARAMS ((void));
+extern void define_automatic_variables PARAMS ((void));
+extern void initialize_file_variables PARAMS ((struct file *file));
+extern void print_file_variables PARAMS ((struct file *file));
+extern void merge_variable_set_lists PARAMS ((struct variable_set_list **setlist0, struct variable_set_list *setlist1));
+extern struct variable *try_variable_definition PARAMS ((char *filename, unsigned int lineno, char *line, enum variable_origin origin));
+
+extern struct variable *lookup_variable PARAMS ((char *name, unsigned int length));
+extern struct variable *define_variable PARAMS ((char *name, unsigned int length, char *value,
+ enum variable_origin origin, int recursive));
+extern struct variable *define_variable_for_file PARAMS ((char *name, unsigned int length,
+ char *value, enum variable_origin origin, int recursive, struct file *file));
+extern char **target_environment PARAMS ((struct file *file));
-extern char **target_environment ();
extern int export_all_variables;
diff --git a/vmsdir.h b/vmsdir.h
new file mode 100644
index 0000000..50b50e8
--- /dev/null
+++ b/vmsdir.h
@@ -0,0 +1,40 @@
+/* dirent.h for vms */
+
+#include <rms.h>
+
+#define MAXNAMLEN 255
+
+typedef unsigned long u_long;
+typedef unsigned short u_short;
+
+struct direct {
+ off_t d_off;
+ u_long d_fileno;
+ u_short d_reclen;
+ u_short d_namlen;
+ char d_name[MAXNAMLEN + 1];
+};
+
+#undef DIRSIZ
+#define DIRSIZ(dp) \
+ (((sizeof (struct direct) - (MAXNAMLEN+1) + ((dp)->d_namlen+1)) + 3) & ~3)
+
+#define d_ino d_fileno /* compatability */
+
+
+/*
+ * Definitions for library routines operating on directories.
+ */
+
+typedef struct FAB DIR;
+
+#ifndef NULL
+#define NULL 0
+#endif
+extern DIR *opendir PARAMS (());
+extern struct direct *readdir PARAMS ((DIR *dfd));
+#define rewinddir(dirp) seekdir((dirp), (long)0)
+extern int closedir PARAMS ((DIR *dfd));
+extern char *vmsify PARAMS ((char *name, int type));
+
+/* EOF */
diff --git a/vmsfunctions.c b/vmsfunctions.c
new file mode 100644
index 0000000..a76609c
--- /dev/null
+++ b/vmsfunctions.c
@@ -0,0 +1,234 @@
+#define KDEBUG 0
+/* vmsfunctions.c */
+
+#include <stdio.h>
+#include "make.h"
+#ifdef __DECC
+#include <starlet.h>
+#endif
+#include <descrip.h>
+#include <rms.h>
+#include <iodef.h>
+#include <atrdef.h>
+#include <fibdef.h>
+#include "vmsdir.h"
+
+DIR *opendir(char *dspec)
+{
+ static struct FAB *dfab;
+ struct NAM *dnam;
+ char *searchspec;
+
+ if ((dfab = (struct FAB *)xmalloc(sizeof (struct FAB))) == NULL) {
+ printf("Error mallocing for FAB\n");
+ return(NULL);
+ }
+ if ((dnam = (struct NAM *)xmalloc(sizeof (struct NAM))) == NULL) {
+ printf("Error mallocing for NAM\n");
+ free(dfab);
+ return(NULL);
+ }
+ if ((searchspec = (char *)xmalloc(MAXNAMLEN+1)) == NULL) {
+ printf("Error mallocing for searchspec\n");
+ free(dfab);
+ free(dnam);
+ return(NULL);
+ }
+
+ sprintf(searchspec,"%s*.*;",dspec);
+
+ *dfab = cc$rms_fab;
+ dfab->fab$l_fna = searchspec;
+ dfab->fab$b_fns = strlen(searchspec);
+ dfab->fab$l_nam = dnam;
+
+ *dnam = cc$rms_nam;
+ dnam->nam$l_esa = searchspec;
+ dnam->nam$b_ess = MAXNAMLEN;
+
+ if (!(sys$parse(dfab) & 1)) {
+ free(dfab);
+ free(dnam);
+ free(searchspec);
+ return(NULL);
+ }
+
+ return(dfab);
+}
+
+#include <ctype.h>
+#define uppercasify(str) { char *tmp; for(tmp = (str); *tmp != '\0'; tmp++) if(islower(*tmp)) *tmp = toupper(*tmp); }
+
+struct direct *readdir(DIR *dfd)
+{
+ static struct direct *dentry;
+ static char resultspec[MAXNAMLEN+1];
+ int i;
+
+ if ((dentry = (struct direct *)xmalloc(sizeof (struct direct))) == NULL) {
+ printf("Error mallocing for direct\n");
+ return(NULL);
+ }
+
+ dfd->fab$l_nam->nam$l_rsa = resultspec;
+ dfd->fab$l_nam->nam$b_rss = MAXNAMLEN;
+
+ if (debug_flag)
+ printf(".");
+
+ if (!((i = sys$search(dfd)) & 1)) {
+ if (debug_flag)
+ printf("sys$search failed with %d\n", i);
+ free(dentry);
+ return(NULL);
+ }
+
+ dentry->d_off = 0;
+ if (dfd->fab$l_nam->nam$w_fid == 0)
+ dentry->d_fileno = 1;
+ else dentry->d_fileno = dfd->fab$l_nam->nam$w_fid[0]
+ +dfd->fab$l_nam->nam$w_fid[1]<<16;
+ dentry->d_reclen = sizeof (struct direct);
+/*
+ if (!strcmp(dfd->fab$l_nam->nam$l_type,".DIR"))
+ dentry->d_namlen = dfd->fab$l_nam->nam$b_name;
+ else
+*/
+ dentry->d_namlen = dfd->fab$l_nam->nam$b_name+dfd->fab$l_nam->nam$b_type;
+ strncpy(dentry->d_name,dfd->fab$l_nam->nam$l_name,dentry->d_namlen);
+ dentry->d_name[dentry->d_namlen] = '\0';
+ uppercasify(dentry->d_name);
+/* uvUnFixRCSSeparator(dentry->d_name);*/
+
+ return(dentry);
+}
+
+closedir(DIR *dfd)
+{
+ if (dfd != NULL) {
+ if (dfd->fab$l_nam != NULL)
+ free(dfd->fab$l_nam->nam$l_esa);
+ free(dfd->fab$l_nam);
+ free(dfd);
+ }
+}
+
+char *getwd(char *cwd)
+{
+ static char buf[512];
+
+ if (cwd)
+ return(getcwd(cwd,512));
+ else
+ return(getcwd(buf,512));
+}
+
+int
+vms_stat (name, buf)
+ char *name;
+ struct stat *buf;
+{
+ int status;
+ int i;
+
+ static struct FAB Fab;
+ static struct NAM Nam;
+ static struct fibdef Fib; /* short fib */
+ static struct dsc$descriptor FibDesc =
+ {sizeof(Fib), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (char *)&Fib};
+ static struct dsc$descriptor_s DevDesc =
+ {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, &Nam.nam$t_dvi[1]};
+ static char EName[NAM$C_MAXRSS];
+ static char RName[NAM$C_MAXRSS];
+ static struct dsc$descriptor_s FileName =
+ {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
+ static struct dsc$descriptor_s string =
+ {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
+ static unsigned long Rdate[2];
+ static unsigned long Cdate[2];
+ static struct atrdef Atr[] = {
+ {sizeof(Rdate),ATR$C_REVDATE,&Rdate[0]}, /* Revision date */
+ {sizeof(Cdate),ATR$C_CREDATE,&Cdate[0]}, /* Creation date */
+ {0,0,0}
+ };
+ static short int DevChan;
+ static short int iosb[4];
+
+ name = vmsify (name, 0);
+
+ /* initialize RMS structures, we need a NAM to retrieve the FID */
+ Fab = cc$rms_fab;
+ Fab.fab$l_fna = name ; /* name of file */
+ Fab.fab$b_fns = strlen(name);
+ Fab.fab$l_nam = &Nam; /* FAB has an associated NAM */
+
+ Nam = cc$rms_nam;
+ Nam.nam$l_esa = EName; /* expanded filename */
+ Nam.nam$b_ess = sizeof(EName);
+ Nam.nam$l_rsa = RName; /* resultant filename */
+ Nam.nam$b_rss = sizeof(RName);
+
+ /* do $PARSE and $SEARCH here */
+ status = sys$parse(&Fab);
+ if (!(status & 1))
+ return -1;
+
+ DevDesc.dsc$w_length = Nam.nam$t_dvi[0];
+ status = sys$assign(&DevDesc,&DevChan,0,0);
+ if (!(status & 1))
+ return -1;
+
+ FileName.dsc$a_pointer = Nam.nam$l_name;
+ FileName.dsc$w_length = Nam.nam$b_name+Nam.nam$b_type+Nam.nam$b_ver;
+
+ /* Initialize the FIB */
+ for (i=0;i<3;i++)
+ {
+#if __DECC
+ Fib.fib$w_fid[i]=Nam.nam$w_fid[i];
+ Fib.fib$w_did[i]=Nam.nam$w_did[i];
+#else
+ Fib.fib$r_fid_overlay.fib$w_fid[i]=Nam.nam$w_fid[i];
+ Fib.fib$r_did_overlay.fib$w_did[i]=Nam.nam$w_did[i];
+#endif
+ }
+
+ status = sys$qiow(0,DevChan,IO$_ACCESS,&iosb,0,0,
+ &FibDesc,&FileName,0,0,&Atr,0);
+ if (!(status & 1))
+ return -1;
+ status = iosb[0];
+ if (!(status & 1))
+ return -1;
+
+ status = stat (name, buf);
+ if (status)
+ return -1;
+
+ buf->st_mtime = ((Rdate[0]>>24) & 0xff) + ((Rdate[1]<<8) & 0xffffff00);
+ buf->st_ctime = ((Cdate[0]>>24) & 0xff) + ((Cdate[1]<<8) & 0xffffff00);
+ return 0;
+}
+
+char *
+cvt_time(tval)
+ unsigned long tval;
+{
+ static long int date[2];
+ static char str[27];
+ static struct dsc$descriptor date_str =
+ {26, DSC$K_DTYPE_T, DSC$K_CLASS_S, str};
+
+ date[0] = (tval & 0xff) << 24;
+ date[1] = ((tval>>8) & 0xffffff);
+
+ if ((date[0]==0) && (date[1]==0))
+ return("never");
+
+ sys$asctim(0,&date_str,date,0);
+ str[26]='\0';
+
+ return(str);
+}
+
+/* EOF */
diff --git a/vmsify.c b/vmsify.c
new file mode 100644
index 0000000..7d1fa6f
--- /dev/null
+++ b/vmsify.c
@@ -0,0 +1,925 @@
+/*
+ vmsify.c
+
+ Module for vms <-> unix file name conversion
+
+ Written by Klaus Kämpf (kkaempf@didymus.rmi.de)
+
+*/
+
+#include <string.h>
+#include <ctype.h>
+
+#if VMS
+#include <unixlib.h>
+#include <stdlib.h>
+#include <jpidef.h>
+#include <descrip.h>
+#include <uaidef.h>
+#include <ssdef.h>
+#include <starlet.h>
+#include <lib$routines.h>
+/* Initialize a string descriptor (struct dsc$descriptor_s) for an
+ arbitrary string. ADDR is a pointer to the first character
+ of the string, and LEN is the length of the string. */
+
+#define INIT_DSC_S(dsc, addr, len) do { \
+ (dsc).dsc$b_dtype = DSC$K_DTYPE_T; \
+ (dsc).dsc$b_class = DSC$K_CLASS_S; \
+ (dsc).dsc$w_length = (len); \
+ (dsc).dsc$a_pointer = (addr); \
+} while (0)
+
+/* Initialize a string descriptor (struct dsc$descriptor_s) for a
+ NUL-terminated string. S is a pointer to the string; the length
+ is determined by calling strlen(). */
+
+#define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s))
+#endif
+
+/*
+ copy 'from' to 'to' up to but not including 'upto'
+ return 0 if eos on from
+ return 1 if upto found
+
+ return 'to' at last char + 1
+ return 'from' at match + 1 or eos if no match
+
+ if as_dir == 1, change all '.' to '_'
+ else change all '.' but the last to '_'
+*/
+
+static int
+copyto (char **to, char **from, char upto, int as_dir)
+{
+ char *s;
+
+ s = strrchr (*from, '.');
+
+ while (**from)
+ {
+ if (**from == upto)
+ {
+ do
+ {
+ (*from)++;
+ }
+ while (**from == upto);
+ return 1;
+ }
+ if (**from == '.')
+ {
+ if ((as_dir == 1)
+ || (*from != s))
+ **to = '_';
+ else
+ **to = '.';
+ }
+ else
+ {
+ if (islower (**from))
+ **to = toupper (**from);
+ else
+ **to = **from;
+ }
+ (*to)++;
+ (*from)++;
+ }
+
+ return 0;
+}
+
+
+/*
+ get translation of logical name
+
+*/
+
+static char *
+trnlog (char *name)
+{
+ int stat;
+ static char reslt[1024];
+ $DESCRIPTOR (reslt_dsc, reslt);
+ short resltlen;
+ struct dsc$descriptor_s name_dsc;
+ char *s;
+
+ INIT_DSC_CSTRING (name_dsc, name);
+
+ stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
+
+ if ((stat&1) == 0)
+ {
+ return "";
+ }
+ if (stat == SS$_NOTRAN)
+ {
+ return "";
+ }
+ reslt[resltlen] = '\0';
+
+ s = (char *)malloc (resltlen+1);
+ if (s == 0)
+ return "";
+ strcpy (s, reslt);
+ return s;
+}
+
+enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE };
+
+/*
+ convert unix style name to vms style
+ type = 0 -> name is a full name (directory and filename part)
+ type = 1 -> name is a directory
+ type = 2 -> name is a filename without directory
+
+ The following conversions are applied
+ (0) (1) (2)
+ input full name dir name file name
+
+1 ./ <cwd> [] <current directory>.dir
+2 ../ <home of cwd> <home of cwd> <home of cwd>.dir
+
+3 // <dev of cwd>: <dev of cwd>:[000000] <dev of cwd>:000000.dir
+4 //a a: a: a:
+5 //a/ a: a: a:000000.dir
+
+9 / [000000] [000000] 000000.dir
+10 /a [000000]a [a] [000000]a
+11 /a/ [a] [a] [000000]a.dir
+12 /a/b [a]b [a.b] [a]b
+13 /a/b/ [a.b] [a.b] [a]b.dir
+14 /a/b/c [a.b]c [a.b.c] [a.b]c
+15 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir
+
+16 a a [.a] a
+17 a/ [.a] [.a] a.dir
+18 a/b [.a]b [.a.b] [.a]b
+19 a/b/ [.a.b] [.a.b] [.a]b.dir
+20 a/b/c [.a.b]c [.a.b.c] [.a.b]c
+21 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir
+
+22 a.b.c a_b.c [.a_b_c] a_b_c.dir
+
+23 [x][y]z [x.y]z [x.y]z [x.y]z
+24 [x][.y]z [x.y]z [x.y]z [x.y]z
+
+25 filenames with '$' are left unchanged if they contain no '/'
+25 filenames with ':' are left unchanged
+26 filenames with a single pair of '[' ']' are left unchanged
+
+ the input string is not written to
+*/
+
+char *
+vmsify (name, type)
+ char *name;
+ int type;
+{
+/* max 255 device
+ max 39 directory
+ max 39 filename
+ max 39 filetype
+ max 5 version
+*/
+#define MAXPATHLEN 512
+
+ enum namestate nstate;
+ static char vmsname[MAXPATHLEN+1];
+ char *fptr;
+ char *vptr;
+ char *s,*s1;
+ int as_dir;
+ int count;
+
+ if (name == 0)
+ return 0;
+ fptr = name;
+ vptr = vmsname;
+ nstate = N_START;
+
+ /* case 25a */
+
+ s = strpbrk (name, "$:");
+ if (s != 0)
+ {
+ if (*s == '$')
+ {
+ if (strchr (name, '/') == 0)
+ {
+ return name;
+ }
+ }
+ else
+ {
+ return name;
+ }
+ }
+
+ /* case 26 */
+
+ s = strchr (name, '[');
+
+ if (s != 0)
+ {
+ s1 = strchr (s+1, '[');
+ if (s1 == 0)
+ {
+ return name; /* single [, keep unchanged */
+ }
+ s1--;
+ if (*s1 != ']')
+ {
+ return name; /* not ][, keep unchanged */
+ }
+
+ /* we have ][ */
+
+ s = name;
+
+ /* s -> starting char
+ s1 -> ending ']' */
+
+ do
+ {
+ strncpy (vptr, s, s1-s); /* copy up to but not including ']' */
+ vptr += s1-s;
+ if (*s1 == 0)
+ break;
+ s = s1 + 1; /* s -> char behind ']' */
+ if (*s != '[') /* was '][' ? */
+ break; /* no, last ] found, exit */
+ s++;
+ if (*s != '.')
+ *vptr++ = '.';
+ s1 = strchr (s, ']');
+ if (s1 == 0) /* no closing ] */
+ s1 = s + strlen (s);
+ }
+ while (1);
+
+ *vptr++ = ']';
+
+ fptr = s;
+
+ }
+
+ else /* no [ in name */
+
+ {
+
+ int state;
+ int rooted = 1; /* flag if logical is rooted, else insert [000000] */
+
+ state = 0;
+
+ do
+ {
+
+ switch (state)
+ {
+ case 0: /* start of loop */
+ if (*fptr == '/')
+ {
+ fptr++;
+ state = 1;
+ }
+ else if (*fptr == '.')
+ {
+ fptr++;
+ state = 10;
+ }
+ else
+ state = 2;
+ break;
+
+ case 1: /* '/' at start */
+ if (*fptr == '/')
+ {
+ fptr++;
+ state = 3;
+ }
+ else
+ state = 4;
+ break;
+
+ case 2: /* no '/' at start */
+ s = strchr (fptr, '/');
+ if (s == 0) /* no '/' (16) */
+ {
+ if (type == 1)
+ {
+ strcpy (vptr, "[.");
+ vptr += 2;
+ }
+ copyto (&vptr, &fptr, 0, (type==1));
+ if (type == 1)
+ *vptr++ = ']';
+ state = -1;
+ }
+ else /* found '/' (17..21) */
+ {
+ if ((type == 2)
+ && (*(s+1) == 0)) /* 17(2) */
+ {
+ copyto (&vptr, &fptr, '/', 1);
+ state = 7;
+ }
+ else
+ {
+ strcpy (vptr, "[.");
+ nstate = N_DOT;
+ vptr += 2;
+ copyto (&vptr, &fptr, '/', 1);
+ state = 9;
+ }
+ }
+ break;
+
+ case 3: /* '//' at start */
+ while (*fptr == '/') /* collapse all '/' */
+ fptr++;
+ if (*fptr == 0) /* just // */
+ {
+ char cwdbuf[MAXPATHLEN+1];
+
+ s1 = getcwd(cwdbuf, MAXPATHLEN);
+ if (s1 == 0)
+ {
+ return ""; /* FIXME, err getcwd */
+ }
+ s = strchr (s1, ':');
+ if (s == 0)
+ {
+ return ""; /* FIXME, err no device */
+ }
+ strncpy (vptr, s1, s-s1+1);
+ vptr += s-s1+1;
+ state = -1;
+ break;
+ }
+
+ s = vptr;
+
+ if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */
+ {
+ *vptr++ = ':';
+ state = -1;
+ break;
+ }
+ *vptr = ':';
+ nstate = N_DEVICE;
+ if (*fptr == 0) /* just '//a/' */
+ {
+ strcpy (vptr+1, "[000000]");
+ vptr += 9;
+ state = -1;
+ break;
+ }
+ *vptr = 0;
+ /* check logical for [000000] insertion */
+ s1 = trnlog (s);
+ if (*s1 != 0)
+ { /* found translation */
+ char *s2;
+ for (;;) /* loop over all nested logicals */
+ {
+ s2 = s1 + strlen (s1) - 1;
+ if (*s2 == ':') /* translation ends in ':' */
+ {
+ s2 = trnlog (s1);
+ free (s1);
+ if (*s2 == 0)
+ {
+ rooted = 0;
+ break;
+ }
+ s1 = s2;
+ continue; /* next iteration */
+ }
+ if (*s2 == ']') /* translation ends in ']' */
+ {
+ if (*(s2-1) == '.') /* ends in '.]' */
+ {
+ if (strncmp (fptr, "000000", 6) != 0)
+ rooted = 0;
+ }
+ else
+ {
+ strcpy (vmsname, s1);
+ s = strchr (vmsname, ']');
+ *s = '.';
+ nstate = N_DOT;
+ vptr = s;
+ }
+ }
+ break;
+ }
+ free (s1);
+ }
+ else
+ rooted = 0;
+
+ if (*vptr == 0)
+ {
+ nstate = N_DEVICE;
+ *vptr++ = ':';
+ }
+ else
+ vptr++;
+
+ if (rooted == 0)
+ {
+ strcpy (vptr, "[000000.");
+ vptr += 8;
+ s1 = vptr-1;
+ nstate = N_DOT;
+ }
+ else
+ s1 = 0;
+
+ /* s1-> '.' after 000000 or NULL */
+
+ s = strchr (fptr, '/');
+ if (s == 0)
+ { /* no next '/' */
+ if (*(vptr-1) == '.')
+ *(vptr-1) = ']';
+ else if (rooted == 0)
+ *vptr++ = ']';
+ copyto (&vptr, &fptr, 0, (type == 1));
+ state = -1;
+ break;
+ }
+ else
+ {
+ while (*(s+1) == '/') /* skip multiple '/' */
+ s++;
+ }
+
+ if ((rooted != 0)
+ && (*(vptr-1) != '.'))
+ {
+ *vptr++ = '[';
+ nstate = N_DOT;
+ }
+ else
+ if ((nstate == N_DOT)
+ && (s1 != 0)
+ && (*(s+1) == 0))
+ {
+ if (type == 2)
+ {
+ *s1 = ']';
+ nstate = N_CLOSED;
+ }
+ }
+ state = 9;
+ break;
+
+ case 4: /* single '/' at start (9..15) */
+ if (*fptr == 0)
+ state = 5;
+ else
+ state = 6;
+ break;
+
+ case 5: /* just '/' at start (9) */
+ if (type != 2)
+ {
+ *vptr++ = '[';
+ nstate = N_OPEN;
+ }
+ strcpy (vptr, "000000");
+ vptr += 6;
+ if (type == 2)
+ state = 7;
+ else
+ state = 8;
+ break;
+
+ case 6: /* chars following '/' at start 10..15 */
+ *vptr++ = '[';
+ nstate = N_OPEN;
+ s = strchr (fptr, '/');
+ if (s == 0) /* 10 */
+ {
+ if (type != 1)
+ {
+ strcpy (vptr, "000000]");
+ vptr += 7;
+ }
+ copyto (&vptr, &fptr, 0, (type == 1));
+ if (type == 1)
+ {
+ *vptr++ = ']';
+ }
+ state = -1;
+ }
+ else /* 11..15 */
+ {
+ if ( (type == 2)
+ && (*(s+1) == 0)) /* 11(2) */
+ {
+ strcpy (vptr, "000000]");
+ nstate = N_CLOSED;
+ vptr += 7;
+ }
+ copyto (&vptr, &fptr, '/', (*(vptr-1) != ']'));
+ state = 9;
+ }
+ break;
+
+ case 7: /* add '.dir' and exit */
+ if ((nstate == N_OPEN)
+ || (nstate == N_DOT))
+ {
+ s = vptr-1;
+ while (s > vmsname)
+ {
+ if (*s == ']')
+ {
+ break;
+ }
+ if (*s == '.')
+ {
+ *s = ']';
+ break;
+ }
+ s--;
+ }
+ }
+ strcpy (vptr, ".dir");
+ vptr += 4;
+ state = -1;
+ break;
+
+ case 8: /* add ']' and exit */
+ *vptr++ = ']';
+ state = -1;
+ break;
+
+ case 9: /* 17..21, fptr -> 1st '/' + 1 */
+ if (*fptr == 0)
+ {
+ if (type == 2)
+ {
+ state = 7;
+ }
+ else
+ state = 8;
+ break;
+ }
+ s = strchr (fptr, '/');
+ if (s == 0)
+ {
+ if (type != 1)
+ {
+ if (nstate == N_OPEN)
+ {
+ *vptr++ = ']';
+ nstate = N_CLOSED;
+ }
+ as_dir = 0;
+ }
+ else
+ {
+ if (nstate == N_OPEN)
+ {
+ *vptr++ = '.';
+ nstate = N_DOT;
+ }
+ as_dir = 1;
+ }
+ }
+ else
+ {
+ while (*(s+1) == '/')
+ s++;
+ if ( (type == 2)
+ && (*(s+1) == 0)) /* 19(2), 21(2)*/
+ {
+ if (nstate != N_CLOSED)
+ {
+ *vptr++ = ']';
+ nstate = N_CLOSED;
+ }
+ as_dir = 1;
+ }
+ else
+ {
+ if (nstate == N_OPEN)
+ {
+ *vptr++ = '.';
+ nstate = N_DOT;
+ }
+ as_dir = 1;
+ }
+ }
+ if ( (*fptr == '.') /* check for '..' or '../' */
+ && (*(fptr+1) == '.')
+ && ((*(fptr+2) == '/')
+ || (*(fptr+2) == 0)) )
+ {
+ fptr += 2;
+ if (*fptr == '/')
+ {
+ do
+ {
+ fptr++;
+ }
+ while (*fptr == '/');
+ }
+ else if (*fptr == 0)
+ type = 1;
+ vptr--; /* vptr -> '.' or ']' */
+ s1 = vptr;
+ for (;;)
+ {
+ s1--;
+ if (*s1 == '.') /* one back */
+ {
+ vptr = s1;
+ nstate = N_OPEN;
+ break;
+ }
+ if (*s1 == '[') /* top level reached */
+ {
+ if (*fptr == 0)
+ {
+ strcpy (s1, "[000000]");
+ vptr = s1 + 8;
+ nstate = N_CLOSED;
+ s = 0;
+ break;
+ }
+ else
+ {
+ vptr = s1+1;
+ nstate = N_OPEN;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ copyto (&vptr, &fptr, '/', as_dir);
+ if (nstate == N_DOT)
+ nstate = N_OPEN;
+ }
+ if (s == 0)
+ { /* 18,20 */
+ if (type == 1)
+ *vptr++ = ']';
+ state = -1;
+ }
+ else
+ {
+ if (*(s+1) == 0)
+ {
+ if (type == 2) /* 19,21 */
+ {
+ state = 7;
+ }
+ else
+ {
+ *vptr++ = ']';
+ state = -1;
+ }
+ }
+ }
+ break;
+
+ case 10: /* 1,2 first is '.' */
+ if (*fptr == '.')
+ {
+ fptr++;
+ state = 11;
+ }
+ else
+ state = 12;
+ break;
+
+ case 11: /* 2, '..' at start */
+ count = 1;
+ if (*fptr != 0)
+ {
+ if (*fptr != '/') /* got ..xxx */
+ {
+ return name;
+ }
+ do /* got ../ */
+ {
+ fptr++;
+ while (*fptr == '/') fptr++;
+ if (*fptr != '.')
+ break;
+ if (*(fptr+1) != '.')
+ break;
+ fptr += 2;
+ if ((*fptr == 0)
+ || (*fptr == '/'))
+ count++;
+ }
+ while (*fptr == '/');
+ }
+ { /* got '..' or '../' */
+ char cwdbuf[MAXPATHLEN+1];
+
+ s1 = getcwd(cwdbuf, MAXPATHLEN);
+ if (s1 == 0)
+ {
+ return ""; /* FIXME, err getcwd */
+ }
+ strcpy (vptr, s1);
+ s = strchr (vptr, ']');
+ if (s != 0)
+ {
+ while (s > vptr)
+ {
+ s--;
+ if (*s == '[')
+ {
+ s++;
+ strcpy (s, "000000]");
+ state = -1;
+ break;
+ }
+ else if (*s == '.')
+ {
+ if (--count == 0)
+ {
+ if (*fptr == 0) /* had '..' or '../' */
+ {
+ *s++ = ']';
+ state = -1;
+ }
+ else /* had '../xxx' */
+ {
+ state = 9;
+ }
+ *s = 0;
+ break;
+ }
+ }
+ }
+ }
+ vptr += strlen (vptr);
+ }
+ break;
+
+ case 12: /* 1, '.' at start */
+ if (*fptr != 0)
+ {
+ if (*fptr != '/')
+ {
+ return name;
+ }
+ fptr++;
+ }
+
+ {
+ char cwdbuf[MAXPATHLEN+1];
+
+ s1 = getcwd(cwdbuf, MAXPATHLEN);
+ if (s1 == 0)
+ {
+ return ""; /*FIXME, err getcwd */
+ }
+ strcpy (vptr, s1);
+ if (*fptr == 0)
+ {
+ state = -1;
+ break;
+ }
+ else
+ {
+ s = strchr (vptr, ']');
+ if (s == 0)
+ {
+ state = -1;
+ break;
+ }
+ *s = 0;
+ nstate = N_OPEN;
+ vptr += strlen (vptr);
+ state = 9;
+ }
+ }
+ break;
+ }
+
+ }
+ while (state > 0);
+
+
+ }
+
+
+ /* directory conversion done
+ fptr -> filename part of input string
+ vptr -> free space in vmsname
+ */
+
+ *vptr++ = 0;
+
+ return vmsname;
+}
+
+
+
+/*
+ convert from vms-style to unix-style
+
+ dev:[dir1.dir2] //dev/dir1/dir2/
+*/
+
+char *
+unixify (char *name)
+{
+ static char piece[512];
+ char *s, *p;
+
+ if (strchr (name, '/') != 0) /* already in unix style */
+ return name;
+
+ p = piece;
+ *p = 0;
+
+ /* device part */
+
+ s = strchr (name, ':');
+
+ if (s != 0)
+ {
+ *s = 0;
+ *p++ = '/';
+ *p++ = '/';
+ strcpy (p, name);
+ p += strlen (p);
+ *s = ':';
+ }
+
+ /* directory part */
+
+ *p++ = '/';
+ s = strchr (name, '[');
+
+ if (s != 0)
+ {
+ s++;
+ switch (*s)
+ {
+ case ']': /* [] */
+ strcat (p, "./");
+ break;
+ case '-': /* [- */
+ strcat (p, "../");
+ break;
+ case '.':
+ strcat (p, "./"); /* [. */
+ break;
+ default:
+ s--;
+ break;
+ }
+ s++;
+ while (*s)
+ {
+ if (*s == '.')
+ *p++ = '/';
+ else
+ *p++ = *s;
+ s++;
+ if (*s == ']')
+ {
+ s++;
+ break;
+ }
+ }
+ if (*s != 0) /* more after ']' ?? */
+ {
+ if (*(p-1) != '/')
+ *p++ = '/';
+ strcpy (p, s); /* copy it anyway */
+ }
+ }
+
+ else /* no '[' anywhere */
+
+ {
+ *p++ = 0;
+ }
+
+ /* force end with '/' */
+
+ if (*(p-1) != '/')
+ *p++ = '/';
+ *p = 0;
+
+ return piece;
+}
+
+/* EOF */
diff --git a/vpath.c b/vpath.c
index 499864b..3e78a9a 100644
--- a/vpath.c
+++ b/vpath.c
@@ -17,7 +17,7 @@ along with GNU Make; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "make.h"
-#include "file.h"
+#include "filedef.h"
#include "variable.h"
@@ -41,7 +41,7 @@ static struct vpath *vpaths;
static struct vpath *general_vpath;
-static int selective_vpath_search ();
+static int selective_vpath_search PARAMS ((struct vpath *path, char **file, time_t *mtime_ptr));
/* Reverse the chain of selective VPATH lists so they
will be searched in the order given in the makefiles