/* `make' recompile files as needed.
   Copyright (C) 1988 Free Software Foundation, Inc.

		       NO WARRANTY

  BECAUSE THIS PROGRAM IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY
NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW.  EXCEPT
WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC,
RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE THIS PROGRAM "AS IS"
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY
AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE PROGRAM PROVE
DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
CORRECTION.

 IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M.
STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY
WHO MAY MODIFY AND REDISTRIBUTE THIS PROGRAM AS PERMITTED BELOW, BE
LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR
OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR
DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR
A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) THIS
PROGRAM, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY.

		GENERAL PUBLIC LICENSE TO COPY

  1. You may copy and distribute verbatim copies of this source file
as you receive it, in any medium, provided that you conspicuously
and appropriately publish on each copy a valid copyright notice
"Copyright (C) 1988 Free Software Foundation, Inc.", and include
following the copyright notice a verbatim copy of the above disclaimer
of warranty and of this License.

  2. You may modify your copy or copies of this source file or
any portion of it, and copy and distribute such modifications under
the terms of Paragraph 1 above, provided that you also do the following:

    a) cause the modified files to carry prominent notices stating
    that you changed the files and the date of any change; and

    b) cause the whole of any work that you distribute or publish,
    that in whole or in part contains or is a derivative of this
    program or any part thereof, to be licensed at no charge to all
    third parties on terms identical to those contained in this
    License Agreement (except that you may choose to grant more extensive
    warranty protection to some or all third parties, at your option).

    c) You may charge a distribution fee for the physical act of
    transferring a copy, and you may at your option offer warranty
    protection in exchange for a fee.

Mere aggregation of another unrelated program with this program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other program under the scope of these terms.

  3. You may copy and distribute this program (or a portion or derivative
of it, under Paragraph 2) in object code or executable form under the terms
of Paragraphs 1 and 2 above provided that you also do one of the following:

    a) accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of
    Paragraphs 1 and 2 above; or,

    b) accompany it with a written offer, valid for at least three
    years, to give any third party free (except for a nominal
    shipping charge) a complete machine-readable copy of the
    corresponding source code, to be distributed under the terms of
    Paragraphs 1 and 2 above; or,

    c) accompany it with the information you received as to where the
    corresponding source code may be obtained.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form alone.)

For an executable file, complete source code means all the source code for
all modules it contains; but, as a special exception, it need not include
source code for modules which are standard libraries that accompany the
operating system on which the executable file runs.

  4. You may not copy, sublicense, distribute or transfer this program
except as expressly provided under this License Agreement.  Any attempt
otherwise to copy, sublicense, distribute or transfer this program is void and
your rights to use the program under this License agreement shall be
automatically terminated.  However, parties who have received computer
software programs from you with this License Agreement will not have
their licenses terminated so long as such parties remain in full compliance.

  5. If you wish to incorporate parts of this program into other free
programs whose distribution conditions are different, write to the Free
Software Foundation at 675 Mass Ave, Cambridge, MA 02139.  We have not yet
worked out a simple rule that can be stated here, but we will often permit
this.  We will be guided by the two goals of preserving the free status of
all derivatives of our free software and of promoting the sharing and reuse of
software.

 In other words, you are welcome to use, share and improve this program.
 You are forbidden to forbid anyone else to use, share and improve
 what you give them.   Help stamp out software-hoarding!  */

#if 0	/* dummy tags for etags */
endcopyr (){}
endcopyright (){}
endlicense (){}

sysv (){}
sun (){}
#endif

/* Sun/System V (Non-Berkeley) features:
 *
 * Whitespace and newlines in commands are left alone (not turned
 * into a single blank).
 *
 * Lines starting with "include" give the name, after whitespace,
 * of a makefile to be read in at that point.
 *
 * Macros are read in from the environment before
 * any other macro definitions. They are always overridden
 * by definitions from the command line and are overridden
 * by definitions in the makefiles unless the -e flag is given.
 * All macros (not just those from the environment) are placed
 * in the environment of each child (except for the special
 * macros $@, $<, etc.).
 *
 * The macro MAKEFLAGS from the environment is scanned for
 * all command-line options except -f, -p, -d and -c and
 * defined to contain all input options (except -f, -p and -d)
 * for sub-makes.
 *
 * The macro $% (and associated F and D forms, see below)
 * is set to the member name in archive references.
 * E.g.: For foo(bar), $@ = foo and $% = bar.
 *
 * The macros $@, $*, $< and $% have corresponding macros like $(@F)
 * and $(@D) that give just the filename and just the directory,
 * respectively.
 *
 * A macro of the form "$(FOO:BAR=UGH)" returns the value of macro "FOO"
 * with each "BAR" turned into an "UGH".
 *
 * A -b flag is accepted without complaint but does nothing.
 *
 * Implicit-rule suffixes may be null. E.g.: .c:; cc -o $@ $<
 * makes foo.c into foo.
 *
 * A file with a command line containing a reference to
 * the macro MAKE has its commands executed even if
 * -n, -q or -t is given.
 * (SysV itself only manages to do this in the -n case.)
 *
 * An implicit rule `.X.a:' tells how to make `foo(bar.o)'
 * from `bar.X' for any `foo' and any `bar'.
 *
 */

#if 0	/* dummy tag for etags */
bsd (){}
berkeley (){}
#endif

/* Berkeley (non-System V) features:
 *
 * Macro names may be delimited by curly braces {} as well
 * as by parenthesis ().
 *
 * If defined, the macro VPATH is a list of colon-separated
 * directories that will be searched for dependent files not
 * found in the current directory.
 *
 * MFLAGS is a synonym for MAKEFLAGS, with a `-' appended at the front.
 */

#if 0	/* dummy tags for etags */
gnu (){}
new (){}
#endif

/* New (GNU) (non-System V/Sun and non-Berkeley) features:
 *
 * The macro MAKEOVERRIDES is defined to contain each
 * macro definition given on the command line, with special characters
 * backslash-quoted.
 *
 * The command switch -c changes the current working directory
 * to the following argument before anything else is done.
 * These switches are read sequentially, i.e., -c / -c etc
 * is equivalent to -c /etc.  It is a fatal error for a
 * directory given with a -c switch to be unreachable (chdir(2) fails).
 * The main use of the -c switch is so that sub-makes
 * can avoid going through the shell by using "$(MAKE) -c dir ..."
 * rather than "cd dir; $(MAKE) ...".
 *
 * The command "define", which must be at the start of a line,
 * followed by a name, defines the macro with that name as all
 * the literal text until an "endef" at the beginning of a line.
 * The text is not interpreted or expanded in any way, except
 * for the removal of comments.
 *
 * Dependents of the special target ".PHONY" will never
 * be searched for as actual files and the -t (touch) flag
 * will never create them.
 * This is useful for targets such as "all" and "clean", etc.
 *
 * The following forms of string processing are done:
 * Perform search/replace      $(subst FROM,TO,TEXT)
 * Reexpand the value          $(expand TEXT)
 * Wildcard-expand the value       $(wildcard TEXT)
 * Append to each word	       $(addsuffix SUFFIX,TEXT)
 *  $(addsuffix .c,foo bar) produces `foo.c bar.c'
 * Prepend to each word	       $(addprefix PREFIX,TEXT)
 *  $(addprefix src/,foo.c bar.c) produces `src/foo.c src/bar.c'
 * Just directory	       $(dir TEXT)
 * Just filename within directory   $(notdir TEXT)
 * Just suffix                 $(suffix TEXT)
 * Just basename	       $(basename TEXT)
 * (The above four are done on whitespace-separated words as are
 * addsuffix and addprefix.)
 * In each case, the operands (TEXT, SUFFIX, etc.) are macroexpanded
 * individually before the specific function is applied.
 * Thus, $(subst x,y,$(foo)) is equivalent to $(foo:x=y) but
 * the latter form is kept for compatibility.
 *
 * Files given after the flag "-o" will be considered
 * very old (00:00:01.00 Jan 1, 1970) so they won't
 * cause anything to be remade.  Also, if they are targets,
 * they will not themselves be remade.
 *
 * A few primitive conditional commands are interpreted.
 * They all must begin at the start of a line and their
 * tokens are separated by spaces and/or tabs.
 * "ifdef MACRO" ignores the following text until a matching
 * "endif" or "else" iff MACRO is not defined or is null;
 * MACRO is terminated by whitespace or a comment.
 * "ifndef MACRO" ignores text until a matching "endif" or "else"
 * iff MACRO is defined and non-null.
 * "ifeq (s1, s2)" ignores text until a matching "endif" or "else"
 * iff S1 and S2 are not equal after macro expansion.
 * "ifneq" has the same syntax as "ifeq" with reversed meaning.
 * There is no way to escape the , or ) string terminators.
 * Text following an "else" after an "if" of some sort, up to a matching
 * "endif" is ignored iff the text after the "if" was not ignored.
 * Trailing whitespace and comments on conditional lines
 * is ignored, but any other text causes the line to be
 * treated as a normal target or macro definition.
 *
 * "include" commands may have more than just one space or tab
 * before the filename.  Included makefiles never determine
 * the default target.  There is a search path for
 * included makefiles which are not found in the current
 * directory and whose names do not begin with a slash.
 * Directories given after a -I flag will be put into
 * the path in the order given.  A few default directories
 * will be appended onto the (possibly empty) list after
 * all -I flags are read.
 *
 * Implicit rules that are patterns using % are supported.
 * Old-style suffix rules are converted internally to
 * pattern rules.
 * A target with a % in its name is identified as a pattern
 * rule.  Its dependents each may have a % in them which
 * will be replaced by the part of the filename
 * that matched the % in the target name (this part is
 * called the stem).  The $* macro contains the stem.
 * A pattern rule can be removed by re-declaring it
 * with no commands.
 *
 * The special macro $^ is set to all the dependents
 * of a target (not just out-of-date ones like $?).
 *
 * There is a complete set of default implicit rules using
 * all possible combinations of the suffixes .out, .a, .o, .s, .c, .f,
 * .p, .F, .e, .r, .y, .ye, .yr and .l.  Rules are ordered so that
 * .o files will be made directly from sources without going through
 * .s files at the level of Make.
 * There are also rules for RCS and SCCS (s.% -> %, SCCS/s.% -> %,
 * %,v -> % and RCS/%,v -> %).
 *
 * Implicit dependents are searched for as follows:
 *	- as generated
 *	- with an element of VPATH (and a slash) prepended
 * Example: VPATH = "src:foo", target "lib/x.o" searches for:
 *	- lib/x.c
 *	- src/lib/x.c
 *	- foo/lib/x.c
 *
 * Any filename starting with "./" will be treated as
 * if the "./" wasn't there (unless that's all there is).
 * For example, "./foo.c" is remembered as "foo.c", but
 * "./" is remembered as is.
 *
 * Dependent files of the form "-lxxx" that are not found
 * by the normal searching methods are searched for as
 * "libxxx.a" in /lib, /usr/lib, the current directory if
 * "." appears in the VPATH list, and each directory on
 * the VPATH list ("." is normally ignored in the VPATH list),
 * in that order.
 * The main uses of this are so that a macro can give
 * an object file (or a list of object files) or a library,
 * such as "GETOPT = getopt.o" vs "GETOPT = -lgetopt" vs "GETOPT = # in libc",
 * and so that linking commands can use the $^ macro and have it
 * include necessary libraries, e.g.:
 *	cursed: commands.o files.o -lcurses; cc $^ -o $@
 * The name is left as "-lxxx", not replaced by what it is found as,
 * it is assumed you can use LDFLAGS = $(addprefix -L,$(subst :,,$(VPATH))).
 *
 * Suffixes for implicit rules do not need to begin with
 * a dot and may contain slashes. Their only requirement is
 * that they be dependents of .SUFFIXES.
 *
 * The macro MAKELEVEL is read from the environment to determine the
 * number of recursive makes and is incremented for each child marked
 * recursive. This macro may be changed, but its value is stored
 * internally before the command-line and makefile macros are read
 * so the only way to fool sub-makes is to manipulate their environments
 * directly.
 *
 * The macro/envariable "SHFLAGS" specifies flags to be
 * given to the shell before the "-c command".
 * SHELL and SHFLAGS are not accepted from the environment
 * if MAKELEVEL is 0.
 *
 * The macro MAKE is set to the name Make is invoked with (argv[0]).
 *
 * If set, the envariable (macro) MAKEFILES contains a whitespace-separated
 * list of files to be read in before any other makefiles.
 * It is not an error for any of these files to not exist and they
 * will never determine the default goal file.  If not found in
 * the current directory, the makefiles are searched for using the
 * same path used for included makefiles.
 * 
 * Simple commands are executed without forking a shell.
 * Quoting via ' is handled but all other special characters
 * and built-in commands are looked for and a shell is forked
 * if any are found.  A shell is always forked if SHELL is
 * not "/bin/sh" or if IFS contains other than space, tab and newline.
 *
 * Bourne shell style macros using - and + are supported.
 * $(a-b) is $(a) if set, else b.  $(a+b) is b if a is set,
 * else null ("").  $(a+b-c) is b if a is set, else c.
 *
 * Implicit dependents which require an intermediate
 * file can sometimes work.
 * The the created intermediate files are kept in
 * a list and all removed when Make exits (or is killed).
 * If the name of the intermediate file as it appears
 * in the rule dependency list (with % embedded) is
 * marked as precious by being a dependent of the
 * special target .PRECIOUS, the intermediate file
 * will never be deleted.
 */

#if 0	/* dummy tag for etags  */
missing (){}
#endif

/* Missing Berkeley/System V features:
 *
 * Names of the form a((b)) are not supported.
 *
 * SCCS implicit rules (using tildes in suffixes)
 * are not supported, however they are replaced by
 * the more general pattern-rule feature (see above).
 */

#if 0	/* dummy tag for etags  */
flags (){}
#endif

/* Flags:
 *	-b compatability (no-op here)
 *	-c change directory
 *	-d debug
 *	-e env_overrides
 *	-f makefile
 *	-i ignore_errors
 *	-k keep_going
 *	-m unknown standard meaning, so we ignore it.
 *	-n just_print
 *	-o consider file old
 *	-p print_data_base
 *	-q question
 *	-r no_builtin_rules
 *	-s silent
 *	-S turn off -k
 *	-t touch
 *	-w log working directory.
 */

#if 0	/* dummy tag for etags */
definitions (){}
declarations (){}
#endif

#include <signal.h>
#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/file.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>

/* We record the status of a command that got a signal
   as 128 plus the signal number.  */
#define SIGNAL_STATUS 128

#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define streq(a, b) \
  ((a) == (b) || (*(a) == *(b) && (!*(a) || !strcmp ((a) + 1, (b) + 1))))
#define file_mtime(f) ((f)->last_mtime != 0 ? (f)->last_mtime : f_mtime (f))
#define initbuffer(lb) (lb)->buffer = (char *) xmalloc ((lb)->size = 200)
#define freebuffer(lb) free ((lb)->buffer)

/* A `struct linebuffer' is a structure which holds a line of text.
   `readline' reads a line from a stream into a linebuffer
   and works regardless of the length of the line.  */

struct linebuffer
  {
    /* Note:  This is the number of bytes malloc'ed for `buffer'
       It does not indicate `buffer's real length.
       Instead, a losing C asciz null-byte indicates end-of-string */
    long size;
    char *buffer;
  };

/* Nonzero => file to delete if fatal signal happens.
   While actually running shell commands, this is their target.  */

char *signal_delete_file;

/* But only delete the file if it has been changed;
   that is, its mtime is not the same as this.  */

int signal_delete_mtime;

/* When set by the presence of "." in the VPATH list,
   implicit dependents with paths of their own are searched
   for by their basenames in the current directory.  */

int search_cwd;

/* The filename and pointer to line number of the
   makefile currently being read in.  */

char *reading_filename;
long *reading_lineno_ptr;

/* Structure that gives the commands to make a file
   and information about where these commands came from.  */

struct commands
  {
    char *filename;		/* file that contains commands */
    long lineno;		/* line number in file */
    char *commands;		/* commands text */
  };

/* Structure that represents the info on one file
   that the makefile says how to make.
   All of these are chained together through `next'.  */

struct file
  {
    struct file *next;
    char *name;
    struct dep *deps;
    struct commands *cmds;	/* Commands to execute for this target */
    char *stem;			/* common stem, if implicit
    				   rule has been used */
    int update_status;		/* Status of last attempt to update,
				   or -1 if none made.  */
    int last_mtime;		/* File's modtime, if already known.  */
    struct file *prev;		/* Previous entry for same file name;
				   used when there are multiple double-colon
				   entries for the same file.  */
    char double_colon;		/* Nonzero for double-colon entry */
    char precious;		/* Non-0 means don't delete this file on quit */
    char recursive;		/* Non-0 means do file's commands
    				   even if -q or -t or -n.  */
    char tried_implicit;	/* Nonzero if have searched for implicit rule
				   for making this file; don't search again */
    char updating;		/* Nonzero while updating deps of this file.  */
    char updated;		/* Nonzero if this file has been remade.  */
    char is_target;		/* Nonzero if file is described as target */
    char phony;			/* Nonzero if this is a phony file
				   ie, a dependent of .PHONY.  */
    char intermediate;		/* Nonzero if this is an intermediate file.  */
  };

/* Number of intermediate files entered.  */

int num_intermediates;

/* Hash table of files the makefile knows how to make.  */

#define FILE_BUCKETS	53
struct file *files[FILE_BUCKETS];

/* Hash table of files in the various directories.
   This makes file_exists_p faster for files in these directories.  */

struct dirdata
{
  struct dirdata *next;
  char *dir;			/* Name of directory */
  char *name;			/* Name of file in the directory */
  int impossible;		/* This file is impossible */
};

#define DIR_HASH_SIZE 1007

struct dirdata *dir_hash_table[DIR_HASH_SIZE];

/* Structure used for pattern rules.  */

struct rule
  {
    struct rule *next;
    char *name;			/* Name (target) of the rule  */
    int namelen;		/* Length of that string; to save time */
    char *patsuffix;		/* Pointer to char after %  */
    struct dep *deps;		/* Dependents of the rule  */
    struct commands *cmds;	/* Commands to execute  */
    char recursive;		/* If commands contain "$(MAKE)"  */
    char terminal;		/* If terminal (double colon)  */
    char subdir;		/* If references nonexistent subdirectory  */
    char in_use;		/* If in use by a parent pattern_search  */
  };

/* Chain of all pattern rules.  */

struct rule *pattern_rules;

/* Last rule in the chain, so we can add at the end.  */

struct rule *last_pattern_rule;

/* The following three are computed by count_implicit_rule_limits.  */

/* Number of pattern rules defined.  */

int num_pattern_rules;

/* Maximum number of dependencies of any pattern rule.  */

int max_pattern_deps;

/* Maximum length of any dependency of any pattern rule.  */

int max_pattern_dep_length;

/* Incremented when we find a file needs to be remade,
   even if it has no commands or if we are not really executing commands.  */

int files_remade;

/* Structure representing one dependency of a file.
   Each struct file's `deps' points to a chain of these,
   chained through the `next'.

   Note that the first three words of this match a struct nameseq.  */

struct dep
  {
    struct dep *next;
    char *name;
    int quotedparen;
    struct file *file;
    int changed;
  };

/* Structure used in chains of names, for parsing and globbing */

struct nameseq
  {
    struct nameseq *next;
    char *name;
    int quotedparen;
  };

/* First file defined in the makefile whose name does not
   start with `.'.  This is the default to remake if the
   command line does not specify.  */

struct file *default_goal_file;

/* Pointer to structure for the file .SUFFIXES
   whose dependencies are the suffixes to be searched.  */

struct file *suffix_file;

/* Maximum length of a suffix.  */

int maxsuffix;

/* Pointer to structure for the file .DEFAULT
   whose commands are used for any file that has none of its own.
   This is zero if the makefiles do not define .DEFAULT.  */

struct file *default_file;

/* Pointer to the structure for the file .PRECIOUS,
   being depended onby which means that a target should not be
   deleted if its commands are interrupted.  */

struct file *precious_file;

/* Codes in a macro definition saying where the definition came from.
   Increasing numeric values signify less-overridable definitions.  */
enum macro_origin
  {
    o_env,	/* Macro from environment.  */
    o_file,	/* Macro given in a makefile.  */
    o_env_override, /* Macro from environment, if -e.  */
    o_command,	/* Macro given by user.  */
    o_override, /* Macro from an `override' directive in a makefile.  */
  };

/* Structure that represents one macro definition.
   Each bucket of the hash table `macros' is a chain of these,
   chained through `next'.  */

struct macro
  {
    struct macro *next;
    char *name;
    char *value;
    enum macro_origin origin;
  };

/* Hash table of all macro definitions.  */

#define MACRO_BUCKETS	43
struct macro *macros[MACRO_BUCKETS];

/* Pointers to struct macro's for the built-in macros,
   $*, $@, $<, $% and their F and D pairs, $^ and $?, and $($@) and $($/).   */

