summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>1998-07-30 20:54:47 +0000
committerPaul Smith <psmith@gnu.org>1998-07-30 20:54:47 +0000
commite2403327e9913bbcbd515f9c38b8f4e26fb9b0d9 (patch)
tree8ac64ff471e0a976daf75ef913c084adba4972fc
parent65a7296e2c81b04761b3f024572310a02c9de691 (diff)
downloadgunmake-e2403327e9913bbcbd515f9c38b8f4e26fb9b0d9.tar.gz
GNU make release 3.77.
-rw-r--r--AUTHORS23
-rw-r--r--ChangeLog447
-rw-r--r--GNUmakefile6
-rw-r--r--INSTALL10
-rw-r--r--Makefile.DOS.template124
-rw-r--r--Makefile.am52
-rw-r--r--NEWS52
-rw-r--r--NMakefile.template259
-rw-r--r--README.DOS.template25
-rw-r--r--README.W3261
-rw-r--r--README.customs73
-rw-r--r--README.template3
-rw-r--r--SMakefile.template64
-rw-r--r--acinclude.m4131
-rw-r--r--arscan.c9
-rw-r--r--config.ami.template3
-rw-r--r--config.h.W32.template59
-rw-r--r--configure.in51
-rw-r--r--default.c10
-rw-r--r--dir.c84
-rw-r--r--dosbuild.bat4
-rw-r--r--expand.c89
-rw-r--r--file.c25
-rw-r--r--filedef.h7
-rw-r--r--function.c51
-rw-r--r--getloadavg.c14
-rw-r--r--glob/ChangeLog48
-rw-r--r--glob/Makefile.am2
-rw-r--r--glob/Makefile.ami6
-rw-r--r--glob/SMakefile6
-rw-r--r--glob/configure.in1
-rw-r--r--glob/fnmatch.c185
-rw-r--r--glob/fnmatch.h36
-rw-r--r--glob/glob.c762
-rw-r--r--glob/glob.h19
-rw-r--r--implicit.c6
-rw-r--r--job.c214
-rw-r--r--job.h3
-rw-r--r--main.c322
-rw-r--r--maintMakefile39
-rw-r--r--make.118
-rw-r--r--make.h35
-rw-r--r--make.texinfo331
-rw-r--r--makefile.com48
-rw-r--r--misc.c10
-rw-r--r--read.c604
-rw-r--r--readme.vms11
-rw-r--r--remake.c137
-rw-r--r--remote-cstms.c73
-rw-r--r--remote-stub.c3
-rw-r--r--rule.c108
-rw-r--r--rule.h11
-rw-r--r--subproc.bat5
-rw-r--r--variable.c173
-rw-r--r--variable.h15
-rw-r--r--vmsfunctions.c258
-rw-r--r--vmsify.c153
-rw-r--r--vpath.c2
-rw-r--r--w32/subproc/NMakefile3
-rw-r--r--w32/subproc/build.bat4
-rw-r--r--w32/subproc/sub_proc.c345
61 files changed, 4215 insertions, 1517 deletions
diff --git a/AUTHORS b/AUTHORS
index b66bb8f..489c8cd 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,29 +1,30 @@
-----------------------------------
GNU make development up to version 3.75 by:
- Roland McGrath <roland@gnu.ai.mit.edu>
+ Roland McGrath <roland@gnu.org>
-GNU Make User's Manual written by:
- Richard M. Stallman <rms@gnu.ai.mit.edu>
-
- User's Manual edited by:
- Roland McGrath <roland@gnu.ai.mit.edu>
- Bob Chassell <bob@gnu.ai.mit.edu>
- Melissa Weisshaus <melissa@gnu.ai.mit.edu>
+Development starting with GNU make 3.76 by:
+ Paul D. Smith <psmith@gnu.org>
-Development and maintenance starting with GNU make 3.76 by:
- Paul D. Smith <psmith@gnu.ai.mit.edu>
+GNU Make User's Manual written by:
+ Richard M. Stallman <rms@gnu.org>
+ User's Manual edited by:
+ Roland McGrath <roland@gnu.org>
+ Bob Chassell <bob@gnu.org>
+ Melissa Weisshaus <melissa@gnu.org>
+ Paul D. Smith <psmith@gnu.org>
-----------------------------------
-GNU Make porting efforts:
+GNU make porting efforts:
Port to VMS by:
Klaus Kaempf <kkaempf@progis.de>
Archive support/Bug fixes by John W. Eaton <jwe@bevo.che.wisc.edu>
+
Port to Amiga by:
Aaron Digulla <digulla@fh-konstanz.de>
diff --git a/ChangeLog b/ChangeLog
index f773f3c..c3ffc61 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,450 @@
+1998-07-28 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <eliz@is.elta.co.il>
+
+ * Makefile.DOS (*_INSTALL, *_UNINSTALL): Replace `true' with `:'.
+
+1998-07-25 Paul D. Smith <psmith@gnu.org>
+
+ * Version 3.76.94 released.
+
+1998-07-23 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * file.c (print_file_data_base): Fix average calculation.
+
+1998-07-20 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * make.texinfo: Removed "beta" version designator.
+ Updated ISBN for the next printing.
+
+1998-07-13 Paul Eggert <eggert@twinsun.com>
+
+ * 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 <eliz@is.elta.co.il>
+
+ * Makefile.DOS: track changes in Makefile.in.
+
+1998-07-07 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <eliz@is.elta.co.il>
+
+ * job.c (start_job_command): Reset execute_by_shell after an empty
+ command was skipped.
+
+1998-06-09 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * main.c (main): Andreas Luik <luik@isa.de> 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 <schwab@issan.informatik.uni-dortmund.de>
+
+ * remake.c (update_file_1): Don't free the memory for the
+ dependency structure when dropping a circular dependency.
+
+1998-05-30 Eli Zaretskii <eliz@is.elta.co.il>
+
+ * 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 <schwab@issan.informatik.uni-dortmund.de>
+
+ * read.c (read_makefile): Avoid running past EOS when scanning
+ file name after `include'.
+
+1998-05-26 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
+
+ * make.texinfo (Flavors): Correct description of conditional
+ assignment, which is not equivalent to ifndef.
+ (Setting): Likewise.
+
+1998-05-24 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <eliz@is.elta.co.il>
+
+ * 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 <eliz@is.elta.co.il>
+
+ * 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 <psmith@gnu.org>
+
+ * Version 3.76.90 released.
+
+1998-05-19 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * make.man: Minor changes.
+
+1998-05-13 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <rob_tulloh@tivoli.com>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * make.texinfo (Target-specific): Document target-specific
+ variables.
+
+1998-04-21 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * main.c (main): Set the CURDIR makefile variable.
+ * make.texinfo (Recursion): Document it.
+
+1998-03-17 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * variable.c (try_variable_definition): Implement ?=.
+ * make.texinfo (Setting): Document it.
+
+1998-02-28 Eli Zaretskii <eliz@is.elta.co.il>
+
+ * 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 <phillip_brooks@hp.com>
+
+ * 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 <rob_tulloh@dev.tivoli.com>
+
+ * 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 <rob_tulloh@dev.tivoli.com>
+
+ * 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 <jwe@bevo.che.wisc.edu>
+
+ * 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 <rob_tulloh@tivoli.com>
+
+ * 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 <zinser@axp602.gsi.de>
+
+ * 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 <jwe@bevo.che.wisc.edu>
+
+ * 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 <psmith@baynetworks.com>
+
+ * 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 <psmith@baynetworks.com>
+ * 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 <rob_tulloh@tivoli.com>
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 aedde59..15067c6 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 50dbe43..bca44d0 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 856cdc2..b8d44ee 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 5463428..ab1c1f1 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 70cdc62..5bc2974 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 d82dbce..8f2b3f3 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 065c239..6372437 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,
<djgpp@delorie.com>, 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 ac5001d..ca7f32c 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 0000000..9ad21f6
--- /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 <malloc.h> 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 <malloc.h> */
+ #else
+
+ YMMV.
diff --git a/README.template b/README.template
index 0b1736b..e011f99 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 4705713..2caa82e 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 <config.h>'' 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 0000000..343c333
--- /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 <dickey@clark.net>
+dnl and Jim Spath <jspath@mail.bcpl.lib.md.us>
+dnl and Philippe De Muyter <phdm@macqel.be>
+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 <egger@twinsun.com>
+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 9cf746b..13ae45b 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 1be0ccb..b7103ed 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 cf8a888..aa5a027 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 <alloca.h> 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 <sys/wait.h> 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 <unistd.h>. */
#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 <vfork.h>. */
#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 <dirent.h> header file. */
#undef HAVE_DIRENT_H
-#define HAVE_DIRENT_H
+#define HAVE_DIRENT_H 1
/* Define if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
-#define HAVE_FCNTL_H
+#define HAVE_FCNTL_H 1
/* Define if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
-#define HAVE_LIMITS_H
+#define HAVE_LIMITS_H 1
/* Define if you have the <mach/mach.h> header file. */
#undef HAVE_MACH_MACH_H
/* Define if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
-#define HAVE_MEMORY_H
+#define HAVE_MEMORY_H 1
/* Define if you have the <ndir.h> header file. */
#undef HAVE_NDIR_H
/* Define if you have the <string.h> header file. */
#undef HAVE_STRING_H
-#define HAVE_STRING_H
+#define HAVE_STRING_H 1
/* Define if you have the <sys/dir.h> header file. */
#undef HAVE_SYS_DIR_H
@@ -284,7 +284,7 @@
/* Define if you have the <sys/timeb.h> header file. */
#undef HAVE_SYS_TIMEB_H
-#define HAVE_SYS_TIMEB_H
+#define HAVE_SYS_TIMEB_H 1
/* Define if you have the <sys/wait.h> 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 655ee7e..8fb99f7 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 5f5d2b5..653bc81 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 d187c03..9e1cf7a 100644
--- a/dir.c
+++ b/dir.c
@@ -111,19 +111,25 @@ dosify (filename)
#ifdef _AMIGA
#include <ctype.h>
+#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 8ba6850..ac1e6cd 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 5f46ac2..3f4bcfc 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 e4ea0bd..a60e70f 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 b1e6d31..a5de0a1 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 e115522..198ab44 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 adc4bef..154f18d 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 <sys/file.h>
# 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 92c5e7c..e3854a5 100644
--- a/glob/ChangeLog
+++ b/glob/ChangeLog
@@ -1,3 +1,51 @@
+1998-07-29 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <ghazi@caip.rutgers.edu>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <psmith@gnu.org>
+
+ * 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 <eliz@is.elta.co.il>
+
+ * 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 <psmith@gnu.org>
+
+ * SMakefile, Makefile.ami, glob.c, glob.h, fnmatch.c: Updated from
+ the latest glibc version.
+
+1998-04-17 Paul D. Smith <psmith@gnu.org>
+
+ * 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 <psmith@baynetworks.com>
* configure.in: Require autoconf 2.12.
diff --git a/glob/Makefile.am b/glob/Makefile.am
index 3c4ab7a..964ac19 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 3666d3e..d3e3d40 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 1c82e0a..9dcb90b 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 cf0a408..e948bc1 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 e143743..2d6f6af 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 <fnmatch.h>
#include <ctype.h>
+#if HAVE_STRING_H
+# include <string.h>
+#else
+# include <strings.h>
+#endif
+
+#if defined STDC_HEADERS || defined _LIBC
+# include <stdlib.h>
+#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: <wchar.h> must be included before <wctype.h>. */
+# include <wchar.h>
+# include <wctype.h>
+#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;
+
+ 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 (c == '\0')
+ 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 38b7255..4d1eb3e 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 <unistd.h>. */
@@ -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 6a82fe0..eab7919 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 <config.h>
+# include <config.h>
#endif
/* Enable GNU extensions in glob.h. */
#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
+# define _GNU_SOURCE 1
#endif
#include <errno.h>
@@ -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 <gnu-versions.h>
-#if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION
-#define ELIDE_CODE
-#endif
+#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
+# include <gnu-versions.h>
+# if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION
+# define ELIDE_CODE
+# endif
#endif
#ifndef ELIDE_CODE
-#if defined(STDC_HEADERS) || defined(__GNU_LIBRARY__)
-#include <stddef.h>
+#if defined STDC_HEADERS || defined __GNU_LIBRARY__
+# include <stddef.h>
#endif
#if defined HAVE_UNISTD_H || defined _LIBC
-#include <unistd.h>
-#ifndef POSIX
-#ifdef _POSIX_VERSION
-#define POSIX
-#endif
-#endif
+# include <unistd.h>
+# ifndef POSIX
+# ifdef _POSIX_VERSION
+# define POSIX
+# endif
+# endif
#endif
-#if !defined (_AMIGA) && !defined (VMS) && !defined(WINDOWS32)
-#include <pwd.h>
+#if !defined _AMIGA && !defined VMS && !defined WINDOWS32
+# include <pwd.h>
#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 <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
@@ -110,36 +110,42 @@ extern int errno;
/* In GNU systems, <dirent.h> 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 <stdlib.h>
-#include <string.h>
-#define ANSI_STRING
+#if defined STDC_HEADERS || defined __GNU_LIBRARY__
+# include <stdlib.h>
+# include <string.h>
+# define ANSI_STRING
#else /* No standard headers. */
extern char *getenv ();
-#ifdef HAVE_STRING_H
-#include <string.h>
-#define ANSI_STRING
-#else
-#include <strings.h>
-#endif
-#ifdef HAVE_MEMORY_H
-#include <memory.h>
-#endif
+# ifdef HAVE_STRING_H
+# include <string.h>
+# define ANSI_STRING
+# else
+# include <strings.h>
+# endif
+# ifdef HAVE_MEMORY_H
+# include <memory.h>
+# 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 <alloca.h>
-#else /* Not HAVE_ALLOCA_H. */
-#ifndef _AIX
-#ifdef WINDOWS32
-#include <malloc.h>
-#else
+# ifdef __GNUC__
+# undef alloca
+# define alloca(n) __builtin_alloca (n)
+# else /* Not GCC. */
+# ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+# else /* Not HAVE_ALLOCA_H. */
+# ifndef _AIX
+# ifdef WINDOWS32
+# include <malloc.h>
+# 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)
+# 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
+
+#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
+#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 <fnmatch.h> 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 <fnmatch.h>
/* Some system header files erroneously define these.
We want our own definitions from <glob.h> 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 <glob.h>
+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,69 +1151,131 @@ 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;
+ {
+ 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
+ );
+ nfound = 0;
+ flags |= GLOB_MAGCHAR;
- name = d->d_name;
+ 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
- if (fnmatch (pattern, name,
- (!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) |
- ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
-#ifdef _AMIGA
- | FNM_CASEFOLD
+ 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
- ) == 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;
- }
- }
+ new->next = names;
+ names = new;
+ ++nfound;
+ }
+ }
+ }
+ }
}
- if (nfound == 0 && (flags & GLOB_NOMAGIC) &&
- ! __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE)))
- flags |= GLOB_NOCHECK;
-
if (nfound == 0 && (flags & GLOB_NOCHECK))
{
size_t len = strlen (pattern);
@@ -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 (nfound != 0)
+ {
+ 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;
+ 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;
+ 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;
+ pglob->gl_flags = flags;
+ }
+ save = errno;
if (stream != NULL)
- {
- int save = errno;
- if (flags & GLOB_ALTDIRFUNC)
- (*pglob->gl_closedir) (stream);
- else
- closedir ((DIR *) stream);
- __set_errno (save);
- }
+ 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 713117b..a546c86 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 f7298c6..a999a0f 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 2227bef..91bc30b 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;
-
- /* wait for anything to finish */
- if (hPID = process_wait_for_any()) {
+ {
+ HANDLE hPID;
+ int err;
- /* was an error found on this process? */
- err = process_last_err(hPID);
+ /* wait for anything to finish */
+ if (hPID = process_wait_for_any()) {
- /* get exit data */
- exit_code = process_exit_code(hPID);
+ /* was an error found on this process? */
+ err = process_last_err(hPID);
- if (err)
- fprintf(stderr, "make (e=%d): %s",
- exit_code, map_windows32_error_to_string(exit_code));
+ /* get exit data */
+ exit_code = process_exit_code(hPID);
- exit_sig = process_signal(hPID);
+ if (err)
+ fprintf(stderr, "make (e=%d): %s",
+ exit_code, map_windows32_error_to_string(exit_code));
- /* cleanup process */
- process_cleanup(hPID);
+ /* signal */
+ exit_sig = process_signal(hPID);
- if (dos_batch_file) {
- remove (dos_bname);
- remove (dos_bename);
- dos_batch_file = 0;
- }
+ /* cleanup process */
+ process_cleanup(hPID);
- 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 ca7ad1d..eaac492 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 0cf58fb..dcffa37 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,7 +531,98 @@ 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 */
@@ -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
@@ -731,6 +833,16 @@ int main (int argc, char ** argv)
}
#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.
*/
if (!unix_path && windows32_path)
@@ -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,46 +1162,21 @@ 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;
+ /* Define the default variables. */
+ define_default_variables ();
- /*
- * 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);
+ /* Read all the makefiles. */
- if (fn && strcmp(fn, default_shell) && file_exists_p(fn)) {
- char *p;
+ default_file = enter_file (".DEFAULT");
- default_shell = fn;
+ read_makefiles
+ = read_all_makefiles (makefiles == 0 ? (char **) 0 : makefiles->list);
- /* if Makefile says SHELL is sh.exe, believe it */
- if (strstr(default_shell, "sh.exe"))
- no_default_sh_exe = 0;
+#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);
- /*
- * 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.");
@@ -1154,16 +1184,6 @@ int main (int argc, char ** argv)
}
#endif /* WINDOWS32 */
- /* Define the default variables. */
- define_default_variables ();
-
- /* Read all the makefiles. */
-
- default_file = enter_file (".DEFAULT");
-
- read_makefiles
- = read_all_makefiles (makefiles == 0 ? (char **) 0 : makefiles->list);
-
#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 <bug-gnu-utils@prep.ai.mit.edu>.\n\n",
+%sReport bugs to <bug-make@gnu.org>.\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 5aab784..0c9aa9b 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 1bd37a7..ab6ba47 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 d99ccd0..58a0ff2 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 3c7e4d3..05d0746 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 23c720d..b7bb65c 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 dbbe41f..1411e54 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 bf7f80c..0207516 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 <assert.h>
+
#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.
+
+ 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. */
- char *cmdleft;
+ 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);
-
- if (cmdleft == 0)
- /* Look for a semicolon in the expanded line. */
- cmdleft = find_char_unquote (p, ";", 0);
+ /* 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;
+
+ case w_colon:
+ case w_dcolon:
+ /* We accept and ignore rules without targets for
+ compatibility with SunOS 4 make. */
+ no_targets = 1;
+ continue;
+
+ default:
+ break;
+ }
- if (cmdleft != 0)
- /* Cut the line short at the semicolon. */
- *cmdleft = '\0';
+ 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 (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 = 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 18010cf..43b4dd0 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 b4f15cf..9c459a4 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);
-
- 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';
+ /* free (file->name); */
+
+ 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 6aa2c96..e1d63a3 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 <sys/time.h>
#include <netdb.h>
-#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 958c11d..1ff9b04 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 831c18c..6933631 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 9c6b1b0..4effeb0 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 b18694b..d64eeec 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 c0dc3dc..3155a92 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 79d9739..4289c14 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 daaa8b2..2bc93bd 100644
--- a/vmsfunctions.c
+++ b/vmsfunctions.c
@@ -1,7 +1,9 @@
-#define KDEBUG 0
/* vmsfunctions.c */
+#define KDEBUG 0
+
#include <stdio.h>
+#include <ctype.h>
#include "make.h"
#ifdef __DECC
#include <starlet.h>
@@ -13,114 +15,147 @@
#include <fibdef.h>
#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);
- }
-
- sprintf(searchspec,"%s*.*;",dspec);
+ dfab = (struct FAB *) xmalloc (sizeof (struct FAB));
+ if (! dfab)
+ {
+ printf ("Error mallocing for FAB\n");
+ return (NULL);
+ }
+
+ 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 <ctype.h>
-#define uppercasify(str) { char *tmp; for(tmp = (str); *tmp != '\0'; tmp++) if(islower(*tmp)) *tmp = toupper(*tmp); }
-
-struct direct *readdir(DIR *dfd)
+#define uppercasify(str) \
+ do \
+ { \
+ char *tmp; \
+ for (tmp = (str); *tmp != '\0'; tmp++) \
+ if (islower (*tmp)) \
+ *tmp = toupper (*tmp); \
+ } \
+ while (0)
+
+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");
- if ((date[0]==0) && (date[1]==0))
- return("never");
-
- sys$asctim(0,&date_str,date,0);
- str[26]='\0';
+ sys$asctim (0, &date_str, date, 0);
+ str[26] = '\0';
- return(str);
+ return (str);
}
-
-/* EOF */
diff --git a/vmsify.c b/vmsify.c
index 35e30bd..8d242d7 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 ed7267b..ab88ac3 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 ab11d96..f187827 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 955f6d5..26ab1cb 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 4166d34..281c81c 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);
@@ -889,170 +890,224 @@ 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().
+ * Description:
+ * Create a command line buffer to pass to CreateProcess
+ *
+ * Returns: the buffer or NULL for failure
+ * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ...
+ * Otherwise: argv[0] argv[1] argv[2] ...
*
- * The caller should free the return value.
+ * Notes/Dependencies:
+ * CreateProcess does not take an argv, so this command creates a
+ * command line for the executable.
*/
-#define TRACE(x)
-static char *fix_command_line(char *args[])
+static char *
+make_command_line( char *shell_name, char *full_exec_path, char **argv)
{
- 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-- = '\\';
+ 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;
+
+ 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++;
+ }
+
+ argvi = argv;
+ while (*(argvi++)) argc++;
+
+ if (argc) {
+ enclose_in_quotes = (int*) calloc(1, argc * sizeof(int));
+
+ if (!enclose_in_quotes) {
+ return NULL;
+ }
+ }
- /* copy the string in reverse */
- while (p >= args[i]) {
- /* copy the character */
- *q-- = *p--;
+ /* 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.
+ */
- /*
- * Escape any double quote found. Also escape
- * each backslash preceding the double quote.
+ 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 ".
*/
- if (*(p+1) == '"') {
- *q-- = '\\';
- if (p >= args[i] && *p == '\\')
- while (p >= args[i] && *p == '\\')
- *q-- = *p--, *q-- = '\\';
- }
+ 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++;
- /* finish quoting arg, q now points to complete arg */
- *q = '"';
+ p++;
+ }
- /* 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);
+ 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++;
+ }
- /* separate arguments with spaces (if more args to gather) */
- if (args[i+1])
- *nargp++ = ' ';
- *nargp = '\0';
- } /* end for */
+ /*
+ * Add one for the terminating NULL.
+ */
+ bytes_required++;
- /* NULL terminate the arg list */
- *nargp = '\0';
+ command_line = (char*) malloc(bytes_required);
- return (narg);
-}
-#undef TRACE
+ if (!command_line) {
+ if (enclose_in_quotes) free(enclose_in_quotes);
+ return NULL;
+ }
-/*
- * Description:
- * Create a command line buffer to pass to CreateProcess
- *
- * Returns: the buffer or NULL for failure
- * Shell case: sh_name a:/full/path/to/script argv[1] argv[2] ...
- * Otherwise: argv[0] argv[1] argv[2] ...
- *
- * Notes/Dependencies:
- * CreateProcess does not take an argv, so this command creates a
- * command line for the executable.
- */
+ command_line_i = command_line;
-static char *
-make_command_line( char *shell_name, char *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 */
-
- /* 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;
+ if (shell_name && full_exec_path) {
+ while(*shell_name) {
+ *(command_line_i++) = *(shell_name++);
+ }
- /* create string suitable for CreateProcess() */
- buf = fix_command_line(nargv);
+ *(command_line_i++) = ' ';
- if (shell_name) {
- for (j = 0; shargv[j]; j++)
- free(shargv[j]);
- free(shargv);
- free(nargv);
+ while(*full_exec_path) {
+ *(command_line_i++) = *(full_exec_path++);
+ }
+
+ if (*argv) {
+ *(command_line_i++) = ' ';
+ }
}
-
- return buf;
+
+ 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;
}
/*