From 9e443adaf679b071fb3319cfc3259e322dcb6e57 Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 20 Mar 1996 14:57:41 +0000 Subject: Tue Mar 19 20:21:34 1996 Roland McGrath Merged VMS port from Klaus Kaempf . * make.h (PARAMS): New macro. * config.h-vms: New file. * makefile.com: New file. * makefile.vms: New file. * readme.vms: New file. * vmsdir.h: New file. * vmsfunctions.c: New file. * vmsify.c: New file. * file.h: Renamed to filedef.h to avoid conflict with VMS system hdr. * ar.c: Added prototypes and changes for VMS. * commands.c: Likewise. * commands.h: Likewise. * default.c: Likewise. * dep.h: Likewise. * dir.c: Likewise. * expand.c: Likewise. * file.c: Likewise. * function.c: Likewise. * implicit.c: Likewise. * job.c: Likewise. * job.h: Likewise. * main.c: Likewise. * make.h: Likewise. * misc.c: Likewise. * read.c: Likewise. * remake.c: Likewise. * remote-stub.c: Likewise. * rule.c: Likewise. * rule.h: Likewise. * variable.c: Likewise. * variable.h: Likewise. * vpath.c: Likewise. * compatMakefile (srcs): Rename file.h to filedef.h. --- ar.c | 126 ++++++- commands.c | 22 +- commands.h | 8 +- compatMakefile | 2 +- config.h-vms.template | 292 ++++++++++++++++ default.c | 114 ++++++- dep.h | 13 +- dir.c | 192 +++++++++-- expand.c | 3 +- file.c | 55 ++- filedef.h | 120 +++++++ function.c | 98 +++--- implicit.c | 13 +- job.c | 368 ++++++++++++++++++-- job.h | 27 +- main.c | 49 ++- make.h | 121 +++++-- makefile.com | 34 ++ makefile.vms | 121 +++++++ misc.c | 4 + read.c | 103 +++++- readme.vms | 62 ++++ remake.c | 52 ++- remote-stub.c | 2 + rule.c | 21 +- rule.h | 4 +- variable.c | 10 +- variable.h | 57 ++-- vmsdir.h | 40 +++ vmsfunctions.c | 234 +++++++++++++ vmsify.c | 925 ++++++++++++++++++++++++++++++++++++++++++++++++++ vpath.c | 4 +- 32 files changed, 3068 insertions(+), 228 deletions(-) create mode 100644 config.h-vms.template create mode 100644 filedef.h create mode 100644 makefile.com create mode 100644 makefile.vms create mode 100644 readme.vms create mode 100644 vmsdir.h create mode 100644 vmsfunctions.c create mode 100644 vmsify.c 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 /* 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 +#include +#include +#include +#include +#if __DECC +#include +#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 */ +/* 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 . */ +/* #undef DGUX */ + +/* Define if the `getloadavg' function needs to be run setuid or setgid. */ +/* #undef GETLOADAVG_PRIVILEGED 1 */ + +/* Define to `int' if doesn't define. */ +/* #undef gid_t */ + +/* Define if you have alloca, as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define if you have 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 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 . */ +#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 . */ +/* #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 . */ +/* #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 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 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 . */ +/* #undef SYS_SIGLIST_DECLARED */ + +/* Define to `int' if doesn't define. */ +#define uid_t int + +/* Define for Encore UMAX. */ +/* #undef UMAX */ + +/* Define for Encore UMAX 4.3 that has + instead of . */ +/* #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' 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 . */ +/* #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 header file. */ +/* #unddef HAVE_DIRENT_H 1 */ + +/* Define if you have the header file. */ +#ifdef __DECC +#define HAVE_FCNTL_H 1 +#endif + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_MACH_MACH_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_MEMORY_H 1 */ + +/* Define if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_PWD_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_PARAM_H 1 */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TIMEB_H 1 + +/* Define if you have the 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 # endif +# ifdef HAVE_VMSDIR_H +# include "vmsdir.h" +# endif /* HAVE_VMSDIR_H */ #endif /* In GNU systems, 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 @@ -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 #include #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 @@ -36,6 +36,13 @@ static char *dos_bename; static int dos_batch_file; #endif /* MSDOS. */ +#ifdef VMS +#include +#include +#include +#include +#endif + #ifdef HAVE_FCNTL_H #include #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 +#include + +/* 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 +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 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 +#include +#include +#include +#include +#include +#endif -#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)) +#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) || defined(VMS)) #include #include #define ANSI_STRING @@ -170,10 +187,12 @@ extern unsigned int get_path_max (); #include #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 . */ #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 @@ -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 -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 #ifdef HAVE_FCNTL_H @@ -29,17 +29,30 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #endif -extern int try_implicit_rule (); +#ifdef VMS +#include +#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 + +#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 +#include "make.h" +#ifdef __DECC +#include +#endif +#include +#include +#include +#include +#include +#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 +#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 +#include + +#if VMS +#include +#include +#include +#include +#include +#include +#include +#include +/* 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 ./ [] .dir +2 ../ .dir + +3 // : :[000000] :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 -- cgit v1.2.3