struct macro *star_macro, *starF_macro, *starD_macro;
struct macro *at_macro, *atF_macro, *atD_macro;
struct macro *less_macro, *lessF_macro, *lessD_macro;
struct macro *percent_macro, *percentF_macro, *percentD_macro;
struct macro *caret_macro, *qmark_macro;
struct macro *dollar_at_macro, *dollar_slash_macro;

/* Pointer to struct macro for SHELL.  So we can look up the value fast.  */

struct macro *shell_macro;

/* Pointer to struct macro for SHFLAGS (flags for SHELL).  */

struct macro *shflags_macro;

/* Pointer to struct macro for IFS (sh internal field separator).  */

struct macro *ifs_macro;

/* Value of the MAKELEVEL macro at startup (or 0).  */

int makelevel;

/* The next two describe the macro output buffer.
   This buffer is used to hold the macro-expansion of a line of the makefile.
   It is made bigger with realloc whenever it is too small.
   macro_buffer_length is the size currently allocated.
   macro_buffer is the address of the buffer.  */

int macro_buffer_length;
char *macro_buffer;

/* Values of command-line options.  */
   
/* Nonzero means do not print commands to be executed (-s).  */

int silent_flag;

/* Nonzero means just touch the files
   that would appear to need remaking (-t)  */

int touch_flag;

/* Nonzero means just print what commands would need to be executed,
   don't actually execute them (-n).  */

int just_print_flag;

/* Print debugging trace info (-d).  */

int debug_flag;

/* Environment macros override makefile definitions.  */

int env_overrides;

/* Nonzero means ignore status codes returned by commands
   executed to remake files.  Just treat them all as successful (-i).  */

int ignore_errors_flag;

/* Nonzero means don't remake anything, just print the data base
   that results from reading the makefile (-p).  */

int print_data_base_flag;

/* Nonzero means don't remake anything; just return a nonzero status
   if the specified targets are not up to date (-q).  */

int question_flag;

/* Nonzero means do not use any of the builtin rules (-r).  */

int no_builtin_rules_flag;

/* Nonzero means keep going even if remaking some file fails (-k).  */

int keep_going_flag;

/* Nonzero means print working directory before starting and after
   finishing make. */

int print_directory_flag;


/* Forward declarations */

struct macro *define_macro ();
struct macro *lookup_macro ();
char *macro_expand ();
char *macro_buffer_output ();
int try_macro_definition ();
long do_define ();
struct file *enter_file ();
struct file *lookup_file ();
int update_file ();
long readline ();
void print_spaces ();
int f_mtime (), name_mtime ();
int vpath_search (), library_file_mtime ();
char *savestring (), *concat ();
char *xmalloc (), *xrealloc ();
char *alloca ();
char *sindex (), *lindex (), *wstok ();
char *string_glob ();
char *end_of_token (), *next_token (), *find_next_token ();
void new_environ ();
void fatal (), error (), perror_with_name (), pfatal_with_name ();
struct nameseq *parse_file_seq ();
struct nameseq *multi_glob ();
void decode_switches ();
void define_automatic_macros ();
void print_data_base ();
void read_all_makefiles ();
struct dep *copy_dep_chain ();
int conditional_line ();
void snap_deps ();
void construct_vpath_list ();
void construct_include_path ();
void dir_load ();
void file_impossible ();
int file_impossible_p ();
void convert_to_pattern ();
void new_pattern_rule ();
void install_pattern_rule ();
void count_implicit_rule_limits ();
int pattern_search ();

int update_file_1 (), execute_file_commands (), try_implicit_rule ();
int run_shell_command (), execute_command_line ();
int ar_touch (), ar_scan_1 ();
extern int ar_scan (), ar_member_touch ();

/* Data base of implicit rules */

/* For calling install_pattern_rule.  */
struct pspec {char *target, *dep, *commands;};

char *default_suffixes = ".out .a .o .c .y .ye .yr .l .F .e .r .f .p .h .s";

char *default_vpath = 0;

char *default_pattern_rules[] =
  {
    "(%)", "%",
    "ar r $@ $<",

    /* RCS  */
    "%", "%,v",
    "$(CO) $(COFLAGS) $<",
    "%", "RCS/%,v",
    "$(CO) $(COFLAGS) $<",

    /* SCCS  */
    "%", "s.%",
    "$(GET) $(GFLAGS) $<",
    "%", "SCCS/s.%",
    "$(GET) $(GFLAGS) $<",

    /* The X.out rules are only in BSD's default set because
       BSD Make has no null-suffix rules, so foo.out and
       foo are the same thing.  */
    "%.out", "%",
    "@rm -f $@ \n cp $< $@",

    /* For libraries, so they won't get ranlib'd unnecessarily.  */
    "%(__.SYMDEF)", "%",
    "$(RANLIB) $<",

    0
  };

char *default_suffix_rules[] =
  {
    ".o",
    "$(CC) $(LDFLAGS) $^ $(LOADLIBES) -o $@",
    ".c",
    "$(CC) $(CFLAGS) $(LDFLAGS) $^ $(LOADLIBES) -o $@",
    ".f",
    "$(FC) $(FFLAGS) $(LDFLAGS) $^ $(LOADLIBES) -o $@",
    ".p",
    "$(PC) $(PFLAGS) $(LDFLAGS) $^ $(LOADLIBES) -o $@",
    ".F",
    "$(FC) $(FFLAGS) $(LDFLAGS) $^ $(LOADLIBES) -o $@",
    ".e",
    "$(FC) $(FFLAGS) $(LDFLAGS) $^ $(LOADLIBES) -o $@",
    ".r",
    "$(FC) $(FFLAGS) $(LDFLAGS) $^ $(LOADLIBES) -o $@",
    ".s",
    "$(CC) $(ASFLAGS) $(LDFLAGS) $^ $(LOADLIBES) -o $@",

    ".c.o",
    "$(CC) $(CFLAGS) -c $< -o $@",
    ".f.o",
    "$(FC) $(FFLAGS) -c $< -o $@",
    ".p.o",
    "$(PC) $(PFLAGS) -c $< -o $@",
    ".F.o",
    "$(FC) $(FFLAGS) -c $< -o $@",
    ".e.o",
    "$(EC) $(EFLAGS) -c $< -o $@",
    ".r.o",
    "$(RC) $(RFLAGS) -c $< -o $@",
    ".s.o",
    "$(AS) $(ASFLAGS) $< -o $@",

    ".c.s",
    "$(CC) (CFLAGS) -S $< -o $@",
    ".f.s",
    "$(FC) (FFLAGS) -S $< -o $@",
    ".p.s",
    "$(PC) (PFLAGS) -S $< -o $@",
    ".F.s",
    "$(FC) (FFLAGS) -S $< -o $@",
    ".e.s",
    "$(EC) (EFLAGS) -S $< -o $@",
    ".r.s",
    "$(RC) (RFLAGS) -S $< -o $@",

    ".y.c",
    "$(YACC) $(YFLAGS) $< \n mv -f y.tab.c $@",
    ".l.c",
    "$(LEX) $(LFLAGS) $< \n mv -f lex.yy.c $@",

    ".F.f",
    "$(FC) $(FFLAGS) -F $< -o $@",
    ".e.f",
    "$(EC) $(EFLAGS) -F $< -o $@",
    ".r.f",
    "$(RC) $(RFLAGS) -F $< -o $@",

    ".ye.e",
    "$(YACCE) $(YFLAGS) $< \n mv -f y.tab.e $@",

    ".yr.r",
    "$(YACCR) $(YFLAGS) $< \n mv -f y.tab.r $@",
    /* This might actually make lex.yy.c if there's no %R%
       directive in $*.l, but in that case why were you
       trying to make $*.r anyway?  */
    ".l.r",
    "$(LEX) $(LFLAGS) $< \n mv -f lex.yy.r $@",

    0
  };

char *default_macros[] =
  {
    "AS", "as",
    "CC", "cc",
    "CO", "co",
    "EC", "f77",
    "FC", "f77",
    "GET", "get",
    "LEX", "lex",
    "RANLIB", "ranlib",
    "RC", "f77",
    "PC", "pc",
    "YACC", "yacc",
    "YACCE", "yacc -e",
    "YACCR", "yacc -r",
    0
  };

/* Default directories to search for include files in  */

char *default_include_directories[] =
  {
    "/usr/gnu/include",
    "/usr/local/include",
    "/usr/include",
    0
  };

/* List of directories to search for include files in  */

char **include_directories;

/* Maximum length of an element of the above.  */

int max_incl_len;

#if 0	/* dummy tag for etags	*/
code (){}
#endif

/* Handle bus errors, illegal instruction, etc. */
fatal_error_signal (sig)
     int sig;
{
  struct stat st;

  signal (sig, SIG_DFL);
  sigsetmask (0);

  /* Don't die until our children have finished dying.  */
  while (wait (0) != -1)
    ;

  /* If we have specified a file to delete for this moment,
     and it exists and is not a directory, delete it.  */

  if (signal_delete_file
      && stat (signal_delete_file, &st) >= 0
      && (st.st_mode & S_IFMT) != S_IFDIR
      && st.st_mtime != signal_delete_mtime)
    {
      fprintf (stderr, "\nDeleting file %s\n", signal_delete_file);
      fflush (stderr);
      unlink (signal_delete_file);
    }

  /* Delete any non-precious intermediate files that were made.  */

  if (num_intermediates > 0)
    {
      register int i;
      register struct file *f;

      /* Examine each `struct file' in the hash table.  */
      for (i = 0; i < FILE_BUCKETS; ++i)
	for (f = files[i]; f; f = f->next)
	  if (f->intermediate && !f->precious && f->updated)
	    {
	      fprintf (stderr, "Deleting file %s\n", f->name);
	      fflush (stderr);
	      if (!just_print_flag)
		unlink (f->name);
	    }
    }

  /* Signal the same code; this time it will really be fatal.  */
  kill (getpid (), sig);
  /* It shouldn't return, but if it does, die anyway.  */
  pfatal_with_name ("kill");
}

int
main (argc, argv, envp)
     int argc;
     char **argv;
     char **envp;
{
  register struct file *f;
  register int i;
  int num_remade = 0;
  int status = 0;
  int this_status;
  register char *cmd_defs;
  register int cmd_defs_len, cmd_defs_idx;

  bzero (files, sizeof files);
  bzero (macros, sizeof macros);
  bzero (dir_hash_table, sizeof dir_hash_table);

  files_remade = 0;
  macro_buffer = 0;
  default_goal_file = 0;
  signal_delete_file = 0;
  signal_delete_mtime = 0;
  search_cwd = 0;
  reading_filename = 0;
  reading_lineno_ptr = 0;
  num_intermediates = 0;

  signal (SIGHUP, fatal_error_signal);
  signal (SIGQUIT, fatal_error_signal);
  signal (SIGINT, fatal_error_signal);
  signal (SIGILL, fatal_error_signal);
  signal (SIGTRAP, fatal_error_signal);
  signal (SIGIOT, fatal_error_signal);
  signal (SIGEMT, fatal_error_signal);
  signal (SIGFPE, fatal_error_signal);
  signal (SIGBUS, fatal_error_signal);
  signal (SIGSEGV, fatal_error_signal);
  signal (SIGSYS, fatal_error_signal);
  signal (SIGTERM, fatal_error_signal);
#ifdef SIGXCPU
  signal (SIGXCPU, fatal_error_signal);
#endif
#ifdef SIGXFSZ
  signal (SIGXFSZ, fatal_error_signal);
#endif

  /* Search for command line arguments that define macros,
     and do the definitions.  Also save up the text of these
     arguments in CMD_DEFS so we can put them into the values
     of $(MAKEOVERRIDES) and $(MAKE).  */
  
  cmd_defs_len = 100;
  cmd_defs = (char *) xmalloc (cmd_defs_len);
  cmd_defs_idx = 0;

  for (i = 1; i < argc; i++)
    {
      /* Don't even try an arg that is a switch.  */
      if (!strcmp (argv[i], "-f") || !strcmp (argv[i], "-o"))
	i++;
      else if (argv[i][0] != '-')
	{
	  /* It's not a switch; try it as a macro definition.  */
	  if (try_macro_definition (argv[i], o_command))
	    {
	      /* It succeeded.  The macro is already defined.
		 Backslash-quotify it and append it to CMD_DEFS,
		 then clobber it to `-' in ARGV
		 so that it won't be taken for a goal target.  */
	      register char *p = argv[i];
	      int l = strlen(p);
	      if (cmd_defs_len - ((l * 2) + 1) < 0)
		{
		  cmd_defs_len += l * 2;
		  cmd_defs = (char *) xrealloc (cmd_defs, cmd_defs_len);
		}
	      while (*p)
		{
		  if (index ("'\"*?[]$<>(){}|&~`\\ \t\r\n\f\v", *p))
		    cmd_defs[cmd_defs_idx++] = '\\';
		  cmd_defs[cmd_defs_idx++] = *p++;
		}
	      cmd_defs[cmd_defs_idx++] = ' ';
	      argv[i] = "-";
	    }
	}
    }

  if (cmd_defs_idx > 0)
    {
      cmd_defs[cmd_defs_idx] = '\0';
      define_macro ("MAKEOVERRIDES", 13, cmd_defs, o_override);
    }

  /* Set the "MAKE" macro to the name we were invoked with.
     (If it is a relative pathname with a slash, append our directory name
     so the result will run the same program regardless of current dir.
     If it is a name with no slash, we can only hope that PATH did not
     find it in the current directory.)

     Append at the end the command-line macro definitions gathered above
     so sub-makes get them as command-line definitions.  */

  if (argv[0][0] != '/' && index (argv[0], '/'))
    {
      char dir[MAXPATHLEN];
      char *str = concat (getwd (dir), "/", argv[0]);
      if (cmd_defs_idx > 0)
	{
	  char *s = concat (str, " ", cmd_defs);
	  free (str);
	  str = s;
	}
      define_macro ("MAKE", 4, str, o_env);
      free (str);
    }
  else if (cmd_defs_idx > 0)
    {
      char *str = concat (argv[0], " ", cmd_defs);
      define_macro ("MAKE", 4, str, o_env);
      free (str);
    }
  else
    define_macro ("MAKE", 4, argv[0], o_env);

  free (cmd_defs);

  /* Read in macros from the environment.  */

  for (i = 0; envp[i]; ++i)
    {
      register char *ep = envp[i];
      while (*ep++ != '=')
	;
      define_macro (envp[i], ep - envp[i] - 1, ep,
		    env_overrides ? o_env_override : o_env);
    }

  /* Decode the switches now */

  decode_switches (argc, argv);

  /* Parse any -c flags and move ourselves about.  */

  for (i = 1; i < argc; ++i)
    if (!strcmp (argv[i], "-c"))
      {
	++i;
	if (i >= argc)
	  fatal ("no directory given after -c command switch");
	if (chdir (argv[i]) < 0)
	  pfatal_with_name (argv[i]);
      }

  /* Now that we know the default directory, hash its contents.  */

  if (print_directory_flag)
    log_working_directory ("Entering");
  
  dir_load (".");

  /* Define the initial list of suffixes for old-style rules.  */

  pattern_rules = 0;
  last_pattern_rule = 0;

  suffix_file = enter_file (".SUFFIXES");

  if (!no_builtin_rules_flag)
    {
      char *ptr;
      char **p1;

      ptr = default_suffixes;
      /* Why do multi-glob here?  None of the suffixes contains *.
	 But multi-glob is easiest way of reversing the chain.  */
      suffix_file->deps
	= (struct dep *) multi_glob (parse_file_seq (&ptr, 0,
						     sizeof (struct dep)),
				     "", sizeof (struct dep));

      /* Enter the suffix rules as files.  */
      for (p1 = default_suffix_rules; *p1;)
	{
	  struct file *f = enter_file (*p1++);
	  f->cmds = (struct commands *) xmalloc (sizeof (struct commands));
	  f->cmds->commands = *p1++;
	  f->cmds->filename = 0;
	  f->cmds->lineno = 0;
	}

      /* Install the default macro definitions (CC, etc.)  */
      for (p1 = default_macros; *p1;)
	{
	  char *name = *p1++;
	  define_macro (name, strlen (name), *p1++, o_file);
	}
    }

  /* Define some internal and special macros.  */

  define_automatic_macros ();

  /* Read all the specified or default makefiles */

  read_all_makefiles (argc, argv);

  ignore_errors_flag = ignore_errors_flag || lookup_file (".IGNORE");

  silent_flag = silent_flag || lookup_file (".SILENT");

  default_file = lookup_file (".DEFAULT");

  /* Mark files given with -o flags as very old (00:00:01.00 Jan 1, 1970)
     and as having been updated already.  */

  for (i = 1; i < argc; ++i)
    if (argv[i][0] == '-' && argv[i][1] == 'o' && !argv[i][2])
      {
	struct file *f;
	++i;
	if (i >= argc)
	  fatal ("no file name given after -o flag", 0);
	f = enter_file (argv[i]);
	f->last_mtime = 1;
	f->updated = 1;
	f->update_status = 0;
      }

  /* Make each `struct dep' point at the `struct file'
     for the file depended on.  */

  snap_deps ();

  /* Install the default pattern rules.  */

  if (!no_builtin_rules_flag)
    {
      struct pspec *p;
      /* Install the default pattern rules.  */
      for (p = (struct pspec *) default_pattern_rules; p->target; ++p)
	install_pattern_rule (p, 0);
    }

  /* Convert old-style suffix rules to pattern rules.  */

  convert_to_pattern ();

  /* Compute max dep length and max # deps of any implicit rule.  */

  count_implicit_rule_limits ();

  /* Construct the listing of directories in the VPATH macro.  */

  construct_vpath_list ();

  /* Construct the list of include directories to search.  */

  construct_include_path (argc, argv);

  if (print_data_base_flag)
    print_data_base ();

  /* Search command line for files to remake.  */

  for (i = 1; i < argc; i++)
    {
      /* Anything not a switch or an argument of a switch
	 is a file to be remade.
	 Note that macro definition args were replaced with
	 dummies that look like switches.  */
      if (!strcmp (argv[i], "-f") || !strcmp (argv[i], "-c")
          || !strcmp (argv[i], "-o") || !strcmp (argv[i], "-I"))
	++i;
      else if (argv[i][0] != '-')
	{
	  f = enter_file (argv[i]);
	  num_remade++;
	  this_status = update_file (f, 0);
	  if (this_status)
	    {
	      status = this_status;
	      if (!keep_going_flag)
		break;
	    }
	}
    }

  /* Command line did not specify any file to remake => use default.  */

  if (!num_remade)
    {
      if (default_goal_file)
	status = update_file (default_goal_file, 0);
      else
	fatal ("no target");
    }

  /* Remove the intermediate files.  */

  if (num_intermediates > 0)
    for (i = 0; i < FILE_BUCKETS; ++i)
      {
	register struct file *f;
	for (f = files[i]; f; f = f->next)
	  if (f->intermediate && !f->precious && f->updated)
	    {
	      if (!silent_flag)
		printf ("rm -f %s\n", f->name);
	      if (!just_print_flag)
		unlink (f->name);
	    }
      }
  if (print_directory_flag)
    log_working_directory("Exiting");
  
  return (status);
}

void
decode_switches (argc, argv)
     int argc;
     char **argv;
{
  register int i;
  register char *sw;
  char keptflag;
  void decode_env_switches ();

  debug_flag = 0;
  env_overrides = 0;
  ignore_errors_flag = 0;
  keep_going_flag = 0;
  just_print_flag = 0;
  print_data_base_flag = 0;
  question_flag = 0;
  no_builtin_rules_flag = 0;
  silent_flag = 0;
  touch_flag = 0;
  print_directory_flag = 0;
  
  decode_env_switches ("MAKEFLAGS", 9);
  decode_env_switches ("MFLAGS", 5);

  for (i = 1; i < argc; i++)
    {
      keptflag = 0;
      sw = argv[i];
      if (*sw++ == '-')
	while (*sw)
	  switch (*sw++)
	    {
	    case 'b':
	    case 'm':
	      break;
	    case 'c':
	      keptflag = 'c';
	      break;
	    case 'd':
	      debug_flag = 1;
	      break;
	    case 'e':
	      env_overrides = 1;
	      break;
	    case 'f':
	      keptflag = 'f';
	      break;
	    case 'I':
	      keptflag = 'I';
	      break;
	    case 'i':
	      ignore_errors_flag = 1;
	      break;
	    case 'k':
	      keep_going_flag = 1;
	      break;
	    case 'n':
	      just_print_flag = 1;
	      break;
	    case 'o':
	      keptflag = 'o';
	      break;
	    case 'p':
	      print_data_base_flag = 1;
	      break;
	    case 'q':
	      question_flag = 1;
	      break;
	    case 'r':
	      no_builtin_rules_flag = 1;
	      break;
	    case 's':
	      silent_flag = 1;
	      break;
	    case 'S':
	      keep_going_flag = 0;
	      break;
	    case 't':
	      touch_flag = 1;
	      break;
	    case 'w':
	      print_directory_flag = 1;
	      break;
	    default:
	      fatal ("unknown switch: %c", sw[-1]);
	    }
      if (keptflag != '\0')
	{
	  argv[i][1] = keptflag;
	  argv[i][2] = '\0';
	}
    }
}

