diff --git a/AUTHORS b/AUTHORS index b66bb8f9..489c8cdc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,29 +1,30 @@ ----------------------------------- GNU make development up to version 3.75 by: - Roland McGrath + Roland McGrath + + +Development starting with GNU make 3.76 by: + Paul D. Smith GNU Make User's Manual written by: - Richard M. Stallman + Richard M. Stallman User's Manual edited by: - Roland McGrath - Bob Chassell - Melissa Weisshaus - - -Development and maintenance starting with GNU make 3.76 by: - Paul D. Smith - + Roland McGrath + Bob Chassell + Melissa Weisshaus + Paul D. Smith ----------------------------------- -GNU Make porting efforts: +GNU make porting efforts: Port to VMS by: Klaus Kaempf Archive support/Bug fixes by John W. Eaton + Port to Amiga by: Aaron Digulla diff --git a/ChangeLog b/ChangeLog index f773f3c7..c3ffc61f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,450 @@ +1998-07-28 Paul D. Smith + + * Version 3.77 released. + + * dosbuild.bat: Change to DOS CRLF line terminators. + + * make-stds.texi: Update from latest version. + + * make.texinfo (Options Summary): Clarify that the -r option + affects only rules, not builtin variables. + +1998-07-27 Paul D. Smith + + * make.h: Make __attribute__ resolve to empty for non-GCC _and_ + for GCC pre-2.5.x. + + * misc.c (log_access): Print UID/GID's as unsigned long int for + maximum portability. + + * job.c (reap_children): Print PIDs as long int for maximum + portability. + +1998-07-24 Eli Zaretskii + + * Makefile.DOS (*_INSTALL, *_UNINSTALL): Replace `true' with `:'. + +1998-07-25 Paul D. Smith + + * Version 3.76.94 released. + +1998-07-23 Paul D. Smith + + * config.h.W32.template: Make sure all the #defines of macros here + have a value (e.g., use ``#define HAVE_STRING_H 1'' instead of + just ``#define HAVE_STRING_H''. Keeps the preprocessor happy in + some contexts. + + * make.h: Remove __attribute__((format...)) stuff; using it with + un-prototyped functions causes older GCC's to fail. + + * Version 3.76.93 released. + +1998-07-22 Paul D. Smith + + * file.c (print_file_data_base): Fix average calculation. + +1998-07-20 Paul D. Smith + + * main.c (die): Postpone the chdir() until after + remove_intermediates() so that intermediate targets with relative + pathnames are removed properly. + +1998-07-17 Paul D. Smith + + * filedef.h (struct file): New flag: did we print an error or not? + + * remake.c (no_rule_error): New function to print error messages, + extraced from remake_file(). + + * remake.c (remake_file): Invoke the new error print function. + (update_file_1): Invoke the error print function if we see that we + already tried this target and it failed, but that an error wasn't + printed for it. This can happen if a file is included with + -include or sinclude and couldn't be built, then later is also + the dependency of another target. Without this change, make just + silently stops :-/. + +1998-07-16 Paul D. Smith + + * make.texinfo: Removed "beta" version designator. + Updated ISBN for the next printing. + +1998-07-13 Paul Eggert + + * acinclude.m4: New AC_LFS macro to determine if special compiler + flags are needed to allow access to large files (e.g., Solaris 2.6). + * configure.in: Invoke it. + +1998-07-08 Eli Zaretskii + + * Makefile.DOS: track changes in Makefile.in. + +1998-07-07 Paul D. Smith + + * remote-cstms.c (start_remote_job): Move gethostbyaddr() to the + top so host is initialized early enough. + + * acinclude.m4: New file. Need some special autoconf macros to + check for network libraries (-lsocket, -lnsl, etc.) when + configuring Customs. + + * configure.in (make_try_customs): Invoke new network libs macro. + +1998-07-06 Paul D. Smith + + * Version 3.76.92 released. + + * README.customs: Added to the distribution. + + * configure.in (make_try_customs): Rewrite to require an installed + Customs library, rather than looking at the build directory. + + * Makefile.am (man_MANS): Install make.1. + * make.1: Renamed from make.man. + + * make.texinfo (Bugs): New mailing list address for GNU make bug + reports. + +1998-07-02 Paul D. Smith + + * Version 3.76.91 released. + + * default.c: Added default rule for new-style RCS master file + storage; ``% :: RCS/%''. + Added default rules for DOS-style C++ files with suffix ".cpp". + They use the new LINK.cpp and COMPILE.cpp macros, which are set by + default to be equal to LINK.cc and COMPILE.cc. + +1998-06-19 Eli Zaretskii + + * job.c (start_job_command): Reset execute_by_shell after an empty + command was skipped. + +1998-06-09 Paul D. Smith + + * main.c (main): Keep track of the temporary filename created when + reading a makefile from stdin (-f-) and attempt to remove it + as soon as we know we're not going to re-exec. If we are, add it + to the exec'd make's cmd line with "-o" so the exec'd make doesn't + try to rebuild it. We still have a hole: if make re-execs then + the temporary file will never be removed. To fix this we'd need + a brand new option that meant "really delete this". + * AUTHORS, getopt.c, getopt1.c, getopt.h, main.c (print_version): + Updated mailing addresses. + +1998-06-08 Paul D. Smith + + * main.c (main): Andreas Luik points out that the + check for makefile :: rules with commands but no dependencies + causing a loop terminates incorrectly. + + * maintMakefile: Make a template for README.DOS to update version + numbers. + +1998-05-30 Andreas Schwab + + * remake.c (update_file_1): Don't free the memory for the + dependency structure when dropping a circular dependency. + +1998-05-30 Eli Zaretskii + + * dir.c (file_exists_p, file_impossible_p, file_impossible) + [__MSDOS__, WINDOWS32]: Retain trailing slash in "d:/", and make + dirname of "d:foo" be "d:". + +1998-05-26 Andreas Schwab + + * read.c (read_makefile): Avoid running past EOS when scanning + file name after `include'. + +1998-05-26 Andreas Schwab + + * make.texinfo (Flavors): Correct description of conditional + assignment, which is not equivalent to ifndef. + (Setting): Likewise. + +1998-05-24 Paul D. Smith + + * arscan.c (ar_name_equal): strncmp() might be implemented as a + macro, so don't put preprocessor conditions inside the arguments + list. + +1998-05-23 Eli Zaretskii + + * read.c (read_makefile) [__MSDOS__, WINDOWS32]: Skip colons in + drive specs when parsing targets, target-specific variables and + static pattern rules. A colon can only be part of drive spec if + it is after the first letter in a token. + +1998-05-22 Eli Zaretskii + + * remake.c (f_mtime) [__MSDOS__]: Allow up to 3 sec of skew before + yelling bloody murder. + + * dosbuild.bat: Use -DINCLUDEDIR= and -DLIBDIR= where appropriate. + + * read.c (parse_file_seq): Combine the special file-handling code + for WINDOWS32 and __MSDOS__ into a single snippet. + (get_next_mword) [__MSDOS__, WINDOWS32]: Allow a word to include a + colon as part of a drive spec. + + * job.c (batch_mode_shell) [__MSDOS__]: Declare. + +1998-05-20 Paul D. Smith + + * Version 3.76.90 released. + +1998-05-19 Paul D. Smith + + * make.texinfo (Make Errors): Added a new appendix describing + common errors make might generate and how to resolve them (or at + least more information on what they mean). + + * maintMakefile (NMAKEFILES): Use the new automake 1.3 feature + to create a dependency file to construct Makefile.DOS, SMakefile, + and NMakefile. + (.dep_segment): Generate the dependency fragment file. + +1998-05-14 Paul D. Smith + + * make.man: Minor changes. + +1998-05-13 Paul D. Smith + + * function.c (pattern_matches,expand_function): Change variables + and types named "word" to something else, to avoid compilation + problems on Cray C90 Unicos. + * variable.h: Modify the function prototype. + +1998-05-11 Rob Tulloh + + * job.c (construct_command_argv_internal): [WINDOWS32] Turn off + echo when using a batch file, and make sure the command ends in a + newline. + +1998-05-03 Paul D. Smith + + * configure.in (make_try_customs): Add some customs flags if the + user configures custom support. + + * job.c, remote-cstms.c: Merge in changes for custom library. + + * remote-stub.c: Add option to stub start_remote_job_p(). + +1998-05-01 Paul D. Smith + + * remake.c (f_mtime): Install VPATH+ handling for archives; use + the hname field instead of the name field, and rehash when + appropriate. + +1998-04-30 Paul D. Smith + + * rule.c (print_rule_data_base): Print out any pattern-specific + variable values into the rules database. + + * variable.c (print_variable_set): Make this variable extern, to + be called by print_rule_data_base() for pattern-specific variables. + + * make.texinfo (Pattern-specific): Document pattern-specific + variables. + +1998-04-29 Paul D. Smith + + * expand.c (variable_expand_for_file): Make static; its only + called internally. Look up this target in the list of + pattern-specific variables and insert the variable set into the + queue to be searched. + + * filedef.h (struct file): Add a new field to hold the + previously-found pattern-specific variable reference. Add a new + flag to remember whether we already searched for this file. + + * rule.h (struct pattern_var): New structure for storing + pattern-specific variable values. Define new function prototypes. + + * rule.c: New variables pattern_vars and last_pattern_var for + storage and handling of pattern-specific variable values. + (create_pattern_var): Create a new pattern-specific variable value + structure. + (lookup_pattern_var): Try to match a target to one of the + pattern-specific variable values. + +1998-04-22 Paul D. Smith + + * make.texinfo (Target-specific): Document target-specific + variables. + +1998-04-21 Paul D. Smith + + * variable.c (define_variable_in_set): Made globally visible. + (lookup_variable_in_set): New function: like lookup_variable but + look only in a specific variable set. + (target_environment): Use lookup_variable_in_set() to get the + correct export rules for a target-specific variable. + (create_new_variable_set): Create a new variable set, and just + return it without installing it anywhere. + (push_new_variable_scope): Reimplement in terms of + create_new_variable_set. + + * read.c (record_target_var): Like record_files, but instead of + files create a target-specific variable value for each of the + listed targets. Invoked from read_makefile() when the target line + turns out to be a target-specific variable assignment. + +1998-04-19 Paul D. Smith + + * read.c (read_makefile): Rewrite the entire target parsing + section to implement target-specific variables. In particular, we + cannot expand the entire line as soon as it's read in, since we + may want to evaluate parts of it with different variable contexts + active. Instead, start expanding from the beginning until we find + the `:' (or `::'), then determine what kind of line this is and + continue appropriately. + + * read.c (get_next_mword): New function to parse a makefile line + by "words", considering an entire variable or function as one + word. Return the type read in, along with its starting position + and length. + (enum make_word_type): The types of words that are recognized by + get_next_mword(). + + * variable.h (struct variable): Add a flag to specify a per-target + variable. + + * expand.c: Make variable_buffer global. We need this during the + new parsing of the makefile. + (variable_expand_string): New function. Like variable_expand(), + but start at a specific point in the buffer, not the beginning. + (variable_expand): Rewrite to simply call variable_expand_string(). + +1998-04-13 Paul D. Smith + + * remake.c (update_goal_chain): Allow the rebuilding makefiles + step to use parallel jobs. Not sure why this was disabled: + hopefully we won't find out :-/. + +1998-04-11 Paul D. Smith + + * main.c (main): Set the CURDIR makefile variable. + * make.texinfo (Recursion): Document it. + +1998-03-17 Paul D. Smith + + * misc.c (makefile_fatal): If FILE is nil, invoke plain fatal(). + * variable.c (try_variable_definition): Use new feature. + +1998-03-10 Paul D. Smith + + * main.c (main): Don't pass included, rebuilt makefiles to + re-exec'd makes with -o. Reopens a possible loop, but it caused + too many problems. + +1998-03-02 Paul D. Smith + + * variable.c (try_variable_definition): Implement ?=. + * make.texinfo (Setting): Document it. + +1998-02-28 Eli Zaretskii + + * job.c (start_job_command): Reset execute_by_shell after an empty + command, like ":", has been seen. + +Tue Oct 07 15:00:00 1997 Phil Brooks + + * make.h: [WINDOWS32] make case sensitivity configurable + * dir.c: [WINDOWS32] make case sensitivity configurable + * README.W32: Document case sensitivity + * config.ami: Share case warping code with Windows + +Mon Oct 6 18:48:45 CDT 1997 Rob Tulloh + + * w32/subproc/sub_proc.c: Added support for MKS toolkit shell + (turn on HAVE_MKS_SHELL). + * read.c: [WINDOWS32] Fixed a problem with multiple target rules + reported by Gilbert Catipon (gcatipon@tibco.com). If multiple + path tokens in a rule did not have drive letters, make would + incorrectly concatenate the 2 tokens together. + * main.c/variable.c: [WINDOWS32] changed SHELL detection code to + follow what MSDOS did. In addition to watching for SHELL variable + updates, make's main will attempt to default the value of SHELL + before and after makefiles are parsed. + * job.c/job.h: [WINDOWS32] The latest changes made to enable use + of the GNUWIN32 shell from make could cause make to fail due to a + concurrency condition between parent and child processes. Make + now creates a batch file per job instead of trying to reuse the + same singleton batch file. + * job.c/job.h/function.c/config.h.W32: [WINDOWS32] Renamed macro + from HAVE_CYGNUS_GNUWIN32_TOOLS to BATCH_MODE_ONLY_SHELL. Reworked + logic to reduce complexity. WINDOWS32 now uses the unixy_shell + variable to detect Bourne-shell compatible environments. There is + also a batch_mode_shell variable that determines whether not + command lines should be executed via script files. A WINDOWS32 + system with no sh.exe installed would have unixy_shell set to + FALSE and batch_mode_shell set to TRUE. If you have a unixy shell + that does not behave well when invoking things via 'sh -c xxx', + you may want to turn on BATCH_MODE_ONLY_SHELL and see if things + improve. + * NMakefile: Added /D DEBUG to debug build flags so that unhandled + exceptions could be debugged. + +Mon Oct 6 00:04:25 1997 Rob Tulloh + + * main.c: [WINDOWS32] The function define_variable() does not + handle NULL. Test before calling it to set Path. + * main.c: [WINDOWS32] Search Path again after makefiles have been + parsed to detect sh.exe. + * job.c: [WINDOWS32] Added support for Cygnus GNU WIN32 tools. + To use, turn on HAVE_CYGNUS_GNUWIN32_TOOLS in config.h.W32. + * config.h.W32: Added HAVE_CYGNUS_GNUWIN32_TOOLS macro. + +Sun Oct 5 22:43:59 1997 John W. Eaton + + * glob/glob.c (glob_in_dir): [VMS] Globbing shouldn't be + case-sensitive. + * job.c (child_execute_job): [VMS] Use a VMS .com file if the + command contains a newline (e.g. from a define/enddef block). + * vmsify.c (vmsify): Return relative pathnames wherever possible. + * vmsify.c (vmsify): An input string like "../.." returns "[--]". + +Wed Oct 1 15:45:09 1997 Rob Tulloh + + * NMakefile: Changed nmake to $(MAKE). + * subproc.bat: Take the make command name from the command + line. If no command name was given, default to nmake. + * job.c: [WINDOWS32/MSDOS] Fix memory stomp: temporary file names + are now always created in heap memory. + * w32/subproc/sub_proc.c: New implementation of make_command_line() + which is more compatible with different Bourne shell implementations. + Deleted the now obsolete fix_command_line() function. + * main.c: [WINDOWS32] Any arbitrary spelling of Path can be + detected. Make will ensure that the special spelling `Path' is + inserted into the environment when the path variable is propagated + within itself and to make's children. + * main.c: [WINDOWS32] Detection of sh.exe was occurring too + soon. The 2nd check for the existence of sh.exe must come after + the call to read_all_makefiles(). + +Fri Sep 26 01:14:18 1997 + + * makefile.com: [VMS] Fixed definition of sys. + * readme.vms: Comments on what's changed lately. + +Fri Sep 26 01:14:18 1997 John W. Eaton + + * read.c (read_all_makefiles): Allow make to find files named + "MAKEFILE" with no extension on VMS. + * file.c (lookup_file): Lowercase filenames on VMS. + +1997-09-29 Paul D. Smith + + * read.c (read_makefile): Reworked target detection again; the old + version had an obscure quirk. + Fri Sep 19 09:20:49 1997 Paul D. Smith + * Version 3.76.1 released. + * Makefile.am: Add loadavg files to clean rules. * configure.in (AC_OUTPUT): Remove stamp-config; no longer needed. @@ -37,7 +482,7 @@ Thu Aug 28 19:39:06 1997 Rob Tulloh from main() to re-exec make, the call to execvp() would incorrectly return control to parent shell before the exec'ed command could run to completion. I believe this is a feature of - the way that execvp() is implemented on top of WIN32 APIs. To + the way that execvp() is implemented on top of WINDOWS32 APIs. To alleviate the problem, use the supplied process launch function in the sub_proc library and suspend the parent process until the child process has run. When the child exits, exit the parent make diff --git a/GNUmakefile b/GNUmakefile index aedde592..15067c6d 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -7,7 +7,7 @@ NORECURSE = true -# If the user asked for a specific target, invoke the Mkaefile instead. +# If the user asked for a specific target, invoke the Makefile instead. # .DEFAULT: @[ -f Makefile.in -a -f configure -a -f aclocal.m4 -a -f config.h.in ] \ @@ -16,7 +16,7 @@ NORECURSE = true || ./configure $(MAKE) -f Makefile $@ -.PHONY: __cfg __cfg_basic TAGS +.PHONY: __cfg __cfg_basic # This is variable since the glob subdirectory doesn't use it. # @@ -36,7 +36,7 @@ endif __cfg_basic: aclocal.m4 stamp-h.in configure Makefile.in -aclocal.m4: configure.in +aclocal.m4: configure.in $(wildcard acinclude.m4) aclocal config.h.in: stamp-h.in diff --git a/INSTALL b/INSTALL index 50dbe439..bca44d04 100644 --- a/INSTALL +++ b/INSTALL @@ -1,8 +1,6 @@ Basic Installation ================== - These are generic installation instructions. - The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. @@ -36,7 +34,13 @@ The simplest way to compile this package is: 2. Type `make' to compile the package. - 3. Optionally, type `make check' to run any self-tests that come with + If you're building GNU make on a system which does not already have + a `make', you can use the build.sh shell script to compile. Run + `sh ./build.sh'. This should compile the program in the current + directory. Then you will have a Make program that you can use for + `make install', or whatever else. + + 3. Optionally, type `./make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and diff --git a/Makefile.DOS.template b/Makefile.DOS.template index 856cdc25..b8d44ee8 100644 --- a/Makefile.DOS.template +++ b/Makefile.DOS.template @@ -41,12 +41,12 @@ transform = s,x,x, # get "Error -1" instead of "Error 1". EXIT_FAIL = false -NORMAL_INSTALL = true -PRE_INSTALL = true -POST_INSTALL = true -NORMAL_UNINSTALL = true -PRE_UNINSTALL = true -POST_UNINSTALL = true +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : AR = ar CC = gcc CPP = gcc -E @@ -67,12 +67,13 @@ libglob_a_SOURCES = %GLOB_SOURCES% make_LDADD = glob/libglob.a info_TEXINFOS = make.texinfo +man_MANS = make.1 INCLUDES = -I$(srcdir)/glob -DLIBDIR=\"c:/djgpp/lib\" -DINCLUDEDIR=\"c:/djgpp/include\" BUILT_SOURCES = README build.sh.in -EXTRA_DIST = make.man $(BUILT_SOURCES) remote-cstms.c make-stds.texi texinfo.tex SCOPTIONS SMakefile Makefile.ami README.Amiga config.ami amiga.c amiga.h NMakefile README.DOS configh.dos configure.bat makefile.com README.W32 build_w32.bat config.h.W32 subproc.bat make.lnk config.h-vms makefile.vms readme.vms vmsdir.h vmsfunctions.c vmsify.c +EXTRA_DIST = $(BUILT_SOURCES) $(man_MANS) README.customs remote-cstms.c make-stds.texi texinfo.tex SCOPTIONS SMakefile Makefile.ami README.Amiga config.ami amiga.c amiga.h NMakefile README.DOS configh.dos configure.bat makefile.com README.W32 build_w32.bat config.h.W32 subproc.bat make.lnk config.h-vms makefile.vms readme.vms vmsdir.h vmsfunctions.c vmsify.c SUBDIRS = glob mkinstalldirs = ${bindir}/gmkdir -p @@ -99,6 +100,10 @@ TEXINFO_TEX = $(srcdir)/texinfo.tex INFO_DEPS = make.info DVIS = make.dvi TEXINFOS = make.texinfo +man1dir = $(mandir)/man1 +MANS = $(man_MANS) + +NROFF = nroff DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am Makefile.in NEWS acconfig.h aclocal.m4 alloca.c build.sh.in config.h.in configure configure.in getloadavg.c install-sh missing mkinstalldirs stamp-h.in texinfo.tex @@ -116,14 +121,14 @@ default: all .SUFFIXES: .c .dvi .info .o .ps .texi .texinfo distclean-hdr: - rm -f config.h + -rm -f config.h maintainer-clean-hdr: mostlyclean-binPROGRAMS: clean-binPROGRAMS: - test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) distclean-binPROGRAMS: @@ -131,7 +136,7 @@ maintainer-clean-binPROGRAMS: install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) - $(mkinstalldirs) $(bindir) + $(mkinstalldirs) $(DESTDIR)$(bindir) @list='$(bin_PROGRAMS)'; for p in $$list; do if test -f $$p; then echo " $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p | sed '$(transform)'`"; $(INSTALL_PROGRAM) $$p $(bindir)/`echo $$p | sed '$(transform)'`; else :; fi; done uninstall-binPROGRAMS: @@ -142,15 +147,15 @@ uninstall-binPROGRAMS: $(COMPILE) -c $< clean-noinstLIBRARIES: - test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) mostlyclean-compile: - rm -f *.o *.exe make.new core + -rm -f *.o *.exe make.new core clean-compile: distclean-compile: - rm -f *.tab.c + -rm -f *.tab.c maintainer-clean-compile: @@ -188,22 +193,22 @@ DVIPS = dvips install-info-am: $(INFO_DEPS) @$(NORMAL_INSTALL) - $(mkinstalldirs) $(infodir) - @for file in $(INFO_DEPS) make.i; do d=$(srcdir); for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9] $$file[0-9] $$file[0-9][0-9]`; do if test -f $$d/$$ifile; then echo " $(INSTALL_DATA) $$d/$$ifile $(infodir)/$$ifile"; $(INSTALL_DATA) $$d/$$ifile $(infodir)/$$ifile; else : ; fi; done; done + $(mkinstalldirs) $(DESTDIR)$(infodir) + @for file in $(INFO_DEPS) make.i; do d=$(srcdir); for ifile in `cd $$d && echo $$file $$file-[0-9] $$file-[0-9][0-9] $$file[0-9] $$file[0-9][0-9]`; do if test -f $$d/$$ifile; then echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile"; $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$ifile; else : ; fi; done; done @$(POST_INSTALL) - @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then for file in $(INFO_DEPS); do echo " install-info --info-dir=$(infodir) $(infodir)/$$file"; install-info --info-dir=$(infodir) $(infodir)/$$file || :; done; else : ; fi + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then for file in $(INFO_DEPS); do echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file"; install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$file || :; done; else : ; fi uninstall-info: $(PRE_UNINSTALL) - @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then ii=yes; else ii=; fi; for file in $(INFO_DEPS); do test -z $ii || install-info --info-dir=$(infodir) --remove $$file; done + @if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then ii=yes; else ii=; fi; for file in $(INFO_DEPS); do test -z $ii || install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; done $(NORMAL_UNINSTALL) - for file in $(INFO_DEPS) make.i; do (cd $(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9] $$file[0-9] $$file[0-9][0-9]); done + for file in $(INFO_DEPS) make.i; do (cd $(DESTDIR)$(infodir) && rm -f $$file $$file-[0-9] $$file-[0-9][0-9] $$file[0-9] $$file[0-9][0-9]); done dist-info: $(INFO_DEPS) for base in $(INFO_DEPS); do d=$(srcdir); for file in `cd $$d && eval echo $$base*`; do test -f $(distdir)/$$file || ln $$d/$$file $(distdir)/$$file 2> /dev/null || cp -p $$d/$$file $(distdir)/$$file; done; done mostlyclean-aminfo: - rm -f make.aux make.cp make.cps make.dvi make.fn make.fns make.ky make.log make.pg make.toc make.tp make.tps make.vr make.vrs make.op make.tr make.cv + rm -f make.aux make.cp make.cps make.dvi make.fn make.fns make.ky make.kys make.ps make.log make.pg make.toc make.tp make.tps make.vr make.vrs make.op make.tr make.cv make.cn clean-aminfo: @@ -212,6 +217,45 @@ distclean-aminfo: maintainer-clean-aminfo: for i in $(INFO_DEPS) make.i; do rm -f `eval echo $$i*`; done +install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + +uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) install-man1 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) uninstall-man1 + # Assume that the only thing to do in glob is to build libglob.a, # but do a sanity check: if $SUBDIRS will ever have more than # a single directory, yell bloody murder. @@ -266,7 +310,7 @@ mostlyclean-tags: clean-tags: distclean-tags: - rm -f TAGS ID + -rm -f TAGS ID maintainer-clean-tags: @@ -299,32 +343,6 @@ distdir: $(DISTFILES) @for file in $(DISTFILES); do d=$(srcdir); test -f $(distdir)/$$file || ln $$d/$$file $(distdir)/$$file 2> /dev/null || cp -p $$d/$$file $(distdir)/$$file; done; for subdir in $(SUBDIRS); do test -d $(distdir)/$$subdir || mkdir $(distdir)/$$subdir || exit 1; chmod 777 $(distdir)/$$subdir; (cd $$subdir && $(MAKE) top_distdir=../$(top_distdir)/$$subdir distdir=../$(distdir)/$$subdir distdir) || exit 1; done $(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info $(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook -alloca.o alloca.lo: alloca.c config.h -ar.o ar.lo: ar.c make.h config.h filedef.h dep.h glob/fnmatch.h -arscan.o arscan.lo: arscan.c make.h config.h -commands.o commands.lo: commands.c make.h config.h dep.h filedef.h variable.h job.h commands.h -default.o default.lo: default.c make.h config.h rule.h dep.h filedef.h job.h commands.h variable.h -dir.o dir.lo: dir.c make.h config.h glob/glob.h -expand.o expand.lo: expand.c make.h config.h filedef.h job.h commands.h variable.h -file.o file.lo: file.c make.h config.h dep.h filedef.h job.h commands.h variable.h -function.o function.lo: function.c make.h config.h filedef.h variable.h dep.h job.h commands.h -getloadavg.o getloadavg.lo: getloadavg.c config.h -getopt.o getopt.lo: getopt.c config.h getopt.h -getopt1.o getopt1.lo: getopt1.c config.h getopt.h -implicit.o implicit.lo: implicit.c make.h config.h rule.h dep.h filedef.h -job.o job.lo: job.c make.h config.h job.h filedef.h commands.h variable.h -main.o main.lo: main.c make.h config.h dep.h filedef.h variable.h job.h commands.h getopt.h -misc.o misc.lo: misc.c make.h config.h dep.h -read.o read.lo: read.c make.h config.h dep.h filedef.h job.h commands.h variable.h glob/glob.h -remake.o remake.lo: remake.c make.h config.h filedef.h job.h commands.h dep.h -remote-stub.o remote-stub.lo: remote-stub.c make.h config.h filedef.h job.h commands.h -rule.o rule.lo: rule.c make.h config.h dep.h filedef.h job.h commands.h variable.h rule.h -signame.o signame.lo: signame.c config.h signame.h -variable.o variable.lo: variable.c make.h config.h dep.h filedef.h job.h commands.h variable.h -version.o version.lo: version.c config.h -vpath.o vpath.lo: vpath.c make.h config.h filedef.h variable.h -fnmatch.o fnmatch.lo: fnmatch.c fnmatch.h ../config.h -glob.o glob.lo: glob.c fnmatch.h glob.h ../config.h info: $(INFO_DEPS) info-recursive dvi: $(DVIS) dvi-recursive @@ -362,19 +380,19 @@ installdirs: installdirs-recursive mostlyclean-generic: - test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) clean-generic: - test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: - rm -f Makefile $(DISTCLEANFILES) - rm -f config.cache config.log stamp-h stamp-h[0-9]* - test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) maintainer-clean-generic: - test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) - test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) mostlyclean-am: mostlyclean-hdr mostlyclean-binPROGRAMS mostlyclean-compile mostlyclean-aminfo mostlyclean-tags mostlyclean-generic clean-am: clean-hdr clean-binPROGRAMS clean-compile clean-aminfo clean-tags clean-generic mostlyclean-am diff --git a/Makefile.am b/Makefile.am index 54634282..ab1c1f18 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ # -*-Makefile-*-, or close enough -AUTOMAKE_OPTIONS = 1.2 +AUTOMAKE_OPTIONS = 1.3 bin_PROGRAMS = make @@ -13,12 +13,13 @@ make_SOURCES = main.c commands.c job.c dir.c file.c misc.c read.c remake.c \ make_LDADD = @LIBOBJS@ @ALLOCA@ glob/libglob.a info_TEXINFOS = make.texinfo +man_MANS = make.1 INCLUDES = -I$(srcdir)/glob -DLIBDIR=\"$(libdir)\" -DINCLUDEDIR=\"$(includedir)\" BUILT_SOURCES = README build.sh.in -EXTRA_DIST = make.man $(BUILT_SOURCES) remote-cstms.c\ +EXTRA_DIST = $(BUILT_SOURCES) $(man_MANS) README.customs remote-cstms.c\ make-stds.texi texinfo.tex SCOPTIONS SMakefile\ README.Amiga Makefile.ami config.ami make.lnk amiga.c amiga.h\ README.DOS Makefile.DOS configure.bat dosbuild.bat configh.dos\ @@ -31,13 +32,43 @@ SUBDIRS = glob MOSTLYCLEANFILES = loadavg.c CLEANFILES = loadavg + +# --------------- Local INSTALL Section + +# If necessary, change the gid of the app and turn on the setgid flag. +# + +# Whether or not make needs to be installed setgid. +# The value should be either `true' or `false'. +# On many systems, the getloadavg function (used to implement the `-l' +# switch) will not work unless make is installed setgid kmem. +# +inst_setgid = @NEED_SETGID@ + +# Install make setgid to this group so it can get the load average. +# +inst_group = @KMEM_GROUP@ + +install-exec-local: + @if $(inst_setgid); then \ + app=$(DESTDIR)$(bindir)/`echo $(bin_PROGRAMS)|sed '$(transform)'`; \ + if chgrp $(inst_group) $$app && chmod g+s $$app; then \ + echo "chgrp $(inst_group) $$app && chmod g+s $$app"; \ + else \ + echo "$$app needs to be owned by group $(inst_group) and setgid;"; \ + echo "otherwise the \`-l' option will probably not work."; \ + echo "You may need special privileges to complete the installation"; \ + echo "of $$app."; \ + fi; \ + else true; fi + # --------------- Local DIST Section # Install the w32 subdirectory # dist-hook: (cd $(srcdir); \ - w32=`find w32 -follow \( -name CVS -prune \) -o -type f -print`; \ + w32=`find w32 -follow \( -name CVS -prune \) -o \( -name \*.orig -o -name \*.rej -o -name \*~ -prune \) -o -type f -print`; \ tar chf - $$w32) \ | (cd $(distdir); tar xfBp -) @@ -52,11 +83,14 @@ check-local: check-loadavg check-regression loadavg: loadavg.c config.h @rm -f loadavg $(LINK) -I. -I$(srcdir) -DHAVE_CONFIG_H -DTEST $(make_LDFLAGS) loadavg.c $(LIBS) + # We copy getloadavg.c into a different file rather than compiling it # directly because some compilers clobber getloadavg.o in the process. +# loadavg.c: getloadavg.c ln $(srcdir)/getloadavg.c loadavg.c || \ - cp $(srcdir)/getloadavg.c loadavg.c + cp $(srcdir)/getloadavg.c loadavg.c + check-loadavg: loadavg @echo The system uptime program believes the load average to be: -uptime @@ -69,8 +103,10 @@ check-loadavg: loadavg # specified, or else in the srcdir or the distdir, their parents, and _their_ # parents. # +MAKETESTFLAGS = + check-regression: all - here=`pwd`; testdir=""; \ + @here=`pwd`; testdir=""; \ case "$(MAKE_TEST)" in "") \ for d1 in $$here $(srcdir); do \ for d2 in ../.. .. .; do \ @@ -83,10 +119,10 @@ check-regression: all *) testdir="$(MAKE_TEST)" ;; \ esac; \ case "$$testdir" in \ - "") echo "Couldn't find make-test-* test suite."; exit 0;; \ + "") echo "Couldn't find make-test-* regression test suite."; exit 0;; \ esac; \ - echo "cd $$testdir && ./run_make_tests -make_path $$here/make"; \ - cd $$testdir && ./run_make_tests -make_path $$here/make + echo "cd $$testdir && ./run_make_tests -make $$here/make $(MAKETESTFLAGS)"; \ + cd $$testdir && ./run_make_tests -make $$here/make $(MAKETESTFLAGS) # --------------- Maintainer's Section diff --git a/NEWS b/NEWS index 70cdc621..5bc2974f 100644 --- a/NEWS +++ b/NEWS @@ -1,11 +1,57 @@ GNU make NEWS -*-indented-text-*- History of user-visible changes. - 19 Sep 1997 + 19 May 1998 -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. +Copyright (C) 1992,1993,1994,1995,1996,1997,1998 Free Software Foundation, Inc. See the end for copying conditions. -Please send GNU make bug reports to bug-gnu-utils@prep.ai.mit.edu. +Please send GNU make bug reports to bug-make@gnu.org. + +Version 3.77 + +* Implement BSD make's "?=" variable assignment operator. The variable + is assigned the specified value only if that variable is not already + defined. + +* Make defines a new variable, "CURDIR", to contain the current working + directory (after the -C option, if any, has been processed). + Modifying this variable has no effect on the operation of make. + +* Make defines a new default RCS rule, for new-style master file + storage: ``% :: RCS/%'' (note no ``,v'' suffix). + + Make defines new default rules for DOS-style C++ file naming + conventions, with ``.cpp'' suffixes. All the same rules as for + ``.cc'' and ``.C'' suffixes are provided, along with LINK.cpp and + COMPILE.cpp macros (which default to the same value as LINK.cc and + COMPILE.cc). Note CPPFLAGS is still C preprocessor flags! You should + use CXXFLAGS to change C++ compiler flags. + +* A new feature, "target-specific variable values", has been added. + This is a large change so please see the appropriate sections of the + manual for full details. Briefly, syntax like this: + + TARGET: VARIABLE = VALUE + + defines VARIABLE as VALUE within the context of TARGET. This is + similar to SunOS make's "TARGET := VARIABLE = VALUE" feature. Note + that the assignment may be of any type, not just recursive, and that + the override keyword is available. + + COMPATIBILITY: This new syntax means that if you have any rules where + the first or second dependency has an equal sign (=) in its name, + you'll have to escape them with a backslash: "foo : bar\=baz". + Further, if you have any dependencies which already contain "\=", + you'll have to escape both of them: "foo : bar\\\=baz". + +* A new appendix listing the most common error and warning messages + generated by GNU make, with some explanation, has been added to the + GNU make User's Manual. + +* Updates to the GNU make Customs library support (see README.customs). + +* Updates to the Windows 95/NT port from Rob Tulloh (see README.W32), + and to the DOS port from Eli Zaretski (see README.DOS). Version 3.76.1 diff --git a/NMakefile.template b/NMakefile.template index d82dbce4..8f2b3f37 100644 --- a/NMakefile.template +++ b/NMakefile.template @@ -1,141 +1,118 @@ -# NOTE: If you have no `make' program at all to process this makefile, run -# `build_w32.bat' instead. -# -# Copyright (C) 1988,89,91,92,93,94,95,96,97 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. - -# -# NMakefile for GNU Make -# - -LINK = link -CC = cl - -OUTDIR=. -MAKEFILE=NMakefile -SUBPROC_MAKEFILE=NMakefile - -CFLAGS_any = /nologo /MT /W3 /GX /Zi /YX /I . /I glob /I w32/include /D WIN32 /D WINDOWS32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES -CFLAGS_debug = $(CFLAGS_any) /Od /D _DEBUG /FR.\WinDebug/ /Fp.\WinDebug/make.pch /Fo.\WinDebug/ /Fd.\WinDebug/make.pdb -CFLAGS_release = $(CFLAGS_any) /O2 /D NDEBUG /FR.\WinRel/ /Fp.\WinRel/make.pch /Fo.\WinRel/ - -LDFLAGS_debug = w32\subproc\WinDebug\subproc.lib /NOLOGO /SUBSYSTEM:console\ - /INCREMENTAL:no /PDB:WinDebug/make.pdb /MACHINE:I386 \ - /OUT:WinDebug/make.exe /DEBUG -LDFLAGS_release = w32\subproc\WinRel\subproc.lib /NOLOGO /SUBSYSTEM:console\ - /INCREMENTAL:no /MACHINE:I386 /OUT:WinRel/make.exe - -all: config.h subproc Release Debug - -# -# Make sure we build the subproc library first. It has it's own -# makefile. To be portable to Windows 95, we put the instructions -# on how to build the library into a batch file. On NT, we could -# simply have done foo && bar && dog, but this doesn't port. -# -subproc: w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib - -w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib: - subproc.bat $(SUBPROC_MAKEFILE) - -config.h: config.h.W32 - copy $? $@ - -Release: - nmake /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_release)" CFLAGS="$(CFLAGS_release)" OUTDIR=WinRel WinRel/make.exe -Debug: - nmake /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_debug)" CFLAGS="$(CFLAGS_debug)" OUTDIR=WinDebug WinDebug/make.exe - -clean: - rmdir /s /q WinDebug WinRel - rmdir /s /q w32\subproc\WinDebug w32\subproc\WinRel - erase config.h - -$(OUTDIR): - if not exist .\$@\nul mkdir .\$@ - -LIBS = kernel32.lib user32.lib advapi32.lib - -OBJS = \ - $(OUTDIR)/ar.obj \ - $(OUTDIR)/arscan.obj \ - $(OUTDIR)/commands.obj \ - $(OUTDIR)/default.obj \ - $(OUTDIR)/dir.obj \ - $(OUTDIR)/expand.obj \ - $(OUTDIR)/file.obj \ - $(OUTDIR)/function.obj \ - $(OUTDIR)/getloadavg.obj \ - $(OUTDIR)/getopt.obj \ - $(OUTDIR)/getopt1.obj \ - $(OUTDIR)/implicit.obj \ - $(OUTDIR)/job.obj \ - $(OUTDIR)/main.obj \ - $(OUTDIR)/misc.obj \ - $(OUTDIR)/read.obj \ - $(OUTDIR)/remake.obj \ - $(OUTDIR)/remote-stub.obj \ - $(OUTDIR)/rule.obj \ - $(OUTDIR)/signame.obj \ - $(OUTDIR)/variable.obj \ - $(OUTDIR)/version.obj \ - $(OUTDIR)/vpath.obj \ - $(OUTDIR)/glob.obj \ - $(OUTDIR)/fnmatch.obj \ - $(OUTDIR)/dirent.obj \ - $(OUTDIR)/pathstuff.obj - -$(OUTDIR)/make.exe: $(OUTDIR) $(OBJS) - $(LINK) @<< - $(LDFLAGS) $(LIBS) $(OBJS) -<< - -.c{$(OUTDIR)}.obj: - $(CC) $(CFLAGS) /c $< - -$(OUTDIR)/ar.obj : ar.c make.h filedef.h dep.h -$(OUTDIR)/arscan.obj : arscan.c make.h -$(OUTDIR)/commands.obj : commands.c -$(OUTDIR)/default.obj : default.c make.h rule.h dep.h filedef.h job.h commands.h variable.h -$(OUTDIR)/dir.obj : dir.c make.h -$(OUTDIR)/expand.obj : expand.c make.h filedef.h job.h commands.h variable.h -$(OUTDIR)/file.obj : file.c make.h dep.h filedef.h job.h commands.h variable.h -$(OUTDIR)/function.obj : function.c make.h filedef.h variable.h dep.h job.h commands.h -$(OUTDIR)/getloadavg.obj : getloadavg.c -$(OUTDIR)/getopt.obj : getopt.c -$(OUTDIR)/getopt1.obj : getopt1.c getopt.h -$(OUTDIR)/implicit.obj : implicit.c make.h rule.h dep.h filedef.h -$(OUTDIR)/job.obj : job.c make.h job.h filedef.h commands.h variable.h -$(OUTDIR)/main.obj : main.c make.h dep.h filedef.h variable.h job.h commands.h getopt.h -$(OUTDIR)/misc.obj : misc.c make.h dep.h -$(OUTDIR)/read.obj : read.c make.h dep.h filedef.h job.h commands.h variable.h glob/glob.h -$(OUTDIR)/remake.obj : remake.c make.h filedef.h job.h commands.h dep.h -$(OUTDIR)/remote-stub.obj : remote-stub.c make.h filedef.h job.h commands.h -$(OUTDIR)/rule.obj : rule.c make.h dep.h filedef.h job.h commands.h variable.h rule.h -$(OUTDIR)/signame.obj : signame.c signame.h -$(OUTDIR)/variable.obj : variable.c make.h dep.h filedef.h job.h commands.h variable.h -$(OUTDIR)/version.obj : version.c -$(OUTDIR)/vpath.obj : vpath.c make.h filedef.h variable.h -$(OUTDIR)/glob.obj : glob/glob.c - $(CC) $(CFLAGS) /c $? -$(OUTDIR)/fnmatch.obj : glob/fnmatch.c - $(CC) $(CFLAGS) /c $? -$(OUTDIR)/dirent.obj : w32/compat/dirent.c - $(CC) $(CFLAGS) /c $? -$(OUTDIR)/pathstuff.obj : w32/pathstuff.c - $(CC) $(CFLAGS) /c $? - +# NOTE: If you have no `make' program at all to process this makefile, run +# `build_w32.bat' instead. +# +# Copyright (C) 1988,89,91,92,93,94,95,96,97 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. + +# +# NMakefile for GNU Make +# + +LINK = link +CC = cl + +OUTDIR=. +MAKEFILE=NMakefile +SUBPROC_MAKEFILE=NMakefile + +CFLAGS_any = /nologo /MT /W3 /GX /Zi /YX /I . /I glob /I w32/include /D WIN32 /D WINDOWS32 /D _CONSOLE /D HAVE_CONFIG_H /D NO_ARCHIVES +CFLAGS_debug = $(CFLAGS_any) /Od /D DEBUG /D _DEBUG /FR.\WinDebug/ /Fp.\WinDebug/make.pch /Fo.\WinDebug/ /Fd.\WinDebug/make.pdb +CFLAGS_release = $(CFLAGS_any) /O2 /D NDEBUG /FR.\WinRel/ /Fp.\WinRel/make.pch /Fo.\WinRel/ + +LDFLAGS_debug = w32\subproc\WinDebug\subproc.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /PDB:WinDebug/make.pdb /MACHINE:I386 \ + /OUT:WinDebug/make.exe /DEBUG +LDFLAGS_release = w32\subproc\WinRel\subproc.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /MACHINE:I386 /OUT:WinRel/make.exe + +all: config.h subproc Release Debug + +# +# Make sure we build the subproc library first. It has it's own +# makefile. To be portable to Windows 95, we put the instructions +# on how to build the library into a batch file. On NT, we could +# simply have done foo && bar && dog, but this doesn't port. +# +subproc: w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib + +w32/subproc/WinDebug/subproc.lib w32/subproc/WinRel/subproc.lib: + subproc.bat $(SUBPROC_MAKEFILE) $(MAKE) + +config.h: config.h.W32 + copy $? $@ + +Release: + $(MAKE) /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_release)" CFLAGS="$(CFLAGS_release)" OUTDIR=WinRel WinRel/make.exe +Debug: + $(MAKE) /f $(MAKEFILE) LDFLAGS="$(LDFLAGS_debug)" CFLAGS="$(CFLAGS_debug)" OUTDIR=WinDebug WinDebug/make.exe + +clean: + rmdir /s /q WinDebug WinRel + rmdir /s /q w32\subproc\WinDebug w32\subproc\WinRel + erase config.h + erase *.pdb + +$(OUTDIR): + if not exist .\$@\nul mkdir .\$@ + +LIBS = kernel32.lib user32.lib advapi32.lib + +OBJS = \ + $(OUTDIR)/ar.obj \ + $(OUTDIR)/arscan.obj \ + $(OUTDIR)/commands.obj \ + $(OUTDIR)/default.obj \ + $(OUTDIR)/dir.obj \ + $(OUTDIR)/expand.obj \ + $(OUTDIR)/file.obj \ + $(OUTDIR)/function.obj \ + $(OUTDIR)/getloadavg.obj \ + $(OUTDIR)/getopt.obj \ + $(OUTDIR)/getopt1.obj \ + $(OUTDIR)/implicit.obj \ + $(OUTDIR)/job.obj \ + $(OUTDIR)/main.obj \ + $(OUTDIR)/misc.obj \ + $(OUTDIR)/read.obj \ + $(OUTDIR)/remake.obj \ + $(OUTDIR)/remote-stub.obj \ + $(OUTDIR)/rule.obj \ + $(OUTDIR)/signame.obj \ + $(OUTDIR)/variable.obj \ + $(OUTDIR)/version.obj \ + $(OUTDIR)/vpath.obj \ + $(OUTDIR)/glob.obj \ + $(OUTDIR)/fnmatch.obj \ + $(OUTDIR)/dirent.obj \ + $(OUTDIR)/pathstuff.obj + +$(OUTDIR)/make.exe: $(OUTDIR) $(OBJS) + $(LINK) @<< + $(LDFLAGS) $(LIBS) $(OBJS) +<< + +.c{$(OUTDIR)}.obj: + $(CC) $(CFLAGS) /c $< + +$(OUTDIR)/glob.obj : glob/glob.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/fnmatch.obj : glob/fnmatch.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/dirent.obj : w32/compat/dirent.c + $(CC) $(CFLAGS) /c $? +$(OUTDIR)/pathstuff.obj : w32/pathstuff.c + $(CC) $(CFLAGS) /c $? diff --git a/README.DOS.template b/README.DOS.template index 065c2391..6372437b 100644 --- a/README.DOS.template +++ b/README.DOS.template @@ -37,6 +37,10 @@ To build: if you use PKUNZIP). If you build Make on Windows 95, use an unzip program that supports long filenames in zip files. + If you are unpacking an official GNU source distribution, use + either DJTAR (which is part of the DJGPP development + environment), or the DJGPP port of GNU Tar. + 2. Invoke the `configure.bat' batch file. If you are building Make in-place, i.e. in the same directory @@ -44,7 +48,7 @@ To build: [Enter]. Otherwise, you need to supply the path to the source directory as an argument to the batch file, like this: - configure.bat c:/djgpp/gnu/make-3.76 + configure.bat c:/djgpp/gnu/make-%VERSION% Note the forward slashes: you MUST use them here. @@ -65,7 +69,7 @@ To build: If you are building from outside of the source directory, you need to tell Make where the sources are, like this: - make srcdir=c:/djgpp/gnu/make-3.76 + make srcdir=c:/djgpp/gnu/make-%VERSION% (configure.bat will tell you this when it finishes). You MUST use a full, not relative, name of the source directory here, or @@ -73,8 +77,8 @@ To build: 6. After Make finishes, if you have a Unix-style shell installed, you can use the `install' target to install the package. You - will also need GNU Fileutils and GNU Sh-utils for this (they - should be available from the DJGPP sites). + will also need GNU Fileutils and GNU Sed for this (they should + be available from the DJGPP sites). Without a Unix-style shell, you will have to install programs and the docs manually. Copy make.exe to a directory on your @@ -82,7 +86,7 @@ To build: file `dir' in your Info directory by adding the following item to the main menu: - * GNU make: (make.info). The GNU make utility. + * Make: (make.info). The GNU make utility. If you have the `install-info' program (from the GNU Texinfo package), it will do that for you if you invoke it like this: @@ -92,8 +96,8 @@ To build: (If your Info directory is other than C:\DJGPP\INFO, change this command accordingly.) - 7. The `clean' targets also require Unix-style shell and `test' and - `rm' programs (from Fileutils and Sh-utils, accordingly). + 7. The `clean' targets also require Unix-style shell, and GNU Sed + and `rm' programs (the latter from Fileutils). @@ -240,8 +244,7 @@ Notes: doesn't include characters illegal on MSDOS FAT filesystems, will be automatically down-cased.) User reports that I have indicate that this default behavior is generally what you'd - expect; however, since support for long filenames in the DJGPP - port of GNU Make is relatively new, your input is most welcome. + expect; however, your input is most welcome. In any case, if you hit a situation where you must force Make to get the 8+3 DOS filenames in upper case, set FNCASE=y in the @@ -283,8 +286,8 @@ Bug reports: reported first on the comp.os.msdos.djgpp news group (if you cannot post to Usenet groups, write to the DJGPP mailing list, , which is an email gateway into the above news - group). For other bugs, please follow the the procedure explained - in the "Bugs" chapter of the Info docs. If you don't have an Info + group). For other bugs, please follow the procedure explained in + the "Bugs" chapter of the Info docs. If you don't have an Info reader, look up that chapter in the `make.i1' file with any text browser/editor. diff --git a/README.W32 b/README.W32 index ac5001d9..ca7f32c6 100644 --- a/README.W32 +++ b/README.W32 @@ -46,6 +46,35 @@ GNU make and sh.exe: freely available. It may be available someday, but I am not in control of this decision nor do I influence it. Sorry! +GNU make and Cygnus GNU WIN32 tools (BATCH_MODE_ONLY_SHELL) + + GNU make now has support for the Cygnus GNU WIN32 toolset. The + GNU WIN32 version of Bourne shell does not behave well when + invoked as 'sh -c' from CreateProcess(). The main problem is it + seems to have a hard time handling quoted strings correctly. This + problem goes away when invoking the Cygnus shell on a shell script. + + To work around this difficulty, this version of make supports + a new batch mode. When BATCH_MODE_ONLY_SHELL is defined at compile + time, make forces all command lines to be executed via script + files instead of by command line. + + A native WIN32 system with no Bourne shell will also run + in batch mode. All command lines will be put into batch files + and executed via $(COMSPEC) (%COMSPEC%). + + If you wish to use Cygnus' GNUWIN32 shell, be sure you define + BATCH_MODE_ONLY_SHELL in the config.h.W32 prior to building make. + The new feataure was tested with the b18 version of the Cygnus + user tools. + +GNU make and MKS shell + + There is now semi-official support for the MKS shell. To turn this + support on, define HAVE_MKS_SHELL in the config.h.W32 before you + build make. Do not define BATCH_MODE_ONLY_SHELL if you turn + on HAVE_MKS_SHELL. + GNU make handling of drive letters in pathnames (PATH, vpath, VPATH): There is a caveat that should be noted with respect to handling @@ -127,6 +156,38 @@ Pathnames and white space: and you are free to take a crack at making this work. The code in w32/pathstuff.c and vpath.c would be the places to start. +Pathnames and Case insensitivity: + + Unlike Unix, Windows 95/NT systems are case insensitive but case + preserving. For example if you tell the file system to create a + file named "Target", it will preserve the case. Subsequent access to + the file with other case permutations will succeed (i.e. opening a + file named "target" or "TARGET" will open the file "Target"). + + By default, GNU make retains its case sensitivity when comparing + target names and existing files or directories. It can be + configured, however, into a case preserving and case insensitive + mode by adding a define for HAVE_CASE_INSENSITIVE_FS to + config.h.W32. + + For example, the following makefile will create a file named + Target in the directory subdir which will subsequently be used + to satisfy the dependency of SUBDIR/DepTarget on SubDir/TARGET. + Without HAVE_CASE_INSENSITIVE_FS configured, the dependency link + will not be made: + + subdir/Target: + touch $@ + + SUBDIR/DepTarget: SubDir/TARGET + cp $^ $@ + + Reliance on this behavior also eliminates the ability of GNU make + to use case in comparison of matching rules. For example, it is + not possible to set up a C++ rule using %.C that is different + than a C rule using %.c. GNU make will consider these to be the + same rule and will issue a warning. + SAMBA/NTFS/VFAT: I have not had any success building the debug version of this diff --git a/README.customs b/README.customs new file mode 100644 index 00000000..9ad21f62 --- /dev/null +++ b/README.customs @@ -0,0 +1,73 @@ + -*-indented-text-*- + +GNU make can utilize the Customs library, distributed with Pmake, to +provide builds distributed across multiple hosts. + +In order to utilize this capability, you must first download and build +the Customs library. It is contained in the Pmake distribution, which +can be obtained at: + + ftp://ftp.icsi.berkeley.edu/pub/ai/stolcke/software/ + +This integration was tested (superficially) with Pmake 2.1.33. + + +BUILDING CUSTOMS +---------------- + +First, build pmake and Customs. You need to build pmake first, because +Customs require pmake to build. Unfortunately, this is not trivial; +please see the pmake and Customs documentation for details. The best +place to look for instructions is in the pmake-2.1.33/INSTALL file. + +Note that the 2.1.33 Pmake distribution comes with a set of patches to +GNU make, distributed in the pmake-2.1.33/etc/gnumake/ directory. These +patches are based on GNU make 3.75 (there are patches for earlier +versions of GNU make, also). The parts of this patchfile which relate +directly to Customs support have already been incorporated into this +version of GNU make, so you should _NOT_ apply the patch file. + +However, there are a few non-Customs specific (as far as I could tell) +changes here which are not incorporated (for example, the modification +to try expanding -lfoo to libfoo.so). If you rely on these changes +you'll need to re-apply them by hand. + +Install the Customs library and header files according to the +documentation. You should also install the man pages (contrary to +comments in the documentation, they weren't installed automatically for +me; I had to cd to the ``pmake-2.1.33/doc'' directory and run ``pmake +install'' there directly). + + +BUILDING GNU MAKE +----------------- + +Once you've installed Customs, you can build GNU make to use it. When +configuring GNU make, merely use the ``--with-customs=DIR'' option. +Provide the directory containing the ``lib'' and ``include/customs'' +subdirectories as DIR. For example, if you installed the customs +library in /usr/local/lib and the headers in /usr/local/include/customs, +then you'd pass ``--with-customs=/usr/local'' as an option to configure. + +Run make (or use build.sh) normally to build GNU make as described in +the INSTALL file. + +See the documentation for Customs for information on starting and +configuring Customs. + + +PROBLEMS +-------- + +SunOS 4.1.x: + The customs/sprite.h header file #includes the header + files; this conflicts with GNU make's configuration so you'll get a + compile error if you use GCC (or any other ANSI-capable C compiler). + + I commented out the #include in sprite.h:107: + + #if defined(sun) || defined(ultrix) || defined(hpux) || defined(sgi) + /* #include */ + #else + + YMMV. diff --git a/README.template b/README.template index 0b1736bd..e011f999 100644 --- a/README.template +++ b/README.template @@ -14,6 +14,9 @@ Some systems' Make programs are broken and cannot process the Makefile for GNU Make. If you get errors from your system's Make when building GNU Make, try using `build.sh' instead. + - See README.customs for details on integrating GNU make with the + Customs distributed build environment from the Pmake distribution. + - See README.W32 for details about GNU Make on Windows NT or 95. - See README.Amiga for details about GNU Make on AmigaDOS. diff --git a/SMakefile.template b/SMakefile.template index 47057132..2caa82ea 100644 --- a/SMakefile.template +++ b/SMakefile.template @@ -210,67 +210,3 @@ glob-clean glob-realclean: cd glob smake $@ < - -# The automatically generated dependencies below may omit config.h -# because it is included with ``#include '' rather than -# ``#include "config.h"''. So we add the explicit dependency to make sure. -$(objs): config.h - -# Automatically generated dependencies will be put at the end of the file. - -# Automatically generated dependencies. -commands.o: commands.c make.h dep.h filedef.h variable.h job.h \ - commands.h - -job.o: job.c make.h job.h filedef.h commands.h variable.h - -dir.o: dir.c make.h - -file.o: file.c make.h dep.h filedef.h job.h commands.h variable.h - -misc.o: misc.c make.h dep.h - -main.o: main.c make.h dep.h filedef.h variable.h job.h commands.h \ - getopt.h - -read.o: read.c make.h dep.h filedef.h job.h commands.h variable.h \ - glob/glob.h - -remake.o: remake.c make.h filedef.h job.h commands.h dep.h - -rule.o: rule.c make.h dep.h filedef.h job.h commands.h variable.h \ - rule.h - -implicit.o: implicit.c make.h rule.h dep.h filedef.h - -default.o: default.c make.h rule.h dep.h filedef.h job.h commands.h \ - variable.h - -variable.o: variable.c make.h dep.h filedef.h job.h commands.h \ - variable.h - -expand.o: expand.c make.h filedef.h job.h commands.h variable.h - -function.o: function.c make.h filedef.h variable.h dep.h job.h \ - commands.h amiga.h - -vpath.o: vpath.c make.h filedef.h variable.h - -version.o: version.c - -ar.o: ar.c make.h filedef.h dep.h - -arscan.o: arscan.c make.h - -signame.o: signame.c signame.h - -remote-stub.o: remote-stub.c make.h filedef.h job.h commands.h - -getopt.o: getopt.c - -getopt1.o : getopt1.c getopt.h - -getloadavg.o: getloadavg.c - -amiga.o: amiga.c make.h variable.h amiga.h - diff --git a/acinclude.m4 b/acinclude.m4 new file mode 100644 index 00000000..343c3336 --- /dev/null +++ b/acinclude.m4 @@ -0,0 +1,131 @@ +dnl acinclude.m4 -- Extra macros needed for GNU make. +dnl +dnl Automake will incorporate this into its generated aclocal.m4. + +dnl --------------------------------------------------------------------------- +dnl Got this from the lynx 2.8 distribution. +dnl by T.E.Dickey +dnl and Jim Spath +dnl and Philippe De Muyter +dnl +dnl Created: 1997/1/28 +dnl Updated: 1997/12/23 +dnl --------------------------------------------------------------------------- +dnl After checking for functions in the default $LIBS, make a further check +dnl for the functions that are netlib-related (these aren't always in the +dnl libc, etc., and have to be handled specially because there are conflicting +dnl and broken implementations. +dnl Common library requirements (in order): +dnl -lresolv -lsocket -lnsl +dnl -lnsl -lsocket +dnl -lsocket +dnl -lbsd +AC_DEFUN([CF_NETLIBS],[ +cf_test_netlibs=no +AC_MSG_CHECKING(for network libraries) +AC_CACHE_VAL(cf_cv_netlibs,[ +AC_MSG_RESULT(working...) +cf_cv_netlibs="" +cf_test_netlibs=yes +AC_CHECK_FUNCS(gethostname,,[ + CF_RECHECK_FUNC(gethostname,nsl,cf_cv_netlibs,[ + CF_RECHECK_FUNC(gethostname,socket,cf_cv_netlibs)])]) +# +# FIXME: sequent needs this library (i.e., -lsocket -linet -lnsl), but +# I don't know the entrypoints - 97/7/22 TD +AC_CHECK_LIB(inet,main,cf_cv_netlibs="-linet $cf_cv_netlibs") +# +if test "$ac_cv_func_lsocket" != no ; then +AC_CHECK_FUNCS(socket,,[ + CF_RECHECK_FUNC(socket,socket,cf_cv_netlibs,[ + CF_RECHECK_FUNC(socket,bsd,cf_cv_netlibs)])]) +fi +# +AC_CHECK_FUNCS(gethostbyname,,[ + CF_RECHECK_FUNC(gethostbyname,nsl,cf_cv_netlibs)]) +# +AC_CHECK_FUNCS(strcasecmp,,[ + CF_RECHECK_FUNC(strcasecmp,resolv,cf_cv_netlibs)]) +]) +LIBS="$LIBS $cf_cv_netlibs" +test $cf_test_netlibs = no && echo "$cf_cv_netlibs" >&AC_FD_MSG +])dnl +dnl --------------------------------------------------------------------------- +dnl Re-check on a function to see if we can pick it up by adding a library. +dnl $1 = function to check +dnl $2 = library to check in +dnl $3 = environment to update (e.g., $LIBS) +dnl $4 = what to do if this fails +dnl +dnl This uses 'unset' if the shell happens to support it, but leaves the +dnl configuration variable set to 'unknown' if not. This is a little better +dnl than the normal autoconf test, which gives misleading results if a test +dnl for the function is made (e.g., with AC_CHECK_FUNC) after this macro is +dnl used (autoconf does not distinguish between a null token and one that is +dnl set to 'no'). +AC_DEFUN([CF_RECHECK_FUNC],[ +AC_CHECK_LIB($2,$1,[ + CF_UPPER(cf_tr_func,$1) + AC_DEFINE_UNQUOTED(HAVE_$cf_tr_func) + ac_cv_func_$1=yes + $3="-l$2 [$]$3"],[ + ac_cv_func_$1=unknown + unset ac_cv_func_$1 2>/dev/null + $4], + [[$]$3]) +])dnl +dnl --------------------------------------------------------------------------- +dnl Make an uppercase version of a variable +dnl $1=uppercase($2) +AC_DEFUN([CF_UPPER], +[ +changequote(,)dnl +$1=`echo $2 | tr '[a-z]' '[A-Z]'` +changequote([,])dnl +])dnl + +dnl --------------------------------------------------------------------------- +dnl Got this from the GNU fileutils 3.16r distribution +dnl by Paul Eggert +dnl --------------------------------------------------------------------------- + +dnl The problem is that the default compilation flags in Solaris 2.6 won't +dnl let programs access large files; you need to tell the compiler that +dnl you actually want your programs to work on large files. For more +dnl details about this brain damage please see: +dnl http://www.sas.com/standards/large.file/x_open.20Mar96.html + +AC_DEFUN(AC_LFS, +[dnl + # If available, prefer support for large files unless the user specified + # one of the CPPFLAGS, LDFLAGS, or LIBS variables. + AC_MSG_CHECKING(whether large file support needs explicit enabling) + ac_getconfs='' + ac_result=yes + ac_set='' + ac_shellvars='CPPFLAGS LDFLAGS LIBS' + for ac_shellvar in $ac_shellvars; do + case $ac_shellvar in + CPPFLAGS) ac_lfsvar=LFS_CFLAGS ;; + *) ac_lfsvar=LFS_$ac_shellvar ;; + esac + eval test '"${'$ac_shellvar'+set}"' = set && ac_set=$ac_shellvar + (getconf $ac_lfsvar) >/dev/null 2>&1 || { ac_result=no; break; } + ac_getconf=`getconf $ac_lfsvar` + ac_getconfs=$ac_getconfs$ac_getconf + eval ac_test_$ac_shellvar=\$ac_getconf + done + case "$ac_result$ac_getconfs" in + yes) ac_result=no ;; + esac + case "$ac_result$ac_set" in + yes?*) ac_result="yes, but $ac_set is already set, so use its settings" + esac + AC_MSG_RESULT($ac_result) + case $ac_result in + yes) + for ac_shellvar in $ac_shellvars; do + eval $ac_shellvar=\$ac_test_$ac_shellvar + done ;; + esac +]) diff --git a/arscan.c b/arscan.c index 9cf746bb..13ae45ba 100644 --- a/arscan.c +++ b/arscan.c @@ -600,15 +600,12 @@ ar_name_equal (name, mem, truncated) abort (); #else struct ar_hdr hdr; - return !strncmp (name, mem, - sizeof (hdr.ar_name) - #if !defined (__hpux) && !defined (cray) - 1 + return !strncmp (name, mem, sizeof(hdr.ar_name) - 1); #else - 2 + return !strncmp (name, mem, sizeof(hdr.ar_name) - 2); #endif /* !__hpux && !cray */ - ); -#endif +#endif /* !AIAMAG */ } #endif /* !VMS */ diff --git a/config.ami.template b/config.ami.template index 1be0ccbd..b7103ed5 100644 --- a/config.ami.template +++ b/config.ami.template @@ -278,3 +278,6 @@ /* Define if you have the sun library (-lsun). */ #undef HAVE_LIBSUN + +/* Define for Case Insensitve behavior */ +#define HAVE_CASE_INSENSITIVE_FS diff --git a/config.h.W32.template b/config.h.W32.template index cf8a8886..aa5a0277 100644 --- a/config.h.W32.template +++ b/config.h.W32.template @@ -29,7 +29,7 @@ /* Define if you have alloca, as a function or macro. */ #undef HAVE_ALLOCA -#define HAVE_ALLOCA +#define HAVE_ALLOCA 1 /* Define if you have and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H @@ -52,7 +52,7 @@ /* Define if you support file names longer than 14 characters. */ #undef HAVE_LONG_FILE_NAMES -#define HAVE_LONG_FILE_NAMES +#define HAVE_LONG_FILE_NAMES 1 /* Define if you have a working `mmap' system call. */ #undef HAVE_MMAP @@ -69,15 +69,15 @@ /* Define if you have the strcoll function and it is properly defined. */ #undef HAVE_STRCOLL -#define HAVE_STRCOLL +#define HAVE_STRCOLL 1 /* Define if your struct stat has st_rdev. */ #undef HAVE_ST_RDEV -#define HAVE_ST_RDEV +#define HAVE_ST_RDEV 1 /* Define if you have the strftime function. */ #undef HAVE_STRFTIME -#define HAVE_STRFTIME +#define HAVE_STRFTIME 1 /* Define if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H @@ -88,21 +88,21 @@ /* Define if you don't have tm_zone but do have the external array tzname. */ #undef HAVE_TZNAME -#define HAVE_TZNAME +#define HAVE_TZNAME 1 /* Define if you have . */ #undef HAVE_UNISTD_H /* Define if utime(file, NULL) sets file's timestamp to the present. */ #undef HAVE_UTIME_NULL -#define HAVE_UTIME_NULL +#define HAVE_UTIME_NULL 1 /* Define if you have . */ #undef HAVE_VFORK_H /* Define if you have the vprintf function. */ #undef HAVE_VPRINTF -#define HAVE_VPRINTF +#define HAVE_VPRINTF 1 /* Define if you have the wait3 system call. */ #undef HAVE_WAIT3 @@ -129,7 +129,7 @@ /* Define if you need to in order for stat and other things to work. */ #undef _POSIX_SOURCE -#define _POSIX_SOURCE +#define _POSIX_SOURCE 1 /* Define as the return type of signal handlers (int or void). */ #undef RETSIGTYPE @@ -154,7 +154,7 @@ /* Define if you have the ANSI C header files. */ #undef STDC_HEADERS -#define STDC_HEADERS +#define STDC_HEADERS 1 /* Define on System V Release 4. */ #undef SVR4 @@ -200,18 +200,18 @@ /* Define if you have the dup2 function. */ #undef HAVE_DUP2 -#define HAVE_DUP2 +#define HAVE_DUP2 1 /* Define if you have the getcwd function. */ #undef HAVE_GETCWD -#define HAVE_GETCWD +#define HAVE_GETCWD 1 /* Define if you have the getgroups function. */ #undef HAVE_GETGROUPS /* Define if you have the mktemp function. */ #undef HAVE_MKTEMP -#define HAVE_MKTEMP +#define HAVE_MKTEMP 1 /* Define if you have the psignal function. */ #undef HAVE_PSIGNAL @@ -236,7 +236,7 @@ /* Define if you have the strerror function. */ #undef HAVE_STRERROR -#define HAVE_STRERROR +#define HAVE_STRERROR 1 /* Define if you have the strsignal function. */ #undef HAVE_STRSIGNAL @@ -249,29 +249,29 @@ /* Define if you have the header file. */ #undef HAVE_DIRENT_H -#define HAVE_DIRENT_H +#define HAVE_DIRENT_H 1 /* Define if you have the header file. */ #undef HAVE_FCNTL_H -#define HAVE_FCNTL_H +#define HAVE_FCNTL_H 1 /* Define if you have the header file. */ #undef HAVE_LIMITS_H -#define HAVE_LIMITS_H +#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 -#define HAVE_MEMORY_H +#define HAVE_MEMORY_H 1 /* Define if you have the header file. */ #undef HAVE_NDIR_H /* Define if you have the header file. */ #undef HAVE_STRING_H -#define HAVE_STRING_H +#define HAVE_STRING_H 1 /* Define if you have the header file. */ #undef HAVE_SYS_DIR_H @@ -284,7 +284,7 @@ /* Define if you have the header file. */ #undef HAVE_SYS_TIMEB_H -#define HAVE_SYS_TIMEB_H +#define HAVE_SYS_TIMEB_H 1 /* Define if you have the header file. */ #undef HAVE_SYS_WAIT_H @@ -297,3 +297,22 @@ /* Define if you have the sun library (-lsun). */ #undef HAVE_LIBSUN + +/* + * Refer to README.W32 for info on the following settings + */ + +/* + Define if you have the Cygnus GNU WIN32 tool set or a shell + that does not grok 'sh -c quoted-command-line' correctly. + */ +#undef BATCH_MODE_ONLY_SHELL + +/* + Define if you have the MKS tool set or shell. Do NOT define + BATCH_MODE_ONLY_SHELL if you define HAVE_MKS_SHELL + */ +#undef HAVE_MKS_SHELL + +/* Define if you prefer Case Insensitve behavior */ +#undef HAVE_CASE_INSENSITIVE_FS diff --git a/configure.in b/configure.in index 655ee7ee..8fb99f71 100644 --- a/configure.in +++ b/configure.in @@ -3,7 +3,7 @@ AC_REVISION([$Id$]) AC_PREREQ(2.12)dnl dnl Minimum Autoconf version required. AC_INIT(vpath.c)dnl dnl A distinctive file to look for in srcdir. -AM_INIT_AUTOMAKE(make, 3.76.1) +AM_INIT_AUTOMAKE(make, 3.77) AM_CONFIG_HEADER(config.h) AC_CONFIG_SUBDIRS(glob) @@ -15,10 +15,16 @@ AC_PROG_MAKE_SET AC_PROG_CC AC_PROG_INSTALL AC_PROG_CPP dnl Later checks need this. -AC_ARG_PROGRAM +dnl AC_ARG_PROGRAM -- implied by AM_INIT_AUTOMAKE; gives errors if run twice. AC_AIX AC_ISC_POSIX AC_MINIX + +dnl This test must come as early as possible after the compiler configuration +dnl tests, because the choice of the file model can (in principle) affect +dnl whether functions and headers are available, whether they work, etc. +AC_LFS + AC_HEADER_STDC AC_HEADER_DIRENT AC_TYPE_UID_T dnl Also does gid_t. @@ -91,8 +97,25 @@ AC_DECL_SYS_SIGLIST AC_CHECK_LIB(sun, getpwnam) AC_SUBST(REMOTE) REMOTE=stub -AC_ARG_WITH(customs, [export jobs with the Customs daemon (NOT SUPPORTED)], -[REMOTE=cstms LIBS="$LIBS libcustoms.a"]) +make_try_customs=no +AC_ARG_WITH(customs, +[ --with-customs=DIR Enable remote jobs via Customs--see README.customs], +[case "$withval" in + n|no) ;; + *) make_cppflags="$CPPFLAGS" + case "$withval" in + y|ye|yes) ;; + *) CPPFLAGS="$CPPFLAGS -I$with_customs/include/customs" + make_ldflags="$LDFLAGS -L$with_customs/lib" ;; + esac + CF_NETLIBS + AC_CHECK_HEADER(customs.h, + REMOTE=cstms + LIBS="$LIBS -lcustoms" LDFLAGS="$make_ldflags", + with_customs=no + CPPFLAGS="$make_cppflags" make_badcust=yes) + ;; +esac]) echo checking for location of SCCS get command if test -f /usr/sccs/get; then @@ -116,6 +139,26 @@ rm -f s.conftest conftoast AC_OUTPUT(Makefile build.sh) +case "$make_badcust" in + yes) echo + echo "WARNING: --with-customs specified but no customs.h could be found;" + echo " disabling Customs support." + echo ;; +esac + +case "$with_customs" in + ""|n|no|y|ye|yes) ;; + *) if test -f "$with_customs/lib/libcustoms.a"; then + : + else + echo + echo "WARNING: \`$with_customs/lib' does not appear to contain the" + echo " Customs library. You must build and install Customs" + echo " before compiling GNU make." + echo + fi ;; +esac + dnl Local Variables: dnl comment-start: "dnl " dnl comment-end: "" diff --git a/default.c b/default.c index 5f5d2b51..653bc81f 100644 --- a/default.c +++ b/default.c @@ -41,7 +41,7 @@ static char default_suffixes[] .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 \ + = ".out .a .ln .o .c .cc .C .cpp .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 @@ -91,6 +91,8 @@ static struct pspec default_terminal_rules[] = "$(CHECKOUT,v)" }, { "%", "RCS/%,v", "$(CHECKOUT,v)" }, + { "%", "RCS/%", + "$(CHECKOUT,v)" }, /* SCCS. */ { "%", "s.%", @@ -156,6 +158,8 @@ static char *default_suffix_rules[] = "$(LINK.cc) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".C", "$(LINK.C) $^ $(LOADLIBES) $(LDLIBS) -o $@", + ".cpp", + "$(LINK.cpp) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".f", "$(LINK.f) $^ $(LOADLIBES) $(LDLIBS) -o $@", ".p", @@ -183,6 +187,8 @@ static char *default_suffix_rules[] = "$(COMPILE.cc) $< $(OUTPUT_OPTION)", ".C.o", "$(COMPILE.C) $< $(OUTPUT_OPTION)", + ".cpp.o", + "$(COMPILE.cpp) $< $(OUTPUT_OPTION)", ".f.o", "$(COMPILE.f) $< $(OUTPUT_OPTION)", ".p.o", @@ -386,8 +392,10 @@ static char *default_variables[] = "LINK.c", "$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "COMPILE.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c", "COMPILE.C", "$(COMPILE.cc)", + "COMPILE.cpp", "$(COMPILE.cc)", "LINK.cc", "$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)", "LINK.C", "$(LINK.cc)", + "LINK.cpp", "$(LINK.cc)", "YACC.y", "$(YACC) $(YFLAGS)", "LEX.l", "$(LEX) $(LFLAGS) -t", "COMPILE.f", "$(FC) $(FFLAGS) $(TARGET_ARCH) -c", diff --git a/dir.c b/dir.c index d187c03e..9e1cf7af 100644 --- a/dir.c +++ b/dir.c @@ -111,19 +111,25 @@ dosify (filename) #ifdef _AMIGA #include +#endif +#ifdef HAVE_CASE_INSENSITIVE_FS static char * -amigafy (filename) +downcase (filename) char *filename; { - static char amiga_filename[136]; +#ifdef _AMIGA + static char new_filename[136]; +#else + static char new_filename[PATH_MAX]; +#endif char *df; int i; if (filename == 0) return 0; - df = amiga_filename; + df = new_filename; /* First, transform the name part. */ for (i = 0; *filename != '\0'; ++i) @@ -134,9 +140,9 @@ amigafy (filename) *df = 0; - return amiga_filename; + return new_filename; } -#endif /* _AMIGA */ +#endif /* HAVE_CASE_INSENSITIVE_FS */ #ifdef VMS @@ -355,7 +361,7 @@ find_directory (name) for (dc = directories_contents[hash]; dc != 0; dc = dc->next) #ifdef WINDOWS32 - if (!strcmp(dc->path_key, w32_path)) + if (strieq(dc->path_key, w32_path)) #else if (dc->dev == st.st_dev #ifdef VMS @@ -468,8 +474,8 @@ dir_contents_file_exists_p (dir, filename) filename = dosify (filename); #endif -#ifdef _AMIGA - filename = amigafy (filename); +#ifdef HAVE_CASE_INSENSITIVE_FS + filename = downcase (filename); #endif #ifdef VMS @@ -613,6 +619,7 @@ file_exists_p (name) { char *dirend; char *dirname; + char *slash; #ifndef NO_ARCHIVES if (ar_name (name)) @@ -632,8 +639,9 @@ file_exists_p (name) char *bslash = rindex(name, '\\'); if (!dirend || bslash > dirend) dirend = bslash; - /* The case of "d:file" is unhandled. But I don't think - such names can happen here. */ + /* The case of "d:file". */ + if (!dirend && name[0] && name[1] == ':') + dirend = name + 1; } #endif /* WINDOWS32 || __MSDOS__ */ if (dirend == 0) @@ -644,15 +652,22 @@ file_exists_p (name) #endif /* AMIGA */ #endif /* VMS */ + slash = dirend; if (dirend == name) dirname = "/"; else { +#if defined (WINDOWS32) || defined (__MSDOS__) + /* d:/ and d: are *very* different... */ + if (dirend < name + 3 && name[1] == ':' && + (*dirend == '/' || *dirend == '\\' || *dirend == ':')) + dirend++; +#endif dirname = (char *) alloca (dirend - name + 1); bcopy (name, dirname, dirend - name); dirname[dirend - name] = '\0'; } - return dir_file_exists_p (dirname, dirend + 1); + return dir_file_exists_p (dirname, slash + 1); } /* Mark FILENAME as `impossible' for `file_impossible_p'. @@ -682,8 +697,9 @@ file_impossible (filename) char *bslash = rindex(p, '\\'); if (!dirend || bslash > dirend) dirend = bslash; - /* The case of "d:file" is unhandled. But I don't think - such names can happen here. */ + /* The case of "d:file". */ + if (!dirend && p[0] && p[1] == ':') + dirend = p + 1; } #endif /* WINDOWS32 or __MSDOS__ */ if (dirend == 0) @@ -696,16 +712,23 @@ file_impossible (filename) else { char *dirname; + char *slash = dirend; if (dirend == p) dirname = "/"; else { +#if defined (WINDOWS32) || defined (__MSDOS__) + /* d:/ and d: are *very* different... */ + if (dirend < p + 3 && p[1] == ':' && + (*dirend == '/' || *dirend == '\\' || *dirend == ':')) + dirend++; +#endif dirname = (char *) alloca (dirend - p + 1); bcopy (p, dirname, dirend - p); dirname[dirend - p] = '\0'; } dir = find_directory (dirname); - filename = p = dirend + 1; + filename = p = slash + 1; } for (hash = 0; *p != '\0'; ++p) @@ -776,8 +799,9 @@ file_impossible_p (filename) char *bslash = rindex(filename, '\\'); if (!dirend || bslash > dirend) dirend = bslash; - /* The case of "d:file" is unhandled. But I don't think - such names can happen here. */ + /* The case of "d:file". */ + if (!dirend && filename[0] && filename[1] == ':') + dirend = filename + 1; } #endif /* WINDOWS32 || __MSDOS__ */ if (dirend == 0) @@ -790,16 +814,23 @@ file_impossible_p (filename) else { char *dirname; + char *slash = dirend; if (dirend == filename) dirname = "/"; else { +#if defined (WINDOWS32) || defined (__MSDOS__) + /* d:/ and d: are *very* different... */ + if (dirend < filename + 3 && filename[1] == ':' && + (*dirend == '/' || *dirend == '\\' || *dirend == ':')) + dirend++; +#endif dirname = (char *) alloca (dirend - filename + 1); bcopy (p, dirname, dirend - p); dirname[dirend - p] = '\0'; } dir = find_directory (dirname)->contents; - p = filename = dirend + 1; + p = filename = slash + 1; } if (dir == 0 || dir->files == 0) @@ -809,8 +840,8 @@ file_impossible_p (filename) #ifdef __MSDOS__ p = filename = dosify (p); #endif -#ifdef _AMIGA - p = filename = amigafy (p); +#ifdef HAVE_CASE_INSENSITIVE_FS + p = filename = downcase (p); #endif #ifdef VMS p = filename = vmsify (p, 1); @@ -891,8 +922,9 @@ print_dir_data_base () 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); + printf ("# %s (device %ld, inode %ld): ", + dir->name, + (long)dir->contents->dev, (long)dir->contents->ino); #endif #endif /* WINDOWS32 */ if (f == 0) @@ -1016,6 +1048,14 @@ read_dirstream (stream) return 0; } +static void +ansi_free(p) + void *p; +{ + if (p) + free(p); +} + void dir_setup_glob (gl) glob_t *gl; @@ -1025,7 +1065,7 @@ dir_setup_glob (gl) /* Bogus sunos4 compiler complains (!) about & before functions. */ gl->gl_opendir = open_dirstream; gl->gl_readdir = read_dirstream; - gl->gl_closedir = free; + gl->gl_closedir = ansi_free; gl->gl_stat = stat; /* We don't bother setting gl_lstat, since glob never calls it. The slot is only there for compatibility with 4.4 BSD. */ diff --git a/dosbuild.bat b/dosbuild.bat index 8ba68509..ac1e6cd6 100644 --- a/dosbuild.bat +++ b/dosbuild.bat @@ -7,8 +7,8 @@ gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g dir.c -o dir.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g file.c -o file.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g misc.c -o misc.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g main.c -o main.o -gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g read.c -o read.o -gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g remake.c -o remake.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -DINCLUDEDIR=\"c:/djgpp/include\" -O2 -g read.c -o read.o +gcc -c -I. -I./glob -DHAVE_CONFIG_H -DLIBDIR=\"c:/djgpp/lib\" -O2 -g remake.c -o remake.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g rule.c -o rule.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g implicit.c -o implicit.o gcc -c -I. -I./glob -DHAVE_CONFIG_H -O2 -g default.c -o default.o diff --git a/expand.c b/expand.c index 5f46ac27..3f4bcfce 100644 --- a/expand.c +++ b/expand.c @@ -21,15 +21,24 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "job.h" #include "commands.h" #include "variable.h" +#include "rule.h" /* The next two describe the variable output buffer. This buffer is used to hold the variable-expansion of a line of the makefile. It is made bigger with realloc whenever it is too small. variable_buffer_length is the size currently allocated. - variable_buffer is the address of the buffer. */ + variable_buffer is the address of the buffer. + + For efficiency, it's guaranteed that the buffer will always have + VARIABLE_BUFFER_ZONE extra bytes allocated. This allows you to add a few + extra chars without having to call a function. Note you should never use + these bytes unless you're _sure_ you have room (you know when the buffer + length was last checked. */ + +#define VARIABLE_BUFFER_ZONE 5 static unsigned int variable_buffer_length; -static char *variable_buffer; +char *variable_buffer; /* Subroutine of variable_expand and friends: The text to add is LENGTH chars starting at STRING to the variable_buffer. @@ -45,7 +54,7 @@ variable_buffer_output (ptr, string, length) { register unsigned int newlen = length + (ptr - variable_buffer); - if (newlen > variable_buffer_length) + if ((newlen + VARIABLE_BUFFER_ZONE) > variable_buffer_length) { unsigned int offset = ptr - variable_buffer; variable_buffer_length = (newlen + 100 > 2 * variable_buffer_length @@ -93,7 +102,7 @@ recursively_expand (v) v->name); else makefile_fatal - (reading_filename, *reading_lineno_ptr, + (reading_filename, *reading_lineno_ptr, "Recursive variable `%s' references itself (eventually)", v->name); } @@ -153,20 +162,38 @@ reference_variable (o, name, length) return o; } -/* Scan LINE for variable references and expansion-function calls. - Build in `variable_buffer' the result of expanding the references and calls. - Return the address of the resulting string, which is null-terminated - and is valid only until the next time this function is called. */ +/* Scan STRING for variable references and expansion-function calls. Only + LENGTH bytes of STRING are actually scanned. If LENGTH is -1, scan until + a null byte is found. + + Write the results to LINE, which must point into `variable_buffer'. If + LINE is NULL, start at the beginning of the buffer. + Return a pointer to LINE, or to the beginning of the buffer if LINE is + NULL. */ char * -variable_expand (line) +variable_expand_string (line, string, length) register char *line; + char *string; + long length; { register struct variable *v; register char *p, *o, *p1; + char save_char = '\0'; + unsigned int line_offset; - p = line; - o = initialize_variable_output (); + if (!line) + line = initialize_variable_output(); + + p = string; + o = line; + line_offset = line - variable_buffer; + + if (length >= 0) + { + save_char = string[length]; + string[length] = '\0'; + } while (1) { @@ -316,7 +343,7 @@ variable_expand (line) replace_end - replace_beg); replace[replace_end - replace_beg] = '\0'; } - + o = patsubst_expand (o, value, pattern, replace, percent, (char *) 0); } @@ -366,7 +393,7 @@ variable_expand (line) } break; - } + } if (*p == '\0') break; @@ -374,8 +401,23 @@ variable_expand (line) ++p; } - (void) variable_buffer_output (o, "", 1); - return initialize_variable_output (); + if (save_char) + string[length] = save_char; + + (void)variable_buffer_output (o, "", 1); + return (variable_buffer + line_offset); +} + +/* Scan LINE for variable references and expansion-function calls. + Build in `variable_buffer' the result of expanding the references and calls. + Return the address of the resulting string, which is null-terminated + and is valid only until the next time this function is called. */ + +char * +variable_expand (line) + char *line; +{ + return variable_expand_string(NULL, line, -1); } /* Expand an argument for an expansion function. @@ -405,13 +447,13 @@ expand_argument (str, end) /* Expand LINE for FILE. Error messages refer to the file and line where FILE's commands were found. Expansion uses FILE's variable set list. */ -char * +static char * variable_expand_for_file (line, file) char *line; register struct file *file; { char *result; - struct variable_set_list *save; + struct variable_set_list *save, *fnext; if (file == 0) return variable_expand (line); @@ -420,10 +462,23 @@ variable_expand_for_file (line, file) current_variable_set_list = file->variables; reading_filename = file->cmds->filename; reading_lineno_ptr = &file->cmds->lineno; + fnext = file->variables->next; + /* See if there's a pattern-specific variable struct for this target. */ + if (!file->pat_searched) + { + file->patvar = lookup_pattern_var(file->name); + file->pat_searched = 1; + } + if (file->patvar != 0) + { + file->patvar->vars->next = fnext; + file->variables->next = file->patvar->vars; + } result = variable_expand (line); current_variable_set_list = save; reading_filename = 0; reading_lineno_ptr = 0; + file->variables->next = fnext; return result; } diff --git a/file.c b/file.c index e4ea0bd1..a60e70fb 100644 --- a/file.c +++ b/file.c @@ -49,6 +49,9 @@ lookup_file (name) register struct file *f; register char *n; register unsigned int hashval; +#ifdef VMS + register char *lname, *ln; +#endif if (*name == '\0') abort (); @@ -57,6 +60,12 @@ lookup_file (name) for names read from makefiles. It is here for names passed on the command line. */ #ifdef VMS + lname = (char *)malloc(strlen(name) + 1); + for (n=name, ln=lname; *n != '\0'; ++n, ++ln) + *ln = isupper(*n) ? tolower(*n) : *n; + *ln = '\0'; + name = lname; + while (name[0] == '[' && name[1] == ']' && name[2] != '\0') name += 2; #endif @@ -89,9 +98,15 @@ lookup_file (name) { if (strieq (f->hname, name)) { +#ifdef VMS + free (lname); +#endif return f; } } +#ifdef VMS + free (lname); +#endif return 0; } @@ -374,9 +389,9 @@ remove_intermediates (sig) if (f->update_status == -1) /* If nothing would have created this file yet, don't print an "rm" command for it. */ - continue; - else if (just_print_flag) - status = 0; + continue; + else if (just_print_flag) + status = 0; else { status = unlink (f->name); @@ -660,8 +675,8 @@ print_file_data_base () { printf ("\n# %u files in %u hash buckets.\n", nfiles, FILE_BUCKETS); #ifndef NO_FLOAT - printf ("# average %.1f files per bucket, max %u files in one bucket.\n", - ((double) nfiles) / ((double) FILE_BUCKETS) * 100.0, per_bucket); + printf ("# average %.3f files per bucket, max %u files in one bucket.\n", + ((double) nfiles) / ((double) FILE_BUCKETS), per_bucket); #endif } } diff --git a/filedef.h b/filedef.h index b1e6d316..a5de0a11 100644 --- a/filedef.h +++ b/filedef.h @@ -52,6 +52,10 @@ struct file the same file. Otherwise this is null. */ struct file *double_colon; + /* Pattern-specific variable reference for this target, or null if there + isn't one. Also see the pat_searched flag, below. */ + struct pattern_var *patvar; + short int update_status; /* Status of the last attempt to update, or -1 if none has been made. */ @@ -79,7 +83,10 @@ struct file unsigned int secondary:1; unsigned int dontcare:1; /* Nonzero if no complaint is to be made if this target cannot be remade. */ + unsigned int shownerror:1; /* Nonzero if we printed an error */ unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name */ + unsigned int pat_searched:1;/* Nonzero if we already searched for + pattern-specific variables */ }; /* Number of intermediate files entered. */ diff --git a/function.c b/function.c index e1155221..198ab442 100644 --- a/function.c +++ b/function.c @@ -119,7 +119,7 @@ patsubst_expand (o, text, pattern, replace, pattern_percent, replace_percent) register char *pattern_percent, *replace_percent; { unsigned int pattern_prepercent_len, pattern_postpercent_len; - unsigned int replace_prepercent_len, replace_postpercent_len; + unsigned int replace_prepercent_len, replace_postpercent_len = 0; char *t; unsigned int len; int doneany = 0; @@ -282,13 +282,13 @@ static struct { 0, 0, function_invalid } }; -/* Return 1 if PATTERN matches WORD, 0 if not. */ +/* Return 1 if PATTERN matches STR, 0 if not. */ int -pattern_matches (pattern, percent, word) - register char *pattern, *percent, *word; +pattern_matches (pattern, percent, str) + register char *pattern, *percent, *str; { - unsigned int sfxlen, wordlen; + unsigned int sfxlen, strlength; if (percent == 0) { @@ -298,17 +298,17 @@ pattern_matches (pattern, percent, word) pattern = new; percent = find_percent (pattern); if (percent == 0) - return streq (pattern, word); + return streq (pattern, str); } sfxlen = strlen (percent + 1); - wordlen = strlen (word); + strlength = strlen (str); - if (wordlen < (percent - pattern) + sfxlen - || strncmp (pattern, word, percent - pattern)) + if (strlength < (percent - pattern) + sfxlen + || strncmp (pattern, str, percent - pattern)) return 0; - return !strcmp (percent + 1, word + (wordlen - sfxlen)); + return !strcmp (percent + 1, str + (strlength - sfxlen)); } int shell_function_pid = 0, shell_function_completed; @@ -318,13 +318,13 @@ int shell_function_pid = 0, shell_function_completed; The output is written into VARIABLE_BUFFER starting at O. */ /* Note this absorbs a semicolon and is safe to use in conditionals. */ -#define BADARGS(func) \ +#define BADARGS(func) do { \ if (reading_filename != 0) \ makefile_fatal (reading_filename, *reading_lineno_ptr, \ "insufficient arguments to function `%s'", \ func); \ else \ - fatal ("insufficient arguments to function `%s'", func) + fatal ("insufficient arguments to function `%s'", func); } while (0) static char * expand_function (o, function, text, end) @@ -348,6 +348,7 @@ expand_function (o, function, text, end) #ifndef VMS /* not supported for vms yet */ case function_shell: { + char* batch_filename = NULL; #ifdef WINDOWS32 SECURITY_ATTRIBUTES saAttr; HANDLE hIn; @@ -373,7 +374,7 @@ expand_function (o, function, text, end) #ifndef __MSDOS__ /* Construct the argument list. */ argv = construct_command_argv (text, - (char **) NULL, (struct file *) 0); + (char **) NULL, (struct file *) 0, &batch_filename); if (argv == 0) break; #endif @@ -584,6 +585,12 @@ expand_function (o, function, text, end) while (shell_function_completed == 0) reap_children (1, 0); + if (batch_filename) { + if (debug_flag) + printf("Cleaning up temporary batch file %s\n", batch_filename); + remove(batch_filename); + free(batch_filename); + } shell_function_pid = 0; /* The child_handler function will set shell_function_completed @@ -852,6 +859,8 @@ expand_function (o, function, text, end) push_new_variable_scope (); v = define_variable (var, strlen (var), "", o_automatic, 0); + free (v->value); + v->value = 0; p3 = list; while ((p = find_next_token (&p3, &len)) != 0) { @@ -882,10 +891,10 @@ expand_function (o, function, text, end) case function_filter: case function_filter_out: { - struct word + struct a_word { - struct word *next; - char *word; + struct a_word *next; + char *str; int matched; } *words, *wordtail, *wp; @@ -911,7 +920,7 @@ expand_function (o, function, text, end) p3 = text; while ((p = find_next_token (&p3, &len)) != 0) { - struct word *w = (struct word *) alloca (sizeof (struct word)); + struct a_word *w = (struct a_word *)alloca(sizeof(struct a_word)); if (words == 0) words = w; else @@ -921,7 +930,7 @@ expand_function (o, function, text, end) if (*p3 != '\0') ++p3; p[len] = '\0'; - w->word = p; + w->str = p; w->matched = 0; } @@ -939,8 +948,8 @@ expand_function (o, function, text, end) percent = find_percent (p); for (wp = words; wp != 0; wp = wp->next) - wp->matched |= (percent == 0 ? streq (p, wp->word) - : pattern_matches (p, percent, wp->word)); + wp->matched |= (percent == 0 ? streq (p, wp->str) + : pattern_matches (p, percent, wp->str)); p[len] = save; } @@ -949,7 +958,7 @@ expand_function (o, function, text, end) for (wp = words; wp != 0; wp = wp->next) if (function == function_filter ? wp->matched : !wp->matched) { - o = variable_buffer_output (o, wp->word, strlen (wp->word)); + o = variable_buffer_output (o, wp->str, strlen (wp->str)); o = variable_buffer_output (o, " ", 1); doneany = 1; } diff --git a/getloadavg.c b/getloadavg.c index adc4befe..154f18d7 100644 --- a/getloadavg.c +++ b/getloadavg.c @@ -35,6 +35,7 @@ LOAD_AVE_TYPE Type of the load average array in the kernel. Must be defined unless one of apollo, DGUX, NeXT, or UMAX is defined; + or we have libkstat; otherwise, no load average is available. NLIST_STRUCT Include nlist.h, not a.out.h, and the nlist n_name element is a pointer, @@ -500,6 +501,7 @@ extern int errno; # include # endif + /* Avoid static vars inside a function since in HPUX they dump as pure. */ # ifdef NeXT @@ -516,7 +518,7 @@ static unsigned int samples; static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */ # endif /* DGUX */ -# ifdef LOAD_AVE_TYPE +#if !defined(HAVE_LIBKSTAT) && defined(LOAD_AVE_TYPE) /* File descriptor open to /dev/kmem or VMS load ave driver. */ static int channel; /* Nonzero iff channel is valid. */ @@ -524,15 +526,15 @@ static int getloadavg_initialized; /* Offset in kmem to seek to read load average, or 0 means invalid. */ static long offset; -# if !defined(VMS) && !defined(sgi) && !defined(__linux__) +#if !defined(VMS) && !defined(sgi) && !defined(__linux__) static struct nlist nl[2]; -# endif /* Not VMS or sgi */ +#endif -# ifdef SUNOS_5 +#ifdef SUNOS_5 static kvm_t *kd; -# endif /* SUNOS_5 */ +#endif /* SUNOS_5 */ -# endif /* LOAD_AVE_TYPE */ +# endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */ /* Put the 1 minute, 5 minute and 15 minute load averages into the first NELEM elements of LOADAVG. diff --git a/glob/ChangeLog b/glob/ChangeLog index 92c5e7c0..e3854a5a 100644 --- a/glob/ChangeLog +++ b/glob/ChangeLog @@ -1,3 +1,51 @@ +1998-07-29 Paul D. Smith + + * glob.c, fnmatch.c: New versions from the GLIBC folks (Ulrich + Drepper). Fixes a bug reported by Eli Zaretski. Integrates + DOS/Windows32 support. + +1998-07-27 Kaveh R. Ghazi + + * glob.c (glob): Cast away const on assignment of pattern to dirname. + Cast the return type of __alloca() for traditional C compilers. + +1998-07-23 Paul D. Smith + + * glob.c, fnmatch.c: New versions of these files from the GLIBC + folks (Ulrich Drepper). Had to re-integrate some DOS/Windows + code. + +1998-07-10 Paul D. Smith + + * glob.c (glob_in_dir): If no meta chars exist in PATTERN and + GLOB_NOCHECK is present, don't look for the file--whether it's + found or not, we'll always return it, so why bother searching? + + Also, if we are searching and there are no meta chars, don't + bother trying fnmatch() if the strcmp() fails. + +1998-05-30 Eli Zaretskii + + * glob.c (glob) [__MSDOS__, WINDOWS32]: Compute the directory and + filename parts of the pattern correctly when it includes a drive + spec. Disallow wildcards in the drive spec. Prevent recursion + when dirname is of the form "d:/" or "d:". + (prefix_array) [__MSDOS__, WINDOWS32]: Don't append a slash to + "d:/" and "d:". + +1998-05-13 Paul D. Smith + + * SMakefile, Makefile.ami, glob.c, glob.h, fnmatch.c: Updated from + the latest glibc version. + +1998-04-17 Paul D. Smith + + * configure.in: Create a config.h file instead of setting things + on the compile line. This is because when build.sh runs it merely + passes -DHAVE_CONFIG_H to the glob files, just as it does to the + make files. + * config.h.in: Created by autoheader. + Tue Aug 12 10:52:34 1997 Paul D. Smith * configure.in: Require autoconf 2.12. diff --git a/glob/Makefile.am b/glob/Makefile.am index 3c4ab7a3..964ac194 100644 --- a/glob/Makefile.am +++ b/glob/Makefile.am @@ -1,6 +1,6 @@ # -*-Makefile-*-, or close enough -AUTOMAKE_OPTIONS = 1.2 foreign +AUTOMAKE_OPTIONS = 1.3 foreign noinst_LIBRARIES = libglob.a diff --git a/glob/Makefile.ami b/glob/Makefile.ami index 3666d3ef..d3e3d40c 100644 --- a/glob/Makefile.ami +++ b/glob/Makefile.ami @@ -1,6 +1,6 @@ # Makefile for standalone distribution of libglob.a (fnmatch, glob). -# Copyright (C) 1991, 92, 93, 94, 95 Free Software Foundation, Inc. +# Copyright (C) 1991, 92, 93, 94, 95, 97, 98 Free Software Foundation, Inc. # This file is part of the GNU C Library. # This library is free software; you can redistribute it and/or @@ -15,8 +15,8 @@ # You should have received a copy of the GNU Library General Public # License along with this library; see the file COPYING.LIB. If -# not, write to the Free Software Foundation, Inc., 675 Mass Ave, -# Cambridge, MA 02139, USA. +# not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Ultrix 2.2 make doesn't expand the value of VPATH. VPATH = /glob/ diff --git a/glob/SMakefile b/glob/SMakefile index 1c82e0a0..9dcb90b3 100644 --- a/glob/SMakefile +++ b/glob/SMakefile @@ -1,6 +1,6 @@ # Makefile for standalone distribution of libglob.a (fnmatch, glob). -# Copyright (C) 1991, 92, 93, 94, 95 Free Software Foundation, Inc. +# Copyright (C) 1991, 92, 93, 94, 95, 97, 98 Free Software Foundation, Inc. # This file is part of the GNU C Library. # This library is free software; you can redistribute it and/or @@ -15,8 +15,8 @@ # You should have received a copy of the GNU Library General Public # License along with this library; see the file COPYING.LIB. If -# not, write to the Free Software Foundation, Inc., 675 Mass Ave, -# Cambridge, MA 02139, USA. +# not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Ultrix 2.2 make doesn't expand the value of VPATH. VPATH = /glob/ diff --git a/glob/configure.in b/glob/configure.in index cf0a408d..e948bc1a 100644 --- a/glob/configure.in +++ b/glob/configure.in @@ -3,6 +3,7 @@ AC_INIT(fnmatch.c) dnl A distinctive file to look for in srcdir. AC_PREREQ(2.12) dnl Minimum Autoconf version required. AM_INIT_AUTOMAKE(glob, 0.0, nodefs) +AM_CONFIG_HEADER(config.h) AC_PROG_CC AC_CHECK_PROG(AR, ar, ar, ar) diff --git a/glob/fnmatch.c b/glob/fnmatch.c index e1437432..2d6f6afb 100644 --- a/glob/fnmatch.c +++ b/glob/fnmatch.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1991, 92, 93, 96, 97, 98 Free Software Foundation, Inc. This file is part of the GNU C Library. This library is free software; you can redistribute it and/or @@ -29,6 +29,23 @@ #include #include +#if HAVE_STRING_H +# include +#else +# include +#endif + +#if defined STDC_HEADERS || defined _LIBC +# include +#endif + +/* For platform which support the ISO C amendement 1 functionality we + support user defined character classes. */ +#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* Solaris 2.5 has a bug: must be included before . */ +# include +# include +#endif /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C @@ -47,8 +64,64 @@ # define ISASCII(c) isascii(c) # endif -# define ISUPPER(c) (ISASCII (c) && isupper (c)) +#ifdef isblank +# define ISBLANK(c) (ISASCII (c) && isblank (c)) +#else +# define ISBLANK(c) ((c) == ' ' || (c) == '\t') +#endif +#ifdef isgraph +# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) +#else +# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +#endif +#define ISPRINT(c) (ISASCII (c) && isprint (c)) +#define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +#define ISALNUM(c) (ISASCII (c) && isalnum (c)) +#define ISALPHA(c) (ISASCII (c) && isalpha (c)) +#define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +#define ISLOWER(c) (ISASCII (c) && islower (c)) +#define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +#define ISSPACE(c) (ISASCII (c) && isspace (c)) +#define ISUPPER(c) (ISASCII (c) && isupper (c)) +#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) + +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) +/* The GNU C library provides support for user-defined character classes + and the functions from ISO C amendement 1. */ +# ifdef CHARCLASS_NAME_MAX +# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX +# else +/* This shouldn't happen but some implementation might still have this + problem. Use a reasonable default value. */ +# define CHAR_CLASS_MAX_LENGTH 256 +# endif + +# ifdef _LIBC +# define IS_CHAR_CLASS(string) __wctype (string) +# else +# define IS_CHAR_CLASS(string) wctype (string) +# endif +# else +# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ + +# define IS_CHAR_CLASS(string) \ + (STREQ (string, "alpha") || STREQ (string, "upper") \ + || STREQ (string, "lower") || STREQ (string, "digit") \ + || STREQ (string, "alnum") || STREQ (string, "xdigit") \ + || STREQ (string, "space") || STREQ (string, "print") \ + || STREQ (string, "punct") || STREQ (string, "graph") \ + || STREQ (string, "cntrl") || STREQ (string, "blank")) +# endif + +/* Avoid depending on library functions or files + whose names are inconsistent. */ + +# if !defined _LIBC && !defined getenv +extern char *getenv (); +# endif # ifndef errno extern int errno; @@ -66,7 +139,11 @@ fnmatch (pattern, string, flags) register char c; /* Note that this evaluates C many times. */ -# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) +# ifdef _LIBC +# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) +# else +# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) +# endif while ((c = *p++) != '\0') { @@ -137,67 +214,124 @@ fnmatch (pattern, string, flags) case '[': { /* Nonzero if the sense of the character class is inverted. */ + static int posixly_correct; register int not; + char cold; + + if (posixly_correct == 0) + posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; if (*n == '\0') return FNM_NOMATCH; - if ((flags & FNM_PERIOD) && *n == '.' && + if (*n == '.' && (flags & FNM_PERIOD) && (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) return FNM_NOMATCH; - not = (*p == '!' || *p == '^'); + if (*n == '/' && (flags & FNM_FILE_NAME)) + /* `/' cannot be matched. */ + return FNM_NOMATCH; + + not = (*p == '!' || (posixly_correct < 0 && *p == '^')); if (not) ++p; c = *p++; for (;;) { - register char cstart = c, cend = c; + int fn = FOLD (*n); if (!(flags & FNM_NOESCAPE) && c == '\\') { if (*p == '\0') return FNM_NOMATCH; - cstart = cend = *p++; + c = FOLD (*p++); + + if (c == fn) + goto matched; } + else if (c == '[' && *p == ':') + { + /* Leave room for the null. */ + char str[CHAR_CLASS_MAX_LENGTH + 1]; + size_t c1 = 0; +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) + wctype_t wt; +# endif - cstart = cend = FOLD (cstart); + for (;;) + { + if (c1 == CHAR_CLASS_MAX_LENGTH) + /* The name is too long and therefore the pattern + is ill-formed. */ + return FNM_NOMATCH; - if (c == '\0') + c = *++p; + if (c == ':' && p[1] == ']') + { + p += 2; + break; + } + str[c1++] = 'c'; + } + str[c1] = '\0'; + +# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) + wt = IS_CHAR_CLASS (str); + if (wt == 0) + /* Invalid character class name. */ + return FNM_NOMATCH; + + if (__iswctype (__btowc (*n), wt)) + goto matched; +# else + if ((STREQ (str, "alnum") && ISALNUM (*n)) + || (STREQ (str, "alpha") && ISALPHA (*n)) + || (STREQ (str, "blank") && ISBLANK (*n)) + || (STREQ (str, "cntrl") && ISCNTRL (*n)) + || (STREQ (str, "digit") && ISDIGIT (*n)) + || (STREQ (str, "graph") && ISGRAPH (*n)) + || (STREQ (str, "lower") && ISLOWER (*n)) + || (STREQ (str, "print") && ISPRINT (*n)) + || (STREQ (str, "punct") && ISPUNCT (*n)) + || (STREQ (str, "space") && ISSPACE (*n)) + || (STREQ (str, "upper") && ISUPPER (*n)) + || (STREQ (str, "xdigit") && ISXDIGIT (*n))) + goto matched; +# endif + } + else if (c == '\0') /* [ (unterminated) loses. */ return FNM_NOMATCH; + else if (FOLD (c) == fn) + goto matched; + cold = c; c = *p++; - c = FOLD (c); - - if ((flags & FNM_FILE_NAME) && c == '/') - /* [/] can never match. */ - return FNM_NOMATCH; if (c == '-' && *p != ']') { - cend = *p++; + /* It is a range. */ + char cend = *p++; if (!(flags & FNM_NOESCAPE) && cend == '\\') cend = *p++; if (cend == '\0') return FNM_NOMATCH; - cend = FOLD (cend); + + if (cold <= fn && fn <= FOLD (cend)) + goto matched; c = *p++; } - - if (FOLD (*n) >= cstart && FOLD (*n) <= cend) - goto matched; - if (c == ']') break; } + if (!not) return FNM_NOMATCH; break; - matched:; + matched: /* Skip the rest of the [...] that already matched. */ while (c != ']') { @@ -213,6 +347,15 @@ fnmatch (pattern, string, flags) /* XXX 1003.2d11 is unclear if this is right. */ ++p; } + else if (c == '[' && *p == ':') + { + do + if (*++p == '\0') + return FNM_NOMATCH; + while (*p != ':' || p[1] == ']'); + p += 2; + c = *p; + } } if (not) return FNM_NOMATCH; diff --git a/glob/fnmatch.h b/glob/fnmatch.h index 38b7255f..4d1eb3e2 100644 --- a/glob/fnmatch.h +++ b/glob/fnmatch.h @@ -23,18 +23,24 @@ extern "C" { #endif -#if (defined (__cplusplus) || (defined (__STDC__) && __STDC__) \ - || defined (WINDOWS32)) -#undef __P -#define __P(protos) protos +#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 +# undef __P +# define __P(protos) protos #else /* Not C++ or ANSI C. */ -#undef __P -#define __P(protos) () +# undef __P +# define __P(protos) () /* We can get away without defining `const' here only because in this file it is used only inside the prototype for `fnmatch', which is elided in non-ANSI C where `const' is problematical. */ #endif /* C++ or ANSI C. */ +#ifndef const +# if (defined __STDC__ && __STDC__) || defined __cplusplus +# define __const const +# else +# define __const +# endif +#endif /* We #undef these before defining them because some losing systems (HP-UX A.08.07 for example) define these in . */ @@ -47,18 +53,26 @@ extern "C" { #define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */ #define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */ -#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE) -#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ -#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ -#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ +#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE +# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */ +# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */ +# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */ #endif /* Value returned by `fnmatch' if STRING does not match PATTERN. */ #define FNM_NOMATCH 1 +/* This value is returned if the implementation does not support + `fnmatch'. Since this is not the case here it will never be + returned but the conformance test suites still require the symbol + to be defined. */ +#if (_XOPEN_SOURCE - 0) == 500 +# define FNM_NOSYS (-1) +#endif + /* Match STRING against the filename pattern PATTERN, returning zero if it matches, FNM_NOMATCH if not. */ -extern int fnmatch __P ((const char *__pattern, const char *__string, +extern int fnmatch __P ((__const char *__pattern, __const char *__string, int __flags)); #ifdef __cplusplus diff --git a/glob/glob.c b/glob/glob.c index 6a82fe02..eab79194 100644 --- a/glob/glob.c +++ b/glob/glob.c @@ -1,4 +1,4 @@ -/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc. +/* Copyright (C) 1991,92,93,94,95,96,97,98 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as @@ -16,17 +16,17 @@ Boston, MA 02111-1307, USA. */ /* AIX requires this to be the first thing in the file. */ -#if defined (_AIX) && !defined (__GNUC__) +#if defined _AIX && !defined __GNUC__ #pragma alloca #endif #ifdef HAVE_CONFIG_H -#include +# include #endif /* Enable GNU extensions in glob.h. */ #ifndef _GNU_SOURCE -#define _GNU_SOURCE 1 +# define _GNU_SOURCE 1 #endif #include @@ -49,45 +49,45 @@ it is simpler to just do this in the source for each such file. */ #define GLOB_INTERFACE_VERSION 1 -#if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 -#include -#if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION -#define ELIDE_CODE -#endif +#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1 +# include +# if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION +# define ELIDE_CODE +# endif #endif #ifndef ELIDE_CODE -#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__) -#include +#if defined STDC_HEADERS || defined __GNU_LIBRARY__ +# include #endif #if defined HAVE_UNISTD_H || defined _LIBC -#include -#ifndef POSIX -#ifdef _POSIX_VERSION -#define POSIX -#endif -#endif +# include +# ifndef POSIX +# ifdef _POSIX_VERSION +# define POSIX +# endif +# endif #endif -#if !defined (_AMIGA) && !defined (VMS) && !defined(WINDOWS32) -#include +#if !defined _AMIGA && !defined VMS && !defined WINDOWS32 +# include #endif -#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS extern int errno; #endif #ifndef __set_errno -#define __set_errno(val) errno = (val) +# define __set_errno(val) errno = (val) #endif #ifndef NULL -#define NULL 0 +# define NULL 0 #endif -#if defined (HAVE_DIRENT_H) || defined (__GNU_LIBRARY__) +#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else @@ -110,36 +110,42 @@ extern int errno; /* In GNU systems, defines this macro for us. */ #ifdef _D_NAMLEN -#undef NAMLEN -#define NAMLEN(d) _D_NAMLEN(d) +# undef NAMLEN +# define NAMLEN(d) _D_NAMLEN(d) +#endif + +/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available + if the `d_type' member for `struct dirent' is available. */ +#ifdef _DIRENT_HAVE_D_TYPE +# define HAVE_D_TYPE 1 #endif -#if (defined (POSIX) || defined (WINDOWS32)) && !defined (__GNU_LIBRARY__) +#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ /* Posix does not require that the d_ino field be present, and some systems do not provide it. */ -#define REAL_DIR_ENTRY(dp) 1 +# define REAL_DIR_ENTRY(dp) 1 #else -#define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) +# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0) #endif /* POSIX */ -#if (defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)) -#include -#include -#define ANSI_STRING +#if defined STDC_HEADERS || defined __GNU_LIBRARY__ +# include +# include +# define ANSI_STRING #else /* No standard headers. */ extern char *getenv (); -#ifdef HAVE_STRING_H -#include -#define ANSI_STRING -#else -#include -#endif -#ifdef HAVE_MEMORY_H -#include -#endif +# ifdef HAVE_STRING_H +# include +# define ANSI_STRING +# else +# include +# endif +# ifdef HAVE_MEMORY_H +# include +# endif extern char *malloc (), *realloc (); extern void free (); @@ -151,35 +157,40 @@ extern void abort (), exit (); #ifndef ANSI_STRING -#ifndef bzero +# ifndef bzero extern void bzero (); -#endif -#ifndef bcopy +# endif +# ifndef bcopy extern void bcopy (); -#endif +# endif -#define memcpy(d, s, n) bcopy ((s), (d), (n)) -#define strrchr rindex +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# define strrchr rindex /* memset is only used for zero here, but let's be paranoid. */ -#define memset(s, better_be_zero, n) \ +# define memset(s, better_be_zero, n) \ ((void) ((better_be_zero) == 0 ? (bzero((s), (n)), 0) : (abort(), 0))) #endif /* Not ANSI_STRING. */ #if !defined HAVE_STRCOLL && !defined _LIBC -#define strcoll strcmp +# define strcoll strcmp +#endif + +#if !defined HAVE_MEMPCPY && __GLIBC__ - 0 == 2 && __GLIBC_MINOR__ >= 1 +# define HAVE_MEMPCPY 1 +# define mempcpy(Dest, Src, Len) __mempcpy (Dest, Src, Len) #endif #ifndef __GNU_LIBRARY__ -#ifdef __GNUC__ +# ifdef __GNUC__ __inline -#endif -#ifndef __SASC -#ifdef WINDOWS32 +# endif +# ifndef __SASC +# ifdef WINDOWS32 static void * -#else +# else static char * -#endif +# endif my_realloc (p, n) char *p; unsigned int n; @@ -190,68 +201,85 @@ my_realloc (p, n) return (char *) malloc (n); return (char *) realloc (p, n); } -#define realloc my_realloc -#endif /* __SASC */ +# define realloc my_realloc +# endif /* __SASC */ #endif /* __GNU_LIBRARY__ */ -#if !defined(__alloca) && !defined(__GNU_LIBRARY__) +#if !defined __alloca && !defined __GNU_LIBRARY__ -#ifdef __GNUC__ -#undef alloca -#define alloca(n) __builtin_alloca (n) -#else /* Not GCC. */ -#ifdef HAVE_ALLOCA_H -#include -#else /* Not HAVE_ALLOCA_H. */ -#ifndef _AIX -#ifdef WINDOWS32 -#include -#else +# ifdef __GNUC__ +# undef alloca +# define alloca(n) __builtin_alloca (n) +# else /* Not GCC. */ +# ifdef HAVE_ALLOCA_H +# include +# else /* Not HAVE_ALLOCA_H. */ +# ifndef _AIX +# ifdef WINDOWS32 +# include +# else extern char *alloca (); -#endif /* WINDOWS32 */ -#endif /* Not _AIX. */ -#endif /* sparc or HAVE_ALLOCA_H. */ -#endif /* GCC. */ +# endif /* WINDOWS32 */ +# endif /* Not _AIX. */ +# endif /* sparc or HAVE_ALLOCA_H. */ +# endif /* GCC. */ -#define __alloca alloca +# define __alloca alloca #endif #ifndef __GNU_LIBRARY__ -#define __stat stat -#ifdef STAT_MACROS_BROKEN -#undef S_ISDIR -#endif -#ifndef S_ISDIR -#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) -#endif +# define __stat stat +# ifdef STAT_MACROS_BROKEN +# undef S_ISDIR +# endif +# ifndef S_ISDIR +# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) +# endif #endif -#if !(defined (STDC_HEADERS) || defined (__GNU_LIBRARY__)) -#undef size_t -#define size_t unsigned int +#ifdef _LIBC +# define strdup(str) __strdup (str) +# define sysconf(id) __sysconf (id) +# define closedir(dir) __closedir (dir) +# define opendir(name) __opendir (name) +# define readdir(str) __readdir (str) +#endif + +#if !(defined STDC_HEADERS || defined __GNU_LIBRARY__) +# undef size_t +# define size_t unsigned int #endif /* Some system header files erroneously define these. We want our own definitions from to take precedence. */ -#undef FNM_PATHNAME -#undef FNM_NOESCAPE -#undef FNM_PERIOD +#ifndef __GNU_LIBRARY__ +# undef FNM_PATHNAME +# undef FNM_NOESCAPE +# undef FNM_PERIOD +#endif #include /* Some system header files erroneously define these. We want our own definitions from to take precedence. */ -#undef GLOB_ERR -#undef GLOB_MARK -#undef GLOB_NOSORT -#undef GLOB_DOOFFS -#undef GLOB_NOCHECK -#undef GLOB_APPEND -#undef GLOB_NOESCAPE -#undef GLOB_PERIOD +#ifndef __GNU_LIBRARY__ +# undef GLOB_ERR +# undef GLOB_MARK +# undef GLOB_NOSORT +# undef GLOB_DOOFFS +# undef GLOB_NOCHECK +# undef GLOB_APPEND +# undef GLOB_NOESCAPE +# undef GLOB_PERIOD +#endif #include +static +#if __GNUC__ - 0 >= 2 +inline +#endif +const char *next_brace_sub __P ((const char *begin)); static int glob_in_dir __P ((const char *pattern, const char *directory, int flags, int (*errfunc) __P ((const char *, int)), @@ -358,8 +386,12 @@ glob (pattern, flags, errfunc, pglob) #endif /* We know the prefix for all sub-patterns. */ +#ifdef HAVE_MEMPCPY + alt_start = mempcpy (onealt, pattern, begin - pattern); +#else memcpy (onealt, pattern, begin - pattern); alt_start = &onealt[begin - pattern]; +#endif /* Find the first sub-pattern and at the same time find the rest after the closing brace. */ @@ -412,8 +444,12 @@ glob (pattern, flags, errfunc, pglob) int result; /* Construct the new glob expression. */ +#ifdef HAVE_MEMPCPY + mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len); +#else memcpy (alt_start, p, next - p); memcpy (&alt_start[next - p], rest, rest_len); +#endif result = glob (onealt, ((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC)) @@ -453,15 +489,38 @@ glob (pattern, flags, errfunc, pglob) /* Find the filename. */ filename = strrchr (pattern, '/'); +#if defined __MSDOS__ || defined WINDOWS32 + /* The case of "d:pattern". Since `:' is not allowed in + file names, we can safely assume that wherever it + happens in pattern, it signals the filename part. This + is so we could some day support patterns like "[a-z]:foo". */ + if (filename == NULL) + filename = strchr (pattern, ':'); +#endif /* __MSDOS__ || WINDOWS32 */ if (filename == NULL) { - filename = pattern; + /* This can mean two things: a simple name or "~name". The later + case is nothing but a notation for a directory. */ + if ((flags & GLOB_TILDE) && pattern[0] == '~') + { + dirname = (char *) pattern; + dirlen = strlen (pattern); + + /* Set FILENAME to NULL as a special flag. This is ugly but + other solutions would require much more code. We test for + this special case below. */ + filename = NULL; + } + else + { + filename = pattern; #ifdef _AMIGA - dirname = (char *) ""; + dirname = (char *) ""; #else - dirname = (char *) "."; + dirname = (char *) "."; #endif - dirlen = 0; + dirlen = 0; + } } else if (filename == pattern) { @@ -473,19 +532,53 @@ glob (pattern, flags, errfunc, pglob) else { dirlen = filename - pattern; +#if defined __MSDOS__ || defined WINDOWS32 + if ((*filename == ':') + || (filename > pattern + 1 && filename[-1] == ':')) + { + char *drive_spec; + + ++dirlen; + drive_spec = (char *) __alloca (dirlen + 1); +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; +#else + memcpy (drive_spec, pattern, dirlen); + drive_spec[dirlen] = '\0'; +#endif + /* For now, disallow wildcards in the drive spec, to + prevent infinite recursion in glob. */ + if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) + return GLOB_NOMATCH; + /* If this is "d:pattern", we need to copy `:' to DIRNAME + as well. If it's "d:/pattern", don't remove the slash + from "d:/", since "d:" and "d:/" are not the same.*/ + } +#endif dirname = (char *) __alloca (dirlen + 1); +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (dirname, pattern, dirlen)) = '\0'; +#else memcpy (dirname, pattern, dirlen); dirname[dirlen] = '\0'; +#endif ++filename; - } - if (filename[0] == '\0' && dirlen > 1) - /* "pattern/". Expand "pattern", appending slashes. */ - { - int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); - if (val == 0) - pglob->gl_flags = (pglob->gl_flags & ~GLOB_MARK) | (flags & GLOB_MARK); - return val; + if (filename[0] == '\0' +#if defined __MSDOS__ || defined WINDOWS32 + && dirname[dirlen-1] != ':' + && (dirlen < 3 || dirname[dirlen-2] != ':' + || dirname[dirlen-1] != '/') +#endif + && dirlen > 1) + /* "pattern/". Expand "pattern", appending slashes. */ + { + int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob); + if (val == 0) + pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK) + | (flags & GLOB_MARK)); + return val; + } } if (!(flags & GLOB_APPEND)) @@ -503,18 +596,18 @@ glob (pattern, flags, errfunc, pglob) { /* Look up home directory. */ char *home_dir = getenv ("HOME"); -#ifdef _AMIGA +# ifdef _AMIGA if (home_dir == NULL || home_dir[0] == '\0') home_dir = "SYS:"; -#else -#ifdef WINDOWS32 +# else +# ifdef WINDOWS32 if (home_dir == NULL || home_dir[0] == '\0') home_dir = "c:/users/default"; /* poor default */ -#else +# else if (home_dir == NULL || home_dir[0] == '\0') { int success; -#if defined HAVE_GETLOGIN_R || defined _LIBC +# if defined HAVE_GETLOGIN_R || defined _LIBC extern int getlogin_r __P ((char *, size_t)); size_t buflen = sysconf (_SC_LOGIN_NAME_MAX) + 1; char *name; @@ -526,15 +619,15 @@ glob (pattern, flags, errfunc, pglob) name = (char *) __alloca (buflen); success = getlogin_r (name, buflen) >= 0; -#else +# else extern char *getlogin __P ((void)); char *name; success = (name = getlogin ()) != NULL; -#endif +# endif if (success) { -#if defined HAVE_GETPWNAM_R || defined _LIBC +# if defined HAVE_GETPWNAM_R || defined _LIBC size_t pwbuflen = sysconf (_SC_GETPW_R_SIZE_MAX); char *pwtmpbuf; struct passwd pwbuf, *p; @@ -543,18 +636,18 @@ glob (pattern, flags, errfunc, pglob) success = (__getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p) >= 0); -#else +# else struct passwd *p = getpwnam (name); success = p != NULL; -#endif +# endif if (success) home_dir = p->pw_dir; } } if (home_dir == NULL || home_dir[0] == '\0') home_dir = (char *) "~"; /* No luck. */ -#endif /* WINDOWS32 */ -#endif +# endif /* WINDOWS32 */ +# endif /* Now construct the full directory. */ if (dirname[1] == '\0') dirname = home_dir; @@ -563,12 +656,17 @@ glob (pattern, flags, errfunc, pglob) char *newp; size_t home_len = strlen (home_dir); newp = (char *) __alloca (home_len + dirlen); +# ifdef HAVE_MEMPCPY + mempcpy (mempcpy (newp, home_dir, home_len), + &dirname[1], dirlen); +# else memcpy (newp, home_dir, home_len); memcpy (&newp[home_len], &dirname[1], dirlen); +# endif dirname = newp; } } -#if !defined _AMIGA && !defined WINDOWS32 +# if !defined _AMIGA && !defined WINDOWS32 else { char *end_name = strchr (dirname, '/'); @@ -580,13 +678,18 @@ glob (pattern, flags, errfunc, pglob) else { user_name = (char *) __alloca (end_name - dirname); +# ifdef HAVE_MEMPCPY + *((char *) mempcpy (user_name, dirname + 1, end_name - dirname)) + = '\0'; +# else memcpy (user_name, dirname + 1, end_name - dirname); user_name[end_name - dirname - 1] = '\0'; +# endif } /* Look up specific user's home directory. */ { -#if defined HAVE_GETPWNAM_R || defined _LIBC +# if defined HAVE_GETPWNAM_R || defined _LIBC size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX); char *pwtmpbuf = (char *) __alloca (buflen); struct passwd pwbuf, *p; @@ -594,13 +697,13 @@ glob (pattern, flags, errfunc, pglob) home_dir = p->pw_dir; else home_dir = NULL; -#else +# else struct passwd *p = getpwnam (user_name); if (p != NULL) home_dir = p->pw_dir; else home_dir = NULL; -#endif +# endif } /* If we found a home directory use this. */ if (home_dir != NULL) @@ -609,16 +712,74 @@ glob (pattern, flags, errfunc, pglob) size_t home_len = strlen (home_dir); size_t rest_len = end_name == NULL ? 0 : strlen (end_name); newp = (char *) __alloca (home_len + rest_len + 1); +# ifdef HAVE_MEMPCPY + *((char *) mempcpy (mempcpy (newp, home_dir, home_len), + end_name, rest_len)) = '\0'; +# else memcpy (newp, home_dir, home_len); memcpy (&newp[home_len], end_name, rest_len); newp[home_len + rest_len] = '\0'; +# endif dirname = newp; } } -#endif /* Not Amiga && not WINDOWS32. */ +# endif /* Not Amiga && not WINDOWS32. */ } #endif /* Not VMS. */ + /* Now test whether we looked for "~" or "~NAME". In this case we + can give the answer now. */ + if (filename == NULL) + { + struct stat st; + + /* Return the directory if we don't check for error or if it exists. */ + if ((flags & GLOB_NOCHECK) + || (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (dirname, &st) + : __stat (dirname, &st)) == 0 + && S_ISDIR (st.st_mode))) + { + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? + pglob->gl_offs : 0) + + 1 + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + return GLOB_NOSPACE; + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + +#if defined HAVE_STRDUP || defined _LIBC + pglob->gl_pathv[pglob->gl_pathc] = strdup (dirname); +#else + { + size_t len = strlen (dirname) + 1; + char *dircopy = malloc (len); + if (dircopy != NULL) + pglob->gl_pathv[pglob->gl_pathc] = memcpy (dircopy, dirname, + len); + } +#endif + if (pglob->gl_pathv[pglob->gl_pathc] == NULL) + { + free (pglob->gl_pathv); + return GLOB_NOSPACE; + } + pglob->gl_pathv[++pglob->gl_pathc] = NULL; + pglob->gl_flags = flags; + + return 0; + } + + /* Not found. */ + return GLOB_NOMATCH; + } + if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE))) { /* The directory name contains metacharacters, so we @@ -628,8 +789,8 @@ glob (pattern, flags, errfunc, pglob) register int i; status = glob (dirname, - ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) | - GLOB_NOSORT), + ((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE)) + | GLOB_NOSORT | GLOB_ONLYDIR), errfunc, &dirs); if (status != 0) return status; @@ -639,7 +800,7 @@ glob (pattern, flags, errfunc, pglob) appending the results to PGLOB. */ for (i = 0; i < dirs.gl_pathc; ++i) { - int oldcount; + int old_pathc; #ifdef SHELL { @@ -655,9 +816,10 @@ glob (pattern, flags, errfunc, pglob) } #endif /* SHELL. */ - oldcount = pglob->gl_pathc; + old_pathc = pglob->gl_pathc; status = glob_in_dir (filename, dirs.gl_pathv[i], - (flags | GLOB_APPEND) & ~GLOB_NOCHECK, + ((flags | GLOB_APPEND) + & ~(GLOB_NOCHECK | GLOB_ERR)), errfunc, pglob); if (status == GLOB_NOMATCH) /* No matches in this directory. Try the next. */ @@ -672,8 +834,8 @@ glob (pattern, flags, errfunc, pglob) /* Stick the directory on the front of each name. */ if (prefix_array (dirs.gl_pathv[i], - &pglob->gl_pathv[oldcount], - pglob->gl_pathc - oldcount)) + &pglob->gl_pathv[old_pathc], + pglob->gl_pathc - old_pathc)) { globfree (&dirs); globfree (pglob); @@ -683,26 +845,29 @@ glob (pattern, flags, errfunc, pglob) flags |= GLOB_MAGCHAR; + /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls. + But if we have not found any matching entry and thie GLOB_NOCHECK + flag was set we must return the list consisting of the disrectory + names followed by the filename. */ if (pglob->gl_pathc == oldcount) /* No matches. */ if (flags & GLOB_NOCHECK) { - size_t len = strlen (pattern) + 1; - char *patcopy = (char *) malloc (len); - if (patcopy == NULL) - return GLOB_NOSPACE; - memcpy (patcopy, pattern, len); + size_t filename_len = strlen (filename) + 1; + char **new_pathv; + struct stat st; + /* This is an pessimistic guess about the size. */ pglob->gl_pathv = (char **) realloc (pglob->gl_pathv, (pglob->gl_pathc + ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) + - 1 + 1) * + dirs.gl_pathc + 1) * sizeof (char *)); if (pglob->gl_pathv == NULL) { - free (patcopy); + globfree (&dirs); return GLOB_NOSPACE; } @@ -710,12 +875,55 @@ glob (pattern, flags, errfunc, pglob) while (pglob->gl_pathc < pglob->gl_offs) pglob->gl_pathv[pglob->gl_pathc++] = NULL; - pglob->gl_pathv[pglob->gl_pathc++] = patcopy; + for (i = 0; i < dirs.gl_pathc; ++i) + { + const char *dir = dirs.gl_pathv[i]; + size_t dir_len = strlen (dir); + + /* First check whether this really is a directory. */ + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (dir, &st) : __stat (dir, &st)) != 0 + || !S_ISDIR (st.st_mode)) + /* No directory, ignore this entry. */ + continue; + + pglob->gl_pathv[pglob->gl_pathc] = malloc (dir_len + 1 + + filename_len); + if (pglob->gl_pathv[pglob->gl_pathc] == NULL) + { + globfree (&dirs); + globfree (pglob); + return GLOB_NOSPACE; + } + +#ifdef HAVE_MEMPCPY + mempcpy (mempcpy (mempcpy (pglob->gl_pathv[pglob->gl_pathc], + dir, dir_len), + "/", 1), + filename, filename_len); +#else + memcpy (pglob->gl_pathv[pglob->gl_pathc], dir, dir_len); + pglob->gl_pathv[pglob->gl_pathc][dir_len] = '/'; + memcpy (&pglob->gl_pathv[pglob->gl_pathc][dir_len + 1], + filename, filename_len); +#endif + ++pglob->gl_pathc; + } + pglob->gl_pathv[pglob->gl_pathc] = NULL; pglob->gl_flags = flags; + + /* Now we know how large the gl_pathv vector must be. */ + new_pathv = (char **) realloc (pglob->gl_pathv, + ((pglob->gl_pathc + 1) + * sizeof (char *))); + if (new_pathv != NULL) + pglob->gl_pathv = new_pathv; } else return GLOB_NOMATCH; + + globfree (&dirs); } else { @@ -726,9 +934,14 @@ glob (pattern, flags, errfunc, pglob) if (dirlen > 0) { /* Stick the directory on the front of each name. */ + int ignore = oldcount; + + if ((flags & GLOB_DOOFFS) && ignore < pglob->gl_offs) + ignore = pglob->gl_offs; + if (prefix_array (dirname, - &pglob->gl_pathv[oldcount], - pglob->gl_pathc - oldcount)) + &pglob->gl_pathv[ignore], + pglob->gl_pathc - ignore)) { globfree (pglob); return GLOB_NOSPACE; @@ -742,10 +955,10 @@ glob (pattern, flags, errfunc, pglob) int i; struct stat st; for (i = oldcount; i < pglob->gl_pathc; ++i) - if (((flags & GLOB_ALTDIRFUNC) ? - (*pglob->gl_stat) (pglob->gl_pathv[i], &st) : - __stat (pglob->gl_pathv[i], &st)) == 0 && - S_ISDIR (st.st_mode)) + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (pglob->gl_pathv[i], &st) + : __stat (pglob->gl_pathv[i], &st)) == 0 + && S_ISDIR (st.st_mode)) { size_t len = strlen (pglob->gl_pathv[i]) + 2; char *new = realloc (pglob->gl_pathv[i], len); @@ -760,10 +973,17 @@ glob (pattern, flags, errfunc, pglob) } if (!(flags & GLOB_NOSORT)) - /* Sort the vector. */ - qsort ((__ptr_t) &pglob->gl_pathv[oldcount], - pglob->gl_pathc - oldcount, - sizeof (char *), collated_compare); + { + /* Sort the vector. */ + int non_sort = oldcount; + + if ((flags & GLOB_DOOFFS) && pglob->gl_offs > oldcount) + non_sort = pglob->gl_offs; + + qsort ((__ptr_t) &pglob->gl_pathv[non_sort], + pglob->gl_pathc - non_sort, + sizeof (char *), collated_compare); + } return 0; } @@ -816,11 +1036,31 @@ prefix_array (dirname, array, n) { register size_t i; size_t dirlen = strlen (dirname); +#if defined __MSDOS__ || defined WINDOWS32 + int sep_char = '/'; +# define DIRSEP_CHAR sep_char +#else +# define DIRSEP_CHAR '/' +#endif if (dirlen == 1 && dirname[0] == '/') /* DIRNAME is just "/", so normal prepending would get us "//foo". We want "/foo" instead, so don't prepend any chars from DIRNAME. */ dirlen = 0; +#if defined __MSDOS__ || defined WINDOWS32 + else if (dirlen > 1) + { + if (dirname[dirlen - 1] == '/') + /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ + --dirlen; + else if (dirname[dirlen - 1] == ':') + { + /* DIRNAME is "d:". Use `:' instead of `/'. */ + --dirlen; + sep_char = ':'; + } + } +#endif for (i = 0; i < n; ++i) { @@ -833,9 +1073,17 @@ prefix_array (dirname, array, n) return 1; } +#ifdef HAVE_MEMPCPY + { + char *endp = (char *) mempcpy (new, dirname, dirlen); + *endp++ = DIRSEP_CHAR; + mempcpy (endp, array[i], eltlen); + } +#else memcpy (new, dirname, dirlen); - new[dirlen] = '/'; + new[dirlen] = DIRSEP_CHAR; memcpy (&new[dirlen + 1], array[i], eltlen); +#endif free ((__ptr_t) array[i]); array[i] = new; } @@ -895,7 +1143,7 @@ glob_in_dir (pattern, directory, flags, errfunc, pglob) int (*errfunc) __P ((const char *, int)); glob_t *pglob; { - __ptr_t stream; + __ptr_t stream = NULL; struct globlink { @@ -903,68 +1151,130 @@ glob_in_dir (pattern, directory, flags, errfunc, pglob) char *name; }; struct globlink *names = NULL; - size_t nfound = 0; + size_t nfound; + int meta; + int save; - if (!__glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE))) + meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE)); + if (meta == 0) { - stream = NULL; - flags |= GLOB_NOCHECK; + if (flags & (GLOB_NOCHECK|GLOB_NOMAGIC)) + /* We need not do any tests. The PATTERN contains no meta + characters and we must not return an error therefore the + result will always contain exactly one name. */ + flags |= GLOB_NOCHECK; + else + { + /* Since we use the normal file functions we can also use stat() + to verify the file is there. */ + struct stat st; + size_t patlen = strlen (pattern); + size_t dirlen = strlen (directory); + char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1); + +# ifdef HAVE_MEMPCPY + mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), + "/", 1), + pattern, patlen + 1); +# else + memcpy (fullname, directory, dirlen); + fullname[dirlen] = '/'; + memcpy (&fullname[dirlen + 1], pattern, patlen + 1); +# endif + if (((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_stat) (fullname, &st) + : __stat (fullname, &st)) == 0) + /* We found this file to be existing. Now tell the rest + of the function to copy this name into the result. */ + flags |= GLOB_NOCHECK; + } + + nfound = 0; } else { - flags |= GLOB_MAGCHAR; - - stream = ((flags & GLOB_ALTDIRFUNC) ? - (*pglob->gl_opendir) (directory) : - (__ptr_t) opendir (directory)); - if (stream == NULL) + if (pattern[0] == '\0') { - if ((errfunc != NULL && (*errfunc) (directory, errno)) || - (flags & GLOB_ERR)) - return GLOB_ABORTED; + /* This is a special case for matching directories like in + "*a/". */ + names = (struct globlink *) __alloca (sizeof (struct globlink)); + names->name = (char *) malloc (1); + if (names->name == NULL) + goto memory_error; + names->name[0] = '\0'; + names->next = NULL; + nfound = 1; + meta = 0; } else - while (1) - { - const char *name; - size_t len; - struct dirent *d = ((flags & GLOB_ALTDIRFUNC) ? - (*pglob->gl_readdir) (stream) : - readdir ((DIR *) stream)); - if (d == NULL) - break; - if (! REAL_DIR_ENTRY (d)) - continue; - - name = d->d_name; - - if (fnmatch (pattern, name, - (!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) | - ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) -#ifdef _AMIGA - | FNM_CASEFOLD + { + stream = ((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_opendir) (directory) + : (__ptr_t) opendir (directory)); + if (stream == NULL) + { + if ((errfunc != NULL && (*errfunc) (directory, errno)) + || (flags & GLOB_ERR)) + return GLOB_ABORTED; + nfound = 0; + meta = 0; + } + else + { + int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) + | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) +#if defined _AMIGA || defined VMS + | FNM_CASEFOLD #endif - ) == 0) - { - struct globlink *new - = (struct globlink *) __alloca (sizeof (struct globlink)); - len = NAMLEN (d); - new->name - = (char *) malloc (len + 1); - if (new->name == NULL) - goto memory_error; - memcpy ((__ptr_t) new->name, name, len); - new->name[len] = '\0'; - new->next = names; - names = new; - ++nfound; - } - } - } + ); + nfound = 0; + flags |= GLOB_MAGCHAR; - if (nfound == 0 && (flags & GLOB_NOMAGIC) && - ! __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE))) - flags |= GLOB_NOCHECK; + while (1) + { + const char *name; + size_t len; + struct dirent *d = ((flags & GLOB_ALTDIRFUNC) + ? (*pglob->gl_readdir) (stream) + : readdir ((DIR *) stream)); + if (d == NULL) + break; + if (! REAL_DIR_ENTRY (d)) + continue; + +#ifdef HAVE_D_TYPE + /* If we shall match only directories use the information + provided by the dirent call if possible. */ + if ((flags & GLOB_ONLYDIR) + && d->d_type != DT_UNKNOWN && d->d_type != DT_DIR) + continue; +#endif + + name = d->d_name; + + if (fnmatch (pattern, name, fnm_flags) == 0) + { + struct globlink *new = (struct globlink *) + __alloca (sizeof (struct globlink)); + len = NAMLEN (d); + new->name = (char *) malloc (len + 1); + if (new->name == NULL) + goto memory_error; +#ifdef HAVE_MEMPCPY + *((char *) mempcpy ((__ptr_t) new->name, name, len)) + = '\0'; +#else + memcpy ((__ptr_t) new->name, name, len); + new->name[len] = '\0'; +#endif + new->next = names; + names = new; + ++nfound; + } + } + } + } + } if (nfound == 0 && (flags & GLOB_NOCHECK)) { @@ -975,38 +1285,44 @@ glob_in_dir (pattern, directory, flags, errfunc, pglob) names->name = (char *) malloc (len + 1); if (names->name == NULL) goto memory_error; +#ifdef HAVE_MEMPCPY + *((char *) mempcpy (names->name, pattern, len)) = '\0'; +#else memcpy (names->name, pattern, len); names->name[len] = '\0'; +#endif } - pglob->gl_pathv - = (char **) realloc (pglob->gl_pathv, - (pglob->gl_pathc + - ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) + - nfound + 1) * - sizeof (char *)); - if (pglob->gl_pathv == NULL) - goto memory_error; - - if (flags & GLOB_DOOFFS) - while (pglob->gl_pathc < pglob->gl_offs) - pglob->gl_pathv[pglob->gl_pathc++] = NULL; - - for (; names != NULL; names = names->next) - pglob->gl_pathv[pglob->gl_pathc++] = names->name; - pglob->gl_pathv[pglob->gl_pathc] = NULL; - - pglob->gl_flags = flags; - - if (stream != NULL) + if (nfound != 0) { - int save = errno; - if (flags & GLOB_ALTDIRFUNC) - (*pglob->gl_closedir) (stream); - else - closedir ((DIR *) stream); - __set_errno (save); + pglob->gl_pathv + = (char **) realloc (pglob->gl_pathv, + (pglob->gl_pathc + + ((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) + + nfound + 1) * + sizeof (char *)); + if (pglob->gl_pathv == NULL) + goto memory_error; + + if (flags & GLOB_DOOFFS) + while (pglob->gl_pathc < pglob->gl_offs) + pglob->gl_pathv[pglob->gl_pathc++] = NULL; + + for (; names != NULL; names = names->next) + pglob->gl_pathv[pglob->gl_pathc++] = names->name; + pglob->gl_pathv[pglob->gl_pathc] = NULL; + + pglob->gl_flags = flags; } + + save = errno; + if (stream != NULL) + if (flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir) (stream); + else + closedir ((DIR *) stream); + __set_errno (save); + return nfound == 0 ? GLOB_NOMATCH : 0; memory_error: diff --git a/glob/glob.h b/glob/glob.h index 713117bd..a546c865 100644 --- a/glob/glob.h +++ b/glob/glob.h @@ -19,13 +19,11 @@ #define _GLOB_H 1 #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif #undef __ptr_t -#if (defined __cplusplus || (defined __STDC__ && __STDC__) \ - || defined WINDOWS32) +#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 # undef __P # define __P(protos) protos # define __ptr_t void * @@ -57,11 +55,12 @@ extern "C" # define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */ # define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */ # define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */ -# define GLOB_TILDE (1 <<12)/* Expand ~user and ~ to home directories. */ +# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */ +# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */ # define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \ GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \ - GLOB_NOMAGIC|GLOB_TILDE) + GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR) #else # define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \ GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \ @@ -79,6 +78,14 @@ extern "C" # define GLOB_ABEND GLOB_ABORTED #endif +/* This value is returned if the implementation does not support + `glob'. Since this is not the case here it will never be + returned but the conformance test suites still require the symbol + to be defined. */ +#if (_XOPEN_SOURCE - 0) == 500 +# define GLOB_NOSYS (-1) +#endif + /* Structure describing a globbing run. */ #if !defined _AMIGA && !defined VMS /* Buggy compiler. */ struct stat; diff --git a/implicit.c b/implicit.c index f7298c6c..a999a0f6 100644 --- a/implicit.c +++ b/implicit.c @@ -111,14 +111,14 @@ pattern_search (file, archive, depth, recursions) /* This buffer records all the dependencies actually found for a rule. */ char **found_files = (char **) alloca (max_pattern_deps * sizeof (char *)); /* Number of dep names now in FOUND_FILES. */ - unsigned int deps_found; + unsigned int deps_found = 0; /* Names of possible dependencies are constructed in this buffer. */ register char *depname = (char *) alloca (namelen + max_pattern_dep_length); /* The start and length of the stem of FILENAME for the current rule. */ - register char *stem; - register unsigned int stemlen; + register char *stem = 0; + register unsigned int stemlen = 0; /* Buffer in which we store all the rules that are possibly applicable. */ struct rule **tryrules diff --git a/job.c b/job.c index 2227bef7..91bc30b4 100644 --- a/job.c +++ b/job.c @@ -27,11 +27,12 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef WINDOWS32 char *default_shell = "sh.exe"; int no_default_sh_exe = 1; +int batch_mode_shell = 1; #else /* WINDOWS32 */ #ifdef _AMIGA char default_shell[] = ""; extern int MyExecute (char **); -#else +#else /* _AMIGA */ #ifdef __MSDOS__ /* The default shell is a pointer so we can change it if Makefile says so. It is without an explicit path so we get a chance @@ -41,6 +42,7 @@ char *default_shell = "command.com"; #else /* __MSDOS__ */ char default_shell[] = "/bin/sh"; #endif /* __MSDOS__ */ +int batch_mode_shell = 0; #endif /* _AMIGA */ #endif /* WINDOWS32 */ @@ -74,11 +76,6 @@ static int amiga_batch_file; #include "sub_proc.h" #include "w32err.h" #include "pathstuff.h" - -/* this stuff used if no sh.exe is around */ -static char *dos_bname; -static char *dos_bename; -static int dos_batch_file; #endif /* WINDOWS32 */ #ifdef HAVE_FCNTL_H @@ -168,7 +165,7 @@ extern char *allocated_variable_expand_for_file PARAMS ((char *line, struct 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 start_remote_job_p PARAMS ((int)); extern int remote_status PARAMS ((int *exit_code_ptr, int *signal_ptr, int *coredump_ptr, int block)); @@ -327,9 +324,9 @@ reap_children (block, err) any_remote |= c->remote; any_local |= ! c->remote; if (debug_flag) - printf ("Live child 0x%08lx PID %d%s\n", + printf ("Live child 0x%08lx PID %ld%s\n", (unsigned long int) c, - c->pid, c->remote ? " (remote)" : ""); + (long) c->pid, c->remote ? " (remote)" : ""); #ifdef VMS break; #endif @@ -426,38 +423,33 @@ reap_children (block, err) coredump = 0; #endif /* _AMIGA */ #ifdef WINDOWS32 - { - HANDLE hPID; - int err; + { + HANDLE hPID; + int err; - /* wait for anything to finish */ - if (hPID = process_wait_for_any()) { + /* wait for anything to finish */ + if (hPID = process_wait_for_any()) { - /* was an error found on this process? */ - err = process_last_err(hPID); + /* was an error found on this process? */ + err = process_last_err(hPID); - /* get exit data */ - exit_code = process_exit_code(hPID); + /* get exit data */ + exit_code = process_exit_code(hPID); - if (err) - fprintf(stderr, "make (e=%d): %s", - exit_code, map_windows32_error_to_string(exit_code)); + if (err) + fprintf(stderr, "make (e=%d): %s", + exit_code, map_windows32_error_to_string(exit_code)); - exit_sig = process_signal(hPID); + /* signal */ + exit_sig = process_signal(hPID); - /* cleanup process */ - process_cleanup(hPID); + /* cleanup process */ + process_cleanup(hPID); - if (dos_batch_file) { - remove (dos_bname); - remove (dos_bename); - dos_batch_file = 0; - } - - coredump = 0; - } - pid = (int) hPID; - } + coredump = 0; + } + pid = (int) hPID; + } #endif /* WINDOWS32 */ #endif /* Not __MSDOS__ */ } @@ -498,10 +490,22 @@ reap_children (block, err) else { if (debug_flag) - printf ("Reaping %s child 0x%08lx PID %d%s\n", + printf ("Reaping %s child 0x%08lx PID %ld%s\n", child_failed ? "losing" : "winning", (unsigned long int) c, - c->pid, c->remote ? " (remote)" : ""); + (long) c->pid, c->remote ? " (remote)" : ""); + + if (c->sh_batch_file) { + if (debug_flag) + printf("Cleaning up temporary batch file %s\n", c->sh_batch_file); + + /* just try and remove, don't care if this fails */ + remove(c->sh_batch_file); + + /* all done with memory */ + free(c->sh_batch_file); + c->sh_batch_file = NULL; + } /* If this child had the good stdin, say it is now free. */ if (c->good_stdin) @@ -549,7 +553,7 @@ reap_children (block, err) Whether or not we want to changes over time. Also, start_remote_job may need state set up by start_remote_job_p. */ - c->remote = start_remote_job_p (); + c->remote = start_remote_job_p (0); start_job_command (c); /* Fatal signals are left blocked in case we were about to put that child on the chain. But it is @@ -586,9 +590,9 @@ reap_children (block, err) notice_finished_file (c->file); if (debug_flag) - printf ("Removing child 0x%08lx PID %d%s from chain.\n", + printf ("Removing child 0x%08lx PID %ld%s from chain.\n", (unsigned long int) c, - c->pid, c->remote ? " (remote)" : ""); + (long) c->pid, c->remote ? " (remote)" : ""); /* Block fatal signals while frobnicating the list, so that children and job_slots_used are always consistent. Otherwise @@ -740,7 +744,7 @@ start_job_command (child) #ifdef VMS argv = p; #else - argv = construct_command_argv (p, &end, child->file); + argv = construct_command_argv (p, &end, child->file, &child->sh_batch_file); #endif if (end == NULL) child->command_ptr = NULL; @@ -765,6 +769,9 @@ start_job_command (child) if (argv == 0) { next_command: +#ifdef __MSDOS__ + execute_by_shell = 0; /* in case construct_command_argv sets it */ +#endif /* This line has no commands. Go to the next. */ if (job_next_command (child)) start_job_command (child); @@ -887,7 +894,9 @@ start_job_command (child) if (start_remote_job (argv, child->environment, child->good_stdin ? 0 : bad_stdin, &is_remote, &id, &used_stdin)) - goto error; + /* Don't give up; remote execution may fail for various reasons. If + so, simply run the job locally. */ + goto run_local; else { if (child->good_stdin && !used_stdin) @@ -906,6 +915,7 @@ start_job_command (child) char **parent_environ; + run_local: block_sigs (); child->remote = 0; @@ -1066,7 +1076,7 @@ start_waiting_job (c) the local load average. We record that the job should be started remotely in C->remote for start_job_command to test. */ - c->remote = start_remote_job_p (); + c->remote = start_remote_job_p (1); /* If this job is to be started locally, and we are already running some jobs, make this one wait if the load average is too high. */ @@ -1251,6 +1261,7 @@ new_job (file) c->command_line = 0; c->command_ptr = 0; c->environment = 0; + c->sh_batch_file = NULL; /* Fetch the first command line to be run. */ job_next_command (c); @@ -1479,11 +1490,12 @@ child_execute_job (argv, child) } *c = *p; - /* check for maximum dcl length and create *.com file if neccesary */ + /* Check for maximum DCL length and create *.com file if neccesary. + Also create a .com file if the command is more than one line long. */ comname[0] = '\0'; - if (strlen (cmd) > MAXCMDLEN) + if (strlen (cmd) > MAXCMDLEN || strchr (cmd, '\n')) { FILE *outfile; char tmp; @@ -1743,9 +1755,10 @@ void clean_tmp (void) IFS is the value of $IFS, or nil (meaning the default). */ static char ** -construct_command_argv_internal (line, restp, shell, ifs) +construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) char *line, **restp; char *shell, *ifs; + char **batch_filename_ptr; { #ifdef __MSDOS__ /* MSDOS supports both the stock DOS shell and ports of Unixy shells. @@ -1810,7 +1823,11 @@ construct_command_argv_internal (line, restp, shell, ifs) "logout", "set", "umask", "wait", "while", "for", "case", "if", ":", ".", "break", "continue", "export", "read", "readonly", "shift", "times", - "trap", "switch", "test", 0 }; + "trap", "switch", "test", +#ifdef BATCH_MODE_ONLY_SHELL + "echo", +#endif + 0 }; char* sh_chars; char** sh_cmds; #else /* WINDOWS32 */ @@ -2144,38 +2161,6 @@ construct_command_argv_internal (line, restp, shell, ifs) ++line; if (*line == '\0') return 0; - - /* - * only come here if no sh.exe command - */ - if (no_default_sh_exe) - { - FILE *batch; - dos_batch_file = 1; - if (dos_bname == 0) - { - dos_bname = tempnam (".", "mk"); - for (i = 0; dos_bname[i] != '\0'; ++i) - if (dos_bname[i] == '/') - dos_bname[i] = '\\'; - dos_bename = (char *) xmalloc (strlen (dos_bname) + 5); - strcpy (dos_bename, dos_bname); - strcat (dos_bname, ".bat"); - strcat (dos_bename, ".err"); - } - batch = fopen (dos_bename, "w"); /* Create a file. */ - if (batch != NULL) - fclose (batch); - batch = fopen (dos_bname, "w"); - fputs ("@echo off\n", batch); - fputs (line, batch); - fprintf (batch, "\nif errorlevel 1 del %s\n", dos_bename); - fclose (batch); - new_argv = (char **) xmalloc(2 * sizeof(char *)); - new_argv[0] = strdup (dos_bname); - new_argv[1] = 0; - } - else #endif /* WINDOWS32 */ { /* SHELL may be a multi-word command. Construct a command line @@ -2189,12 +2174,14 @@ construct_command_argv_internal (line, restp, shell, ifs) char *new_line = (char *) alloca (shell_len + (sizeof (minus_c) - 1) + (line_len * 2) + 1); + char* command_ptr = NULL; /* used for batch_mode_shell mode */ ap = new_line; bcopy (shell, ap, shell_len); ap += shell_len; bcopy (minus_c, ap, sizeof (minus_c) - 1); ap += sizeof (minus_c) - 1; + command_ptr = ap; for (p = line; *p != '\0'; ++p) { if (restp != NULL && *p == '\n') @@ -2218,14 +2205,14 @@ construct_command_argv_internal (line, restp, shell, ifs) p = next_token (p); --p; - if (unixy_shell) - *ap++ = '\\'; + if (unixy_shell && !batch_mode_shell) + *ap++ = '\\'; *ap++ = ' '; continue; } /* DOS shells don't know about backslash-escaping. */ - if (unixy_shell && + if (unixy_shell && !batch_mode_shell && (*p == '\\' || *p == '\'' || *p == '"' || isspace (*p) || index (sh_chars, *p) != 0)) @@ -2246,9 +2233,63 @@ construct_command_argv_internal (line, restp, shell, ifs) return 0; *ap = '\0'; +#ifdef WINDOWS32 + /* + * Some shells do not work well when invoked as 'sh -c xxx' to run + * a command line (e.g. Cygnus GNUWIN32 sh.exe on WIN32 systems). + * In these cases, run commands via a script file. + */ + if ((no_default_sh_exe || batch_mode_shell) && batch_filename_ptr) { + FILE* batch = NULL; + int id = GetCurrentProcessId(); + PATH_VAR(fbuf); + char* fname = NULL; + + /* create a file name */ + sprintf(fbuf, "make%d", id); + fname = tempnam(".", fbuf); + + /* create batch file name */ + *batch_filename_ptr = xmalloc(strlen(fname) + 5); + strcpy(*batch_filename_ptr, fname); + + /* make sure path name is in DOS backslash format */ + if (!unixy_shell) { + fname = *batch_filename_ptr; + for (i = 0; fname[i] != '\0'; ++i) + if (fname[i] == '/') + fname[i] = '\\'; + strcat(*batch_filename_ptr, ".bat"); + } else { + strcat(*batch_filename_ptr, ".sh"); + } + + if (debug_flag) + printf("Creating temporary batch file %s\n", *batch_filename_ptr); + + /* create batch file to execute command */ + batch = fopen (*batch_filename_ptr, "w"); + fputs ("@echo off\n", batch); + fputs (command_ptr, batch); + fputc ('\n', batch); + fclose (batch); + + /* create argv */ + new_argv = (char **) xmalloc(3 * sizeof(char *)); + if (unixy_shell) { + new_argv[0] = strdup (shell); + new_argv[1] = *batch_filename_ptr; /* only argv[0] gets freed later */ + } else { + new_argv[0] = strdup (*batch_filename_ptr); + new_argv[1] = NULL; + } + new_argv[2] = NULL; + } else +#endif /* WINDOWS32 */ if (unixy_shell) new_argv = construct_command_argv_internal (new_line, (char **) NULL, - (char *) 0, (char *) 0); + (char *) 0, (char *) 0, + (char *) 0); #ifdef __MSDOS__ else { @@ -2262,6 +2303,10 @@ construct_command_argv_internal (line, restp, shell, ifs) new_line + shell_len + sizeof (minus_c) - 1, line_len); new_argv[0][line_len] = '\0'; } +#else + else + fatal("%s (line %d) Invalid shell context (!unixy && !batch_mode_shell)\n", + __FILE__, __LINE__); #endif } #endif /* ! AMIGA */ @@ -2283,9 +2328,10 @@ construct_command_argv_internal (line, restp, shell, ifs) variable expansion for $(SHELL) and $(IFS). */ char ** -construct_command_argv (line, restp, file) +construct_command_argv (line, restp, file, batch_filename_ptr) char *line, **restp; struct file *file; + char** batch_filename_ptr; { char *shell, *ifs; char **argv; @@ -2311,7 +2357,7 @@ construct_command_argv (line, restp, file) warn_undefined_variables_flag = save; } - argv = construct_command_argv_internal (line, restp, shell, ifs); + argv = construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr); free (shell); free (ifs); diff --git a/job.h b/job.h index ca7ad1dc..eaac4921 100644 --- a/job.h +++ b/job.h @@ -44,6 +44,7 @@ struct child unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */ unsigned int deleted:1; /* Nonzero if targets have been deleted. */ + char* sh_batch_file; /* used to execute shell commands via scripts */ }; extern struct child *children; @@ -52,7 +53,7 @@ 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 PARAMS ((char *line, char **restp, struct file *file)); +extern char **construct_command_argv PARAMS ((char *line, char **restp, struct file *file, char** batch_file)); #ifdef VMS extern int child_execute_job PARAMS ((char *argv, struct child *child)); #else diff --git a/main.c b/main.c index 0cf58fbc..dcffa37c 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,5 @@ /* Argument parsing and main program of GNU Make. -Copyright (C) 1988,89,90,91,94,95,96,97 Free Software Foundation, Inc. +Copyright (C) 1988,89,90,91,94,95,96,97,98 Free Software Foundation, Inc. This file is part of GNU Make. GNU Make is free software; you can redistribute it and/or modify @@ -180,7 +180,6 @@ int print_version_flag = 0; static struct stringlist *makefiles = 0; - /* Number of job slots (commands that can be run at once). */ unsigned int job_slots = 1; @@ -532,8 +531,99 @@ handle_runtime_exceptions( struct _EXCEPTION_POINTERS *exinfo ) return EXCEPTION_CONTINUE_SEARCH; #else exit(255); + return (255); /* not reached */ #endif } + +/* + * On WIN32 systems we don't have the luxury of a /bin directory that + * is mapped globally to every drive mounted to the system. Since make could + * be invoked from any drive, and we don't want to propogate /bin/sh + * to every single drive. Allow ourselves a chance to search for + * a value for default shell here (if the default path does not exist). + */ + +int +find_and_set_default_shell(char *token) +{ + int sh_found = 0; + char* search_token; + PATH_VAR(sh_path); + extern char *default_shell; + + if (!token) + search_token = default_shell; + else + search_token = token; + + if (!no_default_sh_exe && + (token == NULL || !strcmp(search_token, default_shell))) { + /* no new information, path already set or known */ + sh_found = 1; + } else if (file_exists_p(search_token)) { + /* search token path was found */ + sprintf(sh_path, "%s", search_token); + default_shell = strdup(w32ify(sh_path,0)); + if (debug_flag) + printf("find_and_set_shell setting default_shell = %s\n", default_shell); + sh_found = 1; + } else { + char *p; + struct variable *v = lookup_variable ("Path", 4); + + /* + * Search Path for shell + */ + if (v && v->value) { + char *ep; + + p = v->value; + ep = strchr(p, PATH_SEPARATOR_CHAR); + + while (ep && *ep) { + *ep = '\0'; + + if (dir_file_exists_p(p, search_token)) { + sprintf(sh_path, "%s/%s", p, search_token); + default_shell = strdup(w32ify(sh_path,0)); + sh_found = 1; + *ep = PATH_SEPARATOR_CHAR; + + /* terminate loop */ + p += strlen(p); + } else { + *ep = PATH_SEPARATOR_CHAR; + p = ++ep; + } + + ep = strchr(p, PATH_SEPARATOR_CHAR); + } + + /* be sure to check last element of Path */ + if (p && *p && dir_file_exists_p(p, search_token)) { + sprintf(sh_path, "%s/%s", p, search_token); + default_shell = strdup(w32ify(sh_path,0)); + sh_found = 1; + } + + if (debug_flag && sh_found) + printf("find_and_set_shell path search set default_shell = %s\n", default_shell); + } + } + + /* naive test */ + if (!unixy_shell && sh_found && + (strstr(default_shell, "sh") || strstr(default_shell, "SH"))) { + unixy_shell = 1; + batch_mode_shell = 0; + } + +#ifdef BATCH_MODE_ONLY_SHELL + batch_mode_shell = 1; +#endif + + return (sh_found); +} #endif /* WINDOWS32 */ #ifdef __MSDOS__ @@ -556,17 +646,21 @@ main (argc, argv, envp) int main (int argc, char ** argv) #endif { + static char *stdin_nm = 0; register struct file *f; register unsigned int i; char **p; struct dep *read_makefiles; PATH_VAR (current_directory); #ifdef WINDOWS32 - extern int no_default_sh_exe; char *unix_path = NULL; char *windows32_path = NULL; SetUnhandledExceptionFilter(handle_runtime_exceptions); + + /* start off assuming we have no shell */ + unixy_shell = 0; + no_default_sh_exe = 1; #endif default_goal_file = 0; @@ -708,20 +802,28 @@ int main (int argc, char ** argv) #ifndef _AMIGA for (i = 0; envp[i] != 0; ++i) { + int do_not_define; register char *ep = envp[i]; + + /* by default, everything gets defined and exported */ + do_not_define = 0; + while (*ep != '=') - ++ep; + ++ep; #ifdef WINDOWS32 if (!unix_path && !strncmp(envp[i], "PATH=", 5)) unix_path = ep+1; - if (!windows32_path && !strncmp(envp[i], "Path=", 5)) + else if (!windows32_path && !strnicmp(envp[i], "Path=", 5)) { + do_not_define = 1; /* it gets defined after loop exits */ windows32_path = ep+1; + } #endif /* The result of pointer arithmetic is cast to unsigned int for machines where ptrdiff_t is a different size that doesn't widen the same. */ - define_variable (envp[i], (unsigned int) (ep - envp[i]), - ep + 1, o_env, 1) + if (!do_not_define) + define_variable (envp[i], (unsigned int) (ep - envp[i]), + ep + 1, o_env, 1) /* Force exportation of every variable culled from the environment. We used to rely on target_environment's v_default code to do this. But that does not work for the case where an environment variable @@ -730,6 +832,16 @@ int main (int argc, char ** argv) ->export = v_export; } #ifdef WINDOWS32 + /* + * Make sure that this particular spelling of 'Path' is available + */ + if (windows32_path) + define_variable("Path", 4, windows32_path, o_env, 1)->export = v_export; + else if (unix_path) + define_variable("Path", 4, unix_path, o_env, 1)->export = v_export; + else + define_variable("Path", 4, "", o_env, 1)->export = v_export; + /* * PATH defaults to Path iff PATH not found and Path is found. */ @@ -840,7 +952,7 @@ int main (int argc, char ** argv) if (! v->recursive) ++len; ++len; - len += 2 * strlen (v->value); + len += 3 * strlen (v->value); } /* Now allocate a buffer big enough and fill it. */ @@ -899,68 +1011,8 @@ int main (int argc, char ** argv) * lookups to fail because the current directory (.) was pointing * at the wrong place when it was first evaluated. */ + no_default_sh_exe = !find_and_set_default_shell(NULL); - /* - * On Windows/NT, we don't have the luxury of a /bin directory that - * is mapped globally to every drive mounted to the system. Since make could - * be invoked from any drive, and we don't want to propogate /bin/sh - * to every single drive. Allow ourselves a chance to search for - * a value for default shell here (if the default path does not exist). - * - * The value of default_shell is set here, but it could get reset after - * the Makefiles are read in. See logic below where SHELL is checked - * after the call to read_all_makefiles() completes. - * - * The reason SHELL is set here is so that macros can be safely evaluated - * as makefiles are read in (some macros require $SHELL). - */ - - { - extern char *default_shell; - - if (!file_exists_p(default_shell)) { - char *p; - struct variable *v = lookup_variable ("Path", 4); - - /* - * Try and make sure we have a full path to default_shell before - * we parse makefiles. - */ - if (v && v->value) { - PATH_VAR(sh_path); - char *ep; - - p = v->value; - ep = strchr(p, PATH_SEPARATOR_CHAR); - - while (ep && *ep) { - *ep = '\0'; - - if (dir_file_exists_p(p, default_shell)) { - sprintf(sh_path, "%s/%s", p, default_shell); - default_shell = strdup(w32ify(sh_path,0)); - no_default_sh_exe = 0; - *ep = PATH_SEPARATOR_CHAR; - - /* terminate loop */ - p += strlen(p); - } else { - *ep = PATH_SEPARATOR_CHAR; - p = ++ep; - } - - ep = strchr(p, PATH_SEPARATOR_CHAR); - } - - /* be sure to check last element of Path */ - if (p && *p && dir_file_exists_p(p, default_shell)) { - sprintf(sh_path, "%s/%s", p, default_shell); - default_shell = strdup(w32ify(sh_path,0)); - no_default_sh_exe = 0; - } - } - } - } #endif /* WINDOWS32 */ /* Figure out the level of recursion. */ { @@ -1007,6 +1059,8 @@ int main (int argc, char ** argv) starting_directory = current_directory; } + (void) define_variable ("CURDIR", 6, current_directory, o_default, 0); + /* Read any stdin makefiles into temporary files. */ if (makefiles != 0) @@ -1034,6 +1088,9 @@ int main (int argc, char ** argv) (void) tmpnam (name); #endif + if (stdin_nm) + fatal("Makefile from standard input specified twice."); + outfile = fopen (name, "w"); if (outfile == 0) pfatal_with_name ("fopen (temporary file)"); @@ -1044,9 +1101,6 @@ int main (int argc, char ** argv) if (n > 0 && fwrite (buf, 1, n, outfile) != n) pfatal_with_name ("fwrite (temporary file)"); } - /* Try to make sure we won't remake the temporary - file when we are re-exec'd. Kludge-o-matic! */ - fprintf (outfile, "%s:;\n", name); (void) fclose (outfile); /* Replace the name that read_all_makefiles will @@ -1060,14 +1114,15 @@ int main (int argc, char ** argv) } /* Make sure the temporary file will not be remade. */ - f = enter_file (savestring (name, sizeof name - 1)); + stdin_nm = savestring (name, sizeof(name) -1); + f = enter_file (stdin_nm); f->updated = 1; f->update_status = 0; f->command_state = cs_finished; - /* Let it be removed when we're done. */ - f->intermediate = 1; - /* But don't mention it. */ - f->dontcare = 1; + /* Can't be intermediate, or it'll be removed too early for + make re-exec. */ + f->intermediate = 0; + f->dontcare = 0; } } @@ -1107,53 +1162,6 @@ int main (int argc, char ** argv) define_makeflags (0, 0); -#ifdef WINDOWS32 - /* - * Now that makefiles are parsed, see if a Makefile gave a - * value for SHELL and use that for default_shell instead if - * that filename exists. This should speed up the - * construct_argv_internal() function by avoiding unnecessary - * recursion. - */ - { - struct variable *v = lookup_variable("SHELL", 5); - extern char* default_shell; - - /* - * to change value: - * - * SHELL must be found, SHELL must be set, value of SHELL - * must be different from current value, and the - * specified file must exist. Whew! - */ - if (v != 0 && *v->value != '\0') { - char *fn = recursively_expand(v); - - if (fn && strcmp(fn, default_shell) && file_exists_p(fn)) { - char *p; - - default_shell = fn; - - /* if Makefile says SHELL is sh.exe, believe it */ - if (strstr(default_shell, "sh.exe")) - no_default_sh_exe = 0; - - /* - * Convert from backslashes to forward slashes so - * create_command_line_argv_internal() is not confused. - */ - for (p = strchr(default_shell, '\\'); p; p = strchr(default_shell, '\\')) - *p = '/'; - } - } - } - if (no_default_sh_exe && job_slots != 1) { - error("Do not specify -j or --jobs if sh.exe is not available."); - error("Resetting make for single job mode."); - job_slots = 1; - } -#endif /* WINDOWS32 */ - /* Define the default variables. */ define_default_variables (); @@ -1164,6 +1172,18 @@ int main (int argc, char ** argv) read_makefiles = read_all_makefiles (makefiles == 0 ? (char **) 0 : makefiles->list); +#ifdef WINDOWS32 + /* look one last time after reading all Makefiles */ + if (no_default_sh_exe) + no_default_sh_exe = !find_and_set_default_shell(NULL); + + if (no_default_sh_exe && job_slots != 1) { + error("Do not specify -j or --jobs if sh.exe is not available."); + error("Resetting make for single job mode."); + job_slots = 1; + } +#endif /* WINDOWS32 */ + #ifdef __MSDOS__ /* We need to know what kind of shell we will be using. */ { @@ -1295,7 +1315,7 @@ int main (int argc, char ** argv) /* Free the storage. */ free ((char *) d); - d = last == 0 ? 0 : last->next; + d = last == 0 ? read_makefiles : last->next; break; } @@ -1416,24 +1436,14 @@ int main (int argc, char ** argv) } } - /* Add -o options for all makefiles that were remade */ - { - register unsigned int i; - struct dep *d; - - for (i = argc+1, d = read_makefiles; d != 0; d = d->next) - i += d->file->updated != 0; - - nargv = (char **)xmalloc(i * sizeof(char *)); - bcopy(argv, nargv, argc * sizeof(char *)); - - for (i = 0, d = read_makefiles; d != 0; ++i, d = d->next) - { - if (d->file->updated) - nargv[nargc++] = concat("-o", dep_name(d), ""); - } - nargv[nargc] = 0; - } + /* Add -o option for the stdin temporary file, if necessary. */ + if (stdin_nm) + { + nargv = (char **)xmalloc((nargc + 2) * sizeof(char *)); + bcopy(argv, nargv, argc * sizeof(char *)); + nargv[nargc++] = concat("-o", stdin_nm, ""); + nargv[nargc] = 0; + } if (directories != 0 && directories->idx > 0) { @@ -1507,6 +1517,11 @@ int main (int argc, char ** argv) /* Set up `MAKEFLAGS' again for the normal targets. */ define_makeflags (1, 0); + /* If there is a temp file from reading a makefile from stdin, get rid of + it now. */ + if (stdin_nm && unlink(stdin_nm) < 0 && errno != ENOENT) + perror_with_name("unlink (temporary file): ", stdin_nm); + { int status; @@ -2324,12 +2339,12 @@ print_version () printf ("-%s", remote_description); printf (", by Richard Stallman and Roland McGrath.\n\ -%sCopyright (C) 1988, 89, 90, 91, 92, 93, 94, 95, 96, 97\n\ +%sCopyright (C) 1988, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98\n\ %s\tFree Software Foundation, Inc.\n\ %sThis is free software; see the source for copying conditions.\n\ %sThere is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n\ %sPARTICULAR PURPOSE.\n\n\ -%sReport bugs to .\n\n", +%sReport bugs to .\n\n", precede, precede, precede, precede, precede, precede); printed_version = 1; @@ -2373,13 +2388,6 @@ die (status) dying = 1; - /* Try to move back to the original directory. This is essential on - MS-DOS (where there is really only one process), and on Unix it - puts core files in the original directory instead of the -C - directory. */ - if (directory_before_chdir != 0) - chdir (directory_before_chdir); - if (print_version_flag) print_version (); @@ -2396,6 +2404,14 @@ die (status) if (print_data_base_flag) print_data_base (); + /* Try to move back to the original directory. This is essential on + MS-DOS (where there is really only one process), and on Unix it + puts core files in the original directory instead of the -C + directory. Must wait until after remove_intermediates(), or unlinks + of relative pathnames fail. */ + if (directory_before_chdir != 0) + chdir (directory_before_chdir); + log_working_directory (0); } @@ -2410,7 +2426,7 @@ log_working_directory (entering) int entering; { static int entered = 0; - char *message = entering ? "Entering" : "Leaving"; + char *msg = entering ? "Entering" : "Leaving"; /* Print nothing without the flag. Don't print the entering message again if we already have. Don't print the leaving message if we @@ -2424,9 +2440,9 @@ log_working_directory (entering) fputs ("# ", stdout); if (makelevel == 0) - printf ("%s: %s ", program, message); + printf ("%s: %s ", program, msg); else - printf ("%s[%u]: %s ", program, makelevel, message); + printf ("%s[%u]: %s ", program, makelevel, msg); if (starting_directory == 0) puts ("an unknown directory"); diff --git a/maintMakefile b/maintMakefile index 5aab784b..0c9aa9be 100644 --- a/maintMakefile +++ b/maintMakefile @@ -7,7 +7,8 @@ globsrc := $(wildcard glob/*.c) globhdr := $(wildcard glob/*.h) -TEMPLATES = README config.ami configh.dos config.h.W32 config.h-vms +TEMPLATES = README README.DOS config.ami configh.dos config.h.W32 config.h-vms +MTEMPLATES = Makefile.DOS SMakefile # General rule for turning a .template into a regular file. # @@ -18,9 +19,9 @@ $(TEMPLATES) : % : %.template configure.in $< > $@ chmod a-w $@ -# Construct Makefile.DOS +# Construct Makefiles by adding on dependencies, etc. # -Makefile.DOS: Makefile.DOS.template Makefile.am configure.in +$(MTEMPLATES) : % : %.template .dep_segment Makefile.am maintMakefile rm -f $@ sed -e 's@%VERSION%@$(VERSION)@' \ -e 's@%PROGRAMS%@$(bin_PROGRAMS)@' \ @@ -29,28 +30,44 @@ Makefile.DOS: Makefile.DOS.template Makefile.am configure.in -e 's@%GLOB_SOURCES%@$(globsrc) $(globhdr)@' \ -e 's@%GLOB_OBJECTS%@$(globsrc:glob/%.c=%.o)@' \ $< > $@ + echo >>$@; echo '# --------------- DEPENDENCIES' >>$@; echo '#' >>$@; \ + cat $(word 2,$^) >>$@ + chmod a-w $@ + +NMakefile: NMakefile.template .dep_segment Makefile.am maintMakefile + rm -f $@ + cp $< $@ + echo >>$@; echo '# --------------- DEPENDENCIES' >>$@; echo '#' >>$@; \ + sed 's/^\([^ ]*\)\.o:/$$(OUTDIR)\/\1.obj:/' $(word 2,$^) >>$@ chmod a-w $@ # Construct build.sh.in # -build.sh.in: build.template Makefile.am +build.sh.in: build.template Makefile.am maintMakefile rm -f $@ sed -e 's@%objs%@$(filter-out remote-%, $(make_OBJECTS)\ $(patsubst %.c,%.o,$(globsrc)))@' \ $< > $@ chmod a-w+x $@ +# Use automake to build a dependency list file, for "foreign" makefiles like +# Makefile.DOS. +# +.dep_segment: Makefile.am maintMakefile $(DEP_FILES) + $(AUTOMAKE) --generate-deps --build-dir=. --srcdir-name=. + # We clean everything here. The GNU standards for makefile conventions say # you shouldn't remove configure, etc., but this makefile is only available # in a full development distribution, so they'll only be removed then. # # And _I_ want them to be removed ;) # -maintFILES = configure aclocal.m4 config.h.in Makefile.in \ - stamp-h.in glob/stamp-h.in +maintFILES = configure aclocal.m4 config.h.in Makefile.in stamp-h.in \ + glob/configure glob/aclocal.m4 glob/config.h.in glob/Makefile.in \ + glob/stamp-h.in -MAINTAINERCLEANFILES = $(TEMPLATES) missing Makefile.DOS build.sh.in \ - $(maintFILES) +MAINTAINERCLEANFILES = $(maintFILES) $(TEMPLATES) $(MTEMPLATES) NMakefile \ + missing build.sh.in .dep_segment # Put the alpha distribution files up for anonymous FTP. # @@ -61,3 +78,9 @@ TARFILE := $(distdir).tar.gz alpha: $(ALPHA) $(TARFILE) @rm -f $(ALPHA)/$(TARFILE) cp -p $(TARFILE) $(ALPHA) + +# This is needed because normal builds with GCC don't compile alloca.c, so +# alloca.P doesn't get built :-/. +# +.deps/alloca.P: alloca.c + $(COMPILE) -M -o $@ $< diff --git a/make.1 b/make.1 index 1bd37a7e..ab6ba479 100644 --- a/make.1 +++ b/make.1 @@ -5,17 +5,16 @@ make \- GNU make utility to maintain groups of programs .B "make " [ .B \-f -makefile ] [ option ] ... +.I makefile +] [ option ] ... target ... .SH WARNING This man page is an extract of the documentation of .I GNU make . It is updated only occasionally, because the GNU project does not use nroff. For complete, current documentation, refer to the Info file -.B make -or the DVI file -.B make.dvi -which are made from the Texinfo source file +.B make.info +which is made from the Texinfo source file .BR make.texinfo . .SH DESCRIPTION .LP @@ -24,7 +23,7 @@ The purpose of the utility is to determine automatically which pieces of a large program need to be recompiled, and issue the commands to recompile them. -This manual describes the GNU implementation of +The manual describes the GNU implementation of .IR make , which was written by Richard Stallman and Roland McGrath. Our examples show C programs, since they are most common, but you can use @@ -288,12 +287,7 @@ command on the given file before running except that the modification time is changed only in the imagination of .IR make . .SH "SEE ALSO" -.PD 0 -.TP 2.0i -/usr/local/doc/gnumake.dvi -.I -The GNU Make Manual -.PD +.I "The GNU Make Manual" .SH BUGS See the chapter `Problems and Bugs' in .I "The GNU Make Manual" . diff --git a/make.h b/make.h index d99ccd01..58a0ff21 100644 --- a/make.h +++ b/make.h @@ -86,11 +86,11 @@ extern int errno; #define POSIX #endif -#ifdef HAVE_SYS_SIGLIST -#ifndef SYS_SIGLIST_DECLARED +#if defined (HAVE_SYS_SIGLIST) && !defined (SYS_SIGLIST_DECLARED) extern char *sys_siglist[]; #endif -#else + +#if !defined (HAVE_SYS_SIGLIST) || !defined (HAVE_STRSIGNAL) #include "signame.h" #endif @@ -241,6 +241,11 @@ extern void bcopy (); extern char *strerror PARAMS ((int errnum)); #endif +#ifndef __attribute__ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# define __attribute__(x) +# endif +#endif #ifdef __GNUC__ #undef alloca @@ -259,7 +264,7 @@ extern char *alloca (); #define streq(a, b) \ ((a) == (b) || \ (*(a) == *(b) && (*(a) == '\0' || !strcmp ((a) + 1, (b) + 1)))) -#ifdef _AMIGA +#ifdef HAVE_CASE_INSENSITIVE_FS #define strieq(a, b) \ ((a) == (b) || \ (tolower(*(a)) == tolower(*(b)) && (*(a) == '\0' || !strcmpi ((a) + 1, (b) + 1)))) @@ -277,7 +282,7 @@ extern char *alloca (); /* Add to VAR the hashing value of C, one character in a name. */ #define HASH(var, c) \ ((var += (c)), (var = ((var) << 7) + ((var) >> 20))) -#ifdef _AMIGA /* Fold filenames on #amiga */ +#ifdef HAVE_CASE_INSENSITIVE_FS /* Fold filenames */ #define HASHI(var, c) \ ((var += tolower((c))), (var = ((var) << 7) + ((var) >> 20))) #else @@ -310,16 +315,23 @@ extern void sync_Path_environment(void); extern int kill(int pid, int sig); extern int safe_stat(char *file, struct stat *sb); extern char *end_of_token_w32(); -#endif +extern int find_and_set_default_shell(char *token); + +/* indicates whether or not we have Bourne shell */ +extern int no_default_sh_exe; + +/* is default_shell unixy? */ +extern int unixy_shell; +#endif /* WINDOWS32 */ -extern void die (); +extern void die () __attribute__ ((noreturn)); extern void message (); -extern void fatal (); +extern void fatal () __attribute__ ((noreturn)); extern void error (); extern void log_working_directory (); extern void makefile_error (); -extern void makefile_fatal (); -extern void pfatal_with_name (); +extern void makefile_fatal () __attribute__ ((noreturn)); +extern void pfatal_with_name () __attribute__ ((noreturn)); extern void perror_with_name (); extern char *savestring (); extern char *concat (); @@ -413,6 +425,9 @@ extern int print_directory_flag, warn_undefined_variables_flag; extern int posix_pedantic; extern int clock_skew_detected; +/* can we run commands via 'sh -c xxx' or must we use batch files? */ +extern int batch_mode_shell; + extern unsigned int job_slots; #ifndef NO_FLOAT extern double max_load_average; diff --git a/make.texinfo b/make.texinfo index 3c7e4d3e..05d07462 100644 --- a/make.texinfo +++ b/make.texinfo @@ -8,12 +8,12 @@ @c FSF publishers: format makebook.texi instead of using this file directly. @set RCSID $Id$ -@set EDITION 0.51 -@set VERSION 3.76 Beta -@set UPDATED 26 Aug 1997 -@set UPDATE-MONTH Aug 1997 +@set EDITION 0.52 +@set VERSION 3.77 +@set UPDATED 20 May 1998 +@set UPDATE-MONTH May 1998 @comment The ISBN number might need to change on next publication. -@set ISBN 1-882114-78-7 @c CHANGE THIS BEFORE PRINTING AGAIN! --roland 9may96 +@set ISBN 1-882114-80-9 @c CHANGE THIS BEFORE PRINTING AGAIN! --psmith 16jul98 @c finalout @@ -27,7 +27,7 @@ @ifinfo @dircategory The GNU make utility @direntry - * GNU make: (make.info). The GNU make utility. + * Make: (make.info). The GNU make utility. @end direntry This file documents the GNU Make utility, which determines @@ -37,7 +37,7 @@ and issues the commands to recompile them. This is Edition @value{EDITION}, last updated @value{UPDATED}, of @cite{The GNU Make Manual}, for @code{make}, Version @value{VERSION}. -Copyright (C) 1988, '89, '90, '91, '92, '93, '94, '95, '96, '97 +Copyright (C) 1988, '89, '90, '91, '92, '93, '94, '95, '96, '97, '98 Free Software Foundation, Inc. Permission is granted to make and distribute verbatim copies of @@ -68,7 +68,7 @@ by the Free Software Foundation. @titlepage @title GNU Make @subtitle A Program for Directing Recompilation -@subtitle Edition @value{EDITION}, for @code{make} Version @value{VERSION}. +@subtitle GNU @code{make} Version @value{VERSION}. @subtitle @value{UPDATE-MONTH} @author Richard M. Stallman and Roland McGrath @page @@ -107,9 +107,9 @@ The GNU @code{make} utility automatically determines which pieces of a large program need to be recompiled, and issues the commands to recompile them.@refill -This is Edition @value{EDITION} of the @cite{GNU Make Manual}, -last updated @value{UPDATED} -for @code{make} Version @value{VERSION}.@refill +This edition of the @cite{GNU Make Manual}, +last updated @value{UPDATED}, +documents GNU @code{make} Version @value{VERSION}.@refill This manual describes @code{make} and contains the following chapters:@refill @end ifinfo @@ -132,6 +132,7 @@ This manual describes @code{make} and contains the following chapters:@refill * Missing:: What GNU @code{make} lacks from other @code{make}s. * Makefile Conventions:: Conventions for makefiles in GNU programs. * Quick Reference:: A quick reference for experienced users. +* Make Errors:: A list of common errors generated by @code{make}. * Complex Makefile:: A real example of a straightforward, but nontrivial, makefile. * Concept Index:: Index of Concepts @@ -425,17 +426,10 @@ send us the makefile and the exact results @code{make} gave you. Also say what you expected to occur; this will help us decide whether the problem was really in the documentation. -Once you've got a precise problem, please send electronic mail either -through the Internet or via UUCP: +Once you've got a precise problem, please send electronic mail to: @example -@group -@r{Internet address:} - bug-gnu-utils@@prep.ai.mit.edu - -@r{UUCP path:} - mit-eddie!prep.ai.mit.edu!bug-gnu-utils -@end group + bug-make@@gnu.org @end example @noindent @@ -3228,6 +3222,14 @@ You can write recursive @code{make} commands just by copying this example, but there are many things to know about how they work and why, and about how the sub-@code{make} relates to the top-level @code{make}. +For your convenience, GNU @code{make} sets the variable @code{CURDIR} to +the pathname of the current working directory for you. If @code{-C} is +in effect, it will contain the path of the new directory, not the +original. The value has the same precedence it would have if it were +set in the makefile (by default, an environment variable @code{CURDIR} +will not override this value). Note that setting this variable has no +effect on the operation of @code{make} + @menu * MAKE Variable:: The special effects of using @samp{$(MAKE)}. * Variables/Recursion:: How to communicate variables to a sub-@code{make}. @@ -3828,6 +3830,10 @@ they have particular specialized uses. @xref{Automatic, ,Automatic Variables}. * Defining:: An alternate way to set a variable to a verbatim string. * Environment:: Variable values can come from the environment. +* Target-specific:: Variable values can be defined on a per-target + basis. +* Pattern-specific:: Target-specific variable values can be applied + to a group of targets that match a pattern. * Automatic:: Some special variables have predefined meanings for use with implicit rules. @end menu @@ -4056,6 +4062,30 @@ Here the value of the variable @code{dir} is @w{@samp{/foo/bar }} (with four trailing spaces), which was probably not the intention. (Imagine something like @w{@samp{$(dir)/file}} with this definition!) +@cindex conditional variable assignment +@cindex variables, conditional assignment +@cindex ?= +There is another assignment operator for variables, @samp{?=}. This +is called a conditional variable assignment operator, because it only +has an effect if the variable is not yet defined. This statement: + +@example +FOO ?= bar +@end example + +@noindent +is exactly equivalent to this +(@pxref{Origin Function, ,The @code{origin} Function}): + +@example +ifeq ($(origin FOO), undefined) + FOO = bar +endif +@end example + +Note that a variable set to an empty value is still defined, so +@samp{?=} will not set that variable. + @node Advanced, Values, Flavors, Using Variables @section Advanced Features for Reference to Variables @cindex reference to variables @@ -4353,6 +4383,7 @@ Several variables have constant initial values. @cindex variables, setting @cindex = @cindex := +@cindex ?= To set a variable from the makefile, write a line starting with the variable name followed by @samp{=} or @samp{:=}. Whatever follows the @@ -4389,6 +4420,24 @@ Several special variables are set automatically to a new value for each rule; these are called the @dfn{automatic} variables (@pxref{Automatic, ,Automatic Variables}). +If you'd like a variable to be set to a value only if it's not already +set, then you can use the shorthand operator @samp{?=} instead of +@samp{=}. These two settings of the variable @samp{FOO} are identical +(@pxref{Origin Function, ,The @code{origin} Function}): + +@example +FOO ?= bar +@end example + +@noindent +and + +@example +ifeq ($(origin FOO), undefined) +FOO = bar +endif +@end example + @node Appending, Override Directive, Setting, Using Variables @section Appending More Text to Variables @cindex += @@ -4646,7 +4695,7 @@ endef @noindent @xref{Override Directive, ,The @code{override} Directive}. -@node Environment, , Defining, Using Variables +@node Environment, Target-specific, Defining, Using Variables @section Variables from the Environment @cindex variables, environment @@ -4690,6 +4739,113 @@ affect @code{make}. So @code{make} ignores the environment value of usually not set. @xref{Execution, ,Special handling of SHELL on MS-DOS}.)@refill +@node Target-specific, Pattern-specific, Environment, Using Variables +@section Target-specific Variable Values +@cindex target-specific variables +@cindex variables, target-specific + +Variable values in @code{make} are usually global; that is, they are the +same regardless of where they are evaluated (unless they're reset, of +course). One exception to that is automatic variables +(@pxref{Automatic, ,Automatic Variables}). + +The other exception is @dfn{target-specific variable values}. This +feature allows you to define different values for the same variable, +based on the target that @code{make} is currently building. As with +automatic variables, these values are only available within the context +of a target's command script (and in other target-specific assignments). + +Set a target-specific variable value like this: + +@example +@var{target} @dots{} : @var{variable-assignment} +@end example + +@noindent +or like this: + +@example +@var{target} @dots{} : override @var{variable-assignment} +@end example + +Multiple @var{target} values create a target-specific variable value for +each member of the target list individually. + +The @var{variable-assignment} can be any valid form of assignment; +recursive (@samp{=}), static (@samp{:=}), appending (@samp{+=}), or +conditional (@samp{?=}). All variables that appear within the +@var{variable-assignment} are evaluated within the context of the +target: thus, any previously-defined target-specific variable values +will be in effect. Note that this variable is actually distinct from +any ``global'' value: the two variables do not have to have the same +flavor (recursive vs. static). + +Target-specific variables have the same priority as any other makefile +variable. Variables provided on the command-line (and in the +environment if the @samp{-e} option is in force) will take precedence. +Specifying the @code{override} directive will allow the target-specific +variable value to be preferred. + +There is one more special feature of target-specific variables: when you +define a target-specific variable, that variable value is also in effect +for all dependencies of this target (unless those dependencies override +it with their own target-specific variable value). So, for example, a +statement like this: + +@example +prog : CFLAGS = -g +prog : prog.o foo.o bar.o +@end example + +@noindent +will set @code{CFLAGS} to @samp{-g} in the command script for +@file{prog}, but it will also set @code{CFLAGS} to @samp{-g} in the +command scripts that create @file{prog.o}, @file{foo.o}, and +@file{bar.o}, and any command scripts which create their dependencies. + +@node Pattern-specific, , Target-specific, Using Variables +@section Pattern-specific Variable Values +@cindex pattern-specific variables +@cindex variables, pattern-specific + +In addition to target-specific variable values (@pxref{Target-specific, +,Target-specific Variable Values}), GNU @code{make} supports +pattern-specific variable values. In this form, a variable is defined +for any target that matches the pattern specified. Variables defined in +this way are searched after any target-specific variables defined +explicitly for that target, and before target-specific variables defined +for the parent target. + +Set a pattern-specific variable value like this: + +@example +@var{pattern} @dots{} : @var{variable-assignment} +@end example + +@noindent +or like this: + +@example +@var{pattern} @dots{} : override @var{variable-assignment} +@end example + +@noindent +where @var{pattern} is a %-pattern. As with target-specific variable +values, multiple @var{pattern} values create a pattern-specific variable +value for each pattern individually. The @var{variable-assignment} can +be any valid form of assignment. Any command-line variable setting will +take precedence, unless @code{override} is specified. + +For example: + +@example +%.o : CFLAGS = -O +@end example + +@noindent +will assign @code{CFLAGS} the value of @samp{-O} for all targets +matching the pattern @code{%.o}. + @node Conditionals, Functions, Using Variables, Top @chapter Conditional Parts of Makefiles @@ -6396,7 +6552,10 @@ pattern rules (@pxref{Pattern Rules, ,Defining and Redefining Pattern Rules}). The @samp{-r} option also clears out the default list of suffixes for suffix rules (@pxref{Suffix Rules, ,Old-Fashioned Suffix Rules}). But you can still define your own suffixes with a rule for -@code{.SUFFIXES}, and then define your own suffix rules. +@code{.SUFFIXES}, and then define your own suffix rules. Note that only +@emph{rules} are affected by the @code{-r} option; default variables +remain in effect (@pxref{Implicit Variables, ,Variables Used by Implicit +Rules}). @item -s @cindex @code{-s} @@ -8546,7 +8705,7 @@ special treatment. @comment included by standards.texi. @include make-stds.texi -@node Quick Reference, Complex Makefile, Makefile Conventions, Top +@node Quick Reference, Make Errors, Makefile Conventions, Top @appendix Quick Reference This appendix summarizes the directives, text manipulation functions, @@ -8821,12 +8980,136 @@ The targets given to @code{make} on the command line. Setting this variable has no effect on the operation of @code{make}.@* @xref{Goals, ,Arguments to Specify the Goals}. +@item CURDIR + +Set to the pathname of the current working directory (after all +@code{-C} options are processed, if any). Setting this variable has no +effect on the operation of @code{make}.@* +@xref{Recursion, ,Recursive Use of @code{make}}. + @item SUFFIXES The default list of suffixes before @code{make} reads any makefiles. @end table -@node Complex Makefile, Concept Index, Quick Reference, Top +@node Make Errors, Complex Makefile, Quick Reference, Top +@comment node-name, next, previous, up +@appendix Errors Generated by Make + +Here is a list of the most common errors you might see generated by +@code{make}, and some information about what they mean and how to fix +them. + +Sometimes @code{make} errors are not fatal, especially in the presence +of a @code{-} prefix on a command script line, or the @code{-k} command +line option. Errors that are fatal are prefixed with the string +@code{***}. + +Error messages are all either prefixed with the name of the program +(usually @samp{make}), or, if the error is found in a makefile, the name +of the file and linenumber containing the problem. + +In the table below, these common prefixes are left off. + +@table @samp + +@item [@var{foo}] Error @var{NN} +@itemx [@var{foo}] @var{signal description} +These errors are not really @code{make} errors at all. They mean that a +program that @code{make} invoked as part of a command script returned a +non-0 error code (@samp{Error @var{NN}}), which @code{make} interprets +as failure, or it exited in some other abnormal fashion (with a +signal of some type). + +If no @code{***} is attached to the message, then the subprocess failed +but the rule in the makefile was prefixed with the @code{-} special +character, so @code{make} ignored the error. + +@item missing separator. Stop. +This is @code{make}'s generic ``Huh?'' error message. It means that +@code{make} was completely unsuccessful at parsing this line of your +makefile. It basically means ``syntax error''. + +One of the most common reasons for this message is that you (or perhaps +your oh-so-helpful editor, as is the case with many MS-Windows editors) +have attempted to indent your command scripts with spaces instead of a +TAB character. Remember that every line in the command script must +begin with a TAB character. Eight spaces do not count. + +@item commands commence before first target. Stop. +@itemx missing rule before commands. Stop. +This means the first thing in the makefile seems to be part of a command +script: it begins with a TAB character and doesn't appear to be a legal +@code{make} command (such as a variable assignment). Command scripts +must always be associated with a target. + +The second form is generated if the line has a semicolon as the first +non-whitespace character; @code{make} interprets this to mean you left +out the "target: dependency" section of a rule. + +@item No rule to make target `@var{xxx}'. +@itemx No rule to make target `@var{xxx}', needed by `@var{yyy}'. +This means that @code{make} decided it needed to build a target, but +then couldn't find any instructions in the makefile on how to do that, +either explicit or implicit (including in the default rules database). + +If you want that file to be built, you will need to add a rule to your +makefile describing how that target can be built. Other possible +sources of this problem are typos in the makefile (if that filename is +wrong) or a corrupted source tree (if that file is not supposed to be +built, but rather only a dependency). + +@item No targets specified and no makefile found. Stop. +@itemx No targets. Stop. +The former means that you didn't provide any targets to be built on the +command line, and @code{make} couldn't find any makefiles to read in. +The latter means that some makefile was found, but it didn't contain any +default target and none was given on the command line. GNU @code{make} +has nothing to do in these situations. + +@item Makefile `@var{xxx}' was not found. +@itemx Included makefile `@var{xxx}' was not found. +A makefile specified on the command line (first form) or included +(second form) was not found. + +@item warning: overriding commands for target `@var{xxx}' +@itemx warning: ignoring old commands for target `@var{xxx}' +GNU @code{make} allows commands to be specified only once per target +(except for double-colon rules). If you give commands for a target +which already has been defined to have commands, this warning is issued +and the second set of commands will overwrite the first set. + +@item Circular @var{xxx} <- @var{yyy} dependency dropped. +This means that @code{make} detected a loop in the dependency graph: +after tracing the dependency @var{yyy} of target @var{xxx}, and its +dependencies, etc., one of them depended on @var{xxx} again. + +@item Recursive variable `@var{xxx}' references itself (eventually). Stop. +This means you've defined a normal (recursive) @code{make} variable +@var{xxx} that, when its expanded, will refer to itself (@var{xxx}). +This is not allowed; either use simply-expanded variables (@code{:=}) or +use the append operator (@code{+=}). + +@item Unterminated variable reference. Stop. +This means you forgot to provide the proper closing parenthesis +or brace in your variable or function reference. + +@item insufficient arguments to function `@var{xxx}'. Stop. +This means you haven't provided the requisite number of arguments for +this function. See the documentation of the function for a description +of its arguments. + +@item missing target pattern. Stop. +@itemx multiple target patterns. Stop. +@itemx target pattern contains no `%'. Stop. +These are generated for malformed static pattern rules. The first means +there's no pattern in the target section of the rule, the second means +there are multiple patterns in the target section, and the third means +the target doesn't contain a pattern character (@code{%}). + +@end table + +@node Complex Makefile, Concept Index, Make Errors, Top @appendix Complex Makefile Example Here is the makefile for the GNU @code{tar} program. This is a diff --git a/makefile.com b/makefile.com index 23c720d3..b7bb65cb 100644 --- a/makefile.com +++ b/makefile.com @@ -4,10 +4,37 @@ $! $! 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 ar arscan 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" +$! In case of problems with the install you might contact me at +$! zinser@decus.decus.de (preferred) or eurmpz@eur.sas.com +$! +$! Look for the compiler used +$! +$ lval = "" +$ if f$search("SYS$SYSTEM:DECC$COMPILER.EXE").eqs."" +$ then +$ if f$trnlnm("SYS").eqs."" then def/nolog sys sys$library: +$ ccopt = "" +$ else +$ ccopt = "/decc/prefix=all" +$ if f$trnlnm("SYS").eqs."" +$ then +$ if f$trnlnm("DECC$LIBRARY_INCLUDE").nes."" +$ then +$ define sys decc$library_include: +$ else +$ if f$search("SYS$COMMON:[DECC$LIB.REFERENCE]DECC$RTLDEF.DIR").nes."" - + then lval = "SYS$COMMON:[DECC$LIB.REFERENCE.DECC$RTLDEF]," +$ if f$search("SYS$COMMON:[DECC$LIB.REFERENCE]SYS$STARLET_C.DIR").nes."" - + then lval = lval+"SYS$COMMON:[DECC$LIB.REFERENCE.SYS$STARLET_C]," +$ lval=lval+"SYS$LIBRARY:" +$ define sys 'lval +$ endif +$ endif +$ endif +$ filelist = "alloca ar arscan 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 getopt1 getopt" $ copy config.h-vms config.h $ n=0 +$ open/write optf make.opt $ loop: $ cfile = f$elem(n," ",filelist) $ if cfile .eqs. " " then goto linkit @@ -16,19 +43,18 @@ $ call compileit 'cfile' 'p1' $ n = n + 1 $ goto loop $ linkit: +$ close optf $ if p1 .nes. "" then goto link_using_library -$ link/exe=make alloca,ar,arscan,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 +$ link/exe=make make.opt/opt $ exit $ link_using_library: -$ link/exe=make alloca,ar,arscan,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,sys$library:vaxcrtl/lib +$ link/exe=make make.opt/opt,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") 'p1' +$ ploc = f$locate("]",p1) +$ filnam = p1 +$ if ploc .lt. f$length(p1) then filnam=f$extract(ploc+1,100,p1) +$ write optf "''filnam'" +$ cc'ccopt'/include=([],[.glob])/define=("allocated_variable_expand_for_file=alloc_var_expand_for_file","unlink=remove","HAVE_CONFIG_H","VMS") 'p1' $ exit $ endsubroutine : compileit diff --git a/misc.c b/misc.c index dbbe41fe..1411e54f 100644 --- a/misc.c +++ b/misc.c @@ -253,6 +253,9 @@ makefile_fatal (file, lineno, s1, s2, s3, s4, s5, s6) unsigned int lineno; char *s1, *s2, *s3, *s4, *s5, *s6; { + if (!file) + fatal(s1, s2, s3, s4, s5, s6); + log_working_directory (1); fprintf (stderr, "%s:%u: *** ", file, lineno); @@ -470,7 +473,7 @@ copy_dep_chain (d) { register struct dep *c; struct dep *firstnew = 0; - struct dep *lastnew; + struct dep *lastnew = 0; while (d != 0) { @@ -564,8 +567,9 @@ log_access (flavor) but we write this one to stderr because it might be run in a child fork whose stdout is piped. */ - fprintf (stderr, "%s access: user %d (real %d), group %d (real %d)\n", - flavor, geteuid (), getuid (), getegid (), getgid ()); + fprintf (stderr, "%s access: user %lu (real %lu), group %lu (real %lu)\n", + flavor, (unsigned long) geteuid (), (unsigned long) getuid (), + (unsigned long) getegid (), (unsigned long) getgid ()); fflush (stderr); } diff --git a/read.c b/read.c index bf7f80ce..02075162 100644 --- a/read.c +++ b/read.c @@ -16,12 +16,15 @@ 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. */ +#include + #include "make.h" #include "dep.h" #include "filedef.h" #include "job.h" #include "commands.h" #include "variable.h" +#include "rule.h" /* This is POSIX.2, but most systems using -DPOSIX probably don't have it. */ #ifdef HAVE_GLOB_H @@ -57,6 +60,14 @@ struct linebuffer #define freebuffer(lb) free ((lb)->buffer) +/* Types of "words" that can be read in a makefile. */ +enum make_word_type + { + w_bogus, w_eol, w_static, w_variable, w_colon, w_dcolon, w_semicolon, + w_comment, w_varassign + }; + + /* A `struct conditionals' contains the information describing all the active conditionals in a makefile. @@ -122,9 +133,14 @@ static unsigned int do_define PARAMS ((char *name, unsigned int namelen, enum va 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, + struct dep *deps, unsigned int cmds_started, char *commands, unsigned int commands_idx, int two_colon, char *filename, unsigned int lineno, int set_default)); +static void record_target_var PARAMS ((struct nameseq *filenames, char *defn, + int two_colon, enum variable_origin origin, + char *filename, unsigned int lineno)); +static enum make_word_type get_next_mword PARAMS ((char *buffer, char *delim, + char **startp, unsigned int *length)); /* Read in all the makefiles and return the chain of their names. */ @@ -200,7 +216,7 @@ read_all_makefiles (makefiles) static char *default_makefiles[] = #ifdef VMS /* all lower case since readdir() (the vms version) 'lowercasifies' */ - { "makefile.vms", "gnumakefile", "makefile", 0 }; + { "makefile.vms", "gnumakefile.", "makefile.", 0 }; #else #ifdef _AMIGA { "GNUmakefile", "Makefile", "SMakefile", 0 }; @@ -268,10 +284,10 @@ read_makefile (filename, flags) unsigned int commands_len = 200; char *commands = (char *) xmalloc (200); unsigned int commands_idx = 0; - unsigned int commands_started; - register char *p; + unsigned int cmds_started; + char *p; char *p2; - int len; + int len, reading_target; int ignoring = 0, in_ignored_define = 0; int no_targets = 0; /* Set when reading a rule without targets. */ char *passed_filename = filename; @@ -280,7 +296,7 @@ read_makefile (filename, flags) struct dep *deps; unsigned int lineno = 1; unsigned int nlines = 0; - int two_colon; + int two_colon = 0; char *pattern = 0, *pattern_percent; int makefile_errno; @@ -293,19 +309,16 @@ read_makefile (filename, flags) { \ if (filenames != 0) \ record_files (filenames, pattern, pattern_percent, deps, \ - commands_started, commands, commands_idx, \ + cmds_started, commands, commands_idx, \ two_colon, filename, lineno, \ !(flags & RM_NO_DEFAULT_GOAL)); \ filenames = 0; \ commands_idx = 0; \ - pattern = 0; \ + if (pattern) { free(pattern); pattern = 0; } \ } while (0) -#ifdef lint /* Suppress `used before set' messages. */ - two_colon = 0; -#endif pattern_percent = 0; - commands_started = lineno; + cmds_started = lineno; if (debug_flag) { @@ -424,7 +437,7 @@ read_makefile (filename, flags) /* Append this command line to the line being accumulated. */ p = lb.buffer; if (commands_idx == 0) - commands_started = lineno; + cmds_started = lineno; len = strlen (p); if (len + 1 + commands_idx > commands_len) { @@ -453,7 +466,7 @@ read_makefile (filename, flags) collapse_continuations (collapsed); remove_comments (collapsed); - /* strncmp is first to avoid dereferencing out into space. */ + /* Compare a word, both length and contents. */ #define word1eq(s, l) (len == l && !strncmp (s, p, l)) p = collapsed; while (isspace (*p)) @@ -462,20 +475,27 @@ read_makefile (filename, flags) /* This line is completely empty. */ continue; - /* Find the end of the first token */ + /* Find the end of the first token. Note we don't need to worry about + * ":" here since we compare tokens by length (so "export" will never + * be equal to "export:"). + */ for (p2 = p+1; *p2 != '\0' && !isspace(*p2); ++p2) {} len = p2 - p; - /* Find the start of the second token. If it's a `:', jump past - preprocessor stuff since it can't be that--this allows targets named - `export', etc. */ + /* Find the start of the second token. If it's a `:' remember it, + since it can't be a preprocessor token--this allows targets named + `ifdef', `export', etc. */ + reading_target = 0; while (isspace (*p2)) ++p2; if (*p2 == '\0') p2 = NULL; else if (p2[0] == ':' && p2[1] == '\0') - goto check_var; + { + reading_target = 1; + goto skip_conditionals; + } /* We must first check for conditional and `define' directives before ignoring anything, since they control what we will do with @@ -494,7 +514,8 @@ read_makefile (filename, flags) "invalid syntax in conditional"); continue; } - else if (word1eq ("endef", 5)) + + if (word1eq ("endef", 5)) { if (in_ignored_define) in_ignored_define = 0; @@ -502,7 +523,8 @@ read_makefile (filename, flags) makefile_fatal (filename, lineno, "extraneous `endef'"); continue; } - else if (word1eq ("define", 6)) + + if (word1eq ("define", 6)) { if (ignoring) in_ignored_define = 1; @@ -521,8 +543,9 @@ read_makefile (filename, flags) } continue; } - else if (word1eq ("override", 8)) - { + + if (word1eq ("override", 8)) + { p2 = next_token (p + 8); if (p2 == 0) makefile_error (filename, lineno, "empty `override' directive"); @@ -551,12 +574,14 @@ read_makefile (filename, flags) continue; } + skip_conditionals: if (ignoring) /* Ignore the line. We continue here so conditionals can appear in the middle of a rule. */ continue; - else if (word1eq ("export", 6)) + + if (!reading_target && word1eq ("export", 6)) { struct variable *v; p2 = next_token (p + 6); @@ -578,7 +603,7 @@ read_makefile (filename, flags) } } } - else if (word1eq ("unexport", 8)) + else if (!reading_target && word1eq ("unexport", 8)) { unsigned int len; struct variable *v; @@ -614,9 +639,7 @@ read_makefile (filename, flags) if (pattern != 0) free (pattern); } - else - check_var: - if (word1eq ("include", 7) || word1eq ("-include", 8) + else if (word1eq ("include", 7) || word1eq ("-include", 8) || word1eq ("sinclude", 8)) { /* We have found an `include' line specifying a nested @@ -627,7 +650,7 @@ read_makefile (filename, flags) exist. "sinclude" is an alias for this from SGI. */ int noerror = p[0] != 'i'; - p = allocated_variable_expand (next_token (p + (noerror ? 9 : 8))); + p = allocated_variable_expand (next_token (p + (noerror ? 8 : 7))); if (*p == '\0') { makefile_error (filename, lineno, @@ -667,6 +690,7 @@ read_makefile (filename, flags) && ! noerror) makefile_error (filename, lineno, "%s: %s", name, strerror (errno)); + free(name); } /* Free any space allocated by conditional_line. */ @@ -701,9 +725,20 @@ read_makefile (filename, flags) } else { - /* This line describes some target files. */ + /* This line describes some target files. This is complicated by + the existence of target-specific variables, because we can't + expand the entire line until we know if we have one or not. So + we expand the line word by word until we find the first `:', + then check to see if it's a target-specific variable. - char *cmdleft; + In this algorithm, `lb_next' will point to the beginning of the + unexpanded parts of the input buffer, while `p2' points to the + parts of the expanded buffer we haven't searched yet. */ + + enum make_word_type wtype; + enum variable_origin v_origin; + char *cmdleft, *lb_next; + unsigned int len, plen = 0; /* Record the previous rule. */ @@ -720,55 +755,176 @@ read_makefile (filename, flags) } else if (cmdleft != 0) /* Found one. Cut the line short there before expanding it. */ - *cmdleft = '\0'; + *(cmdleft++) = '\0'; collapse_continuations (lb.buffer); - /* Expand variable and function references before doing anything - else so that special characters can be inside variables. */ - p = variable_expand (lb.buffer); + /* We can't expand the entire line, since if it's a per-target + variable we don't want to expand it. So, walk from the + beginning, expanding as we go, and looking for "interesting" + chars. The first word is always expandable. */ + wtype = get_next_mword(lb.buffer, NULL, &lb_next, &len); + switch (wtype) + { + case w_eol: + if (cmdleft != 0) + makefile_fatal (filename, lineno, + "missing rule before commands"); + else + /* This line contained a variable reference that + expanded to nothing but whitespace. */ + continue; - if (cmdleft == 0) - /* Look for a semicolon in the expanded line. */ - cmdleft = find_char_unquote (p, ";", 0); + case w_colon: + case w_dcolon: + /* We accept and ignore rules without targets for + compatibility with SunOS 4 make. */ + no_targets = 1; + continue; - if (cmdleft != 0) - /* Cut the line short at the semicolon. */ - *cmdleft = '\0'; + default: + break; + } - p2 = next_token (p); - if (*p2 == '\0') - { - if (cmdleft != 0) - makefile_fatal (filename, lineno, - "missing rule before commands"); - else - /* This line contained a variable reference that - expanded to nothing but whitespace. */ - continue; - } - else if (*p2 == ':') - { - /* We accept and ignore rules without targets for - compatibility with SunOS 4 make. */ - no_targets = 1; - continue; - } + p2 = variable_expand_string(NULL, lb_next, len); + while (1) + { + char *colonp; + + lb_next += len; + if (cmdleft == 0) + { + /* Look for a semicolon in the expanded line. */ + cmdleft = find_char_unquote (p2, ";", 0); + + if (cmdleft != 0) + { + unsigned long p2_off = p2 - variable_buffer; + unsigned long cmd_off = cmdleft - variable_buffer; + char *pend = p2 + strlen(p2); + + /* Append any remnants of lb, then cut the line short + at the semicolon. */ + *cmdleft = '\0'; + + /* One school of thought says that you shouldn't expand + here, but merely copy, since now you're beyond a ";" + and into a command script. However, the old parser + expanded the whole line, so we continue that for + backwards-compatiblity. Also, it wouldn't be + entirely consistent, since we do an unconditional + expand below once we know we don't have a + target-specific variable. */ + (void)variable_expand_string(pend, lb_next, -1); + lb_next += strlen(lb_next); + p2 = variable_buffer + p2_off; + cmdleft = variable_buffer + cmd_off + 1; + } + } + + colonp = find_char_unquote(p2, ":", 0); +#if defined(__MSDOS__) || defined(WINDOWS32) + /* The drive spec brain-damage strikes again... */ + /* FIXME: is whitespace the only possible separator of words + in this context? If not, the `isspace' test below will + need to be changed into a call to `index'. */ + while (colonp && (colonp[1] == '/' || colonp[1] == '\\') && + colonp > p2 && isalpha(colonp[-1]) && + (colonp == p2 + 1 || isspace(colonp[-2]))) + colonp = find_char_unquote(colonp + 1, ":", 0); +#endif + if (colonp != 0) + break; + + wtype = get_next_mword(lb_next, NULL, &lb_next, &len); + if (wtype == w_eol) + makefile_fatal (filename, lineno, "missing separator"); + + p2 += strlen(p2); + *(p2++) = ' '; + p2 = variable_expand_string(p2, lb_next, len); + /* We don't need to worry about cmdleft here, because if it was + found in the variable_buffer the entire buffer has already + been expanded... we'll never get here. */ + } + + p2 = next_token (variable_buffer); filenames = multi_glob (parse_file_seq (&p2, ':', sizeof (struct nameseq), 1), sizeof (struct nameseq)); - if (*p2++ == '\0') - makefile_fatal (filename, lineno, "missing separator"); + + if (!filenames) + { + /* We accept and ignore rules without targets for + compatibility with SunOS 4 make. */ + no_targets = 1; + continue; + } + /* This should never be possible; we handled it above. */ + assert(*p2 != '\0'); + ++p2; + /* Is this a one-colon or two-colon entry? */ two_colon = *p2 == ':'; if (two_colon) p2++; + /* Test to see if it's a target-specific variable. Copy the rest + of the buffer over, possibly temporarily (we'll expand it later + if it's not a target-specific variable). PLEN saves the length + of the unparsed section of p2, for later. */ + if (*lb_next != '\0') + { + unsigned int l = p2 - variable_buffer; + plen = strlen(p2); + (void)variable_buffer_output(p2+plen, + lb_next, strlen(lb_next)+1); + p2 = variable_buffer + l; + } + wtype = get_next_mword(p2, NULL, &p, &len); + v_origin = o_file; + if (wtype == w_static && (len == (sizeof("override")-1) + && !strncmp(p, "override", len))) + { + v_origin = o_override; + (void)get_next_mword(p+len, NULL, &p, &len); + } + else if (wtype != w_eol) + wtype = get_next_mword(p+len, NULL, NULL, NULL); + + if (wtype == w_varassign || v_origin == o_override) + { + record_target_var(filenames, p, two_colon, v_origin, + filename, lineno); + filenames = 0; + continue; + } + + /* This is a normal target, _not_ a target-specific variable. + Unquote any = in the dependency list. */ + find_char_unquote (lb_next, "=", 0); + /* We have some targets, so don't ignore the following commands. */ no_targets = 0; + /* Expand the dependencies, etc. */ + if (*lb_next != '\0') + { + unsigned int l = p2 - variable_buffer; + (void)variable_expand_string(p2 + plen, lb_next, -1); + p2 = variable_buffer + l; + + /* Look for a semicolon in the expanded line. */ + if (cmdleft == 0) + { + cmdleft = find_char_unquote (p2, ";", 0); + if (cmdleft != 0) + *(cmdleft++) = '\0'; + } + } + /* Is this a static pattern rule: `target: %targ: %dep; ...'? */ p = index (p2, ':'); while (p != 0 && p[-1] == '\\') @@ -802,7 +958,8 @@ read_makefile (filename, flags) do { check_again = 0; /* For MSDOS and WINDOWS32, skip a "C:\..." or a "C:/..." */ - if (p != 0 && (p[1] == '\\' || p[1] == '/') && isalpha (p[-1])) { + if (p != 0 && (p[1] == '\\' || p[1] == '/') && + isalpha(p[-1]) && (p == p2 + 1 || index(" \t:", p[-2]) != 0)) { p = index(p + 1, ':'); check_again = 1; } @@ -822,6 +979,7 @@ read_makefile (filename, flags) if (pattern_percent == 0) makefile_fatal (filename, lineno, "target pattern contains no `%%'"); + free((char *)target); } else pattern = 0; @@ -835,9 +993,9 @@ read_makefile (filename, flags) if (cmdleft != 0) { /* Semicolon means rest of line is a command. */ - unsigned int len = strlen (cmdleft + 1); + unsigned int len = strlen (cmdleft); - commands_started = lineno; + cmds_started = lineno; /* Add this command line to the buffer. */ if (len + 2 > commands_len) @@ -845,7 +1003,7 @@ read_makefile (filename, flags) commands_len = (len + 2) * 2; commands = (char *) xrealloc (commands, commands_len); } - bcopy (cmdleft + 1, commands, len); + bcopy (cmdleft, commands, len); commands_idx += len; commands[commands_idx++] = '\n'; } @@ -1216,6 +1374,93 @@ uniquize_deps (chain) } } +/* Record target-specific variable values for files FILENAMES. + TWO_COLON is nonzero if a double colon was used. + + The links of FILENAMES are freed, and so are any names in it + that are not incorporated into other data structures. + + If the target is a pattern, add the variable to the pattern-specific + variable value list. */ + +static void +record_target_var (filenames, defn, two_colon, origin, filename, lineno) + struct nameseq *filenames; + char *defn; + int two_colon; + enum variable_origin origin; + char *filename; + unsigned int lineno; +{ + struct nameseq *nextf; + struct variable_set_list *global; + + global = current_variable_set_list; + + for (; filenames != 0; filenames = nextf) + { + struct variable *v; + register char *name = filenames->name; + struct variable_set_list *vlist; + char *fname; + char *percent; + + nextf = filenames->next; + free ((char *) filenames); + + /* If it's a pattern target, then add it to the pattern-specific + variable list. */ + percent = find_percent (name); + if (percent) + { + struct pattern_var *p; + + /* Get a reference for this pattern-specific variable struct. */ + p = create_pattern_var(name, percent); + vlist = p->vars; + fname = p->target; + } + else + { + struct file *f; + + /* Get a file reference for this file, and initialize it. */ + f = enter_file (name); + initialize_file_variables (f); + vlist = f->variables; + fname = f->name; + } + + /* Make the new variable context current and define the variable. */ + current_variable_set_list = vlist; + v = try_variable_definition(filename, lineno, defn, origin); + if (!v) + makefile_error(filename, lineno, + "Malformed per-target variable definition"); + v->per_target = 1; + + /* If it's not an override, check to see if there was a command-line + setting. If so, reset the value. */ + if (origin != o_override) + { + struct variable *gv; + int len = strlen(v->name); + + current_variable_set_list = global; + gv = lookup_variable(v->name, len); + if (gv && (gv->origin == o_env_override || gv->origin == o_command)) + define_variable_in_set(v->name, len, gv->value, gv->origin, + gv->recursive, vlist->set); + } + + /* Free name if not needed further. */ + if (name != fname && (name < fname || name > fname + strlen (fname))) + free (name); + } + + current_variable_set_list = global; +} + /* Record a description line for files FILENAMES, with dependencies DEPS, commands to execute described by COMMANDS and COMMANDS_IDX, coming from FILENAME:COMMANDS_STARTED. @@ -1228,12 +1473,12 @@ uniquize_deps (chain) that are not incorporated into other data structures. */ static void -record_files (filenames, pattern, pattern_percent, deps, commands_started, +record_files (filenames, pattern, pattern_percent, deps, cmds_started, commands, commands_idx, two_colon, filename, lineno, set_default) struct nameseq *filenames; char *pattern, *pattern_percent; struct dep *deps; - unsigned int commands_started; + unsigned int cmds_started; char *commands; unsigned int commands_idx; int two_colon; @@ -1243,7 +1488,7 @@ record_files (filenames, pattern, pattern_percent, deps, commands_started, { struct nameseq *nextf; int implicit = 0; - unsigned int max_targets, target_idx; + unsigned int max_targets = 0, target_idx = 0; char **targets = 0, **target_percents = 0; struct commands *cmds; @@ -1251,7 +1496,7 @@ record_files (filenames, pattern, pattern_percent, deps, commands_started, { cmds = (struct commands *) xmalloc (sizeof (struct commands)); cmds->filename = filename; - cmds->lineno = commands_started; + cmds->lineno = cmds_started; cmds->commands = savestring (commands, commands_idx); cmds->command_lines = 0; } @@ -1260,6 +1505,7 @@ record_files (filenames, pattern, pattern_percent, deps, commands_started, for (; filenames != 0; filenames = nextf) { + register char *name = filenames->name; register struct file *f; register struct dep *d; @@ -1641,13 +1887,6 @@ parse_file_seq (stringp, stopchar, size, strip) if (p && *p == ',') *p =' '; #endif -#ifdef __MSDOS__ - /* For MS-DOS, skip a "C:\..." or a "C:/..." until we find a - first colon which isn't followed by a slash or a backslash. */ - if (stopchar == ':') - while (p != 0 && (p[1] == '\\' || p[1] == '/') && isalpha (p[-1])) - p = find_char_unquote (p + 1, stopchars, 1); -#endif #ifdef _AMIGA if (stopchar == ':' && p && *p == ':' && !(isspace(p[1]) || !p[1] || isspace(p[-1]))) @@ -1655,16 +1894,15 @@ parse_file_seq (stringp, stopchar, size, strip) p = find_char_unquote (p+1, stopchars, 1); } #endif -#ifdef WINDOWS32 - /* For WINDOWS32, skip a "C:\..." or "C:/...". */ - if (stopchar == ':' && - p != 0 && - (p[1] == '\\' || p[1] == '/') && - isalpha (p[-1])) { - p = end_of_token_w32(++p, ':'); - if (*p == '\0' && p[-1] == ':') - p--; - } +#if defined(WINDOWS32) || defined(__MSDOS__) + /* For WINDOWS32, skip a "C:\..." or a "C:/..." until we find the + first colon which isn't followed by a slash or a backslash. + Note that tokens separated by spaces should be treated as separate + tokens since make doesn't allow path names with spaces */ + if (stopchar == ':') + while (p != 0 && !isspace(*p) && + (p[1] == '\\' || p[1] == '/') && isalpha (p[-1])) + p = find_char_unquote (p + 1, stopchars, 1); #endif if (p == 0) p = q + strlen (q); @@ -1751,7 +1989,7 @@ parse_file_seq (stringp, stopchar, size, strip) Look back for an elt with an opening `(' but no closing `)'. */ struct nameseq *n = new1->next, *lastn = new1; - char *paren; + char *paren = 0; while (n != 0 && (paren = index (n->name, '(')) == 0) { lastn = n; @@ -1944,6 +2182,190 @@ readline (linebuffer, stream, filename, lineno) return nlines; } +/* Parse the next "makefile word" from the input buffer, and return info + about it. + + A "makefile word" is one of: + + w_bogus Should never happen + w_eol End of input + w_static A static word; cannot be expanded + w_variable A word containing one or more variables/functions + w_colon A colon + w_dcolon A double-colon + w_semicolon A semicolon + w_comment A comment character + w_varassign A variable assignment operator (=, :=, +=, or ?=) + + Note that this function is only used when reading certain parts of the + makefile. Don't use it where special rules hold sway (RHS of a variable, + in a command list, etc.) */ + +static enum make_word_type +get_next_mword (buffer, delim, startp, length) + char *buffer; + char *delim; + char **startp; + unsigned int *length; +{ + enum make_word_type wtype = w_bogus; + char *p = buffer, *beg; + char c; + + /* Skip any leading whitespace. */ + while (isblank(*p)) + ++p; + + beg = p; + c = *(p++); + switch (c) + { + case '\0': + wtype = w_eol; + break; + + case '#': + wtype = w_comment; + break; + + case ';': + wtype = w_semicolon; + break; + + case '=': + wtype = w_varassign; + break; + + case ':': + wtype = w_colon; + switch (*p) + { + case ':': + ++p; + wtype = w_dcolon; + break; + + case '=': + ++p; + wtype = w_varassign; + break; + } + break; + + case '+': + case '?': + if (*p == '=') + { + ++p; + wtype = w_varassign; + break; + } + + default: + if (delim && index(delim, c)) + wtype = w_static; + break; + } + + /* Did we find something? If so, return now. */ + if (wtype != w_bogus) + goto done; + + /* This is some non-operator word. A word consists of the longest + string of characters that doesn't contain whitespace, one of [:=#], + or [?+]=, or one of the chars in the DELIM string. */ + + /* We start out assuming a static word; if we see a variable we'll + adjust our assumptions then. */ + wtype = w_static; + + /* We already found the first value of "c", above. */ + while (1) + { + char closeparen; + int count; + + switch (c) + { + case '\0': + case ' ': + case '\t': + case '=': + case '#': + goto done_word; + + case ':': +#if defined(__MSDOS__) || defined(WINDOWS32) + /* A word CAN include a colon in its drive spec. */ + if (!(p - beg == 2 && (*p == '/' || *p == '\\') && isalpha (*beg))) +#endif + goto done_word; + + case '$': + c = *(p++); + if (c == '$') + break; + + /* This is a variable reference, so note that it's expandable. + Then read it to the matching close paren. */ + wtype = w_variable; + + if (c == '(') + closeparen = ')'; + else if (c == '{') + closeparen = '}'; + else + /* This is a single-letter variable reference. */ + break; + + for (count=0; *p != '\0'; ++p) + { + if (*p == c) + ++count; + else if (*p == closeparen && --count < 0) + { + ++p; + break; + } + } + break; + + case '?': + case '+': + if (*p == '=') + goto done_word; + break; + + case '\\': + switch (*p) + { + case ';': + case '=': + case '\\': + ++p; + break; + } + break; + + default: + if (delim && index(delim, c)) + goto done_word; + break; + } + + c = *(p++); + } + done_word: + --p; + + done: + if (startp) + *startp = beg; + if (length) + *length = p - beg; + return wtype; +} + /* Construct the list of include directories from the arguments and the default list. */ @@ -2075,11 +2497,11 @@ tilde_expand (name) if (home_dir == 0 || home_dir[0] == '\0') { extern char *getlogin (); - char *name = getlogin (); + char *logname = getlogin (); home_dir = 0; - if (name != 0) + if (logname != 0) { - struct passwd *p = getpwnam (name); + struct passwd *p = getpwnam (logname); if (p != 0) home_dir = p->pw_dir; } diff --git a/readme.vms b/readme.vms index 18010cf4..43b4dd07 100644 --- a/readme.vms +++ b/readme.vms @@ -47,8 +47,15 @@ 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 +Change history: +3.76.x +====== +Added VMS help version (make.hlp) of the Unix man page. To integrate +that with an existing Help library use a command like the following + $lib/ins/help sys$help:helplib.hlb make.hlp +3.74.3 +====== Lots of default settings are adapted for VMS. See default.c. Long command lines are now converted to command files. diff --git a/remake.c b/remake.c index b4f15cf8..9c459a48 100644 --- a/remake.c +++ b/remake.c @@ -91,9 +91,14 @@ update_goal_chain (goals, makefiles) g->changed = 0; } +#if 0 + /* Only run one job at a time when building makefiles. + No one seems to know why this was done, and no one can think of a good + reason to do it. Hopefully an obvious one won't appear as soon as we + release the next version :-/. */ if (makefiles) - /* Only run one job at a time. */ job_slots = 1; +#endif /* Update all the goals until they are all finished. */ @@ -115,7 +120,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; + int stop = 0, any_not_updated = 0; for (file = g->file->double_colon ? g->file->double_colon : g->file; file != NULL; @@ -248,6 +253,38 @@ update_goal_chain (goals, makefiles) return status; } +/* Generate an error/fatal message if no rules are available for the target. + */ +static void +no_rule_error(file) + struct file *file; +{ + static const char msg_noparent[] + = "%sNo rule to make target `%s'%s"; + static const char msg_parent[] + = "%sNo rule to make target `%s', needed by `%s'%s"; + if (keep_going_flag || file->dontcare) + { + if (!file->dontcare) + { + if (file->parent == 0) + error (msg_noparent, "*** ", file->name, "."); + else + error (msg_parent, "*** ", + file->name, file->parent->name, "."); + file->shownerror = 1; + } + file->update_status = 2; + } + else + { + if (file->parent == 0) + fatal (msg_noparent, "", file->name, ""); + else + fatal (msg_parent, "", file->name, file->parent->name, ""); + } +} + /* If FILE is not up to date, execute the commands for it. Return 0 if successful, 1 if unsuccessful; but with some flag settings, just call `exit' if unsuccessful. @@ -317,6 +354,13 @@ update_file_1 (file, depth) if (file->update_status > 0) { DEBUGPR ("Recently tried and failed to update file `%s'.\n"); + if (!file->shownerror) + { + int dontcare = file->dontcare; + file->dontcare = 0; + no_rule_error(file); + file->dontcare = dontcare; + } return file->update_status; } @@ -394,18 +438,14 @@ update_file_1 (file, depth) { error ("Circular %s <- %s dependency dropped.", file->name, d->file->name); + /* We cannot free D here because our the caller will still have + a reference to it when we were called recursively via + check_dep below. */ if (lastd == 0) - { - file->deps = d->next; - free ((char *) d); - d = file->deps; - } + file->deps = d->next; else - { - lastd->next = d->next; - free ((char *) d); - d = lastd->next; - } + lastd->next = d->next; + d = d->next; continue; } @@ -594,7 +634,7 @@ update_file_1 (file, depth) DEBUGPR ("Must remake target `%s'.\n"); /* It needs to be remade. If it's VPATH and not reset via GPATH, toss the - VPATH */ + VPATH. */ if (!streq(file->name, file->hname)) { if (debug_flag) @@ -910,32 +950,7 @@ remake_file (file) Pretend it was successfully remade. */ file->update_status = 0; else - { - /* This is a dependency file we cannot remake. Fail. */ - static const char msg_noparent[] - = "%sNo rule to make target `%s'%s"; - static const char msg_parent[] - = "%sNo rule to make target `%s', needed by `%s'%s"; - if (keep_going_flag || file->dontcare) - { - if (!file->dontcare) - { - if (file->parent == 0) - error (msg_noparent, "*** ", file->name, "."); - else - error (msg_parent, "*** ", - file->name, file->parent->name, "."); - } - file->update_status = 2; - } - else - { - if (file->parent == 0) - fatal (msg_noparent, "", file->name, ""); - else - fatal (msg_parent, "", file->name, file->parent->name, ""); - } - } + no_rule_error(file); } else { @@ -994,11 +1009,12 @@ f_mtime (file, search) } mtime = f_mtime (arfile, search); check_renamed (arfile); - if (search && strcmp (arfile->name, arname)) + if (search && strcmp (arfile->hname, arname)) { /* The archive's name has changed. Change the archive-member reference accordingly. */ + char *name; unsigned int arlen, memlen; if (!arname_used) @@ -1007,18 +1023,26 @@ f_mtime (file, search) arname_used = 1; } - arname = arfile->name; + arname = arfile->hname; arlen = strlen (arname); memlen = strlen (memname); - free (file->name); + /* free (file->name); */ - file->name = (char *) xmalloc (arlen + 1 + memlen + 2); - bcopy (arname, file->name, arlen); - file->name[arlen] = '('; - bcopy (memname, file->name + arlen + 1, memlen); - file->name[arlen + 1 + memlen] = ')'; - file->name[arlen + 1 + memlen + 1] = '\0'; + name = (char *) xmalloc (arlen + 1 + memlen + 2); + bcopy (arname, name, arlen); + name[arlen] = '('; + bcopy (memname, name + arlen + 1, memlen); + name[arlen + 1 + memlen] = ')'; + name[arlen + 1 + memlen + 1] = '\0'; + + /* If the archive was found with GPATH, make the change permanent; + otherwise defer it until later. */ + if (arfile->name == arfile->hname) + rename_file (file, name); + else + rehash_file (file, name); + check_renamed (file); } if (!arname_used) @@ -1029,7 +1053,7 @@ f_mtime (file, search) /* The archive doesn't exist, so it's members don't exist either. */ return (time_t) -1; - mtime = ar_member_date (file->name); + mtime = ar_member_date (file->hname); } else #endif @@ -1090,17 +1114,20 @@ f_mtime (file, search) * FAT filesystems round time to nearest even second(!). Just * allow for any file (NTFS or FAT) to perhaps suffer from this * braindamage. - * - * Apparently, this doesn't happen with the MS-DOS/DJGPP port, - * although MS-DOS and MS-Windows 3.X/9X also use FAT filesystems. */ if (mtime > now && (((mtime % 2) == 0) && ((mtime-1) > now))) +#else +#ifdef __MSDOS__ + /* Scrupulous testing indicates that some Windows + filesystems can set file times up to 3 sec into the future! */ + if (mtime > now + 3) #else if (mtime > now) +#endif #endif { - error("*** Warning: File `%s' has modification time in the future", - file->name); + error("*** Warning: File `%s' has modification time in the future (%ld > %ld)", + file->name, mtime, now); clock_skew_detected = 1; } } diff --git a/remote-cstms.c b/remote-cstms.c index 6aa2c966..e1d63a3a 100644 --- a/remote-cstms.c +++ b/remote-cstms.c @@ -21,15 +21,15 @@ 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 "job.h" +#include "filedef.h" #include "commands.h" #include "job.h" #include #include -#define __STRICT_BSD__ /* Don't make conflicting declarations. */ #include "customs.h" - char *remote_description = "Customs"; /* File name of the Customs `export' client command. @@ -42,25 +42,47 @@ static ExportPermit permit; /* Normalized path name of the current directory. */ static char *normalized_cwd; +/* Call once at startup even if no commands are run. */ + +void +remote_setup () +{ +} + +/* Called before exit. */ + +void +remote_cleanup () +{ +} + /* Return nonzero if the next job should be done remotely. */ int -start_remote_job_p () +start_remote_job_p (first_p) + int first_p; { static int inited = 0; int status; - - /* Allow the user to turn off job exportation - (useful while he is debugging Customs, for example). */ - if (getenv ("GNU_MAKE_NO_CUSTOMS") != 0) - return 0; + int njobs; if (!inited) { + /* Allow the user to turn off job exportation (useful while he is + debugging Customs, for example). */ + if (getenv ("GNU_MAKE_NO_CUSTOMS") != 0) + { + inited = -1; + return 0; + } + /* For secure Customs, make is installed setuid root and Customs requires a privileged source port be used. */ make_access (); + if (debug_flag) + Rpc_Debug(1); + /* Ping the daemon once to see if it is there. */ inited = Customs_Ping () == RPC_SUCCESS ? 1 : -1; @@ -87,6 +109,15 @@ start_remote_job_p () if (inited < 0) return 0; + njobs = job_slots_used; + if (!first_p) + njobs -= 1; /* correction for being called from reap_children() */ + + /* the first job should run locally, or, if the -l flag is given, we use + that as clue as to how many local jobs should be scheduled locally */ + if (max_load_average < 0 && njobs == 0 || njobs < max_load_average) + return 0; + status = Customs_Host (EXPORT_SAME, &permit); if (status != RPC_SUCCESS) { @@ -113,8 +144,8 @@ start_remote_job (argv, envp, stdin_fd, is_remote, id_ptr, used_stdin) int *id_ptr; int *used_stdin; { - extern int vfork (), execve (); char waybill[MAX_DATA_SIZE], msg[128]; + struct hostent *host; struct timeval timeout; struct sockaddr_in sin; int len; @@ -150,8 +181,8 @@ start_remote_job (argv, envp, stdin_fd, is_remote, id_ptr, used_stdin) /* Modify the waybill as if the remote child had done `child_access ()'. */ { WayBill *wb = (WayBill *) waybill; - wb->euid = wb->ruid; - wb->rgid = wb->rgid; + wb->ruid = wb->euid; + wb->rgid = wb->egid; } /* Send the request to the server, timing out in 20 seconds. */ @@ -164,26 +195,31 @@ start_remote_job (argv, envp, stdin_fd, is_remote, id_ptr, used_stdin) len, (Rpc_Opaque) waybill, sizeof(msg), (Rpc_Opaque) msg, 1, &timeout); + + host = gethostbyaddr((char *)&permit.addr, sizeof(permit.addr), AF_INET); + if (status != RPC_SUCCESS) { (void) close (retsock); (void) close (sock); - error ("exporting: %s", Rpc_ErrorMessage (status)); + error ("exporting to %s: %s", + host ? host->h_name : inet_ntoa (permit.addr), + Rpc_ErrorMessage (status)); return 1; } else if (msg[0] != 'O' || msg[1] != 'k' || msg[2] != '\0') { (void) close (retsock); (void) close (sock); - error ("CUSTOMS_IMPORT: %s", msg); + error ("exporting to %s: %s", + host ? host->h_name : inet_ntoa (permit.addr), + msg); return 1; } - else if (debug_flag) + else { - struct hostent *host = gethostbyaddr (&permit.addr, sizeof (permit.addr), - AF_INET); - printf ("Job exported to %s ID %u\n", - host == 0 ? inet_ntoa (permit.addr) : host->h_name, + error ("*** exported to %s (id %u)", + host ? host->h_name : inet_ntoa (permit.addr), permit.id); } @@ -225,6 +261,7 @@ start_remote_job (argv, envp, stdin_fd, is_remote, id_ptr, used_stdin) (void) close (sock); *is_remote = 0; *id_ptr = pid; + *used_stdin = 1; return 0; } diff --git a/remote-stub.c b/remote-stub.c index 958c11da..1ff9b04a 100644 --- a/remote-stub.c +++ b/remote-stub.c @@ -41,7 +41,8 @@ remote_cleanup () /* Return nonzero if the next job should be done remotely. */ int -start_remote_job_p () +start_remote_job_p (first_p) + int first_p; { return 0; } diff --git a/rule.c b/rule.c index 831c18c5..69336312 100644 --- a/rule.c +++ b/rule.c @@ -50,6 +50,14 @@ unsigned int max_pattern_deps; unsigned int max_pattern_dep_length; +/* Chain of all pattern-specific variables. */ + +static struct pattern_var *pattern_vars; + +/* Pointer to last struct in the chain, so we can add onto the end. */ + +static struct pattern_var *last_pattern_var; + /* Pointer to structure for the file .SUFFIXES whose dependencies are the suffixes to be searched. */ @@ -86,7 +94,7 @@ count_implicit_rule_limits () unsigned int ntargets; ++num_pattern_rules; - + ntargets = 0; while (rule->targets[ntargets] != 0) ++ntargets; @@ -157,7 +165,7 @@ count_implicit_rule_limits () end_main_loop: rule = next; } - + if (name != 0) free (name); } @@ -336,7 +344,7 @@ new_pattern_rule (rule, override) else last_pattern_rule->next = rule; last_pattern_rule = rule; - + /* We got one. Stop looking. */ goto matched; } @@ -519,6 +527,78 @@ create_pattern_rule (targets, target_percents, r->terminal = terminal; } +/* Create a new pattern-specific variable struct. */ + +struct pattern_var * +create_pattern_var (target, suffix) + char *target, *suffix; +{ + register struct pattern_var *p = 0; + unsigned int len = strlen(target); + + /* Look to see if this pattern already exists in the list. */ + for (p = pattern_vars; p != NULL; p = p->next) + if (p->len == len && !strcmp(p->target, target)) + break; + + if (p == 0) + { + p = (struct pattern_var *) xmalloc (sizeof (struct pattern_var)); + if (last_pattern_var != 0) + last_pattern_var->next = p; + else + pattern_vars = p; + last_pattern_var = p; + p->next = 0; + p->target = target; + p->len = len; + p->suffix = suffix + 1; + p->vars = create_new_variable_set(); + } + + return p; +} + +/* Look up a target in the pattern-specific variable list. */ + +struct pattern_var * +lookup_pattern_var (target) + char *target; +{ + struct pattern_var *p; + unsigned int targlen = strlen(target); + + for (p = pattern_vars; p != 0; p = p->next) + { + char *stem; + unsigned int stemlen; + + if (p->len > targlen) + /* It can't possibly match. */ + continue; + + /* From the lengths of the filename and the pattern parts, + find the stem: the part of the filename that matches the %. */ + stem = target + (p->suffix - p->target - 1); + stemlen = targlen - p->len + 1; + + /* Compare the text in the pattern before the stem, if any. */ + if (stem > target && strncmp (p->target, target, stem - target)) + continue; + + /* Compare the text in the pattern after the stem, if any. + We could test simply use streq, but this way we compare the + first two characters immediately. This saves time in the very + common case where the first character matches because it is a + period. */ + if (*p->suffix == stem[stemlen] + && (*p->suffix == '\0'|| streq (&p->suffix[1], &stem[stemlen+1]))) + break; + } + + return p; +} + /* Print the data base of rules. */ static void /* Useful to call from gdb. */ @@ -586,4 +666,26 @@ print_rule_data_base () if (num_pattern_rules != rules) fatal ("BUG: num_pattern_rules wrong! %u != %u", num_pattern_rules, rules); + + puts ("\n# Pattern-specific variable values"); + + { + struct pattern_var *p; + + rules = 0; + for (p = pattern_vars; p != 0; p = p->next) + { + ++rules; + + printf ("\n%s :\n", p->target); + print_variable_set (p->vars->set, "# "); + } + + if (rules == 0) + puts ("\n# No pattern-specific variable values."); + else + { + printf ("\n# %u pattern-specific variable values", rules); + } + } } diff --git a/rule.h b/rule.h index 9c6b1b03..4effeb03 100644 --- a/rule.h +++ b/rule.h @@ -30,6 +30,15 @@ struct rule char in_use; /* If in use by a parent pattern_search. */ }; +struct pattern_var + { + struct pattern_var *next; + char *target; + unsigned int len; + char *suffix; + struct variable_set_list *vars; + }; + /* For calling install_pattern_rule. */ struct pspec { @@ -51,3 +60,5 @@ extern unsigned int maxsuffix; extern void install_pattern_rule PARAMS ((struct pspec *p, int terminal)); extern int new_pattern_rule PARAMS ((struct rule *rule, int override)); +extern struct pattern_var *create_pattern_var PARAMS ((char *target, char *suffix)); +extern struct pattern_var *lookup_pattern_var PARAMS ((char *target)); diff --git a/subproc.bat b/subproc.bat index b18694bf..d64eeec9 100644 --- a/subproc.bat +++ b/subproc.bat @@ -1,3 +1,6 @@ cd w32\subproc -nmake /f %1 +set MAKE=%2 +set MAKEFILE=%1 +if x%2 == x set MAKE=nmake +%MAKE% /f %MAKEFILE% cd ..\.. diff --git a/variable.c b/variable.c index c0dc3dce..3155a925 100644 --- a/variable.c +++ b/variable.c @@ -44,10 +44,8 @@ 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)); - +static struct variable *lookup_variable_in_set PARAMS ((char *name, + unsigned int length, struct variable_set *set)); /* Implement variables. */ @@ -58,7 +56,7 @@ static struct variable *define_variable_in_set PARAMS ((char *name, unsigned int If RECURSIVE is nonzero a flag is set in the variable saying that it should be recursively re-expanded. */ -static struct variable * +struct variable * define_variable_in_set (name, length, value, origin, recursive, set) char *name; unsigned int length; @@ -114,6 +112,7 @@ define_variable_in_set (name, length, value, origin, recursive, set) v->origin = origin; v->recursive = recursive; v->expanding = 0; + v->per_target = 0; v->export = v_default; v->next = set->table[hashval]; set->table[hashval] = v; @@ -184,6 +183,34 @@ lookup_variable (name, length) return 0; } +/* Lookup a variable whose name is a string starting at NAME + and with LENGTH chars in set SET. NAME need not be null-terminated. + Returns address of the `struct variable' containing all info + on the variable, or nil if no such variable is defined. */ + +static struct variable * +lookup_variable_in_set (name, length, set) + char *name; + unsigned int length; + struct variable_set *set; +{ + register unsigned int i; + register unsigned int hash = 0; + register struct variable *v; + + for (i = 0; i < length; ++i) + HASH (hash, name[i]); + hash %= set->buckets; + + for (v = set->table[hash]; v != 0; v = v->next) + if (*v->name == *name + && !strncmp (v->name + 1, name + 1, length - 1) + && v->name[length] == 0) + return v; + + return 0; +} + /* Initialize FILE's variable set list. If FILE already has a variable set list, the topmost variable set is left intact, but the the rest of the chain is replaced with FILE->parent's setlist. */ @@ -245,10 +272,8 @@ pop_variable_scope () free ((char *) set); } -/* Create a new variable set and push it on the current setlist. */ - -void -push_new_variable_scope () +struct variable_set_list * +create_new_variable_set () { register struct variable_set_list *setlist; register struct variable_set *set; @@ -263,7 +288,16 @@ push_new_variable_scope () xmalloc (sizeof (struct variable_set_list)); setlist->set = set; setlist->next = current_variable_set_list; - current_variable_set_list = setlist; + + return setlist; +} + +/* Create a new variable set and push it on the current setlist. */ + +struct variable_set_list * +push_new_variable_scope () +{ + return (current_variable_set_list = create_new_variable_set()); } /* Merge SET1 into SET0, freeing unused storage in SET1. */ @@ -506,6 +540,19 @@ target_environment (file) added specially at the end. */ continue; + /* If this is a per-target variable and it hasn't been touched + already then look up the global version and take its export + value. */ + if (v->per_target && v->export == v_default) + { + struct variable *gv; + + gv = lookup_variable_in_set(v->name, strlen(v->name), + &global_variable_set); + if (gv) + v->export = gv->export; + } + switch (v->export) { case v_default: @@ -524,15 +571,16 @@ target_environment (file) for (++p; *p != '\0'; ++p) if (*p != '_' && (*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9')) - break; + continue; if (*p != '\0') continue; - - case v_export: break; - case v_noexport: - continue; + case v_export: + break; + + case v_noexport: + continue; case v_ifset: if (v->origin == o_default) @@ -540,9 +588,22 @@ target_environment (file) break; } + /* If this was from a different-sized hash table, then + recalculate the bucket it goes in. */ + if (set->buckets != buckets) + { + register char *np; + + j = 0; + for (np = v->name; *np != '\0'; ++np) + HASH (j, *np); + j %= buckets; + } + for (ov = table[j]; ov != 0; ov = ov->next) if (streq (v->name, ov->variable->name)) break; + if (ov == 0) { register struct variable_bucket *entry; @@ -565,6 +626,7 @@ target_environment (file) for (b = table[i]; b != 0; b = b->next) { register struct variable *v = b->variable; + /* If V is recursively expanded and didn't come from the environment, expand its value. If it came from the environment, it should go back into the environment unchanged. */ @@ -607,14 +669,11 @@ target_environment (file) from a makefile, an override directive, the environment with or without the -e switch, or the command line. - A variable definition has the form "name = value" or "name := value". - Any whitespace around the "=" or ":=" is removed. The first form - defines a variable that is recursively re-evaluated. The second form - defines a variable whose value is variable-expanded at the time of - definition and then is evaluated only once at the time of expansion. + See the comments for parse_variable_definition(). - If a variable was defined, a pointer to its `struct variable' is returned. - If not, NULL is returned. */ + If LINE was recognized as a variable definition, a pointer to its `struct + variable' is returned. If LINE is not a variable definition, NULL is + returned. */ struct variable * try_variable_definition (filename, lineno, line, origin) @@ -627,7 +686,8 @@ try_variable_definition (filename, lineno, line, origin) register char *p = line; register char *beg; register char *end; - enum { bogus, simple, recursive, append } flavor = bogus; + enum { f_bogus, + f_simple, f_recursive, f_append, f_conditional } flavor = f_bogus; char *name, *expanded_name, *value; struct variable *v; @@ -639,14 +699,14 @@ try_variable_definition (filename, lineno, line, origin) if (c == '=') { end = p - 1; - flavor = recursive; + flavor = f_recursive; break; } else if (c == ':') if (*p == '=') { end = p++ - 1; - flavor = simple; + flavor = f_simple; break; } else @@ -655,9 +715,15 @@ try_variable_definition (filename, lineno, line, origin) else if (c == '+' && *p == '=') { end = p++ - 1; - flavor = append; + flavor = f_append; break; } + else if (c == '?' && *p == '=') + { + end = p++ - 1; + flavor = f_conditional; + break; + } else if (c == '$') { /* This might begin a variable expansion reference. Make sure we @@ -700,31 +766,35 @@ try_variable_definition (filename, lineno, line, origin) expanded_name = allocated_variable_expand (name); if (expanded_name[0] == '\0') - { - if (filename == 0) - fatal ("empty variable name"); - else - makefile_fatal (filename, lineno, "empty variable name"); - } + makefile_fatal (filename, lineno, "empty variable name"); /* Calculate the variable's new value in VALUE. */ switch (flavor) { - case bogus: + case f_bogus: /* Should not be possible. */ abort (); - return 0; - case simple: + case f_simple: /* A simple variable definition "var := value". Expand the value. */ value = variable_expand (p); break; - case recursive: + case f_conditional: + /* A conditional variable definition "var ?= value". + The value is set IFF the variable is not defined yet. */ + v = lookup_variable(expanded_name, strlen(expanded_name)); + if (v) + { + free(expanded_name); + return v; + } + /* FALLTHROUGH */ + case f_recursive: /* A recursive variable definition "var = value". The value is used verbatim. */ value = p; break; - case append: + case f_append: /* An appending variable definition "var += value". Extract the old value and append the new one. */ v = lookup_variable (expanded_name, strlen (expanded_name)); @@ -733,7 +803,7 @@ try_variable_definition (filename, lineno, line, origin) /* There was no old value. This becomes a normal recursive definition. */ value = p; - flavor = recursive; + flavor = f_recursive; } else { @@ -744,7 +814,7 @@ try_variable_definition (filename, lineno, line, origin) if (v->recursive) /* The previous definition of the variable was recursive. The new value comes from the unexpanded old and new values. */ - flavor = recursive; + flavor = f_recursive; else /* The previous definition of the variable was simple. The new value comes from the old value, which was expanded @@ -791,7 +861,7 @@ try_variable_definition (filename, lineno, line, origin) *p = '/'; } v = define_variable (expanded_name, strlen (expanded_name), - shellpath, origin, flavor == recursive); + shellpath, origin, flavor == f_recursive); } else { @@ -831,7 +901,7 @@ try_variable_definition (filename, lineno, line, origin) *p = '/'; } v = define_variable (expanded_name, strlen (expanded_name), - shellpath, origin, flavor == recursive); + shellpath, origin, flavor == f_recursive); } else v = lookup_variable (expanded_name, strlen (expanded_name)); @@ -841,9 +911,26 @@ try_variable_definition (filename, lineno, line, origin) } else #endif /* __MSDOS__ */ +#ifdef WINDOWS32 + if (origin == o_file + && strcmp (expanded_name, "SHELL") == 0) { + extern char* default_shell; + + /* + * Call shell locator function. If it returns TRUE, then + * set no_default_sh_exe to indicate sh was found and + * set new value for SHELL variable. + */ + if (find_and_set_default_shell(value)) { + v = define_variable (expanded_name, strlen (expanded_name), + default_shell, origin, flavor == f_recursive); + no_default_sh_exe = 0; + } + } else +#endif v = define_variable (expanded_name, strlen (expanded_name), - value, origin, flavor == recursive); + value, origin, flavor == f_recursive); free (expanded_name); @@ -923,7 +1010,7 @@ print_variable (v, prefix) /* Print all the variables in SET. PREFIX is printed before the actual variable definitions (everything else is comments). */ -static void +void print_variable_set (set, prefix) register struct variable_set *set; char *prefix; diff --git a/variable.h b/variable.h index 79d9739f..4289c147 100644 --- a/variable.h +++ b/variable.h @@ -43,7 +43,8 @@ struct variable origin ENUM_BITFIELD (3); /* Variable origin. */ unsigned int recursive:1; /* Gets recursively re-evaluated. */ unsigned int expanding:1; /* Nonzero if currently being expanded. */ - enum + unsigned int per_target:1; /* Nonzero if a target-specific variable. */ + enum variable_export { v_export, /* Export this variable. */ v_noexport, /* Don't export this variable. */ @@ -68,20 +69,22 @@ struct variable_set_list struct variable_set *set; /* Variable set. */ }; +extern char *variable_buffer; extern struct variable_set_list *current_variable_set_list; /* 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 PARAMS ((char *str, char *end)); +extern char *variable_expand_string PARAMS ((char *line, char *string, + long length)); /* function.c */ extern int handle_function PARAMS ((char **op, char **stringp)); -extern int pattern_matches PARAMS ((char *pattern, char *percent, char *word)); +extern int pattern_matches PARAMS ((char *pattern, char *percent, char *str)); 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, @@ -91,17 +94,21 @@ extern char *patsubst_expand PARAMS ((char *o, char *text, char *pattern, char * extern char *recursively_expand PARAMS ((struct variable *v)); /* variable.c */ -extern void push_new_variable_scope PARAMS ((void)); +extern struct variable_set_list *create_new_variable_set PARAMS ((void)); +extern struct variable_set_list *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 print_variable_set PARAMS ((struct variable_set *set, char *prefix)); 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_in_set PARAMS ((char *name, unsigned int length, + char *value, enum variable_origin origin, int recursive, struct variable_set *set)); 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)); diff --git a/vmsfunctions.c b/vmsfunctions.c index daaa8b28..2bc93bd5 100644 --- a/vmsfunctions.c +++ b/vmsfunctions.c @@ -1,7 +1,9 @@ -#define KDEBUG 0 /* vmsfunctions.c */ +#define KDEBUG 0 + #include +#include #include "make.h" #ifdef __DECC #include @@ -13,114 +15,147 @@ #include #include "vmsdir.h" -DIR *opendir(char *dspec) +#if __VMS_VER < 70000000 + +DIR * +opendir (dspec) + 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); - } + dfab = (struct FAB *) xmalloc (sizeof (struct FAB)); + if (! dfab) + { + printf ("Error mallocing for FAB\n"); + return (NULL); + } - sprintf(searchspec,"%s*.*;",dspec); + dnam = (struct NAM *) xmalloc (sizeof (struct NAM)); + if (! dnam) + { + printf ("Error mallocing for NAM\n"); + free (dfab); + return (NULL); + } + + searchspec = (char *) xmalloc (MAXNAMLEN + 1); + if (! searchspec) + { + 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$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); - } + if (! (sys$parse (dfab) & 1)) + { + free (dfab); + free (dnam); + free (searchspec); + return (NULL); + } - return(dfab); + return (dfab); } -#include -#define uppercasify(str) { char *tmp; for(tmp = (str); *tmp != '\0'; tmp++) if(islower(*tmp)) *tmp = toupper(*tmp); } +#define uppercasify(str) \ + do \ + { \ + char *tmp; \ + for (tmp = (str); *tmp != '\0'; tmp++) \ + if (islower (*tmp)) \ + *tmp = toupper (*tmp); \ + } \ + while (0) -struct direct *readdir(DIR *dfd) +struct direct * +readdir (dfd) + DIR * dfd; { static struct direct *dentry; - static char resultspec[MAXNAMLEN+1]; + static char resultspec[MAXNAMLEN + 1]; int i; - if ((dentry = (struct direct *)xmalloc(sizeof (struct direct))) == NULL) { - printf("Error mallocing for direct\n"); - return(NULL); - } + dentry = (struct direct *) xmalloc (sizeof (struct direct)); + if (! dentry) + { + 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("."); + printf ("."); - if (!((i = sys$search(dfd)) & 1)) { - if (debug_flag) - printf("sys$search failed with %d\n", i); - free(dentry); - return(NULL); - } + 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; + 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")) +#if 0 + 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); +#endif + 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);*/ + uppercasify (dentry->d_name); +#if 0 + uvUnFixRCSSeparator(dentry->d_name); +#endif - return(dentry); + return (dentry); } -closedir(DIR *dfd) +closedir (dfd) + 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); - } + if (dfd) + { + if (dfd->fab$l_nam) + free (dfd->fab$l_nam->nam$l_esa); + free (dfd->fab$l_nam); + free (dfd); + } } +#endif /* compiled for OpenVMS prior to V7.x */ -char *getwd(char *cwd) +char * +getwd (cwd) + char *cwd; { static char buf[512]; - if (cwd) - return(getcwd(cwd,512)); - else - return(getcwd(buf,512)); + if (cwd) + return (getcwd (cwd, 512)); + else + return (getcwd (buf, 512)); } int @@ -133,23 +168,33 @@ vms_stat (name, buf) static struct FAB Fab; static struct NAM Nam; - static struct fibdef Fib; /* short fib */ + static struct fibdef Fib; /* short fib */ static struct dsc$descriptor FibDesc = - {sizeof(Fib), DSC$K_DTYPE_Z, DSC$K_CLASS_S, (char *)&Fib}; + { 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]}; + { 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}; + { 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}; + { 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 struct atrdef Atr[] = + { +#if defined(VAX) + /* Revision date */ + { sizeof (Rdate), ATR$C_REVDATE, (unsigned int) &Rdate[0] }, + /* Creation date */ + { sizeof (Cdate), ATR$C_CREDATE, (unsigned int) &Cdate[0] }, +#else + /* Revision date */ + { sizeof (Rdate), ATR$C_REVDATE, &Rdate[0] }, + /* Creation date */ + { sizeof (Cdate), ATR$C_CREDATE, &Cdate[0]}, +#endif + { 0, 0, 0 } }; static short int DevChan; static short int iosb[4]; @@ -158,43 +203,43 @@ vms_stat (name, buf) /* 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 */ - + 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); + 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); + 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); + 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; - + 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++) + 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]; + 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]; + 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); + status = sys$qiow (0, DevChan, IO$_ACCESS, &iosb, 0, 0, + &FibDesc, &FileName, 0, 0, &Atr, 0); sys$dassgn (DevChan); if (!(status & 1)) return -1; @@ -206,30 +251,29 @@ vms_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); + 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; +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}; + { 26, DSC$K_DTYPE_T, DSC$K_CLASS_S, str }; date[0] = (tval & 0xff) << 24; - date[1] = ((tval>>8) & 0xffffff); + date[1] = ((tval >> 8) & 0xffffff); - if ((date[0]==0) && (date[1]==0)) - return("never"); - - sys$asctim(0,&date_str,date,0); - str[26]='\0'; + if ((date[0] == 0) && (date[1] == 0)) + return ("never"); - return(str); + sys$asctim (0, &date_str, date, 0); + str[26] = '\0'; + + return (str); } - -/* EOF */ diff --git a/vmsify.c b/vmsify.c index 35e30bd1..8d242d74 100644 --- a/vmsify.c +++ b/vmsify.c @@ -727,48 +727,21 @@ vmsify (name, type) while (*fptr == '/'); } { /* got '..' or '../' */ - char cwdbuf[MAXPATHLEN+1]; + nstate = N_OPEN; + *vptr++ = '['; + while (count--) + *vptr++ = '-'; - s1 = getcwd(cwdbuf, MAXPATHLEN); - if (s1 == 0) + if (*fptr == 0) /* had '..' or '../' */ { - return ""; /* FIXME, err getcwd */ + *vptr++ = ']'; + state = -1; } - strcpy (vptr, s1); - s = strchr (vptr, ']'); - if (s != 0) + else /* had '../xxx' */ { - nstate = N_OPEN; - 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; - } - } - } + state = 9; } - vptr += strlen (vptr); + *vptr = 0; } break; @@ -782,34 +755,86 @@ vmsify (name, type) fptr++; } - { - char cwdbuf[MAXPATHLEN+1]; + if (*fptr) + { + state = 9; - 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; - } - } + switch (type) + { + case 0: + nstate = N_CLOSED; + *vptr++ = '['; + *vptr++ = ']'; + break; + + case 1: + nstate = N_OPEN; + *vptr++ = '['; + break; + + case 2: + nstate = N_CLOSED; + break; + } + } + else + { + if (type == 1) + { + *vptr++ = '['; + *vptr++ = ']'; + state = -1; + } + else + { + char cwdbuf[MAXPATHLEN+1]; + + s1 = getcwd(cwdbuf, MAXPATHLEN); + if (s1 == 0) + { + return "foo"; /*FIXME, err getcwd */ + } + strcpy (vptr, s1); + vptr += strlen (vptr); + + if (type == 2) + { + s = vptr; + while (s > vmsname) + { + if (*s == '.') + { + *s = ']'; + vptr--; + break; + } + + if (*s == '[') + { + int i; + char *t = vptr - 2; + while (t > s) + { + *(t+7) = *t; + t--; + } + s++; + for (i = 0; i < 6; i++) + *s++ = '0'; + *s = ']'; + vptr += 6; + break; + } + s--; + } + + strcpy (vptr, ".dir"); + vptr += 4; + } + + state = -1; + } + } break; } diff --git a/vpath.c b/vpath.c index ed7267bf..ab88ac31 100644 --- a/vpath.c +++ b/vpath.c @@ -164,7 +164,7 @@ construct_vpath_list (pattern, dirpath) register char **vpath; register unsigned int maxvpath; unsigned int maxelem; - char *percent; + char *percent = NULL; if (pattern != 0) { diff --git a/w32/subproc/NMakefile b/w32/subproc/NMakefile index ab11d964..f1878278 100644 --- a/w32/subproc/NMakefile +++ b/w32/subproc/NMakefile @@ -27,7 +27,7 @@ CC = cl OUTDIR=. MAKEFILE=NMakefile -CFLAGS_any = /nologo /MT /W3 /GX /Z7 /YX /D WIN32 /D WINDOWS32 /D _WINDOWS -I. -I../include +CFLAGS_any = /nologo /MT /W3 /GX /Z7 /YX /D WIN32 /D WINDOWS32 /D _WINDOWS -I. -I../include -I../.. CFLAGS_debug = $(CFLAGS_any) /Od /D _DEBUG /FR.\WinDebug\ /Fp.\WinDebug\subproc.pch /Fo.\WinDebug/ CFLAGS_release = $(CFLAGS_any) /O2 /FR.\WinRel\ /Fp.\WinRel\subproc.pch /Fo.\WinRel/ @@ -40,6 +40,7 @@ Debug: clean: rmdir /s /q WinRel WinDebug + erase *.pdb $(OUTDIR): if not exist .\$@\nul mkdir .\$@ diff --git a/w32/subproc/build.bat b/w32/subproc/build.bat index 955f6d5d..26ab1cbe 100644 --- a/w32/subproc/build.bat +++ b/w32/subproc/build.bat @@ -1,10 +1,10 @@ if not exist .\WinDebug\nul mkdir .\WinDebug cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c misc.c -cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c sub_proc.c +cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c sub_proc.c cl.exe /nologo /MT /W3 /GX /Z7 /YX /Od /I .. /I . /I ../include /D WIN32 /D WINDOWS32 /D _DEBUG /D _WINDOWS /FR.\WinDebug/ /Fp.\WinDebug/subproc.pch /Fo.\WinDebug/ /c w32err.c lib.exe /NOLOGO /OUT:.\WinDebug\subproc.lib .\WinDebug/misc.obj .\WinDebug/sub_proc.obj .\WinDebug/w32err.obj if not exist .\WinRel\nul mkdir .\WinRel cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c misc.c -cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c sub_proc.c +cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /I ../.. /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c sub_proc.c cl.exe /nologo /MT /W3 /GX /YX /O2 /I ../include /D WIN32 /D WINDOWS32 /D NDEBUG /D _WINDOWS /FR.\WinRel/ /Fp.\WinRel/subproc.pch /Fo.\WinRel/ /c w32err.c lib.exe /NOLOGO /OUT:.\WinRel\subproc.lib .\WinRel/misc.obj .\WinRel/sub_proc.obj .\WinRel/w32err.obj diff --git a/w32/subproc/sub_proc.c b/w32/subproc/sub_proc.c index 4166d340..281c81cd 100644 --- a/w32/subproc/sub_proc.c +++ b/w32/subproc/sub_proc.c @@ -6,6 +6,7 @@ #include "sub_proc.h" #include "proc.h" #include "w32err.h" +#include "config.h" static char *make_command_line( char *shell_name, char *exec_path, char **argv); @@ -888,108 +889,6 @@ process_cleanup( } -/* - * Try to protect against WINDOWS32 argument munging. This function takes - * an argv vector and outputs a 'protected' string as a return - * value. The return code can be safely passed to CreateProcess(). - * - * The caller should free the return value. - */ - -#define TRACE(x) -static char *fix_command_line(char *args[]) -{ - int i; - char *narg; - char *nargp; - char *p; - char *q; - int alloc_len = 0; - - for (i = 0; args[i]; i++) - alloc_len += ((strlen(args[i]) * 2) + 1); - /* account for possible enclosing quotes and null termination */ - alloc_len += 3; - - nargp = narg = malloc(alloc_len); - - for (i = 0; args[i]; i++) { - p = args[i]; - TRACE(("original arg: %s\n", p)); - - if (*p == '\0') { - *nargp++ = '"'; - *nargp++ = '"'; - *nargp = '\0'; - TRACE(("empty string arg: %s\n", nargp-2)); - } else if (strpbrk(p, "\" \t")) { - /* point to end of copy buffer */ - q = narg; - q += (alloc_len-1); - *q-- = '\0'; /* ensure null terminated string */ - *q-- = '"'; /* terminating quote of argument */ - - /* point to end of the input string */ - p = args[i]; - p += strlen(args[i]); - p--; - - /* - * Because arg is quoted, escape any backslashes - * that might occur at the end of the string which - * proceed the closing quote. - * Example: - * foo c:\ - * Becomes: - * "foo c:\\" - */ - while (*p == '\\') - *q-- = *p--, *q-- = '\\'; - - /* copy the string in reverse */ - while (p >= args[i]) { - /* copy the character */ - *q-- = *p--; - - /* - * Escape any double quote found. Also escape - * each backslash preceding the double quote. - */ - if (*(p+1) == '"') { - *q-- = '\\'; - if (p >= args[i] && *p == '\\') - while (p >= args[i] && *p == '\\') - *q-- = *p--, *q-- = '\\'; - } - } - - /* finish quoting arg, q now points to complete arg */ - *q = '"'; - - /* rejustify */ - memmove(nargp, q, strlen(q) + 1); - TRACE(("arg with white space or doublequotes: %s\n", nargp)); - nargp += strlen(nargp); - } else { - /* just copy the argument, no protection needed */ - strcpy(nargp, args[i]); - TRACE(("plain arg: %s\n", nargp)); - nargp += strlen(nargp); - } - - /* separate arguments with spaces (if more args to gather) */ - if (args[i+1]) - *nargp++ = ' '; - *nargp = '\0'; - } /* end for */ - - /* NULL terminate the arg list */ - *nargp = '\0'; - - return (narg); -} -#undef TRACE - /* * Description: * Create a command line buffer to pass to CreateProcess @@ -1004,55 +903,211 @@ static char *fix_command_line(char *args[]) */ static char * -make_command_line( char *shell_name, char *exec_path, char **argv) +make_command_line( char *shell_name, char *full_exec_path, char **argv) { - char** nargv; - char* buf; - int i; - char** shargv = NULL; - char* p = NULL; - char* q = NULL; - int j = 0; - - if (shell_name) { - /* handle things like: #!/bin/sh -x */ + int argc = 0; + char** argvi; + int* enclose_in_quotes = NULL; + int* enclose_in_quotes_i; + unsigned int bytes_required = 0; + char* command_line; + char* command_line_i; - /* count tokens */ - q = strdup(shell_name); - for (j = 0, p = q; (p = strtok(p, " \t")) != NULL; p = NULL, j++); - free(q); - - /* copy tokens */ - q = strdup(shell_name); - shargv = (char **) malloc((j+1) * sizeof (char *)); - for (j = 0, p = q; (p = strtok(p, " \t")) != NULL; p = NULL, j++) - shargv[j] = strdup(p); - shargv[j] = NULL; - free(q); - - /* create argv */ - for (i = 0; argv[i]; i++); - i += (j+1); - nargv = (char **) malloc(i * sizeof (char *)); - for (i = 0; shargv[i] != NULL; i++) - nargv[i] = shargv[i]; - for (j = 0; argv[j]; j++, i++) - nargv[i] = argv[j]; - nargv[i] = NULL; - } else - nargv = argv; - - /* create string suitable for CreateProcess() */ - buf = fix_command_line(nargv); - - if (shell_name) { - for (j = 0; shargv[j]; j++) - free(shargv[j]); - free(shargv); - free(nargv); + if (shell_name && full_exec_path) { + bytes_required + = strlen(shell_name) + 1 + strlen(full_exec_path); + /* + * Skip argv[0] if any, when shell_name is given. + */ + if (*argv) argv++; + /* + * Add one for the intervening space. + */ + if (*argv) bytes_required++; } - - return buf; + + argvi = argv; + while (*(argvi++)) argc++; + + if (argc) { + enclose_in_quotes = (int*) calloc(1, argc * sizeof(int)); + + if (!enclose_in_quotes) { + return NULL; + } + } + + /* We have to make one pass through each argv[i] to see if we need + * to enclose it in ", so we might as well figure out how much + * memory we'll need on the same pass. + */ + + argvi = argv; + enclose_in_quotes_i = enclose_in_quotes; + while(*argvi) { + char* p = *argvi; + unsigned int backslash_count = 0; + + /* + * We have to enclose empty arguments in ". + */ + if (!(*p)) *enclose_in_quotes_i = 1; + + while(*p) { + switch (*p) { + case '\"': + /* + * We have to insert a backslash for each " + * and each \ that precedes the ". + */ + bytes_required += (backslash_count + 1); + backslash_count = 0; + break; + + case '\\': + backslash_count++; + break; + /* + * At one time we set *enclose_in_quotes_i for '*' or '?' to suppress + * wildcard expansion in programs linked with MSVC's SETARGV.OBJ so + * that argv in always equals argv out. This was removed. Say you have + * such a program named glob.exe. You enter + * glob '*' + * at the sh command prompt. Obviously the intent is to make glob do the + * wildcarding instead of sh. If we set *enclose_in_quotes_i for '*' or '?', + * then the command line that glob would see would be + * glob "*" + * and the _setargv in SETARGV.OBJ would _not_ expand the *. + */ + case ' ': + case '\t': + *enclose_in_quotes_i = 1; + /* fall through */ + + default: + backslash_count = 0; + break; + } + + /* + * Add one for each character in argv[i]. + */ + bytes_required++; + + p++; + } + + if (*enclose_in_quotes_i) { + /* + * Add one for each enclosing ", + * and one for each \ that precedes the + * closing ". + */ + bytes_required += (backslash_count + 2); + } + + /* + * Add one for the intervening space. + */ + if (*(++argvi)) bytes_required++; + enclose_in_quotes_i++; + } + + /* + * Add one for the terminating NULL. + */ + bytes_required++; + + command_line = (char*) malloc(bytes_required); + + if (!command_line) { + if (enclose_in_quotes) free(enclose_in_quotes); + return NULL; + } + + command_line_i = command_line; + + if (shell_name && full_exec_path) { + while(*shell_name) { + *(command_line_i++) = *(shell_name++); + } + + *(command_line_i++) = ' '; + + while(*full_exec_path) { + *(command_line_i++) = *(full_exec_path++); + } + + if (*argv) { + *(command_line_i++) = ' '; + } + } + + argvi = argv; + enclose_in_quotes_i = enclose_in_quotes; + + while(*argvi) { + char* p = *argvi; + unsigned int backslash_count = 0; + + if (*enclose_in_quotes_i) { + *(command_line_i++) = '\"'; + } + + while(*p) { + if (*p == '\"') { + /* + * We have to insert a backslash for the " + * and each \ that precedes the ". + */ + backslash_count++; + + while(backslash_count) { + *(command_line_i++) = '\\'; + backslash_count--; + }; + + } else if (*p == '\\') { + backslash_count++; + } else { + backslash_count = 0; + } + + /* + * Copy the character. + */ + *(command_line_i++) = *(p++); + } + + if (*enclose_in_quotes_i) { + /* + * Add one \ for each \ that precedes the + * closing ". + */ + while(backslash_count--) { + *(command_line_i++) = '\\'; + }; + + *(command_line_i++) = '\"'; + } + + /* + * Append an intervening space. + */ + if (*(++argvi)) { + *(command_line_i++) = ' '; + } + + enclose_in_quotes_i++; + } + + /* + * Append the terminating NULL. + */ + *command_line_i = '\0'; + + if (enclose_in_quotes) free(enclose_in_quotes); + return command_line; } /*