void
decode_env_switches (envar, len)
     char *envar;
     int len;
{
  struct macro *m;
  register char *args;

  m = lookup_macro (envar, len);
  if (!m || !*m->value)
    return;

  args = m->value;
  while (*args)
    switch (*args++)
      {
      case 'e':
	env_overrides = 1;
        break;
      case 'i':
	ignore_errors_flag = 1;
        break;
      case 'k':
	keep_going_flag = 1;
        break;
      case 'n':
	just_print_flag = 1;
        break;
      case 'q':
	question_flag = 1;
        break;
      case 'r':
	no_builtin_rules_flag = 1;
        break;
      case 's':
	silent_flag = 1;
        break;
      case 't':
	touch_flag = 1;
        break;
      }

  return;
}

/* Implement macros.  */

/* Define macro named NAME with value VALUE.  VALUE is copied.
   LENGTH is the length of NAME, which does not
   need to be null-terminated.
   ORIGIN specifies the origin of the macro (makefile, command line
   or environment).  */

struct macro *
define_macro (name, length, value, origin)
     char *name, *value;
     int length;
     enum macro_origin origin;
{
  register struct macro *m;
  register int i;
  register int hashval = 0;

  for (i = 0; i < length; ++i)
    hashval += name[i];
  hashval %= MACRO_BUCKETS;

  for (m = macros[hashval]; m; m = m->next)
    if (*m->name == *name
        && !strncmp (m->name + 1, name + 1, length - 1) && !m->name[length])
      break;

  if (m)
    {
      /* A macro of this name is already defined.
	 If the old definition is from a stronger source than this one,
	 don't redefine.  */
      if ((int) origin >= (int) m->origin)
	{
	  m->value = savestring (value, strlen (value));
	  m->origin = origin;
	}
      return m;
    }

  /* Create a new macro definition and add to hash table.  */

  m = (struct macro *) xmalloc (sizeof (struct macro));
  m->name = savestring (name, length);
  m->value = savestring (value, strlen (value));
  m->origin = origin;
  m->next = macros[hashval];
  return (macros[hashval] = m);
}

/* Lookup a macro whose name is a string starting at NAME
   and with LENGTH chars.  NAME need not be null-terminated.
   Returns address of the `struct macro' containing all info on the macro,
   or 0 if no such macro is defined.  */

struct macro *
lookup_macro (name, length)
     char *name;
     int length;
{
  register struct macro *m;
  register int i;
  register int hashval = 0;

  for (i = 0; i < length; ++i)
    hashval += name[i];
  hashval %= MACRO_BUCKETS;

  for (m = macros[hashval]; m; m = m->next)
    if (*m->name == *name
        && !strncmp (m->name + 1, name + 1, length - 1)
	&& m->name[length] == 0)
      return m;

  return 0;
}

/* Define the automatic macros, and record the addresses
   of their structures so we can change their values quickly.  */

void
define_automatic_macros ()
{
  char mflags[100];	/* 100 is more than # of distinct option letters */
  register int i;
  register struct macro *m;

  star_macro = define_macro ("*", 1, "", o_override);
  starF_macro = define_macro ("*F", 2, "", o_override);
  starD_macro = define_macro ("*D", 2, "", o_override);
  at_macro = define_macro ("@", 1, "", o_override);
  atF_macro = define_macro ("@F", 2, "", o_override);
  atD_macro = define_macro ("@D", 2, "", o_override);
  less_macro = define_macro ("<", 1, "", o_override);
  lessF_macro = define_macro ("<F", 2, "", o_override);
  lessD_macro = define_macro ("<D", 2, "", o_override);
  percent_macro = define_macro ("%", 1, "", o_override);
  percentF_macro = define_macro ("%F", 2, "", o_override);
  percentD_macro = define_macro ("%D", 2, "", o_override);
  qmark_macro = define_macro ("?", 1, "", o_override);
  caret_macro = define_macro ("^", 1, "", o_override);
  dollar_at_macro = define_macro ("$@", 2, "", o_override);
  dollar_slash_macro = define_macro ("$/", 1, "", o_override);

  if (default_vpath && !lookup_macro ("VPATH", 5))
    define_macro ("VPATH", 5, macro_expand (default_vpath), o_file);

  m = lookup_macro ("MAKELEVEL", 9);
  if (m && m->value)
    makelevel = atoi (m->value);
  else
    makelevel = 0;

  shflags_macro = lookup_macro ("SHFLAGS", 7);
  if (!shflags_macro)
    shflags_macro = define_macro ("SHFLAGS", 7, "", o_file);

  shell_macro = lookup_macro ("SHELL", 5);
  if (!shell_macro)
    shell_macro = define_macro ("SHELL", 5, "/bin/sh", o_file);

  /* Don't let SHELL or SHFLAGS come from the environment
     if MAKELEVEL is 0.  Also, SHELL must not be empty.  */
  if (!*shell_macro->value
      || (shell_macro->origin == o_env && makelevel == 0))
    {
      shell_macro->origin = o_file;
      shell_macro->value = savestring ("/bin/sh", 7);
    }

  if (shflags_macro->origin == o_env && makelevel == 0)
    {
      shflags_macro->origin = o_file;
      shflags_macro->value = savestring (0, 0);
    }

  ifs_macro = lookup_macro ("IFS", 3);

  /* Define the built-in macro MAKEFLAGS to contain the command line switches.
     We can ignore here those switches that cause commands from the
     makefile not to be run.  */

  i = 0;
  mflags[i++] = '-';
  if (env_overrides) mflags[i++] = 'e';
  if (ignore_errors_flag) mflags[i++] = 'i';
  if (keep_going_flag) mflags[i++] = 'k';
  if (just_print_flag) mflags[i++] = 'n';
  if (question_flag) mflags[i++] = 'q';
  if (no_builtin_rules_flag) mflags[i++] = 'r';
  if (silent_flag) mflags[i++] = 's';
  if (touch_flag) mflags[i++] = 't';
  if (i == 1)
    --i;
  mflags[i] = '\0';
  /* On Sun, value of MFLAGS starts with a `-'
     but value of MAKEFLAGS lacks the `-'.  Be compatible.  */
  define_macro ("MAKEFLAGS", 9, &mflags[1], o_env);
  define_macro ("MFLAGS", 6, mflags, o_env);
}

/* Try to interpret LINE (a null-terminated string)
   as a macro definition.  If it is one, define the macro and return 1.
   Otherwise return 0.

   ORIGIN be o_file, o_override, o_env, o_env_override, or o_command
   specifying that the macro definition comes from a makefile,
   an override directive, the environment with or without the -e switch,
   or the command line.  */

int
try_macro_definition (line, origin)
     char *line;
     enum macro_origin origin;
{
  register int c;
  register char *p = line;
  register char *beg;
  register char *end;

  if (*p == '\t')
    return 0;
  while (1)
    {
      c = *p++;
      if (c == '\0' || c == ':' || c == '#')
	return 0;
      if (c == '=')
	break;
    }
  beg = line;
  while (beg[0] == ' ' || beg[0] == '\t') beg++;
  end = p - 1;
  while (end[-1] == ' ' || end[-1] == '\t') end--;

  while (*p == ' ' || *p == '\t') p++;

  macro_expand (p);
  define_macro (beg, end - beg, macro_buffer, origin);

  return (1);
}

/* Store into `macro_buffer' at O the result of scanning TEXT
   and replacing each occurrence of SUBST with REPLACE.
   TEXT is null-terminated.
   SLEN is the length of SUBST and RLEN is the length of REPLACE.  */

char *
subst_expand (o, text, subst, replace, slen, rlen)
     char *o;
     char *text;
     char *subst, *replace;
     int slen, rlen;
{
  register char *t = text;
  register char *p;

  while (p = sindex (t, 0, subst, slen))
    {
      /* Output everything before this occurance of the
	 string to replace and advance T past it.  */
      if (p > t)
	o = macro_buffer_output (o, t, p - t);
      /* Advance T past the string to be replaced.  */
      t = p + slen;
      /* Output the replacement string.  */
      if (rlen > 0)
	o = macro_buffer_output (o, replace, rlen);
    }
  /* Output everything left on the end.  */
  if (*t)
    o = macro_buffer_output (o, t, strlen (t));

  return o;
}

/* Expand Bourne shell style macros of the forms: $(a-b), $(a+b), $(a+b-c)
   The output is put in MACRO_BUFFER at O.
   MACRO should point to the first character of the macro name,
   DELIM should point to the - or + after the macro name and
   END should point to the closing ) or }.  Macros are expanded
   as follows: $(a-b) is $(a) is a is defined, else b.
   $(a+b) is b if a is defined else blank.
   $(a+b-c) is b if a is defined else c.  */

char *
spec_macro_lookup (o, macro, delim, end)
     char *o;
     char *macro, *delim, *end;
{
  struct macro *m;
  char *p;
  /* Beginning of the text after the + or - delimiter.  */
  char *argbeg = delim + 1;

  /* Get the macro.  */
  m = lookup_macro (macro, delim - macro);

  switch (*delim)
    {
    case '-':
      if (m)
	o = macro_buffer_output (o, m->value, strlen (m->value));
      else
	o = macro_buffer_output (o, argbeg, end - argbeg);
      break;

    case '+':
      if (p = lindex (argbeg, end, '-'))
	{
	  /* We got a $(a+b-c).  */
	  if (m)
	    o = macro_buffer_output (o, argbeg, p - argbeg);
	  else
	    {
	      ++p;
	      o = macro_buffer_output (o, p, end - p);
	    }
	}
      else if (m)
	/* We got a $(a+b).  */
	o = macro_buffer_output (o, argbeg, end - argbeg);
      break;

    default:
      abort ();
    }

  return o;
}

/* Handle macro-expansion-time functions such as $(dir foo/bar) ==> foo/  */

/* These enumeration constants distinguish the various expansion-time
   built-in functions.  */

enum function
  {
    function_subst,
    function_expand,
    function_addsuffix,
    function_addprefix,
    function_dir,
    function_notdir,
    function_suffix,
    function_basename,
    function_wildcard,
    function_firstword,
    function_findstring,
    function_invalid
  };

/* Greater than the length of any function name.  */
#define MAXFUNCTIONLEN 11

/* The function names and lengths of names, for looking them up.  */

struct { char *name; int len; enum function function; } function_table[] =
  {
    { "subst", 5, function_subst },
    { "expand", 6, function_expand },
    { "addsuffix", 9, function_addsuffix },
    { "addprefix", 9, function_addprefix },
    { "dir", 3, function_dir },
    { "notdir", 6, function_notdir },
    { "suffix", 6, function_suffix },
    { "basename", 8, function_basename },
    { "wildcard", 8, function_wildcard },
    { "firstword", 9, function_firstword },
    { "findstring", 10, function_findstring },
    { 0, 0, function_invalid }
  };

/* Expand an argument for an expansion function.
   The text starting at STR and ending at END is macro-expanded
   into a null-terminated string that is returned as the value.
   This is done without clobbering `macro_buffer' or the current
   macro-expansion that is in progress.  */

char *
expand_argument (str, end)
     char *str, *end;
{
  char *save_macro_buffer = macro_buffer;
  int save_length = macro_buffer_length;
  char *tmp;
  char *value;

  macro_buffer = 0;
  tmp = savestring (str, end - str);
  value = macro_expand (tmp);
  free (tmp);

  macro_buffer = save_macro_buffer;
  macro_buffer_length = save_length;

  return value;
}


/* Perform the function specified by FUNCTION on the text at TEXT.
   END is points to the end of the argument text (exclusive).
   The output is written into MACRO_BUFFER starting at O.  */

char *
expand_function (o, function, text, end)
     char *o;
     enum function function;
     register char *text;
     char *end;
{
  char *p, *p2;
  int i;

/* Note this absorbs a semicolon and is safe to use in conditionals.  */
#define BADARGS(func)  \
  if (reading_filename)						\
    fatal ("%s:%ld:insufficient arguments to function `%s'",	\
	   reading_filename, *reading_lineno_ptr, func);	\
  else fatal ("insufficient arguments to function `%s'", func)

  switch (function)
    {
      default:
	abort ();

      case function_wildcard:
	text = expand_argument (text, end);
	p = string_glob (text, 0);
	o = macro_buffer_output (o, p, strlen (p));
	break;

      case function_subst:
	/* Get three comma-separated arguments and expand each one.  */
	p = lindex (text, end, ',');
	if (!p)
	  BADARGS ("subst");
	p2 = lindex (p + 1, end, ',');
	if (!p2)
	  BADARGS ("subst");
	text = expand_argument (text, p);
	++p;
	p = expand_argument (p, p2);
	++p2;
	p2 = expand_argument (p2, end);

	o = subst_expand (o, p2, text, p, strlen (text), strlen (p));
	free (text);
	free (p);
	free (p2);
	break;

      case function_firstword:
	text = expand_argument (text, end);
	/* Find the first word in TEXT.  */
	p = wstok (text);
	o = macro_buffer_output (o, p, strlen (p));
	free (text);
	break;

      case function_expand:
	text = expand_argument (text, end);
	/* Take the result of expanding the argument and expand it again.  */
	p = text;
	text = expand_argument (text, strlen (p) + p);
	free (p);
	o = macro_buffer_output (o, text, strlen (text));
	free (text);
	break;

      case function_findstring:
	/* Get two comma-separated arguments and expand each one.  */
	p = lindex (text, end, ',');
	if (!p)
	  BADARGS ("findstring");
	text = expand_argument (text, p);
	++p;
	p = expand_argument (p, end);

	/* Find the first occurence of the first string in the second.  */
	i = strlen (p);
	p2 = sindex (p, i, text, 0);
	if (p2)
	  o = macro_buffer_output (o, p2, i);

	free (p);
	free (text);
	break;

      case function_addsuffix:
      case function_addprefix:
	/* Get two comma-separated arguments and expand each one.  */
	p2 = lindex (text, end, ',');
	if (!p2)
	  BADARGS(function == function_addsuffix ? "addsuffix" : "addprefix");
	text = expand_argument (text, p2);
	i = strlen (text);
	++p2;
	p2 = expand_argument (p2, end);

	for (p = wstok (p2); p; p = wstok (0))
	  {
	    if (function == function_addprefix)
	      o = macro_buffer_output (o, text, i);
	    o = macro_buffer_output (o, p, strlen (p));
	    if (function == function_addsuffix)
	      o = macro_buffer_output (o, text, i);
	    o = macro_buffer_output (o, " ", 1);
	  }
	/* Kill last space.  */
	--o;
	free (p2);
	free (text);
	break;

      case function_dir:
      case function_basename:
	text = expand_argument (text, end);
	for (p2 = wstok (text); p2; p2 = wstok (0))
	  {
	    p = rindex (p2, function == function_dir ? '/' : '.');
	    if (p)
	      {
		if (function == function_dir)
		  ++p;
		o = macro_buffer_output (o, p2, p - p2);
	      }
	    else if (function == function_dir)
	      o = macro_buffer_output (o, "./", 2);
	    else  /* The entire name is the basename.  */
	      o = macro_buffer_output (o, p2, strlen (p2));
	    o = macro_buffer_output (o, " ", 1);
	  }
	/* Kill last space.  */
	--o;
	free (text);
	break;

      case function_notdir:
      case function_suffix:
	text = expand_argument (text, end);
	for (p2 = wstok (text); p2; p2 = wstok (0))
	  {
	    p = rindex (p2, function == function_notdir ? '/' : '.');
	    if (p)
	      {
		++p;
		o = macro_buffer_output (o, p, strlen (p));
	      }
	    else if (function == function_notdir)
	      o = macro_buffer_output (o, p2, strlen (p2));
	    if ((p && *p) || function == function_notdir)
	      o = macro_buffer_output (o, " ", 1);
	  }
	/* Kill last space.  */
	if (o[-1] == ' ')
	  --o;
	free (text);
	break;
    }

  return o;
}

/* Scan LINE for macro references and expansion-function calls.
   Build in `macro_buffer' the result of expanding those 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 *
macro_expand (line)
     char *line;
{
  register char *p, *o, *p1;
  register struct macro *m;

  /* If we don't have a macro output buffer yet, get one.
     The same buffer is reused each time macro_expand is called,
     and made bigger whenever necessary.  */

  if (!macro_buffer)
    {
      macro_buffer_length = 200;
      macro_buffer = (char *) xmalloc (macro_buffer_length);
    }

  p = line;
  o = macro_buffer;
  *o = 0;

  while (1)
    {
      /* Copy all following uninteresting chars
	 all at once to the macro output buffer, and skip them.
	 Uninteresting chars end at the next $ or the end of the input.  */

      p1 = index (p, '$');
      o = macro_buffer_output (o, p, p1 ? p1 - p : strlen (p) + 1);

      if (p1 == 0)
	break;
      p = p1 + 1;

      /* Dispatch on the char that follows the $.  */

      switch (*p)
	{
	case '$':
	  /* $$ seen means output one $ to the output buffer.  */

	  o = macro_buffer_output (o, p, 1);
	  break;

	case '(':
	case '{':
	  /* $(...) or ${...} is the general case of substitution.  */

	  {
	    char openparen = *p;
	    char closeparen = (openparen == '(') ? ')' : '}';
	    register char *beg = p + 1;
	    char *end;
	    register int code;
	    int maxlen;

	    p1 = lindex (beg, beg + MAXFUNCTIONLEN, 0);
	    maxlen = p1 ? p1 - beg : MAXFUNCTIONLEN;

	    /* First, see if this is a reference to a built-in function.
	       That is so if the text inside the parens starts with
	       the name of a function ended by a space or tab.  */

	    for (code = 0; function_table[code].name; ++code)
	      {
		if (maxlen < function_table[code].len)
		  continue;
		p1 = beg + function_table[code].len;
		if ((*p1 == ' ' || *p1 == '\t')
		    && !strncmp (function_table[code].name, beg, 
				 function_table[code].len))
		  break;
	      }
	    if (function_table[code].name)
	      {
		/* We have found a call to an expansion-time function.
		   Find the end of the arguments, and do the function.  */

		int count = 0;
		char *argbeg;

		/* Space after function name isn't part of the args.  */
		p = p1;
		while (*p == ' ' || *p == '\t')
		  ++p;
		argbeg = p;

		/* Count nested use of whichever kind of parens we use,
		   so that nested calls and macro refs work.  */

		for (; *p; ++p)
		  {
		    if (*p == openparen)
		      ++count;
		    else if (*p == closeparen && --count < 0)
		      break;
		  }

		/* We found the end; expand the function call.  */

		o = expand_function (o, function_table[code].function,
				     argbeg, p);
		break;
	      }

	    /* This is not a reference to a built-in function.
	       There are several things it could be.  In any case,
	       find the end of it, which is the first close-paren
	       of the appropriate type.  (We do not count them.)  */

	    end = index (beg, closeparen);
	    if (end == 0)
	      /* There was no ending ) or } !!
		 Swallow the line (and screw the hook and sinker).  */
	      return (macro_buffer);

	    /* This is not a reference to a built-in function.  Is it
	       an old-fashioned substitution spec, $(FOO:BAR=UGH)?  */

	    if ((p = lindex (beg, end, ':'))
		&& (p1 = lindex (p, end, '=')))
	      {
		struct macro *m = lookup_macro (beg, p - beg);
		int slen = p1 - p - 1;
		int rlen = end - p1 - 1;
		if (m && *m->value)
		  o = subst_expand (o, m->value, p+1, p1+1, slen, rlen);
	      }

	    /* This is not a substitution spec.  Is it an expansion-time
	       conditional, as in `sh': $(FOO-BAR) or $(FOO+BAR)?  */

	    else if ((p = lindex (beg, end, '-'))
		     || (p = lindex (beg, end, '+')))
	      o = spec_macro_lookup (o, beg, p, end);

	    /* No, this must be an ordinary macro reference.  */
	    else
	      {
		m = lookup_macro (beg, end - beg);
		if (m && *m->value)
		  o = macro_buffer_output (o, m->value,
					   strlen (m->value));
	      }

	    /* Advance p past the macro reference to resume scan.  */
	    p = end;
	  }
	  break;

	case '\0':
	case '\t':
	case ' ':
	  break;

	default:
	  /* $ followed by a random char is a macro reference:
	     $a is equivalent to $(a).  */

	  m = lookup_macro (p, 1);
	  if (m)
	    o = macro_buffer_output (o, m->value, strlen (m->value));
	  break;
	}
      ++p;
    }
  return macro_buffer;
}

/* Subroutine of macro_expand and friends: 
   The text to add is LENGTH chars starting at STRING to the macro_buffer.
   The text is added to the buffer at PTR, and the updated pointer into
   the buffer is returned as the value.  Thus, the value returned by
   each call to macro_buffer_output should be the first argument to
   the following call.  */

char *
macro_buffer_output (ptr, string, length)
     char *ptr, *string;
     int length;
{
  register int newlen = length + (ptr - macro_buffer);
  register char *new;

  if (newlen > macro_buffer_length)
    {
      macro_buffer_length = max (2 * macro_buffer_length, newlen + 100);
      new = (char *) xrealloc (macro_buffer, macro_buffer_length);
      ptr += new - macro_buffer;
      macro_buffer = new;
    }

  bcopy (string, ptr, length);
  return (ptr + length);
}

/* Access the hash table of all file records.
   lookup_file  given a name, return the struct file * for that name,
           or 0 if there is none.
   enter_file   similar, but create one if there is none.  */

struct file *
lookup_file (name)
     char *name;
{
  register struct file *f;
  register char *n;
  register int hashval = 0;

  while (name[0] == '.' && name[1] == '/' && name[2])
    name += 2;

  if (!*name)
    abort ();

  for (n = name; *n; ++n)
    hashval += *n;
  hashval %= FILE_BUCKETS;

  for (f = files[hashval]; f; f = f->next)
    if (streq (f->name, name))
      return (f);
  return (0);
}

struct file *
enter_file (name)
     char *name;
{
  register struct file *f;
  register char *n;
  register int hashval = 0;

  while (name[0] == '.' && name[1] == '/' && name[2])
    name += 2;

  if (!*name)
    abort ();

  for (n = name; *n; ++n)
    hashval += *n;
  hashval %= FILE_BUCKETS;

  for (f = files[hashval]; f; f = f->next)
    if (streq (f->name, name))
      return (f);

  f = (struct file *) xmalloc (sizeof (struct file));
  bzero (f, sizeof (*f));
  f->name = name;
  f->update_status = -1;
  f->next = files[hashval];
  files[hashval] = f;
  return (f);
}

/* Print the contents of the files and macros hash tables.  */

void
print_data_base ()
{
  register struct macro *m;
  register struct file *f;
  register struct dep *d;
  register struct rule *r;
  register struct dirdata *dir;
  register int i, j, k;

  printf ("Macros\n\n");

  j = 0;
  for (i = 0; i < MACRO_BUCKETS; ++i)
    for (m = macros[i]; m; m = m->next)
      {
	++j;
	printf ("%s = %s\n", m->name, m->value);
      }

  printf ("\n%d macros in %d hash buckets, average %f macros per bucket.\n",
	  j, MACRO_BUCKETS, ((float) j) / MACRO_BUCKETS);

  printf ("\nImplicit rules\n\n");

  j = k = 0;
  for (r = pattern_rules; r; r = r->next)
    {
      ++j;
      printf ("%s:", r->name);
      if (r->terminal)
	{
	  ++k;
	  printf ("   (terminal)");
	}
      putchar ('\n');
      for (d = r->deps; d; d = d->next)
	printf (" depends on %s\n", d->name);
      if (r->cmds)
	{
	  struct commands *c = r->cmds;
	  if (c->filename)
	    printf (" commands to execute (from \"%s\", line %ld):\n  %s",
		    c->filename, c->lineno, c->commands);
	  else
	    printf (" commands to execute:\n  %s\n", c->commands);
	}
    }

  printf ("\n%d implicit rules.\n", j);

  printf ("\nDirectories\n\n");

  j = k = 0;
  for (i = 0; i < DIR_HASH_SIZE; ++i)
    for (dir = dir_hash_table[i]; dir; dir = dir->next)
      {
	++k;
	if (dir->name[0] == '.' && !dir->name[1])
	  {
	    ++j;
	    printf ("%s\n", dir->dir);
	  }
      }

  printf ("\n%d directories with a total of %d files in %d hash buckets,\n",
	   j, k, DIR_HASH_SIZE);
  printf ("average of %f files per bucket.\n", ((float) k) / DIR_HASH_SIZE);

  printf ("\nFiles\n\n");

  j = 0;
  for (i = 0; i < FILE_BUCKETS; ++i)
    for (f = files[i]; f; f = f->next)
      {
	++j;
	printf ("%s", f->name);
	if (f->is_target)
	  putchar (':');
	if (f->double_colon)
	  putchar (':');
	if (f->stem)
	  printf ("   (implicit rule stem \"%s\")", f->stem);
	putchar ('\n');
	for (d = f->deps; d; d = d->next)
	  printf (" depends on %s\n", d->name);
	if (f->cmds)
	  {
	    struct commands *c = f->cmds;
	    if (c->filename)
	      printf (" commands to execute (from \"%s\", line %ld):\n  %s",
		      c->filename, c->lineno, c->commands);
	    else
	      printf (" commands to execute:\n  %s\n", c->commands);
	  }
      }

  printf ("\n%d files in %d hash buckets, average %f files per bucket.\n",
	  j, FILE_BUCKETS, ((float) j) / FILE_BUCKETS);

  printf ("\nDone\n");
  fflush (stdout);
}

void read_makefile (), record_files ();

/* Look at out command args to determine the names of the makefiles
   and read all those files, adding their macro definitions and rules
   to the macro and file hash tables.  */

void
read_all_makefiles (argc, argv)
     int argc;
     char **argv;
{
  struct macro *m;
  register int i;
  int num_makefiles = 0;

  /* If there's a non-null macro MAKEFILES,
     its value a list of files to read first thing.
     But don't let it prevent reading the default makefiles
     and don't let the default goal come from there.  */

  m = lookup_macro ("MAKEFILES", 9);
  if (m && *m->value)
    {
      char *rest = m->value;
      char *name;
      int length;
      /* Set NAME to start of next token and LENGTH to its length.
	 REST is updated for finding remaining tokens.  */
      while (name = find_next_token (&rest, &length))
	{
	  name = savestring (name, length);
	  if (file_exists_p (name))
	    read_makefile (name, 1, 1);
	  free (name);
	}
    }

  /* Read makefiles specified with -f switches.  */

  for (i = 1; i < argc; i++)
    if (!strcmp (argv[i], "-f"))
      {
	++i;
	if (i >= argc)
	  fatal ("no description argument after -f command option");
	read_makefile (argv[i], 0, 0);
	++num_makefiles;
      }

  /* If there were no -f switches, try the default names.  */

  if (num_makefiles == 0)
    {
      if (file_exists_p ("makefile"))
	read_makefile ("makefile", 0, 0);
      else if (file_exists_p ("Makefile"))
	read_makefile ("Makefile", 0, 0);
      else if (argc <= 1)
	fatal ("no target arguments or description file");
    }
}

/* Read file FILENAME as a makefile and add its contents to the data base.
   NODEFAULT means don't take the default goal target from this makefile.
   NOERROR means no error if file is not found.  */

void
read_makefile (filename, nodefault, noerror)
     char *filename;
     int nodefault;
     int noerror;
{
  register FILE *infile;
  struct linebuffer lb;
  int commands_len = 200;
  char *commands = (char *) xmalloc (200);
  int commands_idx = 0;
  long commands_started;
  register char *p;
  char *p2;
  int ignoring = 0;

  struct nameseq *filenames = 0;
  struct dep *deps = 0;
  long lineno = 1;
  long nlines = 0;
  int two_colon;
  char *cmdleft;

  /* First, get a stream to read */

  if (!strcmp (filename, "-"))
    infile = stdin;
  else
    infile = fopen (filename, "r");

  if (!infile && nodefault && *filename != '/' && include_directories)
    {
      register int i;
      char *name = (char *) alloca (max_incl_len + 1 + strlen (filename) + 1);
      for (i = 0; include_directories[i]; ++i)
	{
	  sprintf (name, "%s/%s", include_directories[i], filename);
	  infile = fopen (name, "r");
	  if (infile)
	    {
	      filename = name;
	      break;
	    }
	}
    }

  /* If file can't be found at all, either ignore it or give up entirely.  */

  if (!infile)
    {
      if (noerror)
	return;
      pfatal_with_name (filename);
    }

  reading_filename = filename;
  reading_lineno_ptr = &lineno;

  /* Loop over lines in the file.
     The strategy is to accumulate target names in FILENAMES,
     dependencies in DEPS and commands in COMMANDS.
     These are used to define a rule
     when the start of the next rule (or eof) is encountered.  */

  initbuffer (&lb);

  while (!feof (infile))
    {
      lineno += nlines;
      nlines = readline (&lb, infile, filename, lineno);

      p = lb.buffer;

#define	word1eq(s, l) 	((!p[l] || p[l] == ' ' || p[l] == '\t') &&	\
			 !strncmp (s, p, l))

      while (*p == ' ' || *p == '\t')
	++p;
      if (!*p)
	continue;
      p = lb.buffer;
      if (word1eq ("ifdef", 5) || word1eq ("ifndef", 6)
	  || word1eq ("ifeq", 4) || word1eq ("ifneq", 5)
	  || word1eq ("else", 4) || word1eq ("endif", 5))
	{
	  int i = conditional_line (p, filename, lineno);
	  if (i >= 0)
	    {
	      ignoring = i;
	      continue;
	    }
	}
      if (ignoring)
	continue;
      else if (word1eq ("define", 6))
	{
	  p += 6;
	  p2 = next_token (p);
	  p = end_of_token (p2);
	  lineno = do_define (&lb, savestring (p2, p - p2),
			      lineno, infile, filename);
	  continue;
	}
      else if (word1eq ("endef", 5))
	fatal ("%s:%ld: extraneous `endef'", filename, lineno);
      else if (word1eq ("override", 8))
	{
	  p += 8;
	  p2 = next_token (p);
	  if (!p2 || !try_macro_definition (p2, o_override))
	    fatal ("%s:%ld:empty `override' directive", filename, lineno);
	}
      else if (word1eq ("include", 7))
	{
	  /* We have found an `include' line specifying a nested
	     makefile to be read at this point.  */
	  p += 8;
	  p2 = next_token (p);
	  if (!p2)
	    fatal ("%s:%ld: no filename for `include'", filename, lineno);
	  p = end_of_token (p2);
	  p = savestring (p2, p - p2);
	  read_makefile (p, 1, 0);
	  free (p);
	  continue;
	}
#undef	word1eq
      else if (try_macro_definition (p, o_file))
	continue;
      else if (*p == '\t')
	{
	  /* This line is a shell command */
	  int len;

	  if (!filenames)
	    fatal ("%s:%ld: commands commence before first target",
	           filename, lineno);

	  /* Add this command line to end of the line being accumulated.  */
	  if (commands_idx == 0)
	    commands_started = lineno;
	  len = strlen (p);
	  if (len + 1 + commands_idx > commands_len)
	    {
	      commands_len = (len + 1 + commands_idx) * 2;
	      commands = (char *) xrealloc (commands, commands_len);
	    }
	  bcopy (p, &commands[commands_idx], len);
	  commands_idx += len;
	  commands[commands_idx++] = '\n';
	}
      else
	{
	  /* This line describes some target files.
	     Record the previous rule.  */

	  struct commands *cmds;

	  if (commands_idx > 0)
	    {
	      cmds = (struct commands *) xmalloc (sizeof (struct commands));
	      cmds->filename = filename;
	      cmds->lineno = commands_started;
	      cmds->commands = savestring (commands, commands_idx);
	    }
	  else
	    cmds = 0;
	  record_files (filenames, deps, cmds, two_colon, !nodefault);

	  /* Does this line contain a semicolon (that isn't quoted with \)?
	     If so, find the first such.  */
	  cmdleft = index (p, ';');
	  while (cmdleft && cmdleft[-1] == '\\')
	    {
	      register char *q = &cmdleft[-1];
	      register int backslash = 0;
	      while (*q-- == '\\')
		backslash = !backslash;
	      if (backslash)
		cmdleft = index (cmdleft + 1, ';');
	      else
		break;
	    }
	  if (cmdleft)
	    {
	      p = savestring (p, cmdleft - p);
	      p2 = macro_expand (p);
	      free (p);
	    }
	  else
	    p2 = macro_expand (p);

	  if (!*p2 || *p2 == ':')
	    fatal ("%s:%ld: missing target name", filename, lineno);
	  filenames = multi_glob (parse_file_seq (&p2, ':',
						  sizeof (struct nameseq)),
				  ".",
				  sizeof (struct nameseq));
	  if (!*p2++)
	    fatal ("%s:%ld: missing separator", filename, lineno);
	  /* Is this a one-colon or two-colon entry?  */
	  two_colon = *p2 == ':';
	  if (two_colon) p2++;

	  /* Parse the dependencies.  */
	  deps = (struct dep *)
	    multi_glob (parse_file_seq (&p2, ';', sizeof (struct dep)),
			".",
			sizeof (struct dep));

	  commands_idx = 0;
	  /* Did we stop at end of line, or at a semicolon?  */
	  if (cmdleft)
	    {
	      /* Semicolon means rest of line is a command */
	      int len = strlen (cmdleft + 1);

	      /* Add this command line to the buffer.  */
	      if (len + 2 > commands_len)
		{
		  commands_len = (len + 2) * 2;
		  commands = (char *) xrealloc (commands, commands_len);
		}
	      bcopy (cmdleft + 1, commands, len);
	      commands_idx += len;
	      commands[commands_idx++] = '\n';
	    }
	}
    }

  if (ignoring)
    fatal ("missing endif");

  /* At eof, record the last rule.  */
  {
    struct commands *cmds;

    if (commands_idx > 0)
      {
	cmds = (struct commands *) xmalloc (sizeof (struct commands));
	cmds->filename = filename;
	cmds->lineno = commands_started;
	cmds->commands = savestring (commands, commands_idx);
      }
    else
      cmds = 0;
    record_files (filenames, deps, cmds, two_colon, !nodefault);
  }

  freebuffer (&lb);
  free (commands);
  if (infile != stdin)
    fclose (infile);

  reading_filename = 0;
  reading_lineno_ptr = 0;
}

/* Execute a `define' directive.
   The first line has already been read, and NAME is the name of
   the variable to be defined.  The following lines remain to be read.
   LINENO, INFILE and FILENAME refer to the makefile being read.
   The value returned is LINENO, updated for lines read here.  */

long
do_define (lbp, name, lineno, infile, filename)
     struct linebuffer *lbp;
     char *name;
     long lineno;
     FILE *infile;
     char *filename;
{
  int length = 0;
  int nlines;
  char *definition = (char *) xmalloc (1);
  register char *p;

#define	word1eq(s,l)	((!p[l] || p[l] == ' ' || p[l] == '\t') &&	\
                         !strncmp (s, p, l))

  while (!feof (infile))
    {
      lineno += nlines;
      nlines = readline (lbp, infile, filename, lineno);

      p = lbp->buffer;
      if (word1eq ("endef", 5))
	{
	  /* Define the macro.  */
	  define_macro (name, strlen (name), definition, o_file);
	  break;
	}
      else
	{
	  int len = strlen (p);
	  int olength = length;

	  /* Increase the buffer if necessary.  */
	  length += len + (olength != 0);
	  if (olength == 0)
	    definition = (char *) xmalloc (length + 1);
	  else
	    definition = (char *) xrealloc (definition, length + 1);

	  /* Separate lines with a newline.  */
	  if (olength > 0)
	    definition[olength++] = '\n';
	  bcopy (p, &definition[olength], len);
	  definition[length] = 0;
	}
    }

  return lineno;
}

/* Glob-expand LINE.
   The returned pointer is only good until the next call to this
   routine.

   The RECURSIVE flag is only used internally.  */

char *
string_glob (line, recursive)
     char *line;
     int recursive;
{
  extern char **glob_vector ();
  static char *result, *result_end;
  static int result_length = 0;
  char **globbed;
  register int i, d, len;
  register char *p, *s;

  s = line;
  while (*s && *s != ' ' && *s != '\t')
    ++s;

  p = savestring (line, s - line);
  globbed = glob_vector (p, ".");
  free (p);

  while (*s == ' ' || *s == '\t')
    ++s;

  if ((int) globbed == 0)
    fatal ("virtual memory exhausted", 0);
  else if ((int) globbed == -1)
    pfatal_with_name (".");

  if (result_length == 0)
    {
      result_length = 200;
      result = xmalloc (200);
    }

  p = recursive ? result_end : result;
  *p = '\0';
  for (i = 0; globbed[i]; ++i)
    {
      len = strlen (globbed[i]) + 1;
      d = p - result;
      if (d > 0)
	++d;
      d += len;
      if (d > result_length)
	{
	  result_length = d + (globbed[i + 1] ? 20 : 0);
	  result = xrealloc (result, result_length);
          p = result + (d - len - (d > len ? 1 : 0));
	}
      if (d > len)
	*p++ = ' ';
      bcopy (globbed[i], p, len);
      free (globbed[i]);
      p += len - 1;
    }
  result_end = p;
  free (globbed);

  if (*s)
    string_glob (s, 1);

  return (result);
}

/* Interpret conditional commands "ifdef", "ifndef", "ifeq",
   "ifneq", "else" and "endif".
   LINE is the input line, with the command as its first word.

   FILENAME and LINENO are the filename and line number in the
   current makefile.  They are used for error messages.

   Value is -1 if line is invalid,
   0 if following text should be interpreted,
   1 if following text should be ignored.  */

int
conditional_line (line, filename, lineno)
     char *line;
     char *filename;
     long lineno;
{
  static int if_cmds = 0;
  static char *ignoring = 0;
  static int max_ignoring = 0;
  int notdef;
  char *cmdname;
  register int i;

  if (*line == 'i')
    {
      /* It's an "if..." command.  */
      notdef = line[2] == 'n';
      if (notdef)
	{
	  cmdname = line[3] == 'd' ? "ifndef" : "ifneq";
	  line += cmdname[3] == 'd' ? 7 : 6;
	}
      else
	{
	  cmdname = line[2] == 'd' ? "ifdef" : "ifeq";
	  line += cmdname[2] == 'd' ? 6 : 5;
	}
    }
  else
    {
      /* It's an "else" or "endif" command.  */
      notdef = line[1] == 'n';
      cmdname = notdef ? "endif" : "else";
      line += notdef ? 5 : 4;
    }

  while (*line == ' ' || *line == '\t')
    ++line;

  if (*cmdname == 'e')
    {
      if (*line)
	return (-1);
      /* "Else" or "endif".  */
      if (if_cmds == 0)
	fatal ("%s:%ld: extraneous `%s'\n", filename, lineno, cmdname);
      /* NOTDEF indicates an "endif" command.  */
      if (notdef)
	--if_cmds;
      else
	ignoring[if_cmds - 1] = !ignoring[if_cmds - 1];
      for (i = 0; i < if_cmds; ++i)
	if (ignoring[i]) return (1);
      return (0);
    }

  ++if_cmds;

  if (if_cmds > (max_ignoring - 1))
    {
      max_ignoring += 5;
      if (ignoring)
	ignoring = xrealloc (ignoring, max_ignoring);
      else
	ignoring = xmalloc (max_ignoring);
    }

  if (cmdname[notdef ? 3 : 2] == 'd')
    {
      /* "Ifdef" or "ifndef".  */
      struct macro *m;
      register char *p = line;

      while (*p && *p != ' ' && *p != '\t')
	++p;
      i = p - line;
      while (*p == ' ' || *p == '\t')
	++p;
      if (*p)
	return (-1);
      m = lookup_macro (line, i);
      ignoring[if_cmds - 1] = (m && *m->value) == notdef;
      for (i = 0; i < if_cmds; ++i)
	if (ignoring[i]) return (1);
      return (0);
    }
  else
    {
      /* "Ifeq" or "ifneq".  */
      char *s1, *s2;
      int len;
      char termin = *line == '(' ? ',' : *line;

      if (termin != ',' && termin != '"' && termin != '\'')
	return (-1);

      s1 = ++line;
      /* Find the end of the first string.  */
      if (termin == ',')
	{
	  register int count = 0;
	  for (; *line; ++line)
	      {
		if (*line == '(')
		  ++count;
		else if (*line == ')')
		  --count;
		else if (*line == ',' && count <= 0)
		  break;
	      }
	}
      else
	while (*line && *line != termin)
	  ++line;

      if (!*line)
	return (-1);

      *line = '\0';

      s2 = macro_expand (s1);
      /* We must allocate a new copy of the expanded string because
	 macro_expand re-uses the same buffer.  */
      len = strlen (s2);
      s1 = (char *) alloca (len + 1);
      bcopy (s2, s1, len + 1);

      /* Find and skip the comma unless we already did.  */
      if (termin != ',')
	while (*line && *line != ',')
	  ++line;
      ++line;

      /* Find the start of the second string.  */
      while (*line == ' ' || *line == '\t')
	++line;

      termin = termin == ',' ? ')' : *line;
      if (termin != ')' && termin != '"' && termin != '\'')
	return (-1);
      if (termin != ')')
	++line;
      s2 = line;

      /* Find the end of the second string.  */
      while (*line && *line != termin)
	++line;
      if (!*line)
	return (-1);

      if (*line)
	{
	  *line = '\0';
	  ++line;
	  while (*line == ' ' || *line == '\t')
	    ++line;
	  if (*line)
	    return (-1);
	}
      s2 = macro_expand (s2);
      ignoring[if_cmds - 1] = streq (s1, s2) == notdef;
      for (i = 0; i < if_cmds; ++i)
	if (ignoring[i]) return (1);
      return (0);
    }
}

/* Record a description line for files FILENAMES,
   with dependencies DEPS, commands to execute COMMANDS.
   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 any of the command lines for a file contain "$(MAKE)"
   or "${MAKE}" then the file's recursive flag is set.  */

void
record_files (filenames, deps, commands, two_colon, set_default)
     struct nameseq *filenames;
     struct dep *deps;
     struct commands *commands;
     int two_colon;
     int set_default;
{
  struct nameseq *nextf;

  for (; filenames; filenames = nextf)
    {
      register char *name = filenames->name;
      char *p = index (name, '%');
      register struct file *f, *f1;
      register struct rule *r;
      register struct dep *d;
      struct dep *this;

      nextf = filenames->next;
      free (filenames);

      /* If there are multiple filenames, copy the chain DEPS
	 for all but the last one.  It is not safe for the same deps
	 to go in more than one place in the data base.  */
      this = nextf ? copy_dep_chain (deps) : deps;

      /* Check for a pattern rule.  */
      if (p)
	{
	  r = (struct rule *) xmalloc (sizeof (struct rule));
	  r->name = name;
	  r->namelen = strlen (name);
	  r->patsuffix = p + 1;
	  r->terminal = two_colon;
	  r->deps = this;
	  r->cmds = commands;
	  /* If the new rule duplicates an old one, delete the old one. */
	  new_pattern_rule (r);
	  f = 0;
	}
      else if (!two_colon)
	{
	  /* Single-colon.  Combine these dependencies
	     with any others in file's existing record, if any.  */
	  f = enter_file (name);
	  if (f->double_colon)
	    fatal ("target file \"%s\" has both : and :: entries", f->name);
	  /* Check for two single-colon entries both with commands.
	     Check is_target so that we don't lose on files such as .c.o
	     whose commands were preinitialized.  */
	  if (commands && f->cmds && f->is_target)
	    fatal ("target file \"%s\" has commands specified twice", f->name);
	  f->is_target = 1;
	  f->cmds = commands;
	  /* Defining .SUFFIXES with no dependencies
	     clears out the list of suffixes.  */
	  if (f == suffix_file && !this)
	    f->deps = 0;
	  else if (f->deps)
	    {
	      for (d = f->deps; d->next; d = d->next);
	      d->next = this;
	    }
	  else
	    f->deps = this;
	}
      else
	{
	  /* Double-colon.  Make a new record even if file has one.  */
	  f1 = lookup_file (name);
	  if (f1 && !f1->double_colon)
	    fatal ("target file \"%s\" has both : and :: entries", f->name);
	  f = enter_file (name);
	  f->deps = this;
	  f->cmds = commands;
	  f->double_colon = 1;
	  f->is_target = 1;
	  f->prev = f1;
	}

      /* Check for $(MAKE) or ${MAKE} in the commands.  */
      if (commands && (sindex (commands->commands, 0, "${MAKE}", 0)
	               || sindex (commands->commands, 0, "$(MAKE)", 0)))
	{
	  if (f)
	    f->recursive = 1;
	  else
	    r->recursive = 1;
	}

      /* Free name if not needed further.  */
      if (f && name != f->name)
	free (name);

      /* See if this is first file seen in a top-level makefile
	 whose name does not start with a `.'.  */
      if (!default_goal_file && set_default && f && *name != '.')
	{
	  int reject = 0;

	  /* If this file is a suffix, don't
	     let it be the default goal file.  */

	  for (d = suffix_file->deps; d; d = d->next)
	    if (streq (name, d->name))
	      {
		reject = 1;
		break;
	      }

	  if (!reject)
	    default_goal_file = f;
	}
    }
}

/* Copy a chain of `struct dep', making a new chain
   with the same contents as the old one.  */

struct dep *
copy_dep_chain (d)
     struct dep *d;
{
  register struct dep *c;
  struct dep *firstnew = 0;
  struct dep *lastnew;

  while (d)
    {
      c = (struct dep *) xmalloc (sizeof (struct dep));
      bcopy (d, c, sizeof (struct dep));
      c->next = 0;
      if (firstnew == 0)
	firstnew = lastnew = c;
      else
	lastnew = lastnew->next = c;

      d = d->next;
    }

  return firstnew;
}

/* Parse a string into a sequence of filenames
   represented as a chain of struct nameseq's in reverse order.
   Return that chain.

   The string is passed as STRINGP, the address of a string pointer.
   The string pointer is updated to point at the first character
   not parsed, which either is a null char or equals STOPCHAR.

   SIZE is how big to construct chain elements.
   This is useful if we want them actually to be other structures
   that have room for additional info.  */

struct nameseq *
parse_file_seq (stringp, stopchar, size)
     char **stringp;
     int stopchar;
     int size;
{
  register struct nameseq *new = 0;
  register struct nameseq *new1;
  register char *p = *stringp;
  char *q;
  char *name;
  register int c;

  while (1)
    {
      /* Skip whitespace; see if any more names are left.  */
      while (*p == ' ' || *p == '\t')
	++p;
      if (*p == '\0')
	break;
      if (*p == stopchar)
	break;
      /* Yes, find end of next name.  */
      q = p;
      while (1)
	{
	  c = *p++;
	  if (c == '\0')
	    break;
	  else if (c == '\\' &&
	           (*p == '\\' || *p == ' ' || *p == '\t' || *p == stopchar))
	    ++p;
	  else if (c == ' ' || c == '\t' || c == stopchar)
	    break;
	}
      p--;

      /* Extract the filename just found, and skip it.  */
      name = savestring (q, p - q);

      /* Add it to the front of the chain.  */
      new1 = (struct nameseq *) xmalloc (size);
      new1->name = name;
      new1->next = new;
      new = new1;
    }

  *stringp = p;
  return (new);
}

/* Compare strings *S1 and *S2.
   Return negative if the first is less, positive if it is greater,
   zero if they are equal.  */

int
alpha_compare (s1, s2)
     char **s1, **s2;
{
  if (**s1 != **s2)
    return **s1 - **s2;
  return strcmp (*s1, *s2);
}

/* Remove quoting backslashes from a string
   by compacting the string down into itself.
   Backslashes quoted by other backslashes are not removed.  */

void
dequote (string)
     char *string;
{
  register char *in, *out;
  register int c;

  in = string;
  out = string;

  while (c = *in++)
    {
      if (c != '\\')
	*out++ = c;
      else if (c = *in++)
	*out++ = c;
    }

  *out = '\0';
}

/* Given a chain of struct nameseq's describing a sequence of filenames,
   in reverse of the intended order,
   return a new chain describing the result of globbing the filenames.
   The new chain is in forward order.
   The links of the old chain are freed or used in the new chain.
   Likewise for the names in the old chain.
   Globbing is done in directory DIR.

   SIZE is how big to construct chain elements.
   This is useful if we want them actually to be other structures
   that have room for additional info.  */

struct nameseq *
multi_glob (chain, dir, size)
     struct nameseq *chain;
     char *dir;
     int size;
{
  register struct nameseq *new = 0;
  register struct nameseq *tem;
  register struct nameseq *old;
  register char **vector;
  register int i;
  int length;
  extern char **glob_vector ();
  struct nameseq *nexto;

  for (old = chain; old; old = nexto)
    {
      nexto = old->next;

      if (glob_pattern_p (old->name))
	{
	  vector = glob_vector (old->name, dir);
	  if ((int) vector == 0)
	    fatal ("virtual memory exhausted", 0);
	  else if ((int) vector == -1)
	    pfatal_with_name (dir);
	  free (old->name);
	  for (i = 0; vector[i]; i++);
	  length = i;
	  qsort (vector, length, sizeof (char *), alpha_compare);
	  for (i = length - 1; i >= 0; i--)
	    {
	      tem = (struct nameseq *) xmalloc (size);
	      tem->name = vector[i];
	      tem->next = new;
	      tem->quotedparen = 1;
	      new = tem;
	    }
	  free (vector);
	  free (old);
	}
      else
	{
	  old->quotedparen = !strcmp (old->name + strlen (old->name) - 2,
				      "\\)");
	  dequote (old->name);
	  old->next = new;
	  new = old;
	}
    }
  return (new);
}


/* For each dependency of each file, make it point at the
   file that it depends on.

   Also mark the files depended on by .PRECIOUS and .PHONY.  */

void
snap_deps ()
{
  register struct file *f;
  register struct dep *d, *d2;
  register int i;

  /* Enter each dependency name as a file.  */
  for (i = 0; i < FILE_BUCKETS; ++i)
    for (f = files[i]; f; f = f->next)
      for (d = f->deps; d; d = d->next)
	d->file = enter_file (d->name);

  /* Compute maximum length of all the suffixes.  */
  maxsuffix = 0;
  for (d = suffix_file->deps; d; d = d->next)
    {
      maxsuffix = max (maxsuffix, strlen (d->name));
    }

  f = lookup_file (".PRECIOUS");
  if (f)
    for (d = f->deps; d; d = d->next)
      for (f = d->file; f; f = f->prev)
	f->precious = 1;

  f = lookup_file (".PHONY");
  if (f)
    for (d = f->deps; d; d = d->next)
      for (f = d->file; f; f = f->prev)
	{
	  /* Mark this file as phony and non-existent.  */
	  f->phony = 1;
	  f->last_mtime = -1;
	}
}

/* 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.

   DEPTH is the depth in recursions of this function.
   We increment it during the consideration of our dependencies,
   then decrement it again after finding out whether this file
   is out of date.

   If there are multiple entries for FILE, consider each in turn.  */

int
update_file (file, depth)
     struct file *file;
     int depth;
{
  register int status;
  register struct file *f = file;
  int ofiles_remade = files_remade;

  while (f)
    {
      status = update_file_1 (f, depth);
      if (status && !keep_going_flag)
	return (status);
      f = f->prev;
    }

  /* For a top level target, if we have found nothing whatever to do for it,
     print a message saying nothing needs doing.  */

  if (ofiles_remade == files_remade
      && !print_data_base_flag
      && depth == 0 && !silent_flag && !question_flag)
    {
      printf ("File \"%s\" is up to date.\n", file->name);
      fflush (stdout);
    }

  return (status);
}

/* Consider a single `struct file' and update it as appropriate.  */

#define DEBUGPR(msg) \
  if (debug_flag) \
    {  print_spaces (depth);  printf (msg, file->name); fflush (stdout);  }

int
update_file_1 (file, depth)
     struct file *file;
     int depth;
{
  register int this_mtime;
  int must_make;
  int dep_status = 0;
  register struct dep *d;
  
  DEBUGPR ("Considering target file \"%s\".\n");
  depth++;

  if (file->updated)
    {
      depth--;
      if (file->update_status > 0)
	{
	  DEBUGPR ("Recently tried and failed to update file \"%s\.\n");
	  return (file->update_status);
	}
	
      DEBUGPR ("File \"%s\" was considered already.\n");
      return 0;
    }
  else
    {
      file->updating = 1;	/* Notice recursive update of same file.  */

      /* If file was specified as a target with no commands,
	 come up with some default commands */

      if (!file->phony && file->cmds == 0 && !file->tried_implicit)
	{
	  if (try_implicit_rule (file, depth))
	    {
	      DEBUGPR ("An implicit rule found for \"%s\".\n");
	    }
	  else
	    {
	      DEBUGPR ("No implicit rule found for \"%s\".\n");
	      if (default_file)
		file->cmds = default_file->cmds;
	    }
	  file->tried_implicit = 1;
	}

      this_mtime = file_mtime (file);
      must_make = this_mtime < 0;
      if (must_make)
	DEBUGPR ("File \"%s\" does not exist.\n");

      /* Update all non-intermediate files we depend on, if necessary,
	 and see whether any of them is more recent than this file.  */

      for (d = file->deps; d; d = d->next)
	{
	  if (d->file->updating)
	    fatal ("dependency loop involving %s and %s", d->name, file->name);

	  dep_status |= check_dep (d->file, depth, this_mtime, &must_make);
	  if (dep_status && !keep_going_flag)
	    break;
	}

      /* Now we know whether this target needs updating.
	 If it does, update all the intermediate files we depend on.  */

      if (must_make)
	{
	  for (d = file->deps; d; d = d->next)
	    if (d->file->intermediate)
	      {
		dep_status |= update_file (d->file, depth);
		if (dep_status && !keep_going_flag)
		  break;
	      }
	}

      file->updating = 0;

      DEBUGPR ("Finished dependencies of target file \"%s\".\n");

      if (print_data_base_flag)
	{
	  depth--;
	  DEBUGPR ("Would now consider updating \"%s\".\n");
	  return (0);
	}

      /* If any dependency failed, give up now.  */

      if (dep_status)
	{
	  depth--;
	  if (depth == 0 && keep_going_flag)
	    {
	      printf ("File \"%s\" not remade because of errors.\n", file->name);
	      fflush (stdout);
	    }
	  DEBUGPR ("Giving up on target file \"%s\".\n");
	  return (dep_status);
	}

      /* Now record which dependencies are more recent than this file,
	 so we can create $@.  */

      for (d = file->deps; d; d = d->next)
	{
	  d->changed = this_mtime < 0 || this_mtime < file_mtime (d->file);

	  if (debug_flag && this_mtime > 0)
	    {
	      print_spaces (depth);
	      printf ("File \"%s\" is %s than file \"%s\".\n",
		      file->name, d->changed ? "older" : "newer", d->name);
	      fflush (stdout);
	    }
	}
    }

  /* Here depth returns to the value it had when we were called */
  depth--;

  if (!must_make)
    {
      DEBUGPR ("No need to remake target file \"%s\".\n");
      file->update_status = 0;
      file->updated = 1;
      return (0);
    }

  DEBUGPR ("Must remake target file \"%s\".\n");

  /* Now, take appropriate actions to remake the file.  */
  return remake_file (file);
}

/* Check whether another file (whose mtime is THIS_MTIME)
   needs updating on account of a dependency which is file FILE.
   If it does, store 1 in *MUST_MAKE_PTR.
   In the process, update any non-intermediate files
   that FILE depends on (including FILE itself).
   Return nonzero if any updating failed.  */

int
check_dep (file, depth, this_mtime, must_make_ptr)
     struct file *file;
     int depth;
     int this_mtime;
     int *must_make_ptr;
{
  register struct dep *d;
  int dep_status = 0;

  ++depth;
  file->updating = 1;

  if (! file->intermediate)
    /* If this is a non-intermediate file, update it
       and record whether it is newer than THIS_MTIME.  */
    {
      dep_status = update_file (file, depth);
      if (file_mtime (file) > this_mtime)
	*must_make_ptr = 1;
    }
  else
    /* FILE is an intermediate file.
       Update all non-intermediate files we depend on, if necessary,
       and see whether any of them is more recent than the file
       on whose behalf we are checking.  */
    for (d = file->deps; d; d = d->next)
      {
	if (d->file->updating)
	  fatal ("dependency loop involving %s and %s", d->name, file->name);

	dep_status |= check_dep (d->file, depth, this_mtime, must_make_ptr);
	if (dep_status && !keep_going_flag)
	  break;
      }

  file->updating = 0;
  return dep_status;
}

/* Having checked and updated the dependencies of FILE,
   do whatever is appropriate to remake FILE itself.
   Return the status from executing FILE's commands.  */

int
remake_file (file)
     struct file *file;
{
  int status;

  if (!file->is_target && !file->phony && !file->cmds)
    fatal ("no specification for making file \"%s\"", file->name);

  file->update_status = 0;
  files_remade++;

  /* If file is a recursive submake, ignore -t and -q for this file.  */

  if (question_flag && !file->recursive)
    /* pretend that updating "failed".  */
    status = 1;
  else if (file->cmds == 0)
    {
      /* The only effect of this if statement
	 is that files with no commands (not even implicit ones)
	 and files marked as phony do not get touched with -t.  */
      status = 0;
    }
  else if (touch_flag && !file->phony && !file->recursive)
    {
      /* Should set file's modification date and do nothing else.  */
      if (!silent_flag)
	{
	  printf ("touch(%s)\n", file->name);
	  fflush (stdout);
	}

      if (index (file->name, '(')
	  && file->name[strlen (file->name) - 1] == ')')
	status = ar_touch (file->name);
      else
	{
	  int fd = open (file->name, O_RDWR | O_CREAT, 0666);

	  status = fd < 0;
	  if (status)
	    perror_with_name ("touch: ", file->name);
	  else
	    {
	      struct stat statbuf;
	      char buf;

	      fstat (fd, &statbuf);
	      /* Rewrite character 0 same as it already is.  */
	      read (fd, &buf, 1);
	      lseek (fd, 0, 0);
	      write (fd, &buf, 1);
	      /* If file length was 0, we just changed it.
		 So change it back.  */
	      if (statbuf.st_size == 0)
		ftruncate (fd, 0);
	      close (fd);
	    }
	}
    }
  else
    status = execute_file_commands (file);

  file->update_status = status;
  file->last_mtime = just_print_flag ? time (0) : name_mtime (file->name);
  file->updated = 1;

  return (status);
}

/* Discard each backslash-newline combination from LINE.
   This is done by copying the text at LINE into itself.  */

void
collapse_continuations (line)
     char *line;
{
  register char *in, *out;

  in = out = line;

  while (*in)
    {
      if (in[0] == '\\')
	{
	  if (in[1] == '\n')
	    {
	      in += 2;
	      *out++ = ' ';
	    }
	  else
	    {
	      *out++ = *in++;
	      if (in[0] != 0)
		*out++ = *in++;
	    }
	}
      else
	*out++ = *in++;
    }

  *out = '\0';

  return;
}

/* Execute the commands associated with FILE.
   Returns nonzero if some command got an unignored error.
   Returns zero if have successfully executed the commands.  */

int
execute_file_commands (file)
     struct file *file;
{
  register char *line, *p, *next;
  /* Set to zero if we see that it is not safe
     to execute commands directly.  */
  int use_internal = 1;
  int status = 0;
  char *expansion;
  struct commands *cmds = file->cmds;

  /* Don't go through all the preparations if the
     command is nothing but whitespace.  */

  for (p = cmds->commands; *p; ++p)
    if (*p != ' ' && *p != '\t' && *p != '\n')
      break;
  if (!*p)
    return 0;

  if (file->recursive || !just_print_flag)
    {
      /* See if it is safe to parse commands internally.  */
      if (ifs_macro)
	for (line = ifs_macro->value; use_internal && *line; ++line)
	  switch (*line)
	    {
	    case ' ':
	    case '\t':
	    case '\n':
	      break;
	    default:
	      use_internal = 0;
	      break;
	    }
      if (use_internal && strcmp (shell_macro->value, "/bin/sh"))
	use_internal = 0;
    }

  /* First set the automatic macros according to this file */

  free (atD_macro->value);
  free (starD_macro->value);
  free (lessD_macro->value);
  free (percentD_macro->value);
  free (at_macro->value);
  free (percent_macro->value);

#define	LASTSLASH(m)	rindex (m->value, '/')
#define	FILEONLY(m)	line ? line + 1 : m->value
#define	DIRONLY(m)	!line ? savestring ("./", 2) :			\
			((line == m->value) ? savestring ("/", 1) :	\
			savestring (m->value, line - m->value + 1))

  line = index (file->name, '(');
  if (line && file->name[strlen (file->name) - 1] == ')')
    {
      at_macro->value = savestring (file->name, line - file->name);
      ++line;
      percent_macro->value = savestring (line, strlen (line) - 1);
    }
  else
    {
      at_macro->value = savestring (file->name, strlen (file->name));
      percent_macro->value = savestring (0, 0);
    }
  dollar_at_macro->value = at_macro->value;
  star_macro->value = file->stem ? file->stem : "";
  less_macro->value = file->stem ? file->deps->name : "";
  line = LASTSLASH (at_macro);
  atF_macro->value = FILEONLY (at_macro);
  atD_macro->value = DIRONLY (at_macro);
  dollar_slash_macro->value = atF_macro->value;
  line = LASTSLASH (star_macro);
  starF_macro->value = FILEONLY (star_macro);
  starD_macro->value = DIRONLY (star_macro);
  line = LASTSLASH (less_macro);
  lessF_macro->value = FILEONLY (less_macro);
  lessD_macro->value = DIRONLY (less_macro);
  line = LASTSLASH (percent_macro);
  percentF_macro->value = FILEONLY (percent_macro);
  percentD_macro->value = DIRONLY (percent_macro);
#undef	LASTSLASH
#undef	FILEONLY
#undef	DIRONLY

  /* Compute the values for $^ and $?.  */

  {
    register int dep_size = 0, c_size = 0;
    register char *cline;
    register struct dep *d;

    for (d = file->deps; d; d = d->next)
      {
	register int i = strlen (d->name) + 1;
	c_size += i;
	if (d->changed)
	  dep_size += i;
      }

    /* Add 1 to size here to make room for the null that
       `strcat' inserts after the final space.  */
    line = (char *) xmalloc (dep_size + 1);
    cline = (char *) xmalloc (c_size + 1);
    *line = *cline = '\0';

    if (c_size > 0)
      {
	for (d = file->deps; d; d = d->next)
	  {
	    strcat (cline, d->name);
	    strcat (cline, " ");
	    if (d->changed)
	      {
		strcat (line, d->name);
		strcat (line, " ");
	      }
	  }
	/* remove final space */
	line[dep_size - 1] = cline[c_size - 1] = '\0';
      }
    caret_macro->value = cline;
    qmark_macro->value = line;
  }

  /* Arrange for fatal signal to delete this target,
     unless it depends on .PRECIOUS:  */

  if (!file->precious)
    {
      signal_delete_file = file->name;
      signal_delete_mtime = file->last_mtime;
    }

  /* Expand macros and functions.  Error messages refer to
     the file and line where these commands were found.  */
  reading_filename = cmds->filename;
  reading_lineno_ptr = &(cmds->lineno);
  next = expansion = macro_expand (cmds->commands);
  reading_filename = 0;
  reading_lineno_ptr = 0;

  /* Now execute the command lines */

  line = (char *) alloca (strlen (expansion) + 1);
  while (next && *next)
    {
      int noprint = 0;
      int noerror = 0;
      char *end = next;

      /* Find the end of this line.  Backslash-newlines don't
	 mean the end.  */

      while (*end && *end != '\n')
	{
	  if (end[0] == '\\' && end[1] != 0)
	    end += 2;
	  else
	    end++;
	}

      strncpy (line, next, end - next);
      line[end - next] = 0;
      next = *end ? end + 1 : 0;

      /* Print each line that does not start with `@',
	 unless -s was specified.  */
      while (*line)
	{
	  if (*line == '@')
	    noprint = 1;
	  else if (*line == '-')
	    noerror = 1;
	  else if (*line != ' ' && *line != '\t')
	    break;
	  line++;
	}

      if (just_print_flag || (!silent_flag && !noprint))
	{
	  printf ("%s\n", line);
	  fflush (stdout);
	}

      /* If -n was specified, don't really execute, unless file
	 is a recursive submake.
	 But do pretend we changed this file's date.  */
      if (just_print_flag && !file->recursive)
	continue;

      /* Delete backslash-newlines from this line.  */

      collapse_continuations (line);

      /* Execute the command line; perhaps by the shell, perhaps directly.  */

      if (use_internal)
	status = execute_command_line (line);
      else
	status = run_shell_command (line);

      if (status && !ignore_errors_flag && !noerror)
	{
	  if (status > SIGNAL_STATUS)
	    {
	      extern char *sys_siglist[];
	      int sig = status - SIGNAL_STATUS;
	      if (sig > NSIG)
		fprintf (stderr, "*** Signal %d\n", sig);
	      else
		fprintf (stderr, "*** %s\n", sys_siglist[sig]);
	    }
	  else
	    fprintf (stderr, "*** Error %d\n", status);
	  fflush (stderr);
	  break;
	}
    }

  /* Target is final; no further reason to delete it.  */
  signal_delete_file = 0;
  signal_delete_mtime = 0;

  /* Now free the macro values made above.  */
  free (caret_macro->value);
  free (qmark_macro->value);
  caret_macro->value = qmark_macro->value = "";

  return (status);
}

/* For a FILE which has no commands specified, try to figure out some
   from the implicit pattern rules.
   Returns 1 if a suitable implicit rule was found,
   after modifying FILE to contain the appropriate commands and deps,
   or returns 0 if no implicit rule was found.  */

int
try_implicit_rule (file, depth)
     struct file *file;
     int depth;
{
  register char *filename;

  DEBUGPR ("Looking for an implicit rule for \"%s\".\n");

  /* If this is an archive member reference,
     use just the archive member name to search for implicit rules.  */ 
  filename = index (file->name, '(');
  if (filename && filename[strlen (filename) - 1] == ')')
    {
      DEBUGPR ("Looking for archive-member implicit rule for \"%s\".\n");
      if (pattern_search (file, filename, depth, 0))
	return 1;
    }

  return pattern_search (file, 0, depth, 0);
}

#define DEBUGP2(msg, a1, a2) \
  if (debug_flag) \
    { print_spaces (depth); printf (msg, a1, a2); fflush (stdout);  }

/* Search the pattern rules for a rule with an existing
   dependent to make NAME.  If NAME is nil,
   FILE->name is used.  If a rule is found, the
   appropriate commands and deps are put in FILE
   and 1 is returned.  If not, 0 is returned.

   If an intermediate file is found by pattern search,
   the intermediate file is set up as a target by the recursive call
   and is also made a dependency of FILE.

   DEPTH is used for debugging messages.  */

int
pattern_search (file, name, depth, recursions)
     struct file *file;
     char *name;
     int depth;
     int recursions;
{
  /* Filename we are searching for a rule for.  */
  char *filename = name ? name : file->name;

  /* Length of FILENAME.  */
  int namelen = strlen (filename);

  /* The last slash in FILENAME (or nil if there is none).  */
  char *lastslash;

  /* This is a file-object used as an argument in
     recursive calls.  It never contains any data
     except during a recursive call.  */
  struct file *intermediate_file = 0;

  /* Number of dependencies of the current rule that
     have been found using a recursive pattern_search.  */
  int intermediate_files_found = 0;

  /* List of dependencies found recursively.  */
  struct file **intermediate_files
    = (struct file **) alloca (max_pattern_deps * sizeof (struct file *));

  /* 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.  */
  int deps_found;

  /* 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 int stemlen;

  /* Buffer in which we store all the rules that are possibly applicable.  */
  struct rule **tryrules
    = (struct rule **) alloca (num_pattern_rules * sizeof (struct rule *));

  /* Number of valid elements in tryrules.  */
  int nrules = 0;

  /* Nonzero if should consider intermediate files as dependencies.  */
  int intermed_ok;

  /* Nonzero if we have matched a pattern-rule target
     that is not just `%'.  */
  int specific_rule_matched = 0;

  register int i;
  register struct rule *rule;
  register struct dep *dep;

  char *p;

  /* Set LASTSLASH to point at the last slash in FILENAME
     but not counting any slash at the end.  (foo/bar/ counts as
     bar/ in directory foo/, not empty in directory foo/bar/.)  */

  lastslash = 0;
  p = filename;
  while (*p && p[1])
    {
      if (*p == '/')
	lastslash = p;
      p++;
    }

  /* First see which pattern rules match this target
     and may be considered.  Put them in TRYRULES.  */

  for (rule = pattern_rules; rule; rule = rule->next)
    {
      int check_lastslash;
      /* If the pattern rule has no commands, ignore it.
	 Users cancel built-in rules by redefining them without commands.  */
      if (rule->deps != 0 && rule->cmds == 0)
	continue;

      /* If this rule is in use by a parent pattern_search,
	 don't use it here.  */
      if (rule->in_use)
	continue;

      /* Don't try rules whose dependents are guaranteed
	 to be non-existent.  */
      if (lastslash == 0 && rule->subdir)
	continue;

      /* From the lengths of the filename and the pattern parts,
	 find the stem: the part of the filename that matches the %.  */
      stem = filename + (rule->patsuffix - rule->name - 1);
      stemlen = namelen - rule->namelen + 1;

      /* Set CHECK_LASTSLASH if FILENAME contains a directory prefix
	 and the target pattern does not contain a slash.  */

      check_lastslash = lastslash && !index (rule->name, '/');
      if (check_lastslash)
	{
	  /* In that case, don't include the directory prefix in STEM here.  */
	  stem += lastslash - filename + 1;
	  stemlen -= (lastslash - filename) + 1;
	}

      /* Check that filename is long enough to match the whole pattern.  */
      if (stemlen <= 0)
	continue;

      /* Check that the rule pattern matches the text before the stem.  */
      if (check_lastslash)
	{
	  if (stem > (lastslash + 1)
	      && strncmp (rule->name, lastslash + 1, stem - lastslash - 1))
	    continue;
	}
      else if (stem > filename
               && strncmp (rule->name, filename, stem - filename))
	continue;

      /* Check that the rule pattern matches the text after the stem.
	 We could test simply !streq (rule->patsuffix, stem + stemlen)
	 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 (*rule->patsuffix != stem[stemlen]
	  || (*rule->patsuffix != 0
	      && !streq (&rule->patsuffix[1], &stem[stemlen + 1])))
	continue;

      /* Record if we match some rule that not all filenames will match.  */
      if (rule->name[1] != 0)
	specific_rule_matched = 1;

      /* A rule with no dependencies and no commands exists solely to set
	 specific_rule_matched when it matches.  Don't try to use it.  */
      if (rule->deps != 0 || rule->cmds != 0)
	tryrules[nrules++] = rule;
    }

  /* If we have found a matching rule that won't match all filenames,
     retroactively reject any "terminal" rules that do always match.  */
  if (specific_rule_matched)
    for (i = 0; i < nrules; ++i)
      if (tryrules[i]->terminal && tryrules[i]->name[1] == 0)
	tryrules[i] = 0;

  /* Try each rule once without intermediate files,
     then once with them.  */
  for (intermed_ok = 0; intermed_ok < 2; intermed_ok++)
    {
      /* Try each pattern rule till we find one that applies.
	 If it does, copy the names of its dependencies (as substituted)
	 and store them in FOUND_FILES.  DEPS_FOUND is the number of them.  */
      for (i = 0; i < nrules; i++)
	{
	  int check_lastslash;

	  rule = tryrules[i];

	  /* RULE is 0 when we discovered that a rule, already placed
	     in TRYRULES, should not be applied.  */
	  if (rule == 0)
	    continue;

	  /* Rules that can match any filename and are not terminal
	     should be ignored on the second pass, so that they
	     cannot accept an intermediate file.
	     These rules can only be the end of a chain.  */
	  if (intermed_ok && rule->name[1] == '\0' && !rule->terminal)
	    continue;

	  /* Mark this rule as in use so a recursive
	     pattern_search won't try to use it.  */
	  rule->in_use = 1;

	  /* From the lengths of the filename and the pattern parts,
	     find the stem: the part of the filename that matches the %.  */
	  stem = filename + (rule->patsuffix - rule->name - 1);
	  stemlen = namelen - rule->namelen + 1;
	  check_lastslash = lastslash && !index (rule->name, '/');
	  if (check_lastslash)
	    {
	      stem += lastslash - filename + 1;
	      stemlen -= (lastslash - filename) + 1;
	    }

	  DEBUGP2 ("Trying pattern rule with stem \"%.*s\".\n", 
		   stemlen, stem);

	  /* Try each dependency; see if it "exists".  */

	  intermediate_files_found = 0;
	  deps_found = 0;
	  for (dep = rule->deps; dep; dep = dep->next)
	    {
	      char *p = index (dep->name, '%');

	      /* If the dependency name has a %, substitute the stem.  */
	      if (p)
		{
		  int i;
		  if (check_lastslash)
		    {
		      i = lastslash - filename + 1;
		      bcopy (filename, depname, i);
		    }
		  else
		    i = 0;
		  bcopy (dep->name, depname + i, p - dep->name);
		  i += p - dep->name;
		  bcopy (stem, depname + i, stemlen);
		  i += stemlen;
		  strcpy (depname + i, p + 1);
		  p = depname;
		}
	      else
		p = dep->name;

	      /* P is now the actual dependency name as substituted.  */

	      if (file_impossible_p (p))
		{
		  /* If this dependency has already been ruled
		     "impossible", then the rule fails
		     and don't bother trying it on the second pass either
		     since we know that will fail too.  */
		  DEBUGP2 ("Rejecting impossible %s dependent \"%s\".\n",
		       p == depname ? "implicit" : "rule", p);
		  tryrules[i] = 0;
		  break;
		}

	      DEBUGP2 ("Trying %s dependent \"%s\".\n",
		       p == depname ? "implicit" : "rule", p);
	      if (lookup_file (p) != 0 || file_exists_p (p))
		{
		  found_files[deps_found++] = savestring (p, strlen (p));
		  continue;
		}
#if 0
	      else if (check_lastslash && p == depname)
		{
		  /* If FILENAME is "lib/foo.o" and P is "lib/foo.c",
		     Q gets "foo.c".  */
		  char *q = p + lastslash - filename + 1;
		  /* This code, given FILENAME = "lib/foo.o", 
		     dependency name "lib/foo.c", and `VPATH=.',
		     searches for "foo.c".  */
		  if (search_cwd && !rule->subdir)
		    {
		      if (lookup_file (q) != 0 || file_exists_p (q))
			{
			  found_files[deps_found++]
			    = savestring (q, strlen (q));
			  continue;
			}
		    }
		  /* This code, given FILENAME = "lib/foo.o", 
		     dependency name "lib/foo.c", and VPATH=src,
		     searches for "lib/src/foo.c" and then for "src/foo.c".  */
		  if (vpath_search (&q, filename, lastslash - filename)
		      || vpath_search (&q, 0, 0))
		    {
		      DEBUGP2 ("Found dependent as \"%s\".\n", q, 0);
		      found_files[deps_found++] = q;
		      continue;
		    }
		}
#endif
	      /* This code, given FILENAME = "lib/foo.o", 
		 dependency name "lib/foo.c", and VPATH=src,
		 searches for "src/lib/foo.c".  */
	      if (vpath_search (&p, 0, 0))
		{
		  DEBUGP2 ("Found dependent as \"%s\".\n", p, 0);
		  found_files[deps_found++] = p;
		  continue;
		}

	      /* We could not find the file in any place we should look.  */
	      /* Try to make this dependency as an intermediate file,
		 but only on the second pass.  */

	      if (intermed_ok && p == depname)
		{
		  int i;

		  if (!intermediate_file)
		    intermediate_file
		      = (struct file *) alloca (sizeof (struct file));

		  DEBUGP2 ("Looking for rule with intermediate file \"%s\".\n",
			   p, 0);

		  bzero (intermediate_file, sizeof (struct file));
		  intermediate_file->name = p;
		  i = pattern_search (intermediate_file, 0,
		                      depth + 1, recursions + 1);
		  if (i)
		    {
		      struct file *f;
		      p = savestring (p, strlen (p));
		      found_files[deps_found++] = p;
		      intermediate_file->name = p;
		      f = lookup_file (dep->name);
		      intermediate_file->precious = f && f->precious;
		      intermediate_files[intermediate_files_found++]
			= intermediate_file;
		      intermediate_file = 0;
		      continue;
		    }
		  /* If we have tried to find P as an intermediate file
		     and failed, mark that name as impossible
		     so we won't go through the search again later.  */
		  file_impossible (p);
		}

	      /* A dependent of this rule does not exist.
		 Therefore, this rule fails.  */
	      break;
	    }

	  /* This rule is no longer "in use" for recursive searches.  */
	  rule->in_use = 0;

	  if (dep)
	    {
	      /* This pattern rule does not apply.
		 If some of its dependents succeeded,
		 free the data structure describing them.  */
	      while (deps_found-- > 0)
		free (found_files[deps_found]);
	      while (intermediate_files_found-- > 0)
		{
		  register struct file *f
		    = intermediate_files[intermediate_files_found];
		  if (f->stem < f->name
		      || (f->stem > f->name
			  && (f->stem - f->name) <= strlen (f->name)))
		    free (f->stem);
		}
	    }
	  else
	    /* This pattern rule does apply.  Stop looking for one.  */
	    break;
	}

      /* If we found an applicable rule with intermed_ok == 0,
	 don't try intermed_ok == 1.  */
      if (i < nrules)
	break;

      rule = 0;
    }

  /* RULE is nil if the loop went all the way through and everything failed.  */
  if (!rule)
    return 0;

  /* FOUND_FILES lists the dependencies for the rule we found.
     This includes the intermediate file, if any.
     Convert them into entries on the deps-chain of FILE.  */

  while (deps_found-- > 0)
    {
      register char *s;

      dep = (struct dep *) xmalloc (sizeof (struct dep));
      s = dep->name = found_files[deps_found];
      if (recursions == 0)
	dep->file = enter_file (s);
      dep->next = file->deps;
      file->deps = dep;

      /* If the new dependency duplicates an old one, delete the old one. */
      while (dep)
	{
	  if (dep->next && streq (dep->next->name, s))
	    dep->next = dep->next->next;
	  else
	    dep = dep->next;
	}
    }

  file->stem = !stem[stemlen] ? stem : savestring (stem, stemlen);
  file->cmds = rule->cmds;
  file->recursive = file->recursive || rule->recursive;

  /* If we need to use an intermediate file,
     make sure it is entered as a target, with the info that was
     found for it in the recursive pattern_search call.
     We know that the intermediate file did not already exist as
     a target; therefore we can assume that the deps and cmds
     of F below are null before we change them.  */

  while (intermediate_files_found-- > 0)
    {
      struct file *imf = intermediate_files[intermediate_files_found];
      register struct file *f = enter_file (imf->name);
      f->deps = imf->deps;
      f->cmds = imf->cmds;
      f->stem = imf->stem;
      f->precious = imf->precious;
      f->intermediate = 1;
      f->tried_implicit = 1;
      for (dep = f->deps; dep; dep = dep->next)
	dep->file = enter_file (dep->name);
      num_intermediates++;
    }

  return 1;
}

/* Compute the maximum dependency length and maximum number of
   dependencies of all implicit rules.  Also sets the subdir
   flag for a rule when appropriate.  */

void
count_implicit_rule_limits ()
{
  char *name = 0;
  int namelen = 0;
  register struct rule *rule, *lastrule;

  num_pattern_rules = 0;

  lastrule = pattern_rules;
  for (rule = pattern_rules; rule; lastrule = rule, rule = rule->next)
    {
      int ndeps = 0;
      struct dep *dep;

      num_pattern_rules++;

      for (dep = rule->deps; dep; dep = dep->next)
	{
	  int len = strlen (dep->name);
	  char *p = rindex (dep->name, '/');
	  char *p2 = p ? index (dep->name, '%') : 0;
	  if (len > max_pattern_dep_length)
	    max_pattern_dep_length = len;
	  ndeps++;
	  if (p && p2 > p)
	    {
	      if ((p - dep->name) > namelen)
		{
		  if (name)
		    free (name);
		  namelen = p - dep->name;
		  name = (char *) xmalloc (namelen + 1);
		}
	      bcopy (dep->name, name, p - dep->name);
	      name[p - dep->name] = '\0';
	      if (dir_file_exists_p (name, "."))
		rule->subdir = 0;
	      else
		{
		  struct stat buf;
		  if (stat (name, &buf) < 0
		      || (buf.st_mode & S_IFMT) != S_IFDIR)
		    {
		      if (*name == '/')
			{
			  if (rule == pattern_rules)
			    pattern_rules = rule->next;
			  else
			    lastrule->next = rule->next;
			  free (rule->name);
			  free (rule);
			}
		      else
			rule->subdir = 1;
		    }
		  else
		    {
		      dir_load (name);
		      rule->subdir = 0;
		    }
		}
	    }
	}
      if (ndeps > max_pattern_deps)
	max_pattern_deps = ndeps;
    }

  if (name)
    free (name);
}

/* Read a line of text from `stream' into `linebuffer'.
   Combine continuation lines into one line.
   Return the number of actual lines read. (> 1 if hacked continuation lines)
 */

long
readline (linebuffer, stream, filename, lineno)
     struct linebuffer *linebuffer;
     FILE *stream;
     char *filename;
     long lineno;
{
  register int c;
  char *buffer = linebuffer->buffer;
  register char *p = linebuffer->buffer;
  register char *end = p + linebuffer->size;
  register int backslash = 0;
  register int command = 0;
  register long nlines = 0;

  while (1)
    {
      if (p == end)
	{
	  register int delta = linebuffer->size;
	  end += delta;
	  buffer = (char *) xrealloc (buffer, linebuffer->size += delta);
	  delta = buffer - linebuffer->buffer;
	  p += delta;
	  end += delta;
	  linebuffer->buffer = buffer;
	}
      c = getc (stream);

      if (c < 0)
	/* EOF */
	break;

      if (c == '\0')
	{
	  /* C (and un*x) suck */
	  fatal ("%s:%ld: null character in makefile",
		 filename, lineno + nlines);
	}

      if (c == '\n')
	{
	  if (!backslash)
	    /* Line not continued.  Return what we have so far.  */
	    break;

	  /* Line ends with odd number of backslashes -- continuation!  */
	  /* We leave backslashes before newlines and whitespace
	     after intact for commands.  */
	  if (command < 1)
	    {
	      /* Discard the backslash that means continuation.  */
	      --p;
	      backslash = 0;

	      /* Discard whitespace at start of next line.  */
	      while ((c = getc (stream)) == ' ' || c == '\t')
		;
	      ungetc (c, stream);
	      /* Replace it all with one space.  */
	      c = ' ';
	    }
	  else
	    {
	      /* Eat a leading tab on a continued command line.  */
	      c = getc (stream);
	      if (c != '\t')
		ungetc (c, stream);
	      c = '\n';
	    }
	  nlines++;
	}

      if (command < 1)
	{
	  if (c == ';' || (command == 0 && !backslash && c == '\t'))
	    command = 1;
	  else
	    command = -1;
	}

      if (c == '#' && command < 1)
	{
	  while (1)
	    {
	      c = getc (stream);
	      if (c < 0)
		break;
	      if (c == '\n')
		{
		  ++nlines;
		  if (!backslash)
		    break;
		}
	      backslash = c == '\\';
	    }
	  backslash = 0;
	  break;
	}

      if (c == '\\')
	backslash = !backslash;
      else
	backslash = 0;

      *p++ = c;
    }

  *p = '\0';
  nlines++;
  return (nlines);
}

int
ar_scan_1 (name, function)
     char *name;
     int (*function) ();
{
  char *arname;
  char *memname;
  char *p;
  int val;

  /* This "file" is an archive member */
  p = index (name, '(');
  arname = savestring (name, p - name);
  memname = savestring (p + 1, strlen (p) - 2);

  val = ar_scan (arname, function, memname);
  free (arname);
  free (memname);
  return (val);
}

/* ARGUSED */
int
ar_member_date_1 (desc, name, hdrpos, datapos, size, date, uid, gid, mode, mem)
     int desc;
     char *name;
     int hdrpos, datapos, size, date, uid, gid, mode;
     char *mem;
{
  if (streq (name, mem))
    return (date);
  else
    return (0);
}

int
ar_member_date (name)
     char *name;
{
  return (ar_scan_1 (name, ar_member_date_1));
}

int
ar_touch (name)
     char *name;
{
  register char *p, *arname, *memname;
  register int val;

  p = index (name, '(');
  arname = savestring (name, p - name);
  memname = savestring (p + 1, strlen (p) - 2);

  val = ar_member_touch (arname, memname);
  if (val == -2)
    fatal ("Invalid archive %s", arname);
  if (val < 0)
    pfatal_with_name (arname);
  if (val > 0)
    error ("touch: No such archive member %s", name);

  free (arname);
  free (memname);

  return (val);
}

/* Execute LINE as a command.  Try to avoid forking a shell.
   This routine handles only ' quoting.  Starting quotes may be
   escaped with a backslash.  If any of the characters ;"*?[]&|<>(){}=
   is seen, or any of the builtin commands listed in sh_cmds[]
   is the first word of a line, the shell is used.  */

int
execute_command_line (line)
     char *line;
{
  static char *sh_cmds[] = { "cd", "eval", "exec", "exit", "login",
			     "logout", "set", "umask", "wait", "while", "for",
			     "case", "if", ":", ".", "break", "continue",
			     "export", "read", "readonly", "shift", "times",
			     "trap", "switch", 0 };
  register int i;
  register char *p;
  register char *ap;
  char *end;
  int instring;
  union wait status;
  int pid;
  char **new_argv;

  new_environ ();

  i = strlen (line) + 1;

  /* More than 1 arg per character is impossible.  */
  new_argv = (char **) alloca (i * sizeof (char *));

  /* All the args can fit in a buffer as big as LINE is.   */
  ap = new_argv[0] = (char *) alloca (i);
  end = ap + i;

  /* I is how many complete arguments have been found.  */
  i = 0;
  instring = 0;
  for (p = line; *p; ++p)
    {
      if (ap > end)
	{
	  fflush (stdout);
	  fflush (stderr);
	  abort ();
	}

      if (instring)
	{
	  /* Inside a string, just copy any char except a closing quote.  */
	  if (*p == '\'')
	    instring = 0;
	  else
	    *ap++ = *p;
	}
      else
	/* Not inside a string.  */
	switch (*p)
	  {
	  case '\\':
	    if (p[1] && p[1] != '\n')
	      /* Copy and skip the following char.  */
	      *ap++ = *++p;
	    break;

	  case '\'':
	    instring = 1;
	    break;

	  case ';':
	  case '"':
	  case '*':
	  case '?':
	  case '[':
	  case ']':
	  case '$':
	  case '<':
	  case '>':
	  case '|':
	  case '&':
	  case '=':
	  case '~':
	  case '`':
	  case '(':
	  case ')':
	  case '{':
	  case '}':
	    goto slow;

	  case '\n':
	  case ' ':
	  case '\t':
	    /* We have the end of an argument.
	       Terminate the text of the argument.  */
	    *ap++ = '\0';
	    new_argv[++i] = ap;
	    /* If this argument is the command name,
	       see if it is a built-in shell command.
	       If so, have the shell handle it.  */
	    if (i == 1)
	      {
		register int j;
		for (j = 0; sh_cmds[j]; ++j)
		  if (streq (sh_cmds[j], new_argv[0]))
		    goto slow;
	      }
	    /* Ignore multiple whitespace.  */
	    while (*p == ' ' || *p == '\t')
	      ++p;
	    /* Next iteration should examine the first nonwhite char.  */
	    --p;
	    break;

	  case '#':
	    /* # starts a comment, at beginning of word.  */
	    if (p == line || p[-1] == ' ' || p[-1] == '\t')
	      goto endloop;

	    /* Drops in */
	  default:
	    *ap++ = *p;
	    break;
	  }
    }

 endloop:

  /* Terminate the last argument and the argument list.  */

  *ap = 0;
  if (new_argv[i][0] != 0)
    ++i;
  new_argv[i] = 0;

  if (new_argv[0] == 0)
    /* Line was empty */
    return 0;

  /* Run the command.  */

  pid = vfork ();
  if (pid == 0)
    {
      execvp (new_argv[0], new_argv);
      _exit (127);
    }

  if (pid < 0)
    return (127);

  /* Wait for termination and report the results.  */

  while (1)
    {
      int wpid;
      wpid = wait (&status);
      if (wpid < 0)
	return (127);
      else if (wpid != pid)
	continue;
      else if (WIFEXITED (status))
	return (status.w_retcode);
      else if (WIFSIGNALED (status))
	{
	  struct stat st;

	  /* Delete the output file that the command was supposed to make.  */

	  if (signal_delete_file
	      && stat (signal_delete_file, &st) >= 0
	      && (st.st_mode & S_IFMT) != S_IFDIR
	      && st.st_mtime != signal_delete_mtime)
	    {
	      fprintf (stderr, "\nDeleting file %s\n", signal_delete_file);
	      fflush (stderr);
	      unlink (signal_delete_file);
	    }

	  /* Treat this as failure.  */

	  return SIGNAL_STATUS + status.w_termsig;
	}
    }

  /* Come here if the command is too complicated to handle directly.
     Use a shell to handle it.  */

 slow:
  return (run_shell_command (line));
}

/* New_environ () sets environ with a new environment for child
   processes.  The storage is freed at the next call to this routine.
   The child's MAKELEVEL variable is incremented.  */

void
new_environ ()
{
  extern char **environ;
  register int macro_count, i, mcnt;
  register struct macro *m;

  static int free_env = 0;

  if (free_env)
    {
      for (i = 0; environ[i]; ++i)
	free (environ[i]);
      free (environ);
    }

#define	identifier_char(c) \
  (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') \
   || ((c) >= '0' && (c) <= '9') || (c) == '_')

  macro_count = 0;
  for (i = 0; i < MACRO_BUCKETS; ++i)
    for (m = macros[i]; m; m = m->next)
      {
	register char *p;
	for (p = m->name; *p; ++p)
	  if (!identifier_char (*p))
	    break;
	if (*p == 0)
	  ++macro_count;
      }

  environ = (char **) xmalloc ((macro_count + 2) * sizeof (char *));

  mcnt = 0;
  for (i = 0; i < MACRO_BUCKETS; ++i)
    for (m = macros[i]; m; m = m->next)
      {
	register char *p;

	for (p = m->name; *p; ++p)
	  if (!identifier_char (*p))
	    break;
	if (*p == '\0')
	  {
	    /* 663 mod MACRO_BUCKETS is "MAKELEVEL"s hash bucket number.  */
	    if (i != (663 % MACRO_BUCKETS) || strcmp ("MAKELEVEL", m->name))
	      {
		environ[mcnt] = xmalloc (strlen (m->name) + strlen (m->value) + 2);
		sprintf (environ[mcnt], "%s=%s", m->name, m->value);
	      }
	    ++mcnt;
	  }
      }

  environ[mcnt] = xmalloc (50);
  sprintf (environ[mcnt], "MAKELEVEL=%d", makelevel + 1);

  environ[mcnt + 1] = 0;
  
  free_env = 1;

  return;
}

/* Execute LINE as a command for an inferior shell.
   Wait for completion.
   Return the status that the shell returns.  */

int
run_shell_command (line)
     char *line;
{
  int pid;
  union wait status;
  register char **new_argv;
  register int next_arg;
  register char *s, *arg_start;
  int max_argv;

  max_argv = 4;
  new_argv = (char **) xmalloc (max_argv * sizeof (char *));
  next_arg = 0;

  /* Set up arg 0, which is the name of the shell program.  */
  s = rindex (shell_macro->value, '/');
  if (s)
    ++s;
  else
    s = shell_macro->value;
  new_argv[next_arg++] = s;

  /* Look at the macro SHFLAGS, decompose it into arguments
     and put the arguments into NEW_ARGV.
     First, copy the entire string.  We decompose into
     arguments by storing null characters into the string.  */

  s = alloca (strlen (shflags_macro->value) + 1);
  bcopy (shflags_macro->value, s, strlen (shflags_macro->value) + 1);

  arg_start = 0;
  while (1)
    {
      if (*s == '\\')
	{
	  /* Arg-constituent char.  Record start of new arg
	     unless one has already started.  */
	  if (arg_start == 0)
	    arg_start = s;
	  s++;
	  if (*s) s++;
	}

      switch (*s)
	{
	case '\\':
	  /* Backslash:  Record start of new arg
	     unless one has already started.  */
	  if (arg_start == 0)
	    arg_start = s;
	  /* Include the following character in the arg.  */
	  s++;
	  break;

	case '\0':
	case '\n':
	case '\t':
	case ' ':
	  /* Arg separator char.  If we just ended an arg,
	     store the arg into NEW_ARGV.  */
	  if (arg_start != 0)
	    {
	      if (next_arg == max_argv)
		{
		  max_argv += 2;
		  new_argv = (char **) xrealloc (new_argv,
						 max_argv * sizeof (char *));
		}
	      *s = 0;
	      new_argv[next_arg++] = arg_start;
	      arg_start = 0;
	    }

	default:
	  /* Arg-constituent char.  Record start of new arg
	     unless one has already started.  */
	  if (arg_start == 0)
	    arg_start = s;
	}
      if (*s == 0)
	break;
      s++;
    }

  /* Add a standard shell switch, plus the command it should execute.  */
  new_argv[next_arg++] = "-c";
  new_argv[next_arg++] = line;
  new_argv[next_arg] = 0;

  pid = vfork ();
  if (pid == 0)
    {
      execvp (shell_macro->value, new_argv);
      _exit (127);
    }

  free (new_argv);

  if (pid < 0)
    return (127);

  /* Wait for termination of the shell.  */

  while (1)
    {
      int i = wait (&status);
      if (i != pid)
	continue;
      else if (WIFEXITED (status))
	return (status.w_retcode);
      else if (WIFSIGNALED (status))
	/* If subshell got a fatal signal,
	   give us (in effect) the same one now.
	   if we did't get it already.  */
	fatal_error_signal (status.w_termsig);
    }
}

/* Print N spaces.  */

void
print_spaces (n)
     register int n;
{
  while (n-- > 0)
    putchar (' ');
}

/* Return the mtime of a file, given a struct file.
   Caches the time in the struct file to avoid excess stat calls.
   If the file is not found, VPATH searching and replacement
   is done.  If that fails, a library (-lLIBNAME) is tried but
   the library's actual name (/lib/libLIBNAME.a, etc.) is not
   substituted in.  */

int
f_mtime (file)
     register struct file *file;
{
  register int mtime;

  if (file->last_mtime != 0)
    return (file->last_mtime);

  /* File's mtime is not known;
     must get it now from system.  */

  mtime = name_mtime (file->name);

  if (mtime == -1)
    {
      /* If the stat failed, search VPATH.  */
      if (vpath_search (&(file->name), 0, 0))
	mtime = name_mtime (file->name);
      else
	/* Last resort, is it a library (-lxxx)?  */
	if (file->name[0] == '-' && file->name[1] == 'l')
	  mtime = library_file_mtime (&file->name[2]);
    }

  /* Store the mtime into all the entries for this file.  */

  while (file)
    {
      file->last_mtime = mtime;
      file = file->prev;
    }
  return (mtime);
}

int
name_mtime (name)
     register char *name;
{
  struct stat st;

  if (index (name, '(') && name[strlen (name) - 1] == ')')
    return (ar_member_date (name));

  if (stat (name, &st) < 0)
    return (-1);
  return (st.st_mtime);
}

/* Read the directory named DIRNAME and enter all of its files
   in the dir_hash_table.

   Once a directory's files have been entered,
   `dir_file_exists_p' may be used to check the existence
   of any file in that directory.  */

void
dir_load (dirname)
     char *dirname;
{
  register DIR *reading;
  register struct direct *next;
  int dirhash;
  register char *ptr;

  /* Copy dirname so we can make the hash table entries
     point at something that will never be freed.  */
  dirname = savestring (dirname, strlen (dirname));

  /* Compute hash code of the dir name.
     This is the starting point for hashing each file name.  */

  dirhash = 0;
  ptr = dirname;
  while (*ptr)
    {
      dirhash += *ptr++;
      dirhash = (dirhash << 7) + (dirhash >> 20);
    }

  /* Make a hash table entry for this dir name and no filename,
     to indicate that `dir_load' has been called for this dir.  */
  {
    register int hash;
    register struct dirdata *new;

    /* Compute hash code of this dir name.  */
    hash = dirhash;
    hash &= 0xffffff;
    hash %= DIR_HASH_SIZE;

    /* Add an entry to the hash table.  */

    new = (struct dirdata *) xmalloc (sizeof (struct dirdata));
    new->next = dir_hash_table[hash];
    dir_hash_table[hash] = new;
    new->dir = dirname;
    new->name = "";
    new->impossible = 0;
  }
 
  /* Open the directory and check for errors.  */
  reading = opendir (dirname);
  if (!reading)
    return;

  /* Read the directory entries, and insert the subfiles
     into the `files' table.  */

  while (next = readdir (reading))
    {
      register int hash;
      register struct dirdata *new;

      /* Compute hash code of this file name and dir name.  */
      hash = dirhash;
      ptr = next->d_name;
      while (*ptr)
	{
	  hash += *ptr++;
	  hash = (hash << 7) + (hash >> 20);
	}

      hash &= 0xffffff;
      hash %= DIR_HASH_SIZE;

      /* Add an entry to the hash table.  */

      new = (struct dirdata *) xmalloc (sizeof (struct dirdata));
      new->next = dir_hash_table[hash];
      dir_hash_table[hash] = new;
      new->dir = dirname;
      new->name = savestring (next->d_name, strlen (next->d_name));
      new->impossible = 0;
    }

  closedir (reading);
}

/* Return 1 if the file named NAME exists.
   This could work simply by using `access' or
   by calling `name_mtime', but those ways are too slow.
   Instead, the first inquiry about any particular directory
   records the entire contents of that directory in `dir_hash_table'
   and all inquiries work by checking the table.  */

int
file_exists_p (name)
     register char *name;
{
  char *dirend;
  char *dirname;

  if (index (name, '(') && name[strlen (name) - 1] == ')')
    return (ar_member_date (name) > 0);

  dirend = (char *) rindex (name, '/');
  if (dirend == 0)
    return dir_file_exists_p (".", name);

  dirname = (char *) alloca (dirend - name + 1);
  bcopy (name, dirname, dirend - name);
  dirname[dirend - name] = '\0';
  if (!dir_file_exists_p (dirname, ""))
    dir_load (dirname);
  return dir_file_exists_p (dirname, dirend + 1);
}

char *dir_name ();

/* Marks FILENAME as `impossible' for `file_impossible_p'.
   This means an attempt has been made to search for FILENAME
   as an intermediate file, and it has failed.  */

void
file_impossible (filename)
     char *filename;
{
  register char *name = filename;
  register int hash = 0;
  char *dirend;
  register struct dirdata *new;

  dirend = (char *) rindex (name, '/');

  while (dirend ? name < dirend : *name)
    {
      hash += *name++;
      hash = (hash << 7) + (hash >> 20);
    }

  if (dirend)
    for (name = ++dirend; *name; ++name)
      {
	hash += *name;
	hash = (hash << 7) + (hash >> 20);
      }

  hash &= 0xffffff;
  hash %= DIR_HASH_SIZE;

  new = (struct dirdata *) xmalloc (sizeof (struct dirdata));
  if (dirend)
    {
      --dirend;
      *dirend = '\0';
      new->dir = dir_name (filename);
      *dirend = '/';
      ++dirend;
      new->name = savestring (dirend, strlen (dirend));
    }
  else
    {
      new->dir = dir_name (".");
      new->name = savestring (filename, strlen (filename));
    }
  new->impossible = 1;

  /* Now put this entry in the table.  */

  new->next = dir_hash_table[hash];
  dir_hash_table[hash] = new;
}

/* Returns 1 if FILENAME has been marked impossible.  */

int
file_impossible_p (filename)
     char *filename;
{
  register char *name = filename;
  register int hash = 0;
  char *dirend;
  register struct dirdata *next;

  dirend = (char *) rindex (name, '/');

  while (dirend ? name < dirend : *name)
    {
      hash += *name++;
      hash = (hash << 7) + (hash >> 20);
    }

  if (dirend)
    for (name = ++dirend; *name; ++name)
      {
	hash += *name;
	hash = (hash << 7) + (hash >> 20);
      }

  hash &= 0xffffff;
  hash %= DIR_HASH_SIZE;

  for (next = dir_hash_table[hash]; next; next = next->next)
    if (dirend)
      {
	if (streq (next->name, dirend)
	    && !strncmp (next->dir, filename, dirend - filename - 1))
	  return (next->impossible);
      }
    else if (next->dir[0] == '.' && !next->dir[1]
             && streq (filename, next->name))
      return (next->impossible);

  return (0);
}

/* Return 1 if the name FILENAME in directory DIRNAME
   is entered in the dir hash table.
   FILENAME must contain no slashes.

   If the directory has been loaded and the value is 0,
   then the file did not exist.

   To see if a directory is described by the table,
   call with "." for FILENAME.  */

int
dir_file_exists_p (dirname, filename)
     register char *dirname;
     register char *filename;
{
  register int hash;
  register char *ptr;
  register struct dirdata *next;

  hash = 0;
  ptr = dirname;
  while (*ptr)
    {
      hash += *ptr++;
      hash = (hash << 7) + (hash >> 20);
    }
  ptr = filename;
  while (*ptr)
    {
      hash += *ptr++;
      hash = (hash << 7) + (hash >> 20);
    }

  hash &= 0xffffff;
  hash %= DIR_HASH_SIZE;

  for (next = dir_hash_table[hash]; next; next = next->next)
    if (streq (next->name, filename) && streq (next->dir, dirname))
      return !next->impossible;
  return 0;
}

/* Return the already allocated name in the directory hash table
   that matches DIR.  The lookup should be fast and never fail
   because this routine is called after a dir_load () or
   dir_file_exists_p () call.  */

char *
dir_name (dir)
     char *dir;
{
  register int hash;
  register char *ptr;
  register struct dirdata *next;

  hash = 0;
  ptr = dir;
  while (*ptr)
    {
      hash += *ptr++;
      hash = (hash << 7) + (hash >> 20);
    }

  hash &= 0xffffff;
  hash %= DIR_HASH_SIZE;

  for (next = dir_hash_table[hash]; next; next = next->next)
    if (streq (next->dir, dir))
      return (next->dir);

  /* "Things are getting strange.  Perhaps you'd better quit --More--"  */
  fflush (stdout);
  fflush (stderr);
  abort ();
}

/* Malloc'd null-pointer-terminated list of malloc'd directories
   in the VPATH macro.  Only existing (and readable) directories
   are put in the list.  */

static char **vpath = 0;

/* Maximum length of a VPATH entry.  */
static int maxvpath = 0;

/* Construct the VPATH listing in the two variables above.
   Existing and readable directories that are not "."
   given in the VPATH macro, separated by colons are
   loaded into the directory hash table if they are not there
   and put in the VPATH list with a trailing slash stripped
   off if present (and if the directory is not the root, "/").
   The length of the longest entry in the list is put in MAXVPATH.  */

void
construct_vpath_list ()
{
  static struct macro *vpath_macro = 0;
  static char *save_vpath = 0;
  register int elem;

  /* Get the struct macro for VPATH and put it in VPATH_MACRO
     if we don't have it.  */
  if (!vpath_macro)
    vpath_macro = lookup_macro ("VPATH", 5);

  /* If the VPATH macro has changed or no longer exists and
     the list has any entries, clear them out.  */
  if (vpath
      && (!vpath_macro || !*vpath_macro->value
	  || vpath_macro->value != save_vpath))
    {
      /* Free the old list.  We don't free its entries because
	 they are in use in dirdata structures in the directory
	 hash table.  */
      free (vpath);
      vpath = 0;
      maxvpath = 0;
    }

  /* If the VPATH macro exists and has a non-null value, construct
     a new list.  */
  if (vpath_macro && *vpath_macro->value && vpath_macro->value != save_vpath)
    {
      register char *p;
      char *v;
      int maxelem, len;

      p = save_vpath = vpath_macro->value;

      /* Skip over any initial colons.  */
      while (*p == ':')
	++p;

      /* Figure out the maximum number of VPATH entries and
	 put it in MAXELEM.  We start with 2, one before the
	 first colon and one nil, the list terminator and
	 increment our estimated number for each colon we find.  */
      maxelem = 2;
      while (*p)
	if (*p++ == ':')
	  ++maxelem;

      vpath = (char **) xmalloc (maxelem * sizeof (char *));

      elem = 0;
      p = save_vpath;
      while (*p)
	{
	  /* Find the next entry.  */
	  while (*p && *p == ':')
	    ++p;
	  if (!*p)
	    break;

	  /* Find the end of this entry.  */
	  v = p;
	  while (*p && *p != ':')
	    ++p;

	  len = p - v;
	  /* Make sure there's no trailing slash,
	     but still allow "/" as a directory.  */
	  if (len > 1 && p[-1] == '/')
	    --len;

	  if (len == 1 && *v == '.')
	    {
	      /* The directory "." is in the VPATH list.
		 Turn on the flag to look in the current directory
		 for implicit dependents, but don't add it
		 to the VPATH list.  */
	      search_cwd = 1;
	      continue;
	    }

	  v = savestring (v, len);
	  if (dir_file_exists_p (v, "."))
	    {
	      /* The directory is already in the directory hash table.  */
	      vpath[elem] = dir_name (v);
	      maxvpath = max (maxvpath, len);
	      free (v);
	      ++elem;
	    }
	  else
	    {
	      struct stat st;
	      if (stat (v, &st) < 0 || (st.st_mode & S_IFMT) != S_IFDIR)
		/* Doesn't exist or isn't a directory.  */
		free (v);
	      else
		{
		  /* Exists and is a directory, so put it in the directory
		     hash table and the VPATH list.  */
		  dir_load (v);
		  vpath[elem] = dir_name (v);
		  maxvpath = max (maxvpath, len);
		  free (v);
		  ++elem;
		}
	    }
	}

      if (elem > 0)
	{
	  /* ELEM is now incremented one element past the last
	     entry, to where the nil-pointer terminator goes.
	     Usually this is maxelem - 1.  If not, shrink vpath down.  */
	  if (elem < (maxelem - 1))
	    {
	      maxelem = elem + 1;
	      vpath = (char **) xrealloc (vpath, maxelem * sizeof (char *));
	    }
	  /* Put the nil-pointer terminator on the end of the VPATH list.  */
	  vpath[elem] = 0;
	}
      else
	{
	  /* There were no entries, so free whatever space we allocated.  */
	  free (vpath);
	  vpath = 0;
	  maxvpath = 0;
	}
    }
}

/* Search the VPATH list for a directory where the name pointed
   to by FILE exists.  If it is found, the pointer in FILE
   is set to the newly malloc'd name of the existing file and we return 1.
   Otherwise we return 0.

   If DIRPREFIX is non-null, it specifies a directory prefix to be
   prepended to the name with VPATH directory and DPLEN
   is the length of this prefix.  */

int
vpath_search (file, dirprefix, dplen)
     char **file;
     char *dirprefix;
     int dplen;
{
  char *name, *n;
  char *filename;
  register int i;
  int flen, vlen;
  int name_dplen;
  int exists;

  /* If there are no vpath entries or FILENAME starts at the root,
     there is nothing we can do.  */
  if (!vpath || **file == '/')
    return 0;

  flen = strlen (*file);

  /* Split *FILE into a directory prefix and a name-within-directory.
     NAME_DPLEN gets the length of the prefix; FILENAME gets the
     pointer to the name-within-directory and FLEN is its length.  */

  n = rindex (*file, '/');
  name_dplen = n ? n - *file : 0;
  filename = name_dplen > 0 ? n + 1 : *file;
  if (name_dplen > 0)
    flen -= name_dplen + 1;

  /* Allocate enough space for the directory prefix, the biggest
     VPATH entry, a slash, the filename, and a null terminator.  */
  name = (char *) alloca (dplen + maxvpath + 1 + flen + 1);

  /* Try each VPATH entry.  */
  for (i = 0; vpath[i]; ++i)
    {
      /* Start with the directory prefix, if any,
	 unless this vpath element is absolute.  */
      if (*vpath[i] != '/' && dirprefix != 0)
	{
	  bcopy (dirprefix, name, dplen);
	  n = name + dplen;
	}
      else
	n = name;

      /* Put the next VPATH entry into NAME at N and increment N past it.  */
      vlen = strlen (vpath[i]);
      bcopy (vpath[i], n, vlen);
      n += vlen;

      /* Add the directory prefix already in *FILE.  */
      if (name_dplen > 0)
	{
	  *n++ = '/';
	  bcopy (*file, n, name_dplen);
	  n += name_dplen;
	}

      /* Null-terminate the string.
	 Now NAME is the name of the directory to look in.  */
      *n = '\0';

      /* Make sure the directory exists and we know its contents.  */
      if ((dirprefix || name_dplen > 0) && !dir_file_exists_p (name, "."))
	{
	  struct stat st;
	  if (stat (name, &st) < 0 || (st.st_mode & S_IFMT) != S_IFDIR)
	    /* Doesn't exist or isn't a directory.  */
	    continue;	/* for I  */
	  else
	    dir_load (name);
	}

      /* We know the directory is in the hash table now because either
         construct_vpath_list or the code just above put it there.
	 Does the file we seek exist in it?  */

      exists = dir_file_exists_p (name, filename);

      /* Now add the name-within-directory at the end of NAME.  */

      if (n != name && n[-1] != '/')
	*n++ = '/';
      bcopy (filename, n, flen + 1);

      /* Is the file mentioned in the makefile?
	 That counts as almost existing.  */

      if (exists || lookup_file (name))
	{
	  /* We have found a file.  */
	  /* Store the name we found into *FILE for the caller.  */

	  *file = savestring (name, (n - name) + flen);

	  return 1;
	}
    }

  return 0;
}

/* Return the mtime of a library file specified as -lLIBNAME,
   searching for a suitable library file in the system library directories
   and the VPATH directories.  */

int
library_file_mtime (lib)
     char *lib;
{
  int mtime;
  char *name;

  if (!dir_file_exists_p ("/usr/lib", "."))
    dir_load ("/usr/lib");
  if (!dir_file_exists_p ("/lib", "."))
    dir_load ("/lib");

  lib = concat ("lib", lib, ".a");
  name = concat ("/usr/lib/", lib, "");
  if (dir_file_exists_p ("/usr/lib", lib))
    mtime = name_mtime (name);
  else if (dir_file_exists_p ("/lib", lib))
    mtime = name_mtime (name + 4);
  else if (dir_file_exists_p (".", lib) && vpath_search (&lib, 0, 0))
    mtime = name_mtime (lib);

  free (lib);
  free (name);

  return (mtime);
}

/* Return a newly-allocated string whose contents concatenate those of s1, s2, s3.  */

char *
concat (s1, s2, s3)
     char *s1, *s2, *s3;
{
  register int len1, len2, len3;
  register char *result;

  len1 = *s1 ? strlen (s1) : 0;
  len2 = *s2 ? strlen (s2) : 0;
  len3 = *s3 ? strlen (s3) : 0;

  result = xmalloc (len1 + len2 + len3 + 1);

  if (*s1)
    bcopy (s1, result, len1);
  if (*s2)
    bcopy (s2, result + len1, len2);
  if (*s3)
    bcopy (s3, result + len1 + len2, len3);
  *(result + len1 + len2 + len3) = '\0';

  return (result);
}

/* Print error message and exit.  */

/* VARARGS1 */
void
fatal (s1, s2, s3, s4, s5)
     char *s1, *s2, *s3, *s4, *s5;
{
  fprintf (stderr, "make: ");
  fprintf (stderr, s1, s2, s3, s4, s5);
  fprintf (stderr, ".  Stop.\n");
  if (print_directory_flag)
    log_working_directory("Exiting");
  exit (1);
}

/* Print error message.  `s1' is printf control string, `s2' is arg for it. */

void
error (s1, s2)
     char *s1, *s2;
{
  fprintf (stderr, "make: ");
  fprintf (stderr, s1, s2);
  putc ('\n', stderr);
  fflush (stderr);
}

void
perror_with_name (str, name)
     char *str, *name;
{
  extern int errno, sys_nerr;
  extern char *sys_errlist[];

  fputs (str, stderr);
  if (errno < sys_nerr)
    fprintf (stderr, "%s for %s\n", sys_errlist[errno], name);
  else
    fprintf (stderr, "cannot open %s", name);
  fflush (stderr);
}

void
pfatal_with_name (name)
     char *name;
{
  extern int errno, sys_nerr;
  extern char *sys_errlist[];

  if (errno < sys_nerr)
    fprintf (stderr, "%s for %s\n", sys_errlist[errno], name);
  else
    fprintf (stderr, "cannot open %s\n", name);

  exit (1);
}


/* Like malloc but get fatal error if memory is exhausted.  */
extern char *malloc (), *realloc ();

char *
xmalloc (size)
     long size;
{
  char *result = malloc (size);
  if (!result)
    fatal ("virtual memory exhausted", 0);
  return (result);
}


char *
xrealloc (ptr, size)
     char *ptr;
     long size;
{
  char *result = realloc (ptr, size);
  if (!result)
    fatal ("virtual memory exhausted");
  return (result);
}

char *
savestring (string, length)
     char *string;
     long length;
{
  register char *out = (char *) xmalloc (length + 1);
  if (length > 0) bcopy (string, out, length);
  out[length] = '\0';
  return (out);
}

/* Search string BIG (length BLEN) for an occurrence of
   string SMALL (length SLEN).  Return a pointer to the
   beginning of the first occurrence, or return 0 if none found.  */

char *
sindex (big, blen, small, slen)
     char *big, *small;
     int blen, slen;
{
  register int b;

  if (blen < 1)
    blen = strlen (big);
  if (slen < 1)
    slen = strlen (small);

  for (b = 0; b < blen; ++b)
    if (big[b] == *small && !strncmp (&big[b + 1], small + 1, slen - 1))
      return (&big[b]);

  return (0);
}

/* Limited INDEX:
   Search through the string STRING, which ends at LIMIT, for the character C.
   Returns a pointer to the first occurrence, or 0 if none is found.
   Like INDEX except that the string searched ends where specified
   instead of at the first null.  */

char *
lindex (string, limit, c)
     register char *string, *limit;
     char c;
{
  while (string != limit)
    if (*string++ == c)
      return string - 1;

  return 0;
}

/* Convert old-style suffix rules to pattern rules.
   All rules for the suffixes on the .SUFFIXES list
   are converted and added to the pattern_rules list.  */

void
convert_to_pattern ()
{
  register struct dep *d, *d2, *newd;
  register struct file *f;
  register struct rule *r, *r2;
  register char *rulename = (char *) alloca (maxsuffix * 2 + 1);
  register char *name;
  register int slen, s2len;

  for (d = suffix_file->deps; d; d = d->next)
    {
      slen = strlen (d->name);
      r = (struct rule *) xmalloc (sizeof (struct rule));
      new_pattern_rule (r);
      r->name = savestring ("%", 1 + slen);
      r->patsuffix = r->name + 1;
      bcopy (d->name, r->patsuffix, slen + 1);
      r->namelen = strlen (r->name);
      r->deps = 0;
      r->cmds = 0;
      f = d->file;
      if (f->cmds && !f->deps)
	{
	  for (r = pattern_rules; r; r = r->next)
	    if (!r->name[1] && r->deps && !r->deps->next
		&& r->deps->name[0] == '%'
		&& streq (r->deps->name + 1, d->name))
	      break;
	  if (!r)
	    {
	      /* Record a pattern for this suffix's null-suffix rule.  */
	      r = (struct rule *) xmalloc (sizeof (struct rule));
	      r->cmds = f->cmds;
	      r->recursive = f->recursive;
	      r->name = savestring ("%", 1);
	      r->namelen = 1;
	      r->patsuffix = r->name + 1;
	      /* Match-anything rules converted from suffix rules
		 are terminal.  */
	      r->terminal = 1;
	      newd = (struct dep *) xmalloc (sizeof (struct dep));
	      newd->name = savestring ("%", 1 + slen);
	      bcopy (d->name, newd->name + 1, slen + 1);
	      newd->next = f->deps;
	      r->deps = newd;
	      /* Install this rule.  */
	      new_pattern_rule (r);
	    }
	}

      bcopy (d->name, rulename, slen);
      /* Record a pattern for each of this suffix's
	 two-suffix rules.  */
      for (d2 = suffix_file->deps; d2; d2 = d2->next)
	{
	  if (streq (d->name, d2->name))
	    continue;

	  s2len = strlen (d2->name);
	  bcopy (d2->name, rulename + slen, s2len + 1);
	  f = lookup_file (rulename);
	  if (!f || !f->cmds || f->deps)
	    continue;

	  for (r = pattern_rules; r; r = r->next)
	    if (r->deps && !r->deps->next
	        && r->name[0] == '%' && streq (r->name + 1, d2->name)
	        && r->deps->name[0] == '%'
		&& streq (r->deps->name + 1, d->name))
              break;
	  if (r)
	    continue;

	  r = (struct rule *) xmalloc (sizeof (struct rule));
	  r->cmds = f->cmds;
	  r->recursive = f->recursive;
	  newd = (struct dep *) xmalloc (sizeof (struct dep));
	  if (s2len == 2 && !strcmp (d2->name, ".a"))
	    {
	      /* A suffix rule `.X.a:' is converted into
	         the pattern rule `(%.o): %.X'.  */
	      r->namelen = 4;
	      r->name = savestring ("(%.o)", 4);
	      r->patsuffix = r->name + 2;
	      newd->name = savestring ("%", 1 + s2len);
	      bcopy (d2->name, newd->name, s2len + 1);
	    }
	  else
	    {
	      r->namelen = 1 + s2len;
	      r->name = savestring ("%", 1 + s2len);
	      r->patsuffix = r->name + 1;
	      bcopy (d2->name, r->patsuffix, s2len + 1);
	      newd->name = savestring ("%", 1 + slen);
	      bcopy (d->name, newd->name + 1, slen + 1);
	    }
	  newd->next = f->deps;
	  r->deps = newd;
	  new_pattern_rule (r);
	}
    }
}

/* Install the pattern rule RULE (whose fields have been filled in)
   at the end of the list (so that any rules previously defined
   will take precedence).  */

void
new_pattern_rule (rule)
     struct rule *rule;
{
  rule->subdir = 0;
  rule->in_use = 0;

  rule->next = 0;
  if (last_pattern_rule)
    last_pattern_rule->next = rule;
  else
    pattern_rules = rule;
  last_pattern_rule = rule;
}

/* Install an implicit pattern rule based on the three text strings
   in the structure P points to.  These strings come from one of
   the arrays on the preceding page.
   TERMINAL specifies what the `terminal' field of the rule should be.  */

void
install_pattern_rule (p, terminal)
     struct pspec *p;
     int terminal;
{
  struct rule *r;
  char *ptr;

  r = (struct rule *) xmalloc (sizeof (struct rule));
  r->name = p->target;
  r->namelen = strlen (r->name);
  r->patsuffix = index (p->target, '%');
  ++r->patsuffix;

  r->terminal = terminal;
  ptr = p->dep;
  r->deps = (struct dep *) multi_glob (parse_file_seq (&ptr, 0,
                                                       sizeof (struct dep)),
				       "", sizeof (struct dep));
  r->cmds = (struct commands *) xmalloc (sizeof (struct commands));
  r->cmds->filename = 0;
  r->cmds->lineno = 0;
  r->cmds->commands = p->commands;
  r->recursive = sindex (p->commands, 0, "$(MAKE)", 0)
                 || sindex (p->commands, 0, "${MAKE}", 0);

  new_pattern_rule (r);
}

/* Construct the list of include directories from the
   arguments and the default list.  */

void
construct_include_path (argc, argv)
     int argc;
     char **argv;
{
  register int i;
  struct stat stbuf;

  /* Table to hold the dirs, long enough for the worst case
     plus a null pointer at the end.  */

  register char **dirs
    = (char **) xmalloc ((argc
			  + (sizeof (default_include_directories)
			     / sizeof (char *)) - 1)
			 * sizeof (char *));
  /* Number of elements in DIRS currently in use.  */
  register int count = 0;

  include_directories = dirs;

  /* First consider any dirs specified with -I switches.
     Ignore dirs that don't exist.  */

  for (i = 0; i < argc; ++i)
    if (!strcmp (argv[i], "-I"))
      {
	++i;
	if (!argv[i])
	  fatal ("no directory given after -I switch");
	if (stat (argv[i], &stbuf) == 0
	    && (stbuf.st_mode & S_IFMT) == S_IFDIR)
	  dirs[count++] = argv[i];
      }
    else if (!strcmp (argv[i], "-f") || !strcmp (argv[i], "-o"))
      ++i;

  /* Now add at the end the standard default dirs.  */

  for (i = 0; default_include_directories[i]; ++i)
    if (stat (default_include_directories[i], &stbuf) == 0
	&& (stbuf.st_mode & S_IFMT) == S_IFDIR)
      dirs[count++] = default_include_directories[i];

  dirs[count] = 0;

  /* Now compute the maximum length of any name in it.  */

  max_incl_len = 0;
  for (i = 0; i < count; ++i)
    {
      int len = strlen (dirs[i]);
      /* If dir name is written with a trailing slash, discard it.  */
      if (dirs[i][len - 1] == '/')
	dirs[i] = savestring (dirs[i], len - 1);
      max_incl_len = max (max_incl_len, len);
    }
}

/* Return the address of the first whitespace or null in the string S.  */

char *
end_of_token (s)
     char *s;
{
  register char *p = s;
  register int backslash = 0;

  while (*p && (!backslash && (*p != ' ' && *p != '\t')))
    {
      if (*p++ == '\\')
	{
	  backslash = !backslash;
	  while (*p == '/')
	    {
	      backslash = !backslash;
	      ++p;
	    }
	}
      else
	backslash = 0;
    }

  return p;
}

/* Return the address of the first nonwhitespace or null in the string S.  */

char *
next_token (s)
     char *s;
{
  register char *p = s;

  while (*p == ' ' || *p == '\t') ++p;
  return p;
}

/* Find the next token in PTR; return the address of it,
   and store the length of the token into *LENGTHPTR.  */

char *
find_next_token (ptr, lengthptr)
     char **ptr;
     int *lengthptr;
{
  char *p = next_token (*ptr);
  char *end;

  if (*p == 0)
    return 0;

  *ptr = end = end_of_token (p);
  *lengthptr = end - p;
  return p;
}

/* Scan a string and find the whitespace-separated tokens composing it.
   wstok (S) specifies the string to scan, and returns the address of the
   first token.  wstok (0) gets the next token.  Repeat wstok (0) until
   the tokens are exhausted, which is indicated by a value of zero.

   The token that is returned is made into a null-terminated string
   by storing a zero at the end of it.  The following call to wstok
   restores the original contents of that character.  */

char *wstok_last_token_end;	/* Address of end of last token, now a null */
char wstok_saved_end_char;	/* Previous contents of that char */

char *
wstok (s)
     char *s;
{
  char *beg;
  int length;

  if (s != 0)
    wstok_last_token_end = s;
  else
    *wstok_last_token_end = wstok_saved_end_char;

  beg = find_next_token (&wstok_last_token_end, &length);
  wstok_saved_end_char = *wstok_last_token_end;
  *wstok_last_token_end = 0;

  return beg;
}

log_working_directory (message)
     char *message;
{
  char pwdbuf[MAXPATHLEN];

  if (getwd (pwdbuf) != NULL)
    printf("#### %s %s ####\n", message, pwdbuf);
  else
    printf("#### %s unknown directory (%s) ####\n", pwdbuf);
